@jarenjs/validate 0.9.2 → 0.34.0
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.
- package/ARCHITECTURE.md +81 -17
- package/README.md +462 -5
- package/dist/types/dollar-data.d.ts +0 -9
- package/dist/types/index.d.ts +167 -69
- package/dist/types/messages.d.ts +142 -0
- package/dist/types/normalize.d.ts +107 -0
- package/dist/types/tools.d.ts +58 -0
- package/docs/ERROR-MESSAGES.md +251 -0
- package/package.json +9 -4
- package/src/array.js +68 -23
- package/src/bigint.js +18 -7
- package/src/combine.js +61 -11
- package/src/condition.js +34 -14
- package/src/content.js +3 -3
- package/src/data.js +11 -387
- package/src/dollar-data.js +55 -472
- package/src/enum.js +0 -1
- package/src/format.js +46 -4
- package/src/index.js +280 -238
- package/src/messages.js +497 -0
- package/src/normalize.js +585 -0
- package/src/number.js +19 -9
- package/src/object.js +126 -33
- package/src/query.js +28 -2
- package/src/schema.js +72 -27
- package/src/string.js +18 -6
- package/src/tools.js +192 -0
- package/src/traverse.js +13 -4
- package/src/unevaluated.js +27 -5
|
@@ -8,13 +8,4 @@
|
|
|
8
8
|
* @returns {function|undefined} The compiled validator function or undefined
|
|
9
9
|
*/
|
|
10
10
|
export declare function compileDollarDataSchema(schemaObj: object, jsonSchema: object): Function | undefined;
|
|
11
|
-
/**
|
|
12
|
-
* Check if the schema has any $data references
|
|
13
|
-
* This is used to determine if we should use the $data-aware compilation path
|
|
14
|
-
* or the standard static compilation path.
|
|
15
|
-
*
|
|
16
|
-
* @param {object} jsonSchema - The JSON schema to check
|
|
17
|
-
* @returns {boolean} True if the schema has any $data references
|
|
18
|
-
*/
|
|
19
|
-
export declare function hasDollarDataReferences(jsonSchema: object): boolean;
|
|
20
11
|
export declare function isDollarDataReference(jsonSchema: any): any;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { TraverseOptions } from './traverse.js';
|
|
2
2
|
import { EvalLog } from './tools.js';
|
|
3
3
|
export { registerFormatCompilers } from './format.js';
|
|
4
|
+
export { ValidationError, messagesEn, compileMessageTemplate, compileMessageCatalog, renderErrorMessage, localizeErrors, } from './messages.js';
|
|
4
5
|
export { TraverseOptions };
|
|
5
6
|
export type DollarDataRef = {
|
|
6
7
|
/**
|
|
@@ -472,38 +473,6 @@ declare class InternalValidationError {
|
|
|
472
473
|
rest: any;
|
|
473
474
|
constructor(obj: any, key: any, expected: any, dataKey: any, value: any, rest: any);
|
|
474
475
|
}
|
|
475
|
-
/**
|
|
476
|
-
* JSON Schema Validation Error
|
|
477
|
-
* Represents a validation error according to the JSON Schema specification.
|
|
478
|
-
* @see https://json-schema.org/draft/2020-12/json-schema-core.html#output
|
|
479
|
-
*/
|
|
480
|
-
export declare class ValidationError {
|
|
481
|
-
keyword: string;
|
|
482
|
-
instancePath: string;
|
|
483
|
-
schemaPath: string;
|
|
484
|
-
params: object;
|
|
485
|
-
message: string;
|
|
486
|
-
/**
|
|
487
|
-
* @param {object} options - Error options
|
|
488
|
-
* @param {string} options.keyword - The keyword that failed validation
|
|
489
|
-
* @param {string} options.instancePath - JSON Pointer to the data location
|
|
490
|
-
* @param {string} options.schemaPath - JSON Pointer to the schema location
|
|
491
|
-
* @param {object} options.params - Keyword-specific parameters
|
|
492
|
-
* @param {string} [options.message] - Human-readable error message
|
|
493
|
-
*/
|
|
494
|
-
constructor(options: {
|
|
495
|
-
keyword: string;
|
|
496
|
-
instancePath: string;
|
|
497
|
-
schemaPath: string;
|
|
498
|
-
params: object;
|
|
499
|
-
message?: string;
|
|
500
|
-
});
|
|
501
|
-
/**
|
|
502
|
-
* Convert error to a plain object
|
|
503
|
-
* @returns {object} Plain object representation
|
|
504
|
-
*/
|
|
505
|
-
toJSON(): object;
|
|
506
|
-
}
|
|
507
476
|
/**
|
|
508
477
|
* ValidationOptions configures the behavior of the validation process.
|
|
509
478
|
* @class
|
|
@@ -523,6 +492,10 @@ export declare class ValidationOptions {
|
|
|
523
492
|
vocabValidation: boolean;
|
|
524
493
|
/** @type {boolean|null} Whether the format keyword asserts (null = auto by draft) */
|
|
525
494
|
formatAssertion: boolean | null;
|
|
495
|
+
/** @type {boolean} Whether collected errors carry rendered message text */
|
|
496
|
+
messages: boolean;
|
|
497
|
+
/** @type {'error'|'ignore'} What an asserting `format` with no registered compiler does */
|
|
498
|
+
unknownFormats: 'error' | 'ignore';
|
|
526
499
|
/**
|
|
527
500
|
* Creates validation options.
|
|
528
501
|
* @param {boolean} [skipErrors=true] - Whether to stop at first error or continue
|
|
@@ -532,8 +505,10 @@ export declare class ValidationOptions {
|
|
|
532
505
|
* @param {number} [draftVersion=7] - The JSON Schema draft version (6, 7, 2019, or 2020)
|
|
533
506
|
* @param {boolean} [vocabValidation=true] - Whether the validation vocabulary is enabled (false when the schema's metaschema omits it via $vocabulary)
|
|
534
507
|
* @param {boolean|null} [formatAssertion=null] - Whether format asserts (null = auto: asserts below draft 2020-12, annotation-only from 2020-12 on)
|
|
508
|
+
* @param {boolean} [messages=true] - Whether collected errors carry rendered message text; false skips rendering (message: '', params/msgid still set)
|
|
509
|
+
* @param {'error'|'ignore'} [unknownFormats='ignore'] - What to do when an ASSERTING `format` names something no compiler is registered for: 'ignore' (the default, and what the specification requires) accepts it as an annotation; 'error' throws at COMPILE time. Never affects instance validation, and never applies where format is annotation-only anyway.
|
|
535
510
|
*/
|
|
536
|
-
constructor(skipErrors?: boolean, useGrapheme?: boolean, collectErrors?: boolean, contentValidation?: boolean | null, draftVersion?: number, vocabValidation?: boolean, formatAssertion?: boolean | null);
|
|
511
|
+
constructor(skipErrors?: boolean, useGrapheme?: boolean, collectErrors?: boolean, contentValidation?: boolean | null, draftVersion?: number, vocabValidation?: boolean, formatAssertion?: boolean | null, messages?: boolean, unknownFormats?: 'error' | 'ignore');
|
|
537
512
|
}
|
|
538
513
|
/**
|
|
539
514
|
* ValidationRoot manages the compilation and validation context for a schema.
|
|
@@ -554,8 +529,6 @@ export declare class ValidationRoot {
|
|
|
554
529
|
* `$ref`s resolve to the owner's `addSchema` registrations
|
|
555
530
|
*/
|
|
556
531
|
constructor(origin: string, schemas: Map<any, any>, formats: Record<string, FormatCompiler>, opts?: ValidationOptions, traverse?: TraverseOptions, owner?: object | null);
|
|
557
|
-
/** @returns {string} The root schema origin/URI */
|
|
558
|
-
get rootOrigin(): string;
|
|
559
532
|
/** @returns {TraverseOptions} Schema traversal options */
|
|
560
533
|
get traverse(): TraverseOptions;
|
|
561
534
|
/** @returns {ValidationOptions} Validation options */
|
|
@@ -564,8 +537,6 @@ export declare class ValidationRoot {
|
|
|
564
537
|
get formats(): object;
|
|
565
538
|
/** @returns {Array} Array of validation errors */
|
|
566
539
|
get errors(): any[];
|
|
567
|
-
/** @returns {ValidationObject} The root schema's ValidationObject */
|
|
568
|
-
get firstSchema(): ValidationObject;
|
|
569
540
|
/** @returns {boolean} Whether any schema in this compilation contains a $data reference */
|
|
570
541
|
get usesDollarData(): boolean;
|
|
571
542
|
/** @returns {boolean} Whether any schema in this compilation contains unevaluatedProperties/unevaluatedItems */
|
|
@@ -574,6 +545,16 @@ export declare class ValidationRoot {
|
|
|
574
545
|
get evalLog(): EvalLog;
|
|
575
546
|
/** @returns {object|null} The owning JarenValidator instance, or null when constructed standalone */
|
|
576
547
|
get owner(): object | null;
|
|
548
|
+
/** @returns {Map<string, object>|null} Compiled 'errorMessage' specs by schema path, or null when the schema set has none */
|
|
549
|
+
get errorMessages(): Map<string, object> | null;
|
|
550
|
+
/**
|
|
551
|
+
* Register a compiled 'errorMessage' spec for a schema location.
|
|
552
|
+
* Called at schema compile time (see compileSchemaObject); the registry
|
|
553
|
+
* is only consulted at report time, over the already-failed set.
|
|
554
|
+
* @param {string} path - The schema path (ValidationObject.path)
|
|
555
|
+
* @param {object} spec - The compiled spec (see messages.js compileErrorMessageSpec)
|
|
556
|
+
*/
|
|
557
|
+
registerErrorMessage(path: string, spec: object): void;
|
|
577
558
|
/**
|
|
578
559
|
* Creates a new ValidationObject for the given path and schema.
|
|
579
560
|
* @param {string} path - The URI path for this schema object
|
|
@@ -588,18 +569,6 @@ export declare class ValidationRoot {
|
|
|
588
569
|
* @returns {ValidationObject|null|undefined} The existing object, null if marked unresolved, or undefined if not known
|
|
589
570
|
*/
|
|
590
571
|
unresolvedObject(path: string): ValidationObject | null | undefined;
|
|
591
|
-
/**
|
|
592
|
-
* Gets the raw schema object for a given reference without compiling it.
|
|
593
|
-
* Used to check schema properties (like $recursiveAnchor) at compile time.
|
|
594
|
-
* @param {string} ref - The reference URI to resolve
|
|
595
|
-
* @param {string} path - The current path (for error messages)
|
|
596
|
-
* @param {object} schema - The schema containing the $ref
|
|
597
|
-
* @returns {{id: string, schema: object}|null} The resolved schema info or null
|
|
598
|
-
*/
|
|
599
|
-
getRawSchema(ref: string, path: string, schema: object): {
|
|
600
|
-
id: string;
|
|
601
|
-
schema: object;
|
|
602
|
-
} | null;
|
|
603
572
|
/**
|
|
604
573
|
* Gets the raw schema object by its URI/ID directly from the schemas map.
|
|
605
574
|
* This performs a direct lookup without following references.
|
|
@@ -621,12 +590,41 @@ export declare class ValidationRoot {
|
|
|
621
590
|
* @returns {boolean} Always returns false for convenience in validators
|
|
622
591
|
*/
|
|
623
592
|
addError(error: InternalValidationError): boolean;
|
|
593
|
+
/**
|
|
594
|
+
* A checkpoint in the collected-error list.
|
|
595
|
+
*
|
|
596
|
+
* A SPECULATIVE applicator - an `anyOf` branch, an `if` condition, the
|
|
597
|
+
* subschema of a `not`, a `contains` candidate - runs a validator whose
|
|
598
|
+
* failure may be entirely expected. Those failures still call `addError`,
|
|
599
|
+
* so without a checkpoint they leak into the caller's issue list and blame
|
|
600
|
+
* a document for not matching a branch it was never required to match.
|
|
601
|
+
* Marking before the probe and rolling back after is the same discipline
|
|
602
|
+
* `EvalLog` already uses for annotations.
|
|
603
|
+
* @returns {number} The mark to pass to {@link rollbackErrors}
|
|
604
|
+
*/
|
|
605
|
+
errorMark(): number;
|
|
606
|
+
/**
|
|
607
|
+
* Discard every error collected since `mark`.
|
|
608
|
+
* @param {number} mark - A value from {@link errorMark}
|
|
609
|
+
*/
|
|
610
|
+
rollbackErrors(mark: number): void;
|
|
624
611
|
/**
|
|
625
612
|
* Validates data against the root schema.
|
|
626
613
|
* @param {unknown} data - The data to validate
|
|
627
614
|
* @returns {boolean} True if valid, false otherwise
|
|
628
615
|
*/
|
|
629
616
|
validate(data: unknown): boolean;
|
|
617
|
+
/**
|
|
618
|
+
* Returns the fastest repeated-validation entry point for this root.
|
|
619
|
+
* Error collection and root-level dynamic anchors need the per-call
|
|
620
|
+
* bookkeeping of validate(); without them the compiled root validator
|
|
621
|
+
* only needs the annotation log cleared (when tracking is on) and can
|
|
622
|
+
* otherwise be invoked directly. Dynamic anchors pushed during
|
|
623
|
+
* validation are balanced by try/finally, so the anchor map needs no
|
|
624
|
+
* per-call clearing here.
|
|
625
|
+
* @returns {(data: unknown) => boolean} The validation entry point
|
|
626
|
+
*/
|
|
627
|
+
createValidateFn(): (data: unknown) => boolean;
|
|
630
628
|
/**
|
|
631
629
|
* Get the stored validator for a dynamic anchor.
|
|
632
630
|
* Used by $dynamicRef for runtime resolution.
|
|
@@ -702,8 +700,6 @@ export declare class ValidationObject {
|
|
|
702
700
|
get path(): string;
|
|
703
701
|
/** @returns {string} The effective base URI for resolving relative $refs */
|
|
704
702
|
get baseUri(): string;
|
|
705
|
-
/** @returns {Array} The current validation errors from the root */
|
|
706
|
-
get errors(): any[];
|
|
707
703
|
/** @returns {function} The compiled validator function */
|
|
708
704
|
get validate(): Function;
|
|
709
705
|
/** @returns {ValidationOptions} The validation options */
|
|
@@ -765,9 +761,103 @@ export declare class ValidatorOptions {
|
|
|
765
761
|
*/
|
|
766
762
|
constructor(formats?: object | object[], schemas?: object[], validation?: ValidationOptions, traverse?: TraverseOptions);
|
|
767
763
|
}
|
|
764
|
+
export type ValidationResultObject = {
|
|
765
|
+
valid: boolean;
|
|
766
|
+
errors: import("./messages.js").ValidationError[];
|
|
767
|
+
};
|
|
768
|
+
export type CompiledPredicate<T> = (data: unknown) => data is T;
|
|
769
|
+
export type CompiledCollector = (data: unknown) => ValidationResultObject;
|
|
770
|
+
export type ValidatorInit<TCollect extends boolean = false> = {
|
|
771
|
+
/**
|
|
772
|
+
* - Format compilers to register
|
|
773
|
+
*/
|
|
774
|
+
formats?: Record<string, FormatCompiler>;
|
|
775
|
+
/**
|
|
776
|
+
* - Schemas to register
|
|
777
|
+
*/
|
|
778
|
+
schemas?: (JSONSchema | boolean)[];
|
|
779
|
+
/**
|
|
780
|
+
* - Validation behavior options
|
|
781
|
+
*/
|
|
782
|
+
validation?: ValidationOptions;
|
|
783
|
+
/**
|
|
784
|
+
* - Schema traversal options
|
|
785
|
+
*/
|
|
786
|
+
traverse?: TraverseOptions;
|
|
787
|
+
/**
|
|
788
|
+
* - Return `{ valid, errors }` instead of a boolean
|
|
789
|
+
*/
|
|
790
|
+
collectErrors?: TCollect;
|
|
791
|
+
/**
|
|
792
|
+
* - Stop at the first failure (defaults to `!collectErrors`)
|
|
793
|
+
*/
|
|
794
|
+
skipErrors?: boolean;
|
|
795
|
+
/**
|
|
796
|
+
* - Count grapheme clusters for string length
|
|
797
|
+
*/
|
|
798
|
+
useGrapheme?: boolean;
|
|
799
|
+
/**
|
|
800
|
+
* - Assert contentEncoding/contentMediaType
|
|
801
|
+
*/
|
|
802
|
+
contentValidation?: boolean;
|
|
803
|
+
/**
|
|
804
|
+
* - The JSON Schema draft version
|
|
805
|
+
*/
|
|
806
|
+
draftVersion?: number;
|
|
807
|
+
/**
|
|
808
|
+
* - Assert the format keyword
|
|
809
|
+
*/
|
|
810
|
+
formatAssertion?: boolean;
|
|
811
|
+
/**
|
|
812
|
+
* - Render English message text on collected errors
|
|
813
|
+
*/
|
|
814
|
+
messages?: boolean;
|
|
815
|
+
/**
|
|
816
|
+
* - What an ASSERTING `format` with no registered compiler does: 'ignore' (default, per spec) accepts it as an annotation, 'error' throws at compile time
|
|
817
|
+
*/
|
|
818
|
+
unknownFormats?: 'error' | 'ignore';
|
|
819
|
+
};
|
|
820
|
+
/**
|
|
821
|
+
* The object a compiled validator returns when `collectErrors` is enabled.
|
|
822
|
+
* @typedef {{ valid: boolean, errors: import("./messages.js").ValidationError[] }} ValidationResultObject
|
|
823
|
+
*/
|
|
824
|
+
/**
|
|
825
|
+
* A compiled validator in the default boolean mode. It is a type guard, so
|
|
826
|
+
* `T` is whatever the caller asserts the schema describes; with no `T` it
|
|
827
|
+
* behaves as an ordinary boolean predicate.
|
|
828
|
+
* @template T
|
|
829
|
+
* @typedef {(data: unknown) => data is T} CompiledPredicate
|
|
830
|
+
*/
|
|
831
|
+
/**
|
|
832
|
+
* A compiled validator in collect-errors mode.
|
|
833
|
+
* @typedef {(data: unknown) => ValidationResultObject} CompiledCollector
|
|
834
|
+
*/
|
|
835
|
+
/**
|
|
836
|
+
* The plain-object form accepted by the JarenValidator constructor, mixing
|
|
837
|
+
* validator-level settings with the ValidationOptions fields.
|
|
838
|
+
* @template {boolean} [TCollect=false]
|
|
839
|
+
* @typedef {object} ValidatorInit
|
|
840
|
+
* @property {Record<string, FormatCompiler>} [formats] - Format compilers to register
|
|
841
|
+
* @property {(JSONSchema | boolean)[]} [schemas] - Schemas to register
|
|
842
|
+
* @property {ValidationOptions} [validation] - Validation behavior options
|
|
843
|
+
* @property {TraverseOptions} [traverse] - Schema traversal options
|
|
844
|
+
* @property {TCollect} [collectErrors] - Return `{ valid, errors }` instead of a boolean
|
|
845
|
+
* @property {boolean} [skipErrors] - Stop at the first failure (defaults to `!collectErrors`)
|
|
846
|
+
* @property {boolean} [useGrapheme] - Count grapheme clusters for string length
|
|
847
|
+
* @property {boolean} [contentValidation] - Assert contentEncoding/contentMediaType
|
|
848
|
+
* @property {number} [draftVersion] - The JSON Schema draft version
|
|
849
|
+
* @property {boolean} [formatAssertion] - Assert the format keyword
|
|
850
|
+
* @property {boolean} [messages] - Render English message text on collected errors
|
|
851
|
+
* @property {'error'|'ignore'} [unknownFormats] - What an ASSERTING `format` with no registered compiler does: 'ignore' (default, per spec) accepts it as an annotation, 'error' throws at compile time
|
|
852
|
+
*/
|
|
768
853
|
/**
|
|
769
854
|
* JarenValidator is the main entry point for JSON Schema validation.
|
|
770
855
|
* It manages schema registration, format registration, and compilation.
|
|
856
|
+
*
|
|
857
|
+
* The `collectErrors` option decides what a compiled validator returns, and
|
|
858
|
+
* it is carried in the type parameter so the two shapes never have to be
|
|
859
|
+
* distinguished at runtime.
|
|
860
|
+
* @template {boolean} [TCollect=false]
|
|
771
861
|
* @class
|
|
772
862
|
* @example
|
|
773
863
|
* const validator = new JarenValidator();
|
|
@@ -775,37 +865,37 @@ export declare class ValidatorOptions {
|
|
|
775
865
|
* const validate = validator.compile({ $ref: 'http://example.com/schema' });
|
|
776
866
|
* const valid = validate({ foo: 'bar' }); // true
|
|
777
867
|
*/
|
|
778
|
-
export declare class JarenValidator {
|
|
868
|
+
export declare class JarenValidator<TCollect extends boolean = false> {
|
|
779
869
|
#private;
|
|
780
870
|
/**
|
|
781
871
|
* Creates a new JarenValidator instance.
|
|
782
|
-
* @param {ValidatorOptions} [options] - Validator options including formats, schemas, validation options, and traverse options
|
|
872
|
+
* @param {ValidatorOptions | ValidatorInit<TCollect>} [options] - Validator options including formats, schemas, validation options, and traverse options
|
|
783
873
|
*/
|
|
784
|
-
constructor(options?: ValidatorOptions);
|
|
874
|
+
constructor(options?: ValidatorOptions | ValidatorInit<TCollect>);
|
|
785
875
|
/**
|
|
786
876
|
* Adds a format validator.
|
|
787
877
|
* @param {string} name - The format name (e.g., 'email', 'uri', 'date-time')
|
|
788
878
|
* @param {FormatCompiler} formatCompiler - A function that compiles format validators
|
|
789
|
-
* @returns {
|
|
879
|
+
* @returns {this} This validator instance for chaining (the polymorphic `this` keeps the collectErrors type parameter across a chain)
|
|
790
880
|
* @example
|
|
791
881
|
* validator.addFormat('custom', (schemaObj, schema) => {
|
|
792
882
|
* return (data) => data.startsWith('custom:');
|
|
793
883
|
* });
|
|
794
884
|
*/
|
|
795
|
-
addFormat(name: string, formatCompiler: FormatCompiler):
|
|
885
|
+
addFormat(name: string, formatCompiler: FormatCompiler): this;
|
|
796
886
|
/**
|
|
797
887
|
* Adds multiple format validators at once.
|
|
798
888
|
* @param {Record<string, FormatCompiler>} formatCompilers - Object mapping format names to compiler functions
|
|
799
|
-
* @returns {
|
|
889
|
+
* @returns {this} This validator instance for chaining (the polymorphic `this` keeps the collectErrors type parameter across a chain)
|
|
800
890
|
*/
|
|
801
|
-
addFormats(formatCompilers: Record<string, FormatCompiler>):
|
|
891
|
+
addFormats(formatCompilers: Record<string, FormatCompiler>): this;
|
|
802
892
|
/**
|
|
803
893
|
* Adds schema(s) to the validator instance.
|
|
804
894
|
* This method does not compile schemas - it only registers them for reference.
|
|
805
895
|
* Dependencies can be added in any order, and circular dependencies are supported.
|
|
806
896
|
* @param {JSONSchema | boolean | (JSONSchema | boolean)[]} schema - The schema(s) to add
|
|
807
897
|
* @param {string} [key] - Optional key/URI to register the schema under
|
|
808
|
-
* @returns {
|
|
898
|
+
* @returns {this} This validator instance for chaining (the polymorphic `this` keeps the collectErrors type parameter across a chain)
|
|
809
899
|
* @example
|
|
810
900
|
* // Add a single schema
|
|
811
901
|
* validator.addSchema({ $id: 'http://example.com/user', type: 'object' });
|
|
@@ -816,18 +906,18 @@ export declare class JarenValidator {
|
|
|
816
906
|
* // Add with explicit key
|
|
817
907
|
* validator.addSchema({ type: 'string' }, 'http://example.com/name');
|
|
818
908
|
*/
|
|
819
|
-
addSchema(schema: JSONSchema | boolean | (JSONSchema | boolean)[], key?: string):
|
|
909
|
+
addSchema(schema: JSONSchema | boolean | (JSONSchema | boolean)[], key?: string): this;
|
|
820
910
|
static normalizeUriKey(key: any): any;
|
|
821
911
|
/**
|
|
822
912
|
* Adds meta-schema(s) that can be used to validate schemas.
|
|
823
913
|
* Meta-schemas are schemas that describe the structure of valid JSON schemas.
|
|
824
914
|
* @param {JSONSchema | boolean | (JSONSchema | boolean)[]} schema - The meta-schema(s) to add
|
|
825
915
|
* @param {string} [key] - Optional key/URI for the meta-schema
|
|
826
|
-
* @returns {
|
|
916
|
+
* @returns {this} This validator instance for chaining (the polymorphic `this` keeps the collectErrors type parameter across a chain)
|
|
827
917
|
* @example
|
|
828
918
|
* validator.addMetaSchema(draft7MetaSchema, 'http://json-schema.org/draft-07/schema');
|
|
829
919
|
*/
|
|
830
|
-
addMetaSchema(schema: JSONSchema | boolean | (JSONSchema | boolean)[], key?: string):
|
|
920
|
+
addMetaSchema(schema: JSONSchema | boolean | (JSONSchema | boolean)[], key?: string): this;
|
|
831
921
|
/**
|
|
832
922
|
* Retrieves a registered schema by its key/URI.
|
|
833
923
|
* @param {string} key - The schema URI/key
|
|
@@ -848,9 +938,16 @@ export declare class JarenValidator {
|
|
|
848
938
|
* Compiles a schema into a validation function.
|
|
849
939
|
* This is the main method for creating validators. It resolves all $ref references,
|
|
850
940
|
* compiles the schema structure, and returns a function that validates data.
|
|
941
|
+
* The return type follows the instance's `collectErrors` setting: a type
|
|
942
|
+
* guard over `unknown` by default, or a function producing
|
|
943
|
+
* `{ valid, errors }` when errors are collected. Jaren does not infer `T`
|
|
944
|
+
* from the schema — the caller asserts what the schema describes, which is
|
|
945
|
+
* what a checked contract wrapper wants; pair it with a schema-to-type
|
|
946
|
+
* generator if you need the shape derived mechanically.
|
|
947
|
+
* @template [T=unknown]
|
|
851
948
|
* @param {JSONSchema | boolean} schema - The schema to compile
|
|
852
949
|
* @param {(JSONSchema | boolean)[]} [schemas] - Additional schemas to reference during compilation
|
|
853
|
-
* @returns {
|
|
950
|
+
* @returns {TCollect extends true ? CompiledCollector : CompiledPredicate<T>} A validation function
|
|
854
951
|
* @example
|
|
855
952
|
* const validate = validator.compile({
|
|
856
953
|
* type: 'object',
|
|
@@ -862,13 +959,14 @@ export declare class JarenValidator {
|
|
|
862
959
|
* const valid = validate({ name: 'John' }); // true
|
|
863
960
|
* const invalid = validate({ name: 123 }); // false
|
|
864
961
|
*
|
|
962
|
+
* // Narrowing to a caller-asserted type
|
|
963
|
+
* const isUser = validator.compile<{ name: string }>(userSchema);
|
|
964
|
+
* if (isUser(input)) input.name; // input is { name: string } here
|
|
965
|
+
*
|
|
865
966
|
* // With error collection
|
|
866
|
-
*
|
|
867
|
-
* const result =
|
|
967
|
+
* const collecting = new JarenValidator({ collectErrors: true });
|
|
968
|
+
* const result = collecting.compile(schema)({ name: 123 });
|
|
868
969
|
* // result = { valid: false, errors: [...] }
|
|
869
970
|
*/
|
|
870
|
-
compile(schema: JSONSchema | boolean, schemas?: (JSONSchema | boolean)[]):
|
|
871
|
-
valid: boolean;
|
|
872
|
-
errors: ValidationError[];
|
|
873
|
-
};
|
|
971
|
+
compile<T = unknown>(schema: JSONSchema | boolean, schemas?: (JSONSchema | boolean)[]): TCollect extends true ? CompiledCollector : CompiledPredicate<T>;
|
|
874
972
|
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
export { compileMessageTemplate, compileMessageCatalog, } from '@jarenjs/core/message';
|
|
2
|
+
/**
|
|
3
|
+
* The built-in English catalog: one entry per message key the validator
|
|
4
|
+
* produces, rendering the exact strings of the historical `#convertErrors`
|
|
5
|
+
* if/else chain. Keywords without an entry (`const`, `enum`,
|
|
6
|
+
* `dependentRequired`, ...) fall back to the generic
|
|
7
|
+
* `validation failed for keyword '<keyword>'` - as before.
|
|
8
|
+
* @type {Record<string, string | ((params: object, error?: object) => string)>}
|
|
9
|
+
*/
|
|
10
|
+
export declare const messagesEn: Record<string, string | ((params: object, error?: object) => string)>;
|
|
11
|
+
/**
|
|
12
|
+
* JSON Schema Validation Error
|
|
13
|
+
* Represents a validation error according to the JSON Schema specification.
|
|
14
|
+
* @see https://json-schema.org/draft/2020-12/json-schema-core.html#output
|
|
15
|
+
*/
|
|
16
|
+
export declare class ValidationError {
|
|
17
|
+
keyword: string;
|
|
18
|
+
instancePath: string;
|
|
19
|
+
schemaPath: string;
|
|
20
|
+
params: object;
|
|
21
|
+
msgid: string;
|
|
22
|
+
message: string;
|
|
23
|
+
/**
|
|
24
|
+
* @param {object} options - Error options
|
|
25
|
+
* @param {string} options.keyword - The keyword that failed validation
|
|
26
|
+
* @param {string} options.instancePath - JSON Pointer to the data location
|
|
27
|
+
* @param {string} options.schemaPath - JSON Pointer to the schema location
|
|
28
|
+
* @param {object} options.params - Keyword-specific parameters
|
|
29
|
+
* @param {string} [options.msgid] - Stable message key resolving this error in a catalog
|
|
30
|
+
* @param {string} [options.message] - Human-readable error message
|
|
31
|
+
*/
|
|
32
|
+
constructor(options: {
|
|
33
|
+
keyword: string;
|
|
34
|
+
instancePath: string;
|
|
35
|
+
schemaPath: string;
|
|
36
|
+
params: object;
|
|
37
|
+
msgid?: string;
|
|
38
|
+
message?: string;
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Convert error to a plain object
|
|
42
|
+
* @returns {object} Plain object representation
|
|
43
|
+
*/
|
|
44
|
+
toJSON(): object;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Render the message of an error through a catalog - the tail of the
|
|
48
|
+
* resolution precedence chain (no `errorMessage` registry involvement):
|
|
49
|
+
* catalog[msgid], built-in English[msgid], catalog[keyword],
|
|
50
|
+
* built-in English[keyword], then the generic fallback text.
|
|
51
|
+
* @param {ValidationError | {keyword: string, msgid?: string, params?: object}} error - The error to render
|
|
52
|
+
* @param {Readonly<Record<string, (params: object, error?: object) => string>>} [catalog] - A compiled catalog (see {@link compileMessageCatalog})
|
|
53
|
+
* @returns {string} The rendered message
|
|
54
|
+
*/
|
|
55
|
+
export declare function renderErrorMessage(error: ValidationError | {
|
|
56
|
+
keyword: string;
|
|
57
|
+
msgid?: string;
|
|
58
|
+
params?: object;
|
|
59
|
+
}, catalog?: Readonly<Record<string, (params: object, error?: object) => string>>): string;
|
|
60
|
+
/**
|
|
61
|
+
* Re-render the `message` of every error from its `msgid` + `params`
|
|
62
|
+
* through the given catalog, with built-in English fallback. This is the
|
|
63
|
+
* whole post-hoc i18n story:
|
|
64
|
+
* `localizeErrors(validate(data).errors, compileMessageCatalog(nl))`.
|
|
65
|
+
*
|
|
66
|
+
* Inline schema-authored messages (a MessageSpec without `$msgid`) are
|
|
67
|
+
* single-language by definition and are NOT re-rendered - that is why
|
|
68
|
+
* `$msgid` exists. An error whose `msgid` resolves in no catalog keeps
|
|
69
|
+
* its current message (e.g. the spec's inline fallback text).
|
|
70
|
+
* @param {ValidationError[]} errors - Errors from a collect-mode validation
|
|
71
|
+
* @param {Readonly<Record<string, (params: object, error?: object) => string>>} catalog - A compiled catalog (see {@link compileMessageCatalog})
|
|
72
|
+
* @returns {ValidationError[]} The same array, messages re-rendered
|
|
73
|
+
*/
|
|
74
|
+
export declare function localizeErrors(errors: ValidationError[], catalog: Readonly<Record<string, (params: object, error?: object) => string>>): ValidationError[];
|
|
75
|
+
export type CompiledMessageSpec = {
|
|
76
|
+
/**
|
|
77
|
+
* - Catalog key to resolve at render time
|
|
78
|
+
*/
|
|
79
|
+
msgid: string | null;
|
|
80
|
+
/**
|
|
81
|
+
* - Compiled inline template
|
|
82
|
+
*/
|
|
83
|
+
render: ((params: object, error?: object) => string) | null;
|
|
84
|
+
/**
|
|
85
|
+
* - Author params, merged OVER the error's params
|
|
86
|
+
*/
|
|
87
|
+
params: object | null;
|
|
88
|
+
};
|
|
89
|
+
export type CompiledErrorMessageNode = {
|
|
90
|
+
/**
|
|
91
|
+
* - String-form spec: covers this node AND its subtree
|
|
92
|
+
*/
|
|
93
|
+
all: CompiledMessageSpec | null;
|
|
94
|
+
/**
|
|
95
|
+
* - Map-form per-keyword specs (this node only)
|
|
96
|
+
*/
|
|
97
|
+
keywords: Map<string, CompiledMessageSpec | {
|
|
98
|
+
perKey: Map<string, CompiledMessageSpec>;
|
|
99
|
+
fallback: CompiledMessageSpec | null;
|
|
100
|
+
}> | null;
|
|
101
|
+
/**
|
|
102
|
+
* - The '_' entry (this node only)
|
|
103
|
+
*/
|
|
104
|
+
catchAll: CompiledMessageSpec | null;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* A compiled 'errorMessage' node registered on the ValidationRoot.
|
|
108
|
+
* @typedef {object} CompiledErrorMessageNode
|
|
109
|
+
* @property {CompiledMessageSpec|null} all - String-form spec: covers this node AND its subtree
|
|
110
|
+
* @property {Map<string, CompiledMessageSpec | {perKey: Map<string, CompiledMessageSpec>, fallback: CompiledMessageSpec|null}>|null} keywords - Map-form per-keyword specs (this node only)
|
|
111
|
+
* @property {CompiledMessageSpec|null} catchAll - The '_' entry (this node only)
|
|
112
|
+
*/
|
|
113
|
+
/**
|
|
114
|
+
* Compile the value of an 'errorMessage' keyword into a registry node.
|
|
115
|
+
* Grammar (validated here, at schema compile time):
|
|
116
|
+
* - MessageSpec (string / `$msgid` object): covers the whole subtree;
|
|
117
|
+
* - map form: per-keyword MessageSpecs for this node, where `required`
|
|
118
|
+
* also accepts a per-missing-property map, `$query` a per-runtime-code
|
|
119
|
+
* map (with `default` for the EBV-false failure), and `_` is the
|
|
120
|
+
* node-level catch-all.
|
|
121
|
+
* @param {unknown} errorMessage - The keyword's value
|
|
122
|
+
* @param {string} path - The schema path, for compile error messages
|
|
123
|
+
* @returns {CompiledErrorMessageNode} The compiled node
|
|
124
|
+
*/
|
|
125
|
+
export declare function compileErrorMessageSpec(errorMessage: unknown, path: string): CompiledErrorMessageNode;
|
|
126
|
+
/**
|
|
127
|
+
* Convert internal validation errors to the public ValidationError format.
|
|
128
|
+
* Params extraction is table-driven off the failed keyword; message text
|
|
129
|
+
* goes through the errorMessage registry (if any) and the built-in
|
|
130
|
+
* English catalog. With `options.messages === false` no message is
|
|
131
|
+
* rendered at all (`message: ''`, params and msgid still set).
|
|
132
|
+
* @param {Array<{object: any, key: string|string[], expected: any, dataKey: any, value: any, rest: any[]}>} internalErrors - The root's internal error records
|
|
133
|
+
* @returns {ValidationError[]} The public errors
|
|
134
|
+
*/
|
|
135
|
+
export declare function convertInternalErrors(internalErrors: Array<{
|
|
136
|
+
object: any;
|
|
137
|
+
key: string | string[];
|
|
138
|
+
expected: any;
|
|
139
|
+
dataKey: any;
|
|
140
|
+
value: any;
|
|
141
|
+
rest: any[];
|
|
142
|
+
}>): ValidationError[];
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
export type Normalizer<In = unknown, Out = In> = (data: In) => Out;
|
|
2
|
+
export type NormalizeOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* - Materialize `default` for absent object properties, recursively
|
|
5
|
+
*/
|
|
6
|
+
useDefaults?: boolean | ((schemaNode: Record<string, unknown>) => boolean);
|
|
7
|
+
/**
|
|
8
|
+
* - Strip unknown properties: `true` only where `additionalProperties: false`, `'all'` wherever an object shape is declared
|
|
9
|
+
*/
|
|
10
|
+
removeAdditional?: boolean | 'all';
|
|
11
|
+
/**
|
|
12
|
+
* - Convert a value to the node's declared scalar `type` when it is convertible
|
|
13
|
+
*/
|
|
14
|
+
coerceTypes?: boolean | ((schemaNode: Record<string, unknown>) => boolean);
|
|
15
|
+
/**
|
|
16
|
+
* - Trim leading/trailing whitespace from strings, before coercion
|
|
17
|
+
*/
|
|
18
|
+
trimStrings?: boolean | ((schemaNode: Record<string, unknown>) => boolean);
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Collect the `$anchor` declarations of one schema document: a map from
|
|
22
|
+
* anchor name to the schema node that declares it. Exported because
|
|
23
|
+
* `@jarenjs/emit` resolves the same references when it derives types, and two
|
|
24
|
+
* walks with different scope rules would make a generated type disagree with
|
|
25
|
+
* this normalizer — the one defect class that package must not have.
|
|
26
|
+
*
|
|
27
|
+
* The scope is the same-document scope the rest of this module uses: a
|
|
28
|
+
* subtree that declares its own `$id` is an embedded resource with its own
|
|
29
|
+
* anchor scope, so it is not descended. First declaration wins, which keeps
|
|
30
|
+
* the map deterministic for a document that (invalidly) repeats a name.
|
|
31
|
+
* @param {object|boolean} root - The root schema of the document
|
|
32
|
+
* @returns {Map<string, object>} anchor name -> schema node
|
|
33
|
+
*/
|
|
34
|
+
export declare function collectSameDocumentAnchors(root: object | boolean): Map<string, object>;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a same-document `$ref` — `#`, `#/` followed by a JSON Pointer, or
|
|
37
|
+
* `#name` for a plain `$anchor` — to the schema it addresses. Refs into other
|
|
38
|
+
* documents are not followed: a normalizer compiles one schema, and reaching
|
|
39
|
+
* a registered sibling would mean owning the whole resolution scope that
|
|
40
|
+
* `compile` owns. Exported for `@jarenjs/emit`, which must resolve references
|
|
41
|
+
* with exactly these rules when it derives the accepted/normalized variants.
|
|
42
|
+
* @param {string} ref - The reference
|
|
43
|
+
* @param {object|boolean} root - The root schema being compiled
|
|
44
|
+
* @param {Map<string, object>} [anchors] - The document's anchor map, from
|
|
45
|
+
* {@link collectSameDocumentAnchors}; omit to skip anchor resolution
|
|
46
|
+
* @returns {object|boolean|undefined} The addressed schema, or undefined
|
|
47
|
+
*/
|
|
48
|
+
export declare function resolveSameDocumentRef(ref: string, root: object | boolean, anchors?: Map<string, object>): object | boolean | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a per-node normalization switch at COMPILE time. Exported because
|
|
51
|
+
* `@jarenjs/emit` has to answer the same question when it derives the accepted
|
|
52
|
+
* and normalized type variants: two implementations of this rule would drift,
|
|
53
|
+
* and a type that disagrees with the normalizer is worse than no type. `true` turns the
|
|
54
|
+
* behavior on everywhere, `false` nowhere, and a predicate decides per schema
|
|
55
|
+
* node — which is how a consumer expresses "trim these 34 string fields, not
|
|
56
|
+
* the other 185" without the option becoming a whole-schema blunt instrument.
|
|
57
|
+
* Because it runs during compilation, a predicate costs nothing at runtime.
|
|
58
|
+
* @param {boolean|((node: Record<string, unknown>) => boolean)|undefined} option
|
|
59
|
+
* @param {object} node - The schema node the switch applies to
|
|
60
|
+
* @returns {boolean}
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveNormalizeSwitch(option: boolean | ((node: Record<string, unknown>) => boolean) | undefined, node: object): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Compile a JSON Schema into a normalizer: a function that returns a
|
|
65
|
+
* normalized copy of its input, leaving the input untouched.
|
|
66
|
+
*
|
|
67
|
+
* Validation is unaffected and unchanged - normalize first, then hand the
|
|
68
|
+
* result to a compiled validator:
|
|
69
|
+
*
|
|
70
|
+
* ```javascript
|
|
71
|
+
* const normalize = compileNormalizer(schema, { useDefaults: true, trimStrings: true });
|
|
72
|
+
* const validate = new JarenValidator({ collectErrors: true }).compile(schema);
|
|
73
|
+
* const shaped = normalize(input);
|
|
74
|
+
* const result = validate(shaped);
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* **What is normalized.** `properties`, `patternProperties`,
|
|
78
|
+
* `additionalProperties`, `items`/`prefixItems`/`additionalItems`, same-document
|
|
79
|
+
* `$ref` (`#`, `#/pointer` and plain `#anchor` forms), and `allOf` (composed,
|
|
80
|
+
* with stripping disabled inside it).
|
|
81
|
+
*
|
|
82
|
+
* **What is not, and why.** `anyOf`, `oneOf`, `if`/`then`/`else` and `not`
|
|
83
|
+
* are not descended: which branch applies is only known after validating,
|
|
84
|
+
* and normalizing under a branch can change which branch validates. Nothing
|
|
85
|
+
* arbitrary runs either - there is no transform hook, because an arbitrary
|
|
86
|
+
* transform is application code, not schema semantics, and belongs on the
|
|
87
|
+
* caller's side of the boundary.
|
|
88
|
+
* @template [In=unknown]
|
|
89
|
+
* @template [Out=In]
|
|
90
|
+
* @param {object|boolean} schema - The schema to compile
|
|
91
|
+
* @param {NormalizeOptions} [options] - Which normalizations to apply
|
|
92
|
+
* @returns {Normalizer<In, Out>} The compiled normalizer
|
|
93
|
+
* @example
|
|
94
|
+
* const normalize = compileNormalizer({
|
|
95
|
+
* type: 'object',
|
|
96
|
+
* properties: {
|
|
97
|
+
* name: { type: 'string' },
|
|
98
|
+
* port: { type: 'integer', default: 8080 },
|
|
99
|
+
* },
|
|
100
|
+
* additionalProperties: false,
|
|
101
|
+
* }, { useDefaults: true, removeAdditional: true, coerceTypes: true, trimStrings: true });
|
|
102
|
+
*
|
|
103
|
+
* const input = { name: ' jaren ', port: '9000', stray: 1 };
|
|
104
|
+
* normalize(input); // { name: 'jaren', port: 9000 }
|
|
105
|
+
* input; // { name: ' jaren ', port: '9000', stray: 1 } - untouched
|
|
106
|
+
*/
|
|
107
|
+
export declare function compileNormalizer<In = unknown, Out = In>(schema: object | boolean, options?: NormalizeOptions): Normalizer<In, Out>;
|