Skip to content

feat(next): Custom user defined validations #196

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

SimoneErba
Copy link

Allow users to write their custom functions to use in jsonLogic. We register them once when we create the form. Added customJsonLogicOps to the ValidationOptions that is a dictionary of name: function

I added the test in the v0 file because the new one doesn't use createHeadlessForm and mocks the jsonLogic

@SimoneErba SimoneErba changed the title feat: Custom user defined validations feat(next): Custom user defined validations Jun 11, 2025
@lukad
Copy link
Collaborator

lukad commented Jul 7, 2025

Hi @SimoneErba! Thanks for your PR and first of all, sorry for the long delay in getting back to you.

I'd like to accept your PR, but we need to make some adjustments. Unfortunately json-logic has no concept of scopes, instances or similar which means it would be possible for multiple uses of createHeadlessForm to add conflicting custom operators. This could happen in a SPA rendering many different forms.

My proposal here is that we only add the custom ops before validation via add_operation and then remove them afterwards via rm_operation. This should prevent possible conflicts and keep the global json-logic state clean.

@SimoneErba SimoneErba force-pushed the custom-user-defined-validations branch from aaf2ecd to 12a74bd Compare July 8, 2025 10:15
@SimoneErba
Copy link
Author

Hi @lukad, thanks for your review! It makes sense, I changed the code to add and remove the functions everytime we run the validation

@antoniocapelo
Copy link
Collaborator

Hi @SimoneErba , there's a small issue with one of the lint jobs, if you can take a look we can move this to the finish line 🙂

@SimoneErba
Copy link
Author

Hi @antoniocapelo, can you run the CI again to see if it's all good now? Thanks

Comment on lines +266 to +277
if (customJsonLogicOps) {
if (typeof customJsonLogicOps !== 'object' || customJsonLogicOps === null) {
throw new TypeError('validationOptions.customJsonLogicOps must be an object.')
}

for (const [name, func] of Object.entries(customJsonLogicOps)) {
if (typeof func !== 'function') {
throw new TypeError(
`Custom JSON Logic operator '${name}' must be a function, but received type '${typeof func}'.`,
)
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion

Moving this block to a validateCustomJsonLogicOps function would make things easier to read 🙂

Copy link
Author

Choose a reason for hiding this comment

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

@antoniocapelo There was a validateOptions function, I moved it there

next/src/form.ts Outdated
const customJsonLogicOps = options?.validationOptions?.customJsonLogicOps

try {
if (customJsonLogicOps) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion

Similar approach in the other comment, we could have 2 functions:

function addCustomJsonLogicOperations(ops) {
  if (ops) {
          for (const [name, func] of Object.entries(customJsonLogicOps)) {
          jsonLogic.add_operation(name, func)
        }
  }
}

// similar one for removing

So this handleValidation would look like:

const customJsonLogicOps = options?.validationOptions?.customJsonLogicOps

    try {
     addJsonLogicCustomOperations(customJsonLogicOps)

      const updatedSchema = calculateFinalSchema({
        schema,
        values: value,
        options: options.validationOptions,
      })

      const result = validate(value, updatedSchema, options.validationOptions)

      updateFieldProperties(fields, updatedSchema, schema)

      return result
    }
    finally {
     removeJsonLogicCustomOperations(customJsonLogicOps)
    }

Copy link
Author

Choose a reason for hiding this comment

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

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.

3 participants