Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type checking to items expression #69

Closed
wants to merge 7 commits into from

Conversation

CharString
Copy link
Contributor

src/context.ts Outdated
@@ -47,6 +48,43 @@ export interface DocumentTypeOption {
};
}

export interface ServiceFetchConfiguration {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hrm, I'm not sure this belongs in the form-builder repository - does something break if you ignore serviceFetchConfiguration in the VariableDefinition type?

Perhaps it makes more sense to pass getInfernoLogicContext via the builder context rather than providing the inputs and creating this context? That way we can build that context in our backend JS and pass it to the builder, and the open-forms specific stuff is more decoupled from the formio domain for the builder? Ultimately you sort of initialize the builder with "here, this is the infernologic type checking context, use that for your type checks and please validate the things in the builder" without the builder itself needing to understand what infer needs (other than the function signature).


const NAME = 'openForms.itemsExpression';

const dataTypeForComponent = (component: AnyComponentSchema): JSONValue => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to add this to the infernologic library itself? In a contrib/formio package or something like that? That would also make it more easily shared between the builder & backend.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend depends on the builder, even if the feature flag is off.

This failed build illustrates why this code lives here: https://github.com/open-formulieren/formio-builder/actions/runs/7101208159/job/19328836339?pr=69

The exhaustiveness checks for components that have been added since the version the PR was based on. CI telling us we should explicitly specify what type these form components expect 💚

@CharString CharString force-pushed the 3597-add-type-checking-to-items-expression branch 2 times, most recently from d33dd0f to 9613441 Compare December 5, 2023 14:12
.storybook/decorators.tsx Outdated Show resolved Hide resolved
@@ -1081,7 +1095,7 @@ export const SelectBoxes: Story = {
isSensitiveData: false,
openForms: {
dataSrc: 'variable',
itemsExpression: {var: 'someVar'},
itemsExpression: {var: 'current_year'}, // valid JSON, invalid expression
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes the validation non-blocking, no? even if it's an invalid expression, it gets submitted and saved, that's what this assertion is doing. What's the reason for not preventing the <form> submission?

src/components/JSONEdit.tsx Outdated Show resolved Hide resolved
src/components/JSONEdit.tsx Outdated Show resolved Hide resolved
src/utils/jsonlogic.ts Show resolved Hide resolved
src/utils/jsonlogic.ts Outdated Show resolved Hide resolved
}
): JSONValue => {
// For now return example values as accepted by InferNoLogic
// But example values cannot distinguish arrays from tuples!
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not even when using [...] as const?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what Chris and you meant here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the issue is that some expressions like ['foo, 'bar'] get inferred as string[] where-as they should be a two-tuple. If you define a fixed-length array of types, then it becomes a tuple in TS: https://www.typescriptlang.org/docs/handbook/basic-types.html#tuple

I was wondering if using the value as const construct would make TS infer it as a tuple rather than an Array

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is not TS, but open-formulieren/InferNoLogic/issues/5

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point the returntype of this function will have to become some form of type annotation. Not just to distinguish array from tuple, but also to distinguish string from date, datetime etc.

checkbox: true,
//@ts-ignore selectboxes always have component.defaultValue (this does work when rewritten as a lengthy switch/case)
selectboxes: component.defaultValue,
npFamilyMembers: {}, // TODO record type
Copy link
Member

@sergei-maertens sergei-maertens Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this eventually becomes the same as selectboxes BUT it can also become a type: 'content' component if there's an error 😬

src/utils/jsonlogic.ts Show resolved Hide resolved
@@ -46,6 +46,7 @@ const JSONEdit: React.FC<JSONEditProps & TextareaHTMLAttributes<HTMLTextAreaElem
}

updateValue(updatedData);
name && validateField(name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sergei-maertens we are hitting an issue here and don't know how to get things working:

name && validateField(name) was added because the updateValue call above did not trigger the validate callback here (even though validateOnChange is set to true).

The issue is data gets out of sync, as here updatedData corresponds to the latest version of the user input data, whereas adding a console.log in the parent validate callback shows an outdated value.

I've tried adding a call to the base Formik onChange:

const {onChange: formikOnChange} = getFieldProps(name);
// Then calling `formikOnChange` in our custom `onChange`

But nothing works out

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't think that wiring up this validate behaviour directly in the component is the right approach. Especially because this JSONEdit component is also used to edit the entire form component, but it could also point at a different subtree that has nothing to do with JSONLogic.

IMO hooking up the validator belongs in the zod validation schema, where you can make use of .refine or .superRefine to invoke this validator:

const schema = z.object({
  itemsExpression: z.record(z.unknown()).superRefine(
    ...  // in the callback here you'd call the `infer` validator/checker
  ),
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cleaner indeed. Unfortunately I seem to be facing robertLichtnow/zod-formik-adapter#15, will have to look closer.

Copy link
Member

@sergei-maertens sergei-maertens Dec 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems weird since the (super)refine is used in the columns component validation. It could be that the error information is present, but just not displayed.

edit: hrm this might be why the validation errors are not shown onChange but only onBlur 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see it being called with some logs, but the error doesn't seem to be displayed.

@Viicos Viicos force-pushed the 3597-add-type-checking-to-items-expression branch from 09a25e8 to d672e94 Compare December 22, 2023 14:13
@Viicos Viicos force-pushed the 3597-add-type-checking-to-items-expression branch 2 times, most recently from 8343b96 to 414a9b0 Compare December 27, 2023 15:11
@sergei-maertens
Copy link
Member

Sorry, postponing this :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create an InferNoLogic Context from Variables Component tab Add typechecking to keuzeopties expressie
3 participants