@rjsf/validator-ata 6.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +94 -0
  2. package/dist/compileSchemaValidators.cjs +110 -0
  3. package/dist/compileSchemaValidators.cjs.map +7 -0
  4. package/dist/compileSchemaValidators.esm.js +79 -0
  5. package/dist/compileSchemaValidators.esm.js.map +7 -0
  6. package/dist/index.cjs +461 -0
  7. package/dist/index.cjs.map +7 -0
  8. package/dist/validator-ata.esm.js +450 -0
  9. package/dist/validator-ata.esm.js.map +7 -0
  10. package/dist/validator-ata.umd.js +422 -0
  11. package/lib/compileSchemaValidators.d.ts +16 -0
  12. package/lib/compileSchemaValidators.js +21 -0
  13. package/lib/compileSchemaValidators.js.map +1 -0
  14. package/lib/compileSchemaValidatorsCode.d.ts +13 -0
  15. package/lib/compileSchemaValidatorsCode.js +80 -0
  16. package/lib/compileSchemaValidatorsCode.js.map +1 -0
  17. package/lib/createAtaInstance.d.ts +27 -0
  18. package/lib/createAtaInstance.js +68 -0
  19. package/lib/createAtaInstance.js.map +1 -0
  20. package/lib/createPrecompiledValidator.d.ts +15 -0
  21. package/lib/createPrecompiledValidator.js +17 -0
  22. package/lib/createPrecompiledValidator.js.map +1 -0
  23. package/lib/customizeValidator.d.ts +8 -0
  24. package/lib/customizeValidator.js +9 -0
  25. package/lib/customizeValidator.js.map +1 -0
  26. package/lib/index.d.ts +7 -0
  27. package/lib/index.js +7 -0
  28. package/lib/index.js.map +1 -0
  29. package/lib/precompiledValidator.d.ts +89 -0
  30. package/lib/precompiledValidator.js +107 -0
  31. package/lib/precompiledValidator.js.map +1 -0
  32. package/lib/processRawValidationErrors.d.ts +28 -0
  33. package/lib/processRawValidationErrors.js +137 -0
  34. package/lib/processRawValidationErrors.js.map +1 -0
  35. package/lib/tsconfig.tsbuildinfo +1 -0
  36. package/lib/types.d.ts +63 -0
  37. package/lib/types.js +2 -0
  38. package/lib/types.js.map +1 -0
  39. package/lib/validator.d.ts +85 -0
  40. package/lib/validator.js +154 -0
  41. package/lib/validator.js.map +1 -0
  42. package/package.json +113 -0
  43. package/src/compileSchemaValidators.ts +30 -0
  44. package/src/compileSchemaValidatorsCode.ts +92 -0
  45. package/src/createAtaInstance.ts +81 -0
  46. package/src/createPrecompiledValidator.ts +29 -0
  47. package/src/customizeValidator.ts +16 -0
  48. package/src/index.ts +8 -0
  49. package/src/precompiledValidator.ts +188 -0
  50. package/src/processRawValidationErrors.ts +197 -0
  51. package/src/tsconfig.json +15 -0
  52. package/src/types.ts +71 -0
  53. package/src/validator.ts +231 -0
package/src/types.ts ADDED
@@ -0,0 +1,71 @@
1
+ import type { ValidationError, Validator, ValidatorOptions } from 'ata-validator';
2
+
3
+ /** Custom format checker. Receives a string and returns true when the value
4
+ * is considered valid for this format. Mirrors the function shape used by
5
+ * `ata-validator`'s `formats` option.
6
+ */
7
+ export type AtaFormatChecker = (value: string) => boolean;
8
+
9
+ /** Controls which duplicate error filtering is suppressed; see
10
+ * `processRawValidationErrors#filterDuplicateErrors` for the full semantics.
11
+ * Mirrors `@rjsf/validator-ajv8`'s option of the same name.
12
+ */
13
+ export type SuppressDuplicateFilteringType = 'anyOf' | 'oneOf' | 'all' | 'none';
14
+
15
+ /** A function that takes a list of `ata-validator` `ValidationError`s and
16
+ * mutates them in place (or replaces messages) to produce localized output.
17
+ * Same shape as the AJV-validator `Localizer`, except the input type is
18
+ * `ata-validator`'s `ValidationError` rather than ajv's `ErrorObject`.
19
+ */
20
+ export type Localizer = (errors?: null | ValidationError[]) => void;
21
+
22
+ /** Options used to customize the underlying `ata-validator` instance.
23
+ *
24
+ * The shape mirrors `@rjsf/validator-ajv8`'s `CustomValidatorOptionsType`
25
+ * where there is a direct correspondence; AJV-only knobs (`AjvClass`,
26
+ * `ajvFormatOptions`, `ajvOptionsOverrides`) are intentionally omitted
27
+ * because they don't map to ata's API. `extenderFn` is preserved so users
28
+ * can run arbitrary setup against the constructed `Validator`.
29
+ */
30
+ export interface CustomValidatorOptionsType {
31
+ /** Additional schemas registered for cross-schema `$ref` resolution.
32
+ * Mirrors `ajv.addMetaSchema` / `ajv.addSchema` semantics; ata resolves
33
+ * `$ref` against the registered set.
34
+ */
35
+ additionalMetaSchemas?: ReadonlyArray<object>;
36
+
37
+ /** Custom format checkers. Keys are format names referenced from `format`
38
+ * in the schema. Values are validation functions, RegExps, or pre-anchored
39
+ * regex source strings (compiled into a function for ata).
40
+ */
41
+ customFormats?: {
42
+ [k: string]: string | RegExp | AtaFormatChecker;
43
+ };
44
+
45
+ /** Overrides spread on top of the default `ata-validator` options. Use this
46
+ * to flip `coerceTypes`, `removeAdditional`, `verbose`, or `abortEarly`.
47
+ */
48
+ ataOptionsOverrides?: ValidatorOptions;
49
+
50
+ /** Hook for applying additional setup against a freshly-built `Validator`.
51
+ * Returning a different instance is supported.
52
+ */
53
+ extenderFn?: (validator: Validator) => Validator;
54
+
55
+ /** Suppress duplicate error filtering for the specified keyword(s). See
56
+ * `processRawValidationErrors#filterDuplicateErrors`.
57
+ */
58
+ suppressDuplicateFiltering?: SuppressDuplicateFilteringType;
59
+ }
60
+
61
+ /** The simplified `ValidateFunction` shape produced by ata's compiled
62
+ * standalone modules. Kept for symmetry with the AJV validator package and
63
+ * for the upcoming precompiled-validator support; not consumed by the
64
+ * runtime path in this initial release.
65
+ */
66
+ export interface CompiledValidateFunction {
67
+ errors?: null | ValidationError[];
68
+ (data: unknown): boolean;
69
+ }
70
+
71
+ export type ValidatorFunctions = { [key: string]: CompiledValidateFunction };
@@ -0,0 +1,231 @@
1
+ import {
2
+ CustomValidator,
3
+ deepEquals,
4
+ ErrorTransformer,
5
+ FormContextType,
6
+ hashForSchema,
7
+ ID_KEY,
8
+ RJSFSchema,
9
+ ROOT_SCHEMA_PREFIX,
10
+ StrictRJSFSchema,
11
+ UiSchema,
12
+ ValidationData,
13
+ ValidatorType,
14
+ withIdRefPrefix,
15
+ } from '@rjsf/utils';
16
+ import type { ValidationError, Validator } from 'ata-validator';
17
+ import cloneDeep from 'lodash/cloneDeep';
18
+
19
+ import createAtaInstance from './createAtaInstance';
20
+ import processRawValidationErrors, { type RawValidationErrorsType } from './processRawValidationErrors';
21
+ import type { CustomValidatorOptionsType, Localizer, SuppressDuplicateFilteringType } from './types';
22
+
23
+ /** `ValidatorType` implementation backed by `ata-validator`.
24
+ *
25
+ * ata is schema-bound (one `Validator` per schema) rather than instance-with-
26
+ * registry like AJV, so this class maintains its own per-schema-id cache and
27
+ * registers cross-schema dependencies through ata's `addSchema` so `$ref`
28
+ * still resolves between schemas RJSF passes in.
29
+ */
30
+ export default class ATAValidator<
31
+ T = any,
32
+ S extends StrictRJSFSchema = RJSFSchema,
33
+ F extends FormContextType = any,
34
+ > implements ValidatorType<T, S, F> {
35
+ /** Stable copy of the constructor options, used when (re)building per-schema
36
+ * `Validator` instances on demand.
37
+ *
38
+ * @private
39
+ */
40
+ readonly options: CustomValidatorOptionsType;
41
+
42
+ /** The Localizer function applied to ata errors before they are returned.
43
+ *
44
+ * @private
45
+ */
46
+ readonly localizer?: Localizer;
47
+
48
+ /** Controls which duplicate error filtering is suppressed; see
49
+ * `processRawValidationErrors#filterDuplicateErrors`.
50
+ *
51
+ * @private
52
+ */
53
+ readonly suppressDuplicateFiltering?: SuppressDuplicateFilteringType;
54
+
55
+ /** Per-schema-id cache of constructed ata `Validator` instances. AJV uses a
56
+ * single instance with a schema registry; ata is schema-bound, so we
57
+ * maintain the registry ourselves.
58
+ */
59
+ private readonly validators = new Map<string, { validator: Validator; schema: object }>();
60
+
61
+ /** Most recent `rootSchema` reference seen by `handleSchemaUpdate`, used as
62
+ * a fast-path to skip a deep-equality check when the same root is passed
63
+ * back-to-back.
64
+ */
65
+ private lastSeenRootSchema?: S;
66
+
67
+ /** True once a `rootSchema` has been registered in this lifecycle. */
68
+ private hasRegisteredRootSchema = false;
69
+
70
+ constructor(options: CustomValidatorOptionsType, localizer?: Localizer) {
71
+ this.options = options;
72
+ this.localizer = localizer;
73
+ this.suppressDuplicateFiltering = options.suppressDuplicateFiltering;
74
+ }
75
+
76
+ /** Resets the cached validators and root-schema bookkeeping. Mirrors
77
+ * `AJV8Validator#reset` so RJSF's test harness can flush state between runs.
78
+ */
79
+ reset() {
80
+ this.validators.clear();
81
+ this.lastSeenRootSchema = undefined;
82
+ this.hasRegisteredRootSchema = false;
83
+ }
84
+
85
+ /** The most recently registered rootSchema, kept so we can pass it to ata's
86
+ * `schemas` constructor option when building validators for sub-schemas.
87
+ * This is how `$ref` to root-level definitions resolves under ata's
88
+ * per-schema model (vs AJV's single-instance registry).
89
+ */
90
+ private cachedRootSchema?: object;
91
+
92
+ /** Returns a structural copy of `formData` so ata's default-applier
93
+ * (which writes `default` values into the input object during validation)
94
+ * doesn't leak a mutation back to the caller. RJSF probes the same data
95
+ * through `isValid` repeatedly while resolving oneOf/anyOf options, and
96
+ * a mutated probe changes subsequent answers, so the wrapper has to
97
+ * preserve referential purity that AJV provides by default.
98
+ */
99
+ private cloneForValidation<D>(data: D): D {
100
+ if (data === null || typeof data !== 'object') {
101
+ return data;
102
+ }
103
+ if (typeof globalThis.structuredClone === 'function') {
104
+ return globalThis.structuredClone(data);
105
+ }
106
+ return cloneDeep(data);
107
+ }
108
+
109
+ /** Returns the cached ata `Validator` for the given id, or builds and
110
+ * caches a new one. When a rootSchema has been registered via
111
+ * `handleSchemaUpdate`, it is supplied as a sibling schema so `$ref` to
112
+ * the root resolves regardless of which sub-schema is being validated.
113
+ */
114
+ private getOrBuild(id: string, schema: object): Validator {
115
+ const existing = this.validators.get(id);
116
+ if (existing && deepEquals(existing.schema, schema)) {
117
+ return existing.validator;
118
+ }
119
+ // Pass the rootSchema as a sibling so `$ref` to its definitions resolves.
120
+ // Skip when the schema itself is the root, otherwise ata sees a
121
+ // self-referential addition.
122
+ const siblingRoots = this.cachedRootSchema && this.cachedRootSchema !== schema ? [this.cachedRootSchema] : [];
123
+ const optionsWithSchemas = {
124
+ ...this.options,
125
+ ataOptionsOverrides: {
126
+ ...(this.options.ataOptionsOverrides || {}),
127
+ ...(siblingRoots.length ? { schemas: siblingRoots } : {}),
128
+ },
129
+ };
130
+ const validator = createAtaInstance(schema, optionsWithSchemas);
131
+ this.validators.set(id, { validator, schema });
132
+ return validator;
133
+ }
134
+
135
+ /** Runs raw validation against the given schema. Equivalent to
136
+ * `AJV8Validator#rawValidation`: returns ata's error array (already in
137
+ * AJV-compatible shape) plus any compilation error encountered.
138
+ */
139
+ rawValidation<Result = any>(schema: S, formData?: T): RawValidationErrorsType<Result> {
140
+ let compilationError: Error | undefined;
141
+ let errors: ValidationError[] | undefined;
142
+
143
+ try {
144
+ const id = (schema[ID_KEY] as string | undefined) ?? hashForSchema(schema);
145
+ const validator = this.getOrBuild(id, schema);
146
+ const result = validator.validate(this.cloneForValidation(formData));
147
+ errors = result.valid ? undefined : result.errors;
148
+
149
+ if (errors && typeof this.localizer === 'function') {
150
+ // ata freezes `error.params`, so the AJV-validator's pre-quote dance
151
+ // (used to coax `ajv-i18n` into producing quoted property names)
152
+ // can't be applied verbatim. The hook is invoked with the raw
153
+ // ata errors; localizers that mutate `message` in place still work.
154
+ this.localizer(errors);
155
+ }
156
+ } catch (err) {
157
+ compilationError = err as Error;
158
+ }
159
+
160
+ return {
161
+ errors: errors as unknown as Result[] | undefined,
162
+ validationError: compilationError,
163
+ };
164
+ }
165
+
166
+ /** Validates `formData` and returns RJSF's `ValidationData<T>`. See
167
+ * `processRawValidationErrors` for the shape of the post-processing
168
+ * pipeline (custom validation, transform hook, ui-title resolution).
169
+ */
170
+ validateFormData(
171
+ formData: T | undefined,
172
+ schema: S,
173
+ customValidate?: CustomValidator<T, S, F>,
174
+ transformErrors?: ErrorTransformer<T, S, F>,
175
+ uiSchema?: UiSchema<T, S, F>,
176
+ ): ValidationData<T> {
177
+ const rawErrors = this.rawValidation<ValidationError>(schema, formData);
178
+ return processRawValidationErrors(
179
+ this,
180
+ rawErrors,
181
+ formData,
182
+ schema,
183
+ customValidate,
184
+ transformErrors,
185
+ uiSchema,
186
+ this.suppressDuplicateFiltering,
187
+ );
188
+ }
189
+
190
+ /** Registers (or refreshes) the rootSchema in the per-schema registry so
191
+ * subsequent `$ref`-resolving validators can see it. Mirrors AJV's
192
+ * `addSchema(rootSchema, rootSchemaId)` flow.
193
+ */
194
+ handleSchemaUpdate(rootSchema: S): void {
195
+ if (this.lastSeenRootSchema === rootSchema && this.hasRegisteredRootSchema) {
196
+ return;
197
+ }
198
+ const rootSchemaId = (rootSchema[ID_KEY] as string | undefined) ?? ROOT_SCHEMA_PREFIX;
199
+ // Inject $id into a copy of the rootSchema so ata's schema registry can
200
+ // resolve `<rootSchemaId>#/...` refs produced by `withIdRefPrefix`.
201
+ // The original user-supplied schema is left untouched.
202
+ const rootWithId =
203
+ rootSchema[ID_KEY] === rootSchemaId
204
+ ? (rootSchema as object)
205
+ : { ...(rootSchema as object), [ID_KEY]: rootSchemaId };
206
+ this.cachedRootSchema = rootWithId;
207
+ const cached = this.validators.get(rootSchemaId);
208
+ if (!cached || !deepEquals(cached.schema, rootWithId)) {
209
+ this.getOrBuild(rootSchemaId, rootWithId);
210
+ }
211
+ this.lastSeenRootSchema = rootSchema;
212
+ this.hasRegisteredRootSchema = true;
213
+ }
214
+
215
+ /** Boolean validation entrypoint. Returns false on validation failure or
216
+ * compilation error. Mirrors `AJV8Validator#isValid` semantics.
217
+ */
218
+ isValid(schema: S, formData: T | undefined, rootSchema: S) {
219
+ try {
220
+ this.handleSchemaUpdate(rootSchema);
221
+ const schemaWithIdRefPrefix = withIdRefPrefix<S>(schema) as S;
222
+ const id = (schemaWithIdRefPrefix[ID_KEY] as string | undefined) ?? hashForSchema(schemaWithIdRefPrefix);
223
+ const validator = this.getOrBuild(id, schemaWithIdRefPrefix);
224
+ return validator.validate(this.cloneForValidation(formData)).valid;
225
+ } catch (e) {
226
+ // eslint-disable-next-line no-console
227
+ console.warn('Error encountered compiling schema:', e);
228
+ return false;
229
+ }
230
+ }
231
+ }