Repository navigation
feat(core): create no default Ajv instance when a Form Validator is set - #2648
Open
gigibiffi84 wants to merge 18 commits into
Open
gigibiffi84 wants to merge 18 commits into
gigibiffi84 wants to merge 18 commits into
Conversation
Update to latest
The SET_AJV reducer compiled the schema with the new Ajv instance but never wrote it to state, so every later setSchema or re-enabled validation silently went back to the previous instance. Part of eclipsesource#1498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing them with Ajv Combinator tab selection compiled every oneOf/anyOf/allOf branch with Ajv and then ignored all errors except the structural keywords required, additionalProperties, type, enum and const. The new isStructuralMatch evaluates exactly those keywords itself, recursively through properties, patternProperties, items, $ref, nested combinators and if/then/else. Tab selection therefore no longer depends on an Ajv instance or on code generation, so it also works under a Content Security Policy without unsafe-eval. Equivalence with the previous filtered-Ajv behaviour is covered by tests comparing both approaches keyword by keyword. Part of eclipsesource#1498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds the validation seam from issue eclipsesource#1498 as a non-breaking addition: the `validator` init/updateCore option takes a FormValidatorFactory `(schema) => FormValidator` or a FormValidator already bound to the schema. The types mirror the FormValidator / ValidationIssue of the 4.x presentation-model branch, restricted to synchronous results. - The core reducer creates the Form Validator through the factory whenever the schema changes and caches it in `state.formValidator`; `state.validator` keeps holding the compiled Ajv function when Ajv validates, so existing consumers are unaffected. - Issues from custom validators are converted to the Ajv error shape the rest of core and the renderers read (`issuesToErrors`): missing `key` becomes `custom`, `required` issues addressed to the missing property are split into parent path plus `params.missingProperty`, non-error severities are dropped and a missing `parentSchema` is resolved from the form schema. - `createAjvValidator(ajv?)` is the built-in adapter; `compiledAjvValidator(validateFn)` wraps Ajv standalone code for CSP setups without unsafe-eval. - `getValidator(state)` exposes the bound Form Validator. - Switching to NoValidation via setValidationMode now also drops the cached validator, as init and updateCore already did. Precedence: `validator` wins, otherwise `ajv`, otherwise the default Ajv instance. Existing users notice nothing. Part of eclipsesource#1498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Resolved with the bridge's reducer (which already stores the Ajv instance on setAjv), both util exports, and both groups of reducer tests.
Schema based rule conditions were always evaluated with ajv.validate(condition.schema, value), the last place where a custom Form Validator did not apply. - Widen the `ajv` parameter of isVisible, isEnabled, isReadonly, the eval* functions and Runtime.isVisible/isEnabled to RuleValidator: an Ajv instance (unchanged behaviour), a FormValidator (its `matches`, or the Structural Matcher when it has none), a FormValidatorFactory (one Form Validator per condition schema, cached) or undefined (the Structural Matcher alone). - Add matchesConditionSchema and the getRuleValidator selector; core's own mappers pass getRuleValidator(state) instead of getAjv(state). Part of eclipsesource#1498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- React, Vue and Angular JsonForms gain a `validator` prop/input next to `ajv`, forwarded to init/updateCore; Vue adds useValidator(); JsonFormsAngularService.updateCoreState takes an optional validator. - Material and vanilla withAjvProps additionally inject `ruleValidator` (getRuleValidator), used by the categorization layouts; Angular Material evaluates category visibility with getRuleValidator too. - ExampleDescription gains an optional `validator`, passed through by all five example apps; new "Custom validator" example with a dependency-free handwritten Form Validator and a schema-based rule. Part of eclipsesource#1498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rule conditions evaluated without a validator (none configured, or a custom Form Validator without `matches`) only knew the structural keywords. The new isSchemaMatch extends the Structural Matcher with minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minLength, maxLength, pattern, minItems, maxItems, uniqueItems, minProperties, maxProperties and not, mirroring Ajv's semantics, and matchesConditionSchema uses it for both validator-free paths. isStructuralMatch is unchanged, so combinator tab selection keeps ignoring value keywords as before. Part of eclipsesource#1498 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
New package to use any Standard Schema library (Valibot, Zod, ArkType) as the JSON Forms validator: fromStandardSchema derives the JSON Schema through Standard JSON Schema and returns a Form Validator validating with the library itself, so no schema is compiled at runtime and forms work under a CSP without unsafe-eval. - Issue paths become JSON Pointers; Valibot, Zod and ArkType issue kinds map to JSON Schema keywords, others become `custom`. - Asynchronous schemas are rejected with guidance (3.x is synchronous). - New "Standard Schema (Valibot)" example in all five example apps and a serve-csp script to demonstrate the CSP case. - examples rollup config: load .d.mts/.d.cts as empty modules, which rollup-plugin-typescript2 0.34 would otherwise parse as JavaScript. Part of eclipsesource#1498 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a custom `validator` option is in effect and no `ajv` is passed, INIT and UPDATE_CORE no longer create a default Ajv instance, so `core.ajv` stays undefined and nothing can compile schemas with an instance nobody configured. getOrCreateAjv gains an optional `createDefault` parameter; an explicit `ajv` is still stored and switching back to Ajv creates the default as before. vue-vuetify's AdditionalProperties reads Ajv optionally. Ajv is not imported lazily: measured, importing core and createAjv() perform no `new Function` calls (only compile() does), and a lazy import would make the synchronous reducer API asynchronous. Part of eclipsesource#1498 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ Deploy Preview for jsonforms-examples ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #1498. Stacked on #2644 (Form Validator bridge) and the PRs after it; the diff shrinks to the last commit once those are merged.
What changed
When a
validatoroption is configured and noajvis passed, core no longer creates a default Ajv instance.state.jsonforms.core.ajvstaysundefined, so nothing in the form (core, renderers, adopters' code) can compile schemas with an Ajv instance nobody configured.getOrCreateAjv(state, action?, createDefault = true): new optional third parameter;INITandUPDATE_COREpassfalsewhile a custom validator is in effect. The return type is nowAjv | undefined.ajvis still stored. Switching back to Ajv (validator: undefined) creates the default instance as before.AdditionalPropertiesreads Ajv withuseAjv(true), since it may legitimately be absent now.Why not also import Ajv lazily
Measured on the built core: importing
@jsonforms/core(withajvandajv-formats) and callingcreateAjv()perform zeronew Functioncalls; onlycompile()does (4 on the first compile). So the instance itself never violated a CSP, and with a Form Validator configured core never compiles. A lazyimport()would make the synchronous reducer API asynchronous, and the default path still needs Ajv, so bundlers would keep it either way. Removing Ajv from the bundle is the@jsonforms/validator-ajvsplit of 4.x.For adopters
No change without the
validatoroption. With it, code that readscore.ajv/getAjv(state)getsundefinedunless anajvis passed explicitly; rule helpers such asisVisible(..., getAjv(state), ...)keep working (they fall back to core's schema matcher), andgetRuleValidator(state)is the intended replacement.Tests
New
core.test.tscases: no instance acrossinit,updateCore,setSchemaand a validation-mode round trip; explicitajvkept; switching back to Ajv creates the default;getOrCreateAjvwithcreateDefault = false. Adapter end-to-end test assertscore.ajvis undefined. 574 core tests, 13 adapter tests, React (29) and Vue (4) binding tests and vue-vuetify additional/complex tests (17) green; core, the three bindings, the renderer sets, vue-vanilla, vue-vuetify, examples and the adapter build.🤖 Generated with Claude Code