z-schema 12.2.0 → 12.3.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.
- package/README.md +2 -2
- package/bin/z-schema +1 -1
- package/cjs/{index.js → index.cjs} +696 -687
- package/cjs/{index.d.ts → index.d.cts} +47 -26
- package/dist/{errors.d.mts → errors.d.ts} +2 -2
- package/dist/{errors.mjs → errors.js} +1 -2
- package/dist/{format-validators.mjs → format-validators.js} +43 -36
- package/dist/{index.d.mts → index.d.ts} +9 -9
- package/dist/{index.mjs → index.js} +3 -3
- package/dist/{json-schema-versions.d.mts → json-schema-versions.d.ts} +34 -3
- package/dist/{json-schema.d.mts → json-schema.d.ts} +7 -7
- package/dist/{json-schema.mjs → json-schema.js} +7 -12
- package/dist/{json-validation.mjs → json-validation.js} +143 -127
- package/dist/{report.d.mts → report.d.ts} +7 -8
- package/dist/{report.mjs → report.js} +28 -31
- package/dist/{schema-cache.d.mts → schema-cache.d.ts} +4 -4
- package/dist/{schema-cache.mjs → schema-cache.js} +10 -11
- package/dist/{schema-compiler.d.mts → schema-compiler.d.ts} +4 -4
- package/dist/{schema-compiler.mjs → schema-compiler.js} +95 -77
- package/dist/{schema-validator.d.mts → schema-validator.d.ts} +5 -5
- package/dist/{schema-validator.mjs → schema-validator.js} +138 -166
- package/dist/utils/{array.mjs → array.js} +4 -3
- package/dist/utils/{base64.mjs → base64.js} +3 -2
- package/dist/utils/{clone.mjs → clone.js} +18 -20
- package/dist/utils/{hostname.mjs → hostname.js} +19 -22
- package/dist/utils/{json.mjs → json.js} +11 -7
- package/dist/utils/{schema-regex.mjs → schema-regex.js} +5 -5
- package/dist/utils/{time.mjs → time.js} +5 -5
- package/dist/utils/unicode.js +22 -0
- package/dist/utils/{what-is.mjs → what-is.js} +1 -2
- package/dist/validation/{array.mjs → array.js} +18 -20
- package/dist/validation/{combinators.mjs → combinators.js} +16 -16
- package/dist/validation/{numeric.mjs → numeric.js} +11 -11
- package/dist/validation/{object.mjs → object.js} +35 -34
- package/dist/validation/{ref.mjs → ref.js} +4 -4
- package/dist/validation/{shared.mjs → shared.js} +12 -11
- package/dist/validation/{string.mjs → string.js} +32 -32
- package/dist/validation/type.js +34 -0
- package/dist/{z-schema-base.d.mts → z-schema-base.d.ts} +11 -12
- package/dist/{z-schema-base.mjs → z-schema-base.js} +45 -40
- package/dist/{z-schema-options.d.mts → z-schema-options.d.ts} +3 -3
- package/dist/{z-schema-options.mjs → z-schema-options.js} +4 -4
- package/dist/{z-schema-reader.d.mts → z-schema-reader.d.ts} +1 -1
- package/dist/{z-schema-versions.mjs → z-schema-versions.js} +21 -21
- package/dist/{z-schema.d.mts → z-schema.d.ts} +5 -13
- package/dist/{z-schema.mjs → z-schema.js} +37 -47
- package/package.json +22 -23
- package/src/errors.ts +1 -2
- package/src/format-validators.ts +139 -59
- package/src/json-schema-versions.ts +56 -2
- package/src/json-schema.ts +10 -9
- package/src/json-validation.ts +189 -146
- package/src/report.ts +37 -49
- package/src/schema-cache.ts +13 -13
- package/src/schema-compiler.ts +170 -117
- package/src/schema-validator.ts +239 -238
- package/src/utils/array.ts +9 -6
- package/src/utils/base64.ts +13 -2
- package/src/utils/clone.ts +28 -30
- package/src/utils/date.ts +6 -3
- package/src/utils/hostname.ts +27 -27
- package/src/utils/json.ts +16 -9
- package/src/utils/properties.ts +2 -2
- package/src/utils/schema-regex.ts +4 -4
- package/src/utils/time.ts +5 -5
- package/src/utils/unicode.ts +12 -5
- package/src/utils/what-is.ts +1 -5
- package/src/validation/array.ts +24 -22
- package/src/validation/combinators.ts +14 -14
- package/src/validation/numeric.ts +14 -28
- package/src/validation/object.ts +32 -36
- package/src/validation/ref.ts +5 -6
- package/src/validation/shared.ts +22 -21
- package/src/validation/string.ts +29 -39
- package/src/validation/type.ts +17 -17
- package/src/z-schema-base.ts +49 -38
- package/src/z-schema-options.ts +4 -3
- package/src/z-schema.ts +35 -45
- package/umd/ZSchema.js +711 -695
- package/umd/ZSchema.min.js +2 -2
- package/umd/package.json +3 -0
- package/dist/utils/unicode.mjs +0 -12
- package/dist/validation/type.mjs +0 -32
- /package/dist/{format-validators.d.mts → format-validators.d.ts} +0 -0
- /package/dist/{json-schema-versions.mjs → json-schema-versions.js} +0 -0
- /package/dist/schemas/{draft-04-schema.mjs → draft-04-schema.js} +0 -0
- /package/dist/schemas/{draft-06-schema.mjs → draft-06-schema.js} +0 -0
- /package/dist/schemas/{draft-07-schema.mjs → draft-07-schema.js} +0 -0
- /package/dist/schemas/{draft-2019-09-meta-applicator.mjs → draft-2019-09-meta-applicator.js} +0 -0
- /package/dist/schemas/{draft-2019-09-meta-content.mjs → draft-2019-09-meta-content.js} +0 -0
- /package/dist/schemas/{draft-2019-09-meta-core.mjs → draft-2019-09-meta-core.js} +0 -0
- /package/dist/schemas/{draft-2019-09-meta-format.mjs → draft-2019-09-meta-format.js} +0 -0
- /package/dist/schemas/{draft-2019-09-meta-meta-data.mjs → draft-2019-09-meta-meta-data.js} +0 -0
- /package/dist/schemas/{draft-2019-09-meta-validation.mjs → draft-2019-09-meta-validation.js} +0 -0
- /package/dist/schemas/{draft-2019-09-schema.mjs → draft-2019-09-schema.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-applicator.mjs → draft-2020-12-meta-applicator.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-content.mjs → draft-2020-12-meta-content.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-core.mjs → draft-2020-12-meta-core.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-format-annotation.mjs → draft-2020-12-meta-format-annotation.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-format-assertion.mjs → draft-2020-12-meta-format-assertion.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-meta-data.mjs → draft-2020-12-meta-meta-data.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-unevaluated.mjs → draft-2020-12-meta-unevaluated.js} +0 -0
- /package/dist/schemas/{draft-2020-12-meta-validation.mjs → draft-2020-12-meta-validation.js} +0 -0
- /package/dist/schemas/{draft-2020-12-schema.mjs → draft-2020-12-schema.js} +0 -0
- /package/dist/utils/{constants.mjs → constants.js} +0 -0
- /package/dist/utils/{date.mjs → date.js} +0 -0
- /package/dist/utils/{properties.mjs → properties.js} +0 -0
- /package/dist/utils/{symbols.mjs → symbols.js} +0 -0
- /package/dist/utils/{uri.mjs → uri.js} +0 -0
- /package/dist/{z-schema-reader.mjs → z-schema-reader.js} +0 -0
package/src/validation/string.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { JsonSchemaInternal } from '../json-schema-versions.js';
|
|
|
2
2
|
import type { Report } from '../report.js';
|
|
3
3
|
import type { ZSchemaBase } from '../z-schema-base.js';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { resolveFormatValidator } from '../format-validators.js';
|
|
6
6
|
import { decodeBase64, isValidBase64 } from '../utils/base64.js';
|
|
7
7
|
import { compileSchemaRegex } from '../utils/schema-regex.js';
|
|
8
8
|
import { unicodeLength } from '../utils/unicode.js';
|
|
@@ -13,9 +13,9 @@ import { isFormatAssertionVocabEnabled, shouldSkipValidate } from './shared.js';
|
|
|
13
13
|
// minLength
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
15
|
|
|
16
|
-
export function minLengthValidator(
|
|
16
|
+
export function minLengthValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
17
17
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.2.2
|
|
18
|
-
if (shouldSkipValidate(
|
|
18
|
+
if (shouldSkipValidate(ctx.validateOptions, ['MIN_LENGTH'])) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
if (typeof json !== 'string') {
|
|
@@ -30,9 +30,9 @@ export function minLengthValidator(this: ZSchemaBase, report: Report, schema: Js
|
|
|
30
30
|
// maxLength
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
32
|
|
|
33
|
-
export function maxLengthValidator(
|
|
33
|
+
export function maxLengthValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
34
34
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1.2
|
|
35
|
-
if (shouldSkipValidate(
|
|
35
|
+
if (shouldSkipValidate(ctx.validateOptions, ['MAX_LENGTH'])) {
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
if (typeof json !== 'string') {
|
|
@@ -47,9 +47,9 @@ export function maxLengthValidator(this: ZSchemaBase, report: Report, schema: Js
|
|
|
47
47
|
// pattern
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
49
49
|
|
|
50
|
-
export function patternValidator(
|
|
50
|
+
export function patternValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
51
51
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3.2
|
|
52
|
-
if (shouldSkipValidate(
|
|
52
|
+
if (shouldSkipValidate(ctx.validateOptions, ['PATTERN'])) {
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
if (typeof json !== 'string') {
|
|
@@ -70,27 +70,24 @@ export function patternValidator(this: ZSchemaBase, report: Report, schema: Json
|
|
|
70
70
|
// format
|
|
71
71
|
// ---------------------------------------------------------------------------
|
|
72
72
|
|
|
73
|
-
export function formatValidator(
|
|
73
|
+
export function formatValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
74
74
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.2
|
|
75
|
-
if (
|
|
75
|
+
if (ctx.options.formatAssertions === false) {
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// When formatAssertions is explicitly true, respect the meta-schema vocabulary:
|
|
80
80
|
// for draft 2019-09/2020-12, format is annotation-only unless the format-assertion
|
|
81
81
|
// vocabulary is enabled in the meta-schema.
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
82
|
+
if (ctx.options.formatAssertions === true && !isFormatAssertionVocabEnabled(schema, report, ctx.options.version)) {
|
|
83
|
+
return;
|
|
86
84
|
}
|
|
87
85
|
|
|
88
|
-
const isModernDraft =
|
|
86
|
+
const isModernDraft = ctx.options.version === 'draft2019-09' || ctx.options.version === 'draft2020-12';
|
|
89
87
|
|
|
90
|
-
const
|
|
91
|
-
const formatValidatorFn = formatValidators[schema.format!];
|
|
88
|
+
const formatValidatorFn = resolveFormatValidator(schema.format!, ctx.options);
|
|
92
89
|
if (typeof formatValidatorFn === 'function') {
|
|
93
|
-
if (shouldSkipValidate(
|
|
90
|
+
if (shouldSkipValidate(ctx.validateOptions, ['INVALID_FORMAT'])) {
|
|
94
91
|
return;
|
|
95
92
|
}
|
|
96
93
|
if (report.hasError('INVALID_TYPE', [schema.type, whatIs(json)])) {
|
|
@@ -98,40 +95,38 @@ export function formatValidator(this: ZSchemaBase, report: Report, schema: JsonS
|
|
|
98
95
|
}
|
|
99
96
|
if (formatValidatorFn.length === 2) {
|
|
100
97
|
// callback-based async
|
|
101
|
-
report.addAsyncTaskWithPath(formatValidatorFn, [json],
|
|
98
|
+
report.addAsyncTaskWithPath(formatValidatorFn, [json], (result) => {
|
|
102
99
|
if (result !== true) {
|
|
103
100
|
report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
|
|
104
101
|
}
|
|
105
102
|
});
|
|
106
103
|
} else {
|
|
107
|
-
const result = formatValidatorFn.call(
|
|
104
|
+
const result = formatValidatorFn.call(ctx, json);
|
|
108
105
|
if (result instanceof Promise) {
|
|
109
106
|
// Promise-based async
|
|
110
107
|
const promiseResult = result;
|
|
111
108
|
report.addAsyncTaskWithPath(
|
|
112
|
-
async (callback) => {
|
|
109
|
+
async (callback: (result: unknown) => void) => {
|
|
113
110
|
try {
|
|
114
111
|
const resolved = await promiseResult;
|
|
115
112
|
callback(resolved);
|
|
116
|
-
} catch
|
|
113
|
+
} catch {
|
|
117
114
|
callback(false);
|
|
118
115
|
}
|
|
119
116
|
},
|
|
120
|
-
[]
|
|
121
|
-
|
|
117
|
+
[],
|
|
118
|
+
(resolvedResult) => {
|
|
122
119
|
if (resolvedResult !== true) {
|
|
123
120
|
report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
|
|
124
121
|
}
|
|
125
122
|
}
|
|
126
123
|
);
|
|
127
|
-
} else {
|
|
124
|
+
} else if (!result) {
|
|
128
125
|
// sync
|
|
129
|
-
|
|
130
|
-
report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
|
|
131
|
-
}
|
|
126
|
+
report.addError('INVALID_FORMAT', [schema.format!, JSON.stringify(json)], undefined, schema, 'format');
|
|
132
127
|
}
|
|
133
128
|
}
|
|
134
|
-
} else if (
|
|
129
|
+
} else if (ctx.options.ignoreUnknownFormats !== true && !isModernDraft) {
|
|
135
130
|
report.addError('UNKNOWN_FORMAT', [schema.format!], undefined, schema, 'format');
|
|
136
131
|
}
|
|
137
132
|
}
|
|
@@ -140,15 +135,15 @@ export function formatValidator(this: ZSchemaBase, report: Report, schema: JsonS
|
|
|
140
135
|
// contentEncoding
|
|
141
136
|
// ---------------------------------------------------------------------------
|
|
142
137
|
|
|
143
|
-
export function contentEncodingValidator(
|
|
144
|
-
if (
|
|
138
|
+
export function contentEncodingValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
139
|
+
if (ctx.options.version !== 'draft-07') {
|
|
145
140
|
return;
|
|
146
141
|
}
|
|
147
142
|
if (typeof json !== 'string') {
|
|
148
143
|
return;
|
|
149
144
|
}
|
|
150
145
|
|
|
151
|
-
const contentEncoding = schema
|
|
146
|
+
const { contentEncoding } = schema;
|
|
152
147
|
if (contentEncoding !== 'base64') {
|
|
153
148
|
return;
|
|
154
149
|
}
|
|
@@ -168,20 +163,15 @@ export function contentEncodingValidator(this: ZSchemaBase, report: Report, sche
|
|
|
168
163
|
// contentMediaType
|
|
169
164
|
// ---------------------------------------------------------------------------
|
|
170
165
|
|
|
171
|
-
export function contentMediaTypeValidator(
|
|
172
|
-
|
|
173
|
-
report: Report,
|
|
174
|
-
schema: JsonSchemaInternal,
|
|
175
|
-
json: unknown
|
|
176
|
-
) {
|
|
177
|
-
if (this.options.version !== 'draft-07') {
|
|
166
|
+
export function contentMediaTypeValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
167
|
+
if (ctx.options.version !== 'draft-07') {
|
|
178
168
|
return;
|
|
179
169
|
}
|
|
180
170
|
if (typeof json !== 'string') {
|
|
181
171
|
return;
|
|
182
172
|
}
|
|
183
173
|
|
|
184
|
-
const contentMediaType = schema
|
|
174
|
+
const { contentMediaType } = schema;
|
|
185
175
|
if (contentMediaType !== 'application/json') {
|
|
186
176
|
return;
|
|
187
177
|
}
|
package/src/validation/type.ts
CHANGED
|
@@ -10,9 +10,9 @@ import { shouldSkipValidate } from './shared.js';
|
|
|
10
10
|
// type
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
|
|
13
|
-
export function typeValidator(
|
|
13
|
+
export function typeValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
14
14
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.2.2
|
|
15
|
-
if (shouldSkipValidate(
|
|
15
|
+
if (shouldSkipValidate(ctx.validateOptions, ['INVALID_TYPE'])) {
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
const jsonType = whatIs(json);
|
|
@@ -20,10 +20,8 @@ export function typeValidator(this: ZSchemaBase, report: Report, schema: JsonSch
|
|
|
20
20
|
if (jsonType !== schema.type && (jsonType !== 'integer' || schema.type !== 'number')) {
|
|
21
21
|
report.addError('INVALID_TYPE', [schema.type, jsonType], undefined, schema, 'type');
|
|
22
22
|
}
|
|
23
|
-
} else {
|
|
24
|
-
|
|
25
|
-
report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema, 'type');
|
|
26
|
-
}
|
|
23
|
+
} else if (!schema.type!.includes(jsonType) && (jsonType !== 'integer' || !schema.type!.includes('number'))) {
|
|
24
|
+
report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema, 'type');
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
27
|
|
|
@@ -31,25 +29,27 @@ export function typeValidator(this: ZSchemaBase, report: Report, schema: JsonSch
|
|
|
31
29
|
// enum
|
|
32
30
|
// ---------------------------------------------------------------------------
|
|
33
31
|
|
|
34
|
-
export function enumValidator(
|
|
32
|
+
export function enumValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
35
33
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.1.2
|
|
36
|
-
if (shouldSkipValidate(
|
|
34
|
+
if (shouldSkipValidate(ctx.validateOptions, ['ENUM_CASE_MISMATCH', 'ENUM_MISMATCH'])) {
|
|
37
35
|
return;
|
|
38
36
|
}
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const eqOpts = { maxDepth: ctx.options.maxRecursionDepth };
|
|
38
|
+
const eqOptsCI = { caseInsensitiveComparison: true, maxDepth: ctx.options.maxRecursionDepth };
|
|
39
|
+
let caseInsensitiveMatch = false,
|
|
40
|
+
match = false;
|
|
41
41
|
for (const enumVal of schema.enum!) {
|
|
42
|
-
if (areEqual(json, enumVal,
|
|
42
|
+
if (areEqual(json, enumVal, eqOpts)) {
|
|
43
43
|
match = true;
|
|
44
44
|
break;
|
|
45
|
-
} else if (areEqual(json, enumVal,
|
|
45
|
+
} else if (areEqual(json, enumVal, eqOptsCI)) {
|
|
46
46
|
caseInsensitiveMatch = true;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
if (match
|
|
50
|
+
if (!match) {
|
|
51
51
|
const error =
|
|
52
|
-
caseInsensitiveMatch &&
|
|
52
|
+
caseInsensitiveMatch && ctx.options.enumCaseInsensitiveComparison ? 'ENUM_CASE_MISMATCH' : 'ENUM_MISMATCH';
|
|
53
53
|
report.addError(error, [JSON.stringify(json)], undefined, schema, 'enum');
|
|
54
54
|
}
|
|
55
55
|
}
|
|
@@ -58,9 +58,9 @@ export function enumValidator(this: ZSchemaBase, report: Report, schema: JsonSch
|
|
|
58
58
|
// const
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
60
|
|
|
61
|
-
export function constValidator(
|
|
61
|
+
export function constValidator(ctx: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
62
62
|
const constValue = schema.const;
|
|
63
|
-
if (areEqual(json, constValue, { maxDepth:
|
|
64
|
-
report.addError('CONST', [JSON.stringify(constValue)], undefined, schema
|
|
63
|
+
if (!areEqual(json, constValue, { maxDepth: ctx.options.maxRecursionDepth })) {
|
|
64
|
+
report.addError('CONST', [JSON.stringify(constValue)], undefined, schema);
|
|
65
65
|
}
|
|
66
66
|
}
|
package/src/z-schema-base.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { ValidateError } from './errors.js';
|
|
1
|
+
import type { Errors, ValidateError } from './errors.js';
|
|
2
2
|
import type { FormatValidatorFn } from './format-validators.js';
|
|
3
3
|
import type { JsonSchema, JsonSchemaInternal, JsonSchemaVersion } from './json-schema-versions.js';
|
|
4
4
|
import type { SchemaErrorDetail } from './report.js';
|
|
5
5
|
import type { ZSchemaOptions } from './z-schema-options.js';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { getValidateError } from './errors.js';
|
|
8
8
|
import { getSupportedFormats } from './format-validators.js';
|
|
9
9
|
import { VERSION_SCHEMA_URL_MAPPING } from './json-schema-versions.js';
|
|
10
10
|
import { isInternalKey } from './json-schema.js';
|
|
@@ -26,7 +26,10 @@ export interface ValidateOptions {
|
|
|
26
26
|
excludeErrors?: Array<keyof typeof Errors>;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export
|
|
29
|
+
export interface ValidateResponse {
|
|
30
|
+
valid: boolean;
|
|
31
|
+
err?: ValidateError;
|
|
32
|
+
}
|
|
30
33
|
|
|
31
34
|
export type ValidateCallback = (err: ValidateResponse['err'], valid: ValidateResponse['valid']) => void;
|
|
32
35
|
|
|
@@ -62,7 +65,7 @@ export class ZSchemaBase {
|
|
|
62
65
|
* create a circular dependency).
|
|
63
66
|
*/
|
|
64
67
|
_jsonValidate(report: Report, schema: boolean | JsonSchemaInternal, json: unknown): boolean {
|
|
65
|
-
return validateJson
|
|
68
|
+
return validateJson(this, report, schema, json);
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
getDefaultSchemaId(): string {
|
|
@@ -73,8 +76,7 @@ export class ZSchemaBase {
|
|
|
73
76
|
|
|
74
77
|
_validate(json: unknown, schema: JsonSchema | string, options: ValidateOptions, callback: ValidateCallback): void;
|
|
75
78
|
_validate(json: unknown, schema: JsonSchema | string, callback: ValidateCallback): void;
|
|
76
|
-
_validate(json: unknown, schema: JsonSchema | string, options
|
|
77
|
-
_validate(json: unknown, schema: JsonSchema | string): true;
|
|
79
|
+
_validate(json: unknown, schema: JsonSchema | string, options?: ValidateOptions): true;
|
|
78
80
|
_validate(
|
|
79
81
|
json: unknown,
|
|
80
82
|
schema: JsonSchema | string,
|
|
@@ -93,10 +95,10 @@ export class ZSchemaBase {
|
|
|
93
95
|
|
|
94
96
|
if (typeof schema !== 'string' && typeof schema !== 'boolean' && !isObject(schema)) {
|
|
95
97
|
const e = new Error(
|
|
96
|
-
|
|
98
|
+
`Invalid .validate call - schema must be a string or object but ${whatIs(schema)} was passed!`
|
|
97
99
|
);
|
|
98
100
|
if (callback) {
|
|
99
|
-
setTimeout(
|
|
101
|
+
setTimeout(() => {
|
|
100
102
|
callback(e, false);
|
|
101
103
|
}, 0);
|
|
102
104
|
return;
|
|
@@ -113,9 +115,9 @@ export class ZSchemaBase {
|
|
|
113
115
|
const schemaName = schema;
|
|
114
116
|
_schema = this.scache.getSchema(report, schemaName)!;
|
|
115
117
|
if (!_schema) {
|
|
116
|
-
const e = new Error(
|
|
118
|
+
const e = new Error(`Schema with id '${schemaName}' wasn't found in the validator cache!`);
|
|
117
119
|
if (callback) {
|
|
118
|
-
setTimeout(
|
|
120
|
+
setTimeout(() => {
|
|
119
121
|
callback(e, false);
|
|
120
122
|
}, 0);
|
|
121
123
|
return;
|
|
@@ -144,11 +146,11 @@ export class ZSchemaBase {
|
|
|
144
146
|
|
|
145
147
|
if (options.schemaPath) {
|
|
146
148
|
report.rootSchema = _schema;
|
|
147
|
-
_schema = get(_schema, options.schemaPath);
|
|
149
|
+
_schema = get(_schema, options.schemaPath) as JsonSchemaInternal;
|
|
148
150
|
if (!_schema) {
|
|
149
|
-
const e = new Error(
|
|
151
|
+
const e = new Error(`Schema path '${options.schemaPath}' wasn't found in the schema!`);
|
|
150
152
|
if (callback) {
|
|
151
|
-
setTimeout(
|
|
153
|
+
setTimeout(() => {
|
|
152
154
|
callback(e, false);
|
|
153
155
|
}, 0);
|
|
154
156
|
return;
|
|
@@ -158,7 +160,7 @@ export class ZSchemaBase {
|
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
if (!foundError) {
|
|
161
|
-
validateJson
|
|
163
|
+
validateJson(this, report, _schema, json);
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
if (callback) {
|
|
@@ -187,13 +189,13 @@ export class ZSchemaBase {
|
|
|
187
189
|
const report = new Report(this.options);
|
|
188
190
|
|
|
189
191
|
if (Array.isArray(schemaOrArr)) {
|
|
190
|
-
const arr = this.scache.getSchema(report, schemaOrArr)
|
|
192
|
+
const arr = this.scache.getSchema(report, schemaOrArr);
|
|
191
193
|
const compiled = this.sc.compileSchema(report, arr);
|
|
192
194
|
if (compiled) {
|
|
193
195
|
this.sv.validateSchema(report, arr);
|
|
194
196
|
}
|
|
195
197
|
} else {
|
|
196
|
-
const schema = this.scache.getSchema(report, schemaOrArr)
|
|
198
|
+
const schema = this.scache.getSchema(report, schemaOrArr);
|
|
197
199
|
const compiled = this.sc.compileSchema(report, schema);
|
|
198
200
|
if (compiled) {
|
|
199
201
|
this.sv.validateSchema(report, schema);
|
|
@@ -256,11 +258,13 @@ export class ZSchemaBase {
|
|
|
256
258
|
* @returns An array of unresolvable reference URIs.
|
|
257
259
|
*/
|
|
258
260
|
getMissingReferences(err: ValidateError): string[] {
|
|
259
|
-
if (!err)
|
|
261
|
+
if (!err) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
260
264
|
const details = err.details || [];
|
|
261
265
|
const missingRefs: string[] = [];
|
|
262
|
-
function collect(
|
|
263
|
-
for (const detail of
|
|
266
|
+
function collect(items: SchemaErrorDetail[]) {
|
|
267
|
+
for (const detail of items) {
|
|
264
268
|
if (detail.code === 'UNRESOLVABLE_REFERENCE' || detail.code === 'SCHEMA_NOT_REACHABLE') {
|
|
265
269
|
missingRefs.push(detail.params[0] as string);
|
|
266
270
|
}
|
|
@@ -281,9 +285,11 @@ export class ZSchemaBase {
|
|
|
281
285
|
getMissingRemoteReferences(err: ValidateError) {
|
|
282
286
|
const missingReferences = this.getMissingReferences(err);
|
|
283
287
|
const missingRemoteReferences: string[] = [];
|
|
288
|
+
const seen = new Set<string>();
|
|
284
289
|
for (const ref of missingReferences) {
|
|
285
290
|
const remoteReference = getRemotePath(ref);
|
|
286
|
-
if (remoteReference && !
|
|
291
|
+
if (remoteReference && !seen.has(remoteReference)) {
|
|
292
|
+
seen.add(remoteReference);
|
|
287
293
|
missingRemoteReferences.push(remoteReference);
|
|
288
294
|
}
|
|
289
295
|
}
|
|
@@ -299,41 +305,46 @@ export class ZSchemaBase {
|
|
|
299
305
|
getResolvedSchema(schemaId: string): JsonSchema | undefined {
|
|
300
306
|
const report = new Report(this.options);
|
|
301
307
|
const schema = this.scache.getSchemaByUri(report, schemaId);
|
|
302
|
-
if (!schema)
|
|
308
|
+
if (!schema) {
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
303
311
|
|
|
304
312
|
const clonedSchema = deepClone(schema, this.options.maxRecursionDepth);
|
|
305
313
|
|
|
306
314
|
const visited = new WeakSet<object>();
|
|
307
315
|
|
|
308
316
|
// clean-up the schema and resolve references
|
|
309
|
-
const cleanup =
|
|
310
|
-
|
|
311
|
-
const typeOf = whatIs(schema);
|
|
317
|
+
const cleanup = (node: unknown) => {
|
|
318
|
+
const typeOf = whatIs(node);
|
|
312
319
|
if (typeOf !== 'object' && typeOf !== 'array') {
|
|
313
320
|
return;
|
|
314
321
|
}
|
|
315
322
|
|
|
316
|
-
if (visited.has(
|
|
323
|
+
if (visited.has(node as object)) {
|
|
317
324
|
return;
|
|
318
325
|
}
|
|
319
326
|
|
|
320
|
-
visited.add(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
delete
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
visited.add(node as object);
|
|
328
|
+
|
|
329
|
+
const schemaNode = node as JsonSchemaInternal;
|
|
330
|
+
if (schemaNode.$ref && schemaNode.__$refResolved) {
|
|
331
|
+
const from = schemaNode.__$refResolved;
|
|
332
|
+
const to = schemaNode;
|
|
333
|
+
delete schemaNode.$ref;
|
|
334
|
+
delete schemaNode.__$refResolved;
|
|
335
|
+
for (const key in from) {
|
|
336
|
+
if (Object.hasOwn(from, key)) {
|
|
337
|
+
copyProp(from, to, key);
|
|
338
|
+
}
|
|
329
339
|
}
|
|
330
340
|
}
|
|
331
|
-
|
|
332
|
-
|
|
341
|
+
const record = node as Record<string, unknown>;
|
|
342
|
+
for (const key in record) {
|
|
343
|
+
if (Object.hasOwn(record, key)) {
|
|
333
344
|
if (isInternalKey(key)) {
|
|
334
|
-
delete
|
|
345
|
+
delete record[key];
|
|
335
346
|
} else {
|
|
336
|
-
cleanup(
|
|
347
|
+
cleanup(record[key]);
|
|
337
348
|
}
|
|
338
349
|
}
|
|
339
350
|
}
|
package/src/z-schema-options.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { FormatValidatorFn } from './format-validators.js';
|
|
2
|
+
import type { JsonSchemaVersion } from './json-schema-versions.js';
|
|
2
3
|
import type { Report } from './report.js';
|
|
3
4
|
|
|
4
|
-
import { CURRENT_DEFAULT_SCHEMA_VERSION
|
|
5
|
+
import { CURRENT_DEFAULT_SCHEMA_VERSION } from './json-schema-versions.js';
|
|
5
6
|
import { shallowClone } from './utils/clone.js';
|
|
6
7
|
import { DEFAULT_MAX_RECURSION_DEPTH, MAX_ASYNC_TIMEOUT } from './utils/constants.js';
|
|
7
8
|
|
|
@@ -103,7 +104,7 @@ export const normalizeOptions = (options?: ZSchemaOptions) => {
|
|
|
103
104
|
// check that the options are correctly configured
|
|
104
105
|
for (const key of keys) {
|
|
105
106
|
if (defaultOptions[key] === undefined) {
|
|
106
|
-
throw new Error(
|
|
107
|
+
throw new Error(`Unexpected option passed to constructor: ${key}`);
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
|
|
@@ -111,7 +112,7 @@ export const normalizeOptions = (options?: ZSchemaOptions) => {
|
|
|
111
112
|
keys = Object.keys(defaultOptions) as Array<keyof ZSchemaOptions>;
|
|
112
113
|
for (const key of keys) {
|
|
113
114
|
if (options[key] === undefined) {
|
|
114
|
-
(options as
|
|
115
|
+
(options as Record<string, unknown>)[key] = shallowClone(defaultOptions[key]);
|
|
115
116
|
}
|
|
116
117
|
}
|
|
117
118
|
|
package/src/z-schema.ts
CHANGED
|
@@ -15,11 +15,6 @@ import { defaultOptions } from './z-schema-options.js';
|
|
|
15
15
|
import { getSchemaReader, setSchemaReader } from './z-schema-reader.js';
|
|
16
16
|
|
|
17
17
|
export class ZSchema extends ZSchemaBase {
|
|
18
|
-
/** @internal Use ZSchema.create() instead. */
|
|
19
|
-
constructor(options: ZSchemaOptions | undefined, token: symbol) {
|
|
20
|
-
super(options, token);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
18
|
// ----- static methods start -----
|
|
24
19
|
|
|
25
20
|
// class scoped format functions
|
|
@@ -30,7 +25,7 @@ export class ZSchema extends ZSchemaBase {
|
|
|
30
25
|
* @param validatorFunction - A sync or async function `(value: unknown) => boolean | Promise<boolean>`.
|
|
31
26
|
*/
|
|
32
27
|
public static registerFormat(name: string, validatorFunction: FormatValidatorFn): void {
|
|
33
|
-
|
|
28
|
+
registerFormat(name, validatorFunction);
|
|
34
29
|
}
|
|
35
30
|
|
|
36
31
|
/**
|
|
@@ -38,7 +33,7 @@ export class ZSchema extends ZSchemaBase {
|
|
|
38
33
|
* @param name - The format name to unregister.
|
|
39
34
|
*/
|
|
40
35
|
public static unregisterFormat(name: string): void {
|
|
41
|
-
|
|
36
|
+
unregisterFormat(name);
|
|
42
37
|
}
|
|
43
38
|
|
|
44
39
|
/** Returns the names of all globally registered format validators. */
|
|
@@ -72,7 +67,7 @@ export class ZSchema extends ZSchemaBase {
|
|
|
72
67
|
* @param schemaReader - A function `(uri: string) => JsonSchema | undefined`, or `undefined` to clear.
|
|
73
68
|
*/
|
|
74
69
|
public static setSchemaReader(schemaReader: SchemaReader | undefined) {
|
|
75
|
-
|
|
70
|
+
setSchemaReader(schemaReader);
|
|
76
71
|
}
|
|
77
72
|
|
|
78
73
|
public static schemaSymbol = schemaSymbol;
|
|
@@ -148,8 +143,8 @@ export class ZSchema extends ZSchemaBase {
|
|
|
148
143
|
try {
|
|
149
144
|
this._validate(json, schema, options ?? {});
|
|
150
145
|
return { valid: true };
|
|
151
|
-
} catch (
|
|
152
|
-
return { valid: false, err:
|
|
146
|
+
} catch (error) {
|
|
147
|
+
return { valid: false, err: error as ValidateError };
|
|
153
148
|
}
|
|
154
149
|
}
|
|
155
150
|
|
|
@@ -164,11 +159,15 @@ export class ZSchema extends ZSchemaBase {
|
|
|
164
159
|
validateAsync(json: unknown, schema: JsonSchema | string, options?: ValidateOptions): Promise<true> {
|
|
165
160
|
return new Promise((resolve, reject) => {
|
|
166
161
|
try {
|
|
167
|
-
this._validate(json, schema, options || {}, (err, valid) =>
|
|
168
|
-
err || valid
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
162
|
+
this._validate(json, schema, options || {}, (err, valid) => {
|
|
163
|
+
if (err || !valid) {
|
|
164
|
+
reject(err ?? new Error('Validation failed'));
|
|
165
|
+
} else {
|
|
166
|
+
resolve(valid);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
reject(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
172
171
|
}
|
|
173
172
|
});
|
|
174
173
|
}
|
|
@@ -187,8 +186,8 @@ export class ZSchema extends ZSchemaBase {
|
|
|
187
186
|
this._validate(json, schema, options || {}, (err, valid) => {
|
|
188
187
|
resolve({ valid, err });
|
|
189
188
|
});
|
|
190
|
-
} catch (
|
|
191
|
-
resolve({ valid: false, err:
|
|
189
|
+
} catch (error) {
|
|
190
|
+
resolve({ valid: false, err: error as ValidateError });
|
|
192
191
|
}
|
|
193
192
|
});
|
|
194
193
|
}
|
|
@@ -212,8 +211,8 @@ export class ZSchema extends ZSchemaBase {
|
|
|
212
211
|
try {
|
|
213
212
|
this._validateSchema(schemaOrArr);
|
|
214
213
|
return { valid: true };
|
|
215
|
-
} catch (
|
|
216
|
-
return { valid: false, err:
|
|
214
|
+
} catch (error) {
|
|
215
|
+
return { valid: false, err: error as ValidateError };
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
218
|
}
|
|
@@ -223,11 +222,6 @@ export class ZSchema extends ZSchemaBase {
|
|
|
223
222
|
* Created via `ZSchema.create({ safe: true })`.
|
|
224
223
|
*/
|
|
225
224
|
export class ZSchemaSafe extends ZSchemaBase {
|
|
226
|
-
/** @internal Use ZSchema.create() instead. */
|
|
227
|
-
constructor(options: ZSchemaOptions | undefined, token: symbol) {
|
|
228
|
-
super(options, token);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
225
|
/**
|
|
232
226
|
* Validate JSON data against a schema.
|
|
233
227
|
* @param json - The data to validate.
|
|
@@ -239,8 +233,8 @@ export class ZSchemaSafe extends ZSchemaBase {
|
|
|
239
233
|
try {
|
|
240
234
|
this._validate(json, schema, options);
|
|
241
235
|
return { valid: true };
|
|
242
|
-
} catch (
|
|
243
|
-
return { valid: false, err:
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return { valid: false, err: error as ValidateError };
|
|
244
238
|
}
|
|
245
239
|
}
|
|
246
240
|
|
|
@@ -253,8 +247,8 @@ export class ZSchemaSafe extends ZSchemaBase {
|
|
|
253
247
|
try {
|
|
254
248
|
this._validateSchema(schemaOrArr);
|
|
255
249
|
return { valid: true };
|
|
256
|
-
} catch (
|
|
257
|
-
return { valid: false, err:
|
|
250
|
+
} catch (error) {
|
|
251
|
+
return { valid: false, err: error as ValidateError };
|
|
258
252
|
}
|
|
259
253
|
}
|
|
260
254
|
}
|
|
@@ -264,11 +258,6 @@ export class ZSchemaSafe extends ZSchemaBase {
|
|
|
264
258
|
* Created via `ZSchema.create({ async: true })`.
|
|
265
259
|
*/
|
|
266
260
|
export class ZSchemaAsync extends ZSchemaBase {
|
|
267
|
-
/** @internal Use ZSchema.create() instead. */
|
|
268
|
-
constructor(options: ZSchemaOptions | undefined, token: symbol) {
|
|
269
|
-
super(options, token);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
261
|
/**
|
|
273
262
|
* Validate JSON data against a schema asynchronously.
|
|
274
263
|
* @param json - The data to validate.
|
|
@@ -280,9 +269,15 @@ export class ZSchemaAsync extends ZSchemaBase {
|
|
|
280
269
|
validate(json: unknown, schema: JsonSchema | string, options: ValidateOptions = {}): Promise<true> {
|
|
281
270
|
return new Promise((resolve, reject) => {
|
|
282
271
|
try {
|
|
283
|
-
this._validate(json, schema, options, (err, valid) =>
|
|
284
|
-
|
|
285
|
-
|
|
272
|
+
this._validate(json, schema, options, (err, valid) => {
|
|
273
|
+
if (err || !valid) {
|
|
274
|
+
reject(err ?? new Error('Validation failed'));
|
|
275
|
+
} else {
|
|
276
|
+
resolve(valid);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
} catch (error) {
|
|
280
|
+
reject(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
286
281
|
}
|
|
287
282
|
});
|
|
288
283
|
}
|
|
@@ -303,11 +298,6 @@ export class ZSchemaAsync extends ZSchemaBase {
|
|
|
303
298
|
* Created via `ZSchema.create({ async: true, safe: true })`.
|
|
304
299
|
*/
|
|
305
300
|
export class ZSchemaAsyncSafe extends ZSchemaBase {
|
|
306
|
-
/** @internal Use ZSchema.create() instead. */
|
|
307
|
-
constructor(options: ZSchemaOptions | undefined, token: symbol) {
|
|
308
|
-
super(options, token);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
301
|
/**
|
|
312
302
|
* Validate JSON data against a schema asynchronously.
|
|
313
303
|
* The promise always resolves (never rejects).
|
|
@@ -322,8 +312,8 @@ export class ZSchemaAsyncSafe extends ZSchemaBase {
|
|
|
322
312
|
this._validate(json, schema, options, (err, valid) => {
|
|
323
313
|
resolve({ valid, err });
|
|
324
314
|
});
|
|
325
|
-
} catch (
|
|
326
|
-
resolve({ valid: false, err:
|
|
315
|
+
} catch (error) {
|
|
316
|
+
resolve({ valid: false, err: error as ValidateError });
|
|
327
317
|
}
|
|
328
318
|
});
|
|
329
319
|
}
|
|
@@ -337,8 +327,8 @@ export class ZSchemaAsyncSafe extends ZSchemaBase {
|
|
|
337
327
|
try {
|
|
338
328
|
this._validateSchema(schemaOrArr);
|
|
339
329
|
return { valid: true };
|
|
340
|
-
} catch (
|
|
341
|
-
return { valid: false, err:
|
|
330
|
+
} catch (error) {
|
|
331
|
+
return { valid: false, err: error as ValidateError };
|
|
342
332
|
}
|
|
343
333
|
}
|
|
344
334
|
}
|