Skip to content

Conversation

@SimoneErba
Copy link
Contributor

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
Contributor 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
Contributor 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
Contributor 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
Contributor Author

Choose a reason for hiding this comment

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

fix test

add and remove functions each time

rebase

try to fix lint

fix lint

move code to new functions
@SimoneErba SimoneErba force-pushed the custom-user-defined-validations branch from ff90548 to d7a0f7b Compare July 16, 2025 16:46
@antoniocapelo
Copy link
Collaborator

@SimoneErba I'm sorry about the delay — I'm about to approve the MR but it seems that because of a v1-release file movement, you'll need to also move your new test to the correct path. Sorry for the disturbance — let me know once it's done and I'll approve this + create a new release for the new feature

@SimoneErba
Copy link
Contributor Author

Hi @antoniocapelo, sorry for the delay. In this branch I did a wrong rebase and so I made a new branch from main, but the problem is that if I run npm run lint I get many format errors, and if I run npm run lint -- --fix I get many changes in the ./json-schema-test-suite folder. Is that fine? Or am I missing something?

@sandrina-p
Copy link
Collaborator

Hi @SimoneErba! For v1, we updated the Node version and you need to use pnpm. The CONTRIBUTING should explain it all. Let us know if get unstuck :)

cc @lukad

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.

4 participants