z-schema 12.0.4 → 12.1.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.
Files changed (176) hide show
  1. package/bin/z-schema +7 -2
  2. package/cjs/index.d.ts +541 -530
  3. package/cjs/index.js +3963 -7740
  4. package/dist/errors.d.mts +64 -0
  5. package/dist/errors.mjs +67 -0
  6. package/dist/format-validators.d.mts +14 -0
  7. package/dist/format-validators.mjs +261 -0
  8. package/dist/index.d.mts +10 -0
  9. package/dist/index.mjs +7 -0
  10. package/dist/json-schema-versions.d.mts +137 -0
  11. package/dist/json-schema-versions.mjs +11 -0
  12. package/dist/json-schema.d.mts +61 -0
  13. package/dist/json-schema.mjs +53 -0
  14. package/dist/json-validation.mjs +441 -0
  15. package/dist/report.d.mts +97 -0
  16. package/dist/report.mjs +194 -0
  17. package/dist/schema-cache.d.mts +23 -0
  18. package/dist/schema-cache.mjs +144 -0
  19. package/dist/schema-compiler.d.mts +23 -0
  20. package/dist/schema-compiler.mjs +265 -0
  21. package/dist/schema-validator.d.mts +15 -0
  22. package/dist/schema-validator.mjs +446 -0
  23. package/dist/schemas/draft-04-schema.mjs +125 -0
  24. package/dist/schemas/draft-06-schema.mjs +126 -0
  25. package/dist/schemas/draft-07-schema.mjs +141 -0
  26. package/dist/schemas/draft-2019-09-meta-applicator.mjs +46 -0
  27. package/dist/schemas/draft-2019-09-meta-content.mjs +15 -0
  28. package/dist/schemas/draft-2019-09-meta-core.mjs +52 -0
  29. package/dist/schemas/draft-2019-09-meta-format.mjs +11 -0
  30. package/dist/schemas/draft-2019-09-meta-meta-data.mjs +31 -0
  31. package/dist/schemas/draft-2019-09-meta-validation.mjs +80 -0
  32. package/dist/schemas/draft-2019-09-schema.mjs +39 -0
  33. package/dist/schemas/draft-2020-12-meta-applicator.mjs +45 -0
  34. package/dist/schemas/draft-2020-12-meta-content.mjs +15 -0
  35. package/dist/schemas/draft-2020-12-meta-core.mjs +46 -0
  36. package/dist/schemas/draft-2020-12-meta-format-annotation.mjs +11 -0
  37. package/dist/schemas/draft-2020-12-meta-format-assertion.mjs +11 -0
  38. package/dist/schemas/draft-2020-12-meta-meta-data.mjs +31 -0
  39. package/dist/schemas/draft-2020-12-meta-unevaluated.mjs +14 -0
  40. package/dist/schemas/draft-2020-12-meta-validation.mjs +80 -0
  41. package/dist/schemas/draft-2020-12-schema.mjs +55 -0
  42. package/dist/utils/array.mjs +54 -0
  43. package/dist/utils/base64.mjs +21 -0
  44. package/dist/utils/clone.mjs +42 -0
  45. package/dist/utils/constants.mjs +16 -0
  46. package/dist/utils/date.mjs +19 -0
  47. package/dist/utils/hostname.mjs +73 -0
  48. package/dist/utils/json.mjs +34 -0
  49. package/dist/utils/properties.mjs +11 -0
  50. package/dist/utils/schema-regex.mjs +49 -0
  51. package/dist/utils/symbols.mjs +5 -0
  52. package/dist/utils/time.mjs +42 -0
  53. package/dist/utils/unicode.mjs +12 -0
  54. package/dist/utils/uri.mjs +12 -0
  55. package/dist/utils/what-is.mjs +23 -0
  56. package/dist/validation/array.mjs +57 -0
  57. package/dist/validation/combinators.mjs +62 -0
  58. package/dist/validation/numeric.mjs +38 -0
  59. package/dist/validation/object.mjs +109 -0
  60. package/dist/validation/ref.mjs +49 -0
  61. package/dist/validation/shared.mjs +97 -0
  62. package/dist/validation/string.mjs +88 -0
  63. package/dist/validation/type.mjs +32 -0
  64. package/dist/z-schema-base.d.mts +85 -0
  65. package/dist/z-schema-base.mjs +230 -0
  66. package/dist/z-schema-options.d.mts +35 -0
  67. package/dist/z-schema-options.mjs +55 -0
  68. package/dist/z-schema-reader.d.mts +6 -0
  69. package/dist/z-schema-reader.mjs +10 -0
  70. package/dist/z-schema-versions.mjs +67 -0
  71. package/dist/z-schema.d.mts +193 -0
  72. package/dist/z-schema.mjs +300 -0
  73. package/package.json +49 -64
  74. package/src/index.ts +3 -3
  75. package/src/schema-compiler.ts +30 -10
  76. package/src/schema-validator.ts +1 -1
  77. package/src/utils/schema-regex.ts +13 -2
  78. package/src/z-schema-base.ts +1 -1
  79. package/src/z-schema-versions.ts +1 -2
  80. package/src/z-schema.ts +0 -1
  81. package/umd/ZSchema.js +5934 -8110
  82. package/umd/ZSchema.min.js +2 -1
  83. package/dist/errors.js +0 -72
  84. package/dist/format-validators.js +0 -392
  85. package/dist/index.js +0 -5
  86. package/dist/json-schema-versions.js +0 -8
  87. package/dist/json-schema.js +0 -84
  88. package/dist/json-validation.js +0 -728
  89. package/dist/package.json +0 -3
  90. package/dist/report.js +0 -265
  91. package/dist/schema-cache.js +0 -211
  92. package/dist/schema-compiler.js +0 -415
  93. package/dist/schema-validator.js +0 -721
  94. package/dist/schemas/draft-04-schema.json +0 -149
  95. package/dist/schemas/draft-06-schema.json +0 -155
  96. package/dist/schemas/draft-07-schema.json +0 -172
  97. package/dist/schemas/draft-2019-09-meta-applicator.json +0 -52
  98. package/dist/schemas/draft-2019-09-meta-content.json +0 -12
  99. package/dist/schemas/draft-2019-09-meta-core.json +0 -53
  100. package/dist/schemas/draft-2019-09-meta-format.json +0 -10
  101. package/dist/schemas/draft-2019-09-meta-meta-data.json +0 -32
  102. package/dist/schemas/draft-2019-09-meta-validation.json +0 -94
  103. package/dist/schemas/draft-2019-09-schema.json +0 -41
  104. package/dist/schemas/draft-2020-12-meta-applicator.json +0 -44
  105. package/dist/schemas/draft-2020-12-meta-content.json +0 -12
  106. package/dist/schemas/draft-2020-12-meta-core.json +0 -47
  107. package/dist/schemas/draft-2020-12-meta-format-annotation.json +0 -10
  108. package/dist/schemas/draft-2020-12-meta-format-assertion.json +0 -10
  109. package/dist/schemas/draft-2020-12-meta-meta-data.json +0 -32
  110. package/dist/schemas/draft-2020-12-meta-unevaluated.json +0 -11
  111. package/dist/schemas/draft-2020-12-meta-validation.json +0 -94
  112. package/dist/schemas/draft-2020-12-schema.json +0 -57
  113. package/dist/types/errors.d.ts +0 -64
  114. package/dist/types/format-validators.d.ts +0 -11
  115. package/dist/types/index.d.ts +0 -14
  116. package/dist/types/json-schema-versions.d.ts +0 -142
  117. package/dist/types/json-schema.d.ts +0 -66
  118. package/dist/types/json-validation.d.ts +0 -6
  119. package/dist/types/report.d.ts +0 -94
  120. package/dist/types/schema-cache.d.ts +0 -27
  121. package/dist/types/schema-compiler.d.ts +0 -31
  122. package/dist/types/schema-validator.d.ts +0 -10
  123. package/dist/types/utils/array.d.ts +0 -9
  124. package/dist/types/utils/base64.d.ts +0 -2
  125. package/dist/types/utils/clone.d.ts +0 -2
  126. package/dist/types/utils/constants.d.ts +0 -19
  127. package/dist/types/utils/date.d.ts +0 -1
  128. package/dist/types/utils/hostname.d.ts +0 -2
  129. package/dist/types/utils/json.d.ts +0 -9
  130. package/dist/types/utils/properties.d.ts +0 -1
  131. package/dist/types/utils/schema-regex.d.ts +0 -10
  132. package/dist/types/utils/symbols.d.ts +0 -2
  133. package/dist/types/utils/time.d.ts +0 -12
  134. package/dist/types/utils/unicode.d.ts +0 -5
  135. package/dist/types/utils/uri.d.ts +0 -4
  136. package/dist/types/utils/what-is.d.ts +0 -4
  137. package/dist/types/validation/array.d.ts +0 -12
  138. package/dist/types/validation/combinators.d.ts +0 -10
  139. package/dist/types/validation/numeric.d.ts +0 -8
  140. package/dist/types/validation/object.d.ts +0 -13
  141. package/dist/types/validation/ref.d.ts +0 -11
  142. package/dist/types/validation/shared.d.ts +0 -26
  143. package/dist/types/validation/string.d.ts +0 -9
  144. package/dist/types/validation/type.d.ts +0 -6
  145. package/dist/types/z-schema-base.d.ts +0 -87
  146. package/dist/types/z-schema-options.d.ts +0 -35
  147. package/dist/types/z-schema-reader.d.ts +0 -4
  148. package/dist/types/z-schema-versions.d.ts +0 -1
  149. package/dist/types/z-schema.d.ts +0 -191
  150. package/dist/utils/array.js +0 -69
  151. package/dist/utils/base64.js +0 -29
  152. package/dist/utils/clone.js +0 -59
  153. package/dist/utils/constants.js +0 -19
  154. package/dist/utils/date.js +0 -21
  155. package/dist/utils/hostname.js +0 -146
  156. package/dist/utils/json.js +0 -70
  157. package/dist/utils/properties.js +0 -10
  158. package/dist/utils/schema-regex.js +0 -52
  159. package/dist/utils/symbols.js +0 -2
  160. package/dist/utils/time.js +0 -50
  161. package/dist/utils/unicode.js +0 -12
  162. package/dist/utils/uri.js +0 -15
  163. package/dist/utils/what-is.js +0 -32
  164. package/dist/validation/array.js +0 -127
  165. package/dist/validation/combinators.js +0 -106
  166. package/dist/validation/numeric.js +0 -97
  167. package/dist/validation/object.js +0 -237
  168. package/dist/validation/ref.js +0 -70
  169. package/dist/validation/shared.js +0 -136
  170. package/dist/validation/string.js +0 -170
  171. package/dist/validation/type.js +0 -55
  172. package/dist/z-schema-base.js +0 -286
  173. package/dist/z-schema-options.js +0 -99
  174. package/dist/z-schema-reader.js +0 -7
  175. package/dist/z-schema-versions.js +0 -110
  176. package/dist/z-schema.js +0 -287
@@ -1,237 +0,0 @@
1
- import { difference } from '../utils/array.js';
2
- import { compileSchemaRegex } from '../utils/schema-regex.js';
3
- import { isObject } from '../utils/what-is.js';
4
- import { deferOrRunSync, shouldSkipValidate, supportsDependentKeywords } from './shared.js';
5
- // ---------------------------------------------------------------------------
6
- // maxProperties
7
- // ---------------------------------------------------------------------------
8
- export function maxPropertiesValidator(report, schema, json) {
9
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.1.2
10
- if (shouldSkipValidate(this.validateOptions, ['OBJECT_PROPERTIES_MAXIMUM'])) {
11
- return;
12
- }
13
- if (!isObject(json)) {
14
- return;
15
- }
16
- const keysCount = Object.keys(json).length;
17
- if (keysCount > schema.maxProperties) {
18
- report.addError('OBJECT_PROPERTIES_MAXIMUM', [keysCount, schema.maxProperties], undefined, schema, 'maxProperties');
19
- }
20
- }
21
- // ---------------------------------------------------------------------------
22
- // minProperties
23
- // ---------------------------------------------------------------------------
24
- export function minPropertiesValidator(report, schema, json) {
25
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.2.2
26
- if (shouldSkipValidate(this.validateOptions, ['OBJECT_PROPERTIES_MINIMUM'])) {
27
- return;
28
- }
29
- if (!isObject(json)) {
30
- return;
31
- }
32
- const keysCount = Object.keys(json).length;
33
- if (keysCount < schema.minProperties) {
34
- report.addError('OBJECT_PROPERTIES_MINIMUM', [keysCount, schema.minProperties], undefined, schema, 'minProperties');
35
- }
36
- }
37
- // ---------------------------------------------------------------------------
38
- // required
39
- // ---------------------------------------------------------------------------
40
- export function requiredValidator(report, schema, json) {
41
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.3.2
42
- if (shouldSkipValidate(this.validateOptions, ['OBJECT_MISSING_REQUIRED_PROPERTY'])) {
43
- return;
44
- }
45
- if (!isObject(json)) {
46
- return;
47
- }
48
- const idx = schema.required.length;
49
- for (let i = 0; i < idx; i++) {
50
- const requiredPropertyName = schema.required[i];
51
- if (!Object.hasOwn(json, requiredPropertyName)) {
52
- report.addError('OBJECT_MISSING_REQUIRED_PROPERTY', [requiredPropertyName], undefined, schema, 'required');
53
- }
54
- }
55
- }
56
- // ---------------------------------------------------------------------------
57
- // additionalProperties (delegates to properties when standalone)
58
- // ---------------------------------------------------------------------------
59
- export function additionalPropertiesValidator(report, schema, json) {
60
- // covered in properties and patternProperties
61
- if (schema.properties === undefined && schema.patternProperties === undefined) {
62
- return propertiesValidator.call(this, report, schema, json);
63
- }
64
- }
65
- // ---------------------------------------------------------------------------
66
- // patternProperties (delegates to properties when standalone)
67
- // ---------------------------------------------------------------------------
68
- export function patternPropertiesValidator(report, schema, json) {
69
- // covered in properties
70
- if (schema.properties === undefined) {
71
- return propertiesValidator.call(this, report, schema, json);
72
- }
73
- }
74
- // ---------------------------------------------------------------------------
75
- // properties
76
- // ---------------------------------------------------------------------------
77
- export function propertiesValidator(report, schema, json) {
78
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.4.2
79
- if (shouldSkipValidate(this.validateOptions, ['OBJECT_ADDITIONAL_PROPERTIES'])) {
80
- return;
81
- }
82
- if (!isObject(json)) {
83
- return;
84
- }
85
- const properties = schema.properties !== undefined ? schema.properties : {};
86
- const patternProperties = schema.patternProperties !== undefined ? schema.patternProperties : {};
87
- if (schema.additionalProperties === false) {
88
- // The property set of the json to validate.
89
- let s = Object.keys(json);
90
- // The property set from "properties".
91
- const p = Object.keys(properties);
92
- // The property set from "patternProperties".
93
- const pp = Object.keys(patternProperties);
94
- // remove from "s" all elements of "p", if any;
95
- s = difference(s, p);
96
- // for each regex in "pp", remove all elements of "s" which this regex matches.
97
- for (const ppKey of pp) {
98
- const result = compileSchemaRegex(ppKey);
99
- if (!result.ok) {
100
- continue;
101
- }
102
- const regExp = result.value;
103
- for (let idx2 = s.length - 1; idx2 >= 0; idx2--) {
104
- if (regExp.test(s[idx2]) === true) {
105
- s.splice(idx2, 1);
106
- }
107
- }
108
- }
109
- // Validation of the json succeeds if, after these two steps, set "s" is empty.
110
- if (s.length > 0) {
111
- // assumeAdditional can be an array of allowed properties
112
- if (Array.isArray(this.options.assumeAdditional)) {
113
- for (const allowed of this.options.assumeAdditional) {
114
- const io = s.indexOf(allowed);
115
- if (io !== -1) {
116
- s.splice(io, 1);
117
- }
118
- }
119
- }
120
- if (s.length > 0) {
121
- for (const extra of s) {
122
- report.addError('OBJECT_ADDITIONAL_PROPERTIES', [extra], undefined, schema, 'properties');
123
- }
124
- }
125
- }
126
- }
127
- }
128
- // ---------------------------------------------------------------------------
129
- // dependencies
130
- // ---------------------------------------------------------------------------
131
- export function dependenciesValidator(report, schema, json) {
132
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.4.5.2
133
- if (shouldSkipValidate(this.validateOptions, ['OBJECT_DEPENDENCY_KEY'])) {
134
- return;
135
- }
136
- if (!isObject(json)) {
137
- return;
138
- }
139
- const keys = Object.keys(schema.dependencies);
140
- for (const dependencyName of keys) {
141
- // iterate all dependencies
142
- if (Object.hasOwn(json, dependencyName)) {
143
- const dependencyDefinition = schema.dependencies[dependencyName];
144
- if (Array.isArray(dependencyDefinition)) {
145
- // Array
146
- // if dependency is an array, object needs to have all properties in this array
147
- for (const requiredPropertyName of dependencyDefinition) {
148
- if (!Object.hasOwn(json, requiredPropertyName)) {
149
- report.addError('OBJECT_DEPENDENCY_KEY', [requiredPropertyName, dependencyName], undefined, schema, 'dependencies');
150
- }
151
- }
152
- }
153
- else {
154
- // if dependency is a schema, validate against this schema
155
- this._jsonValidate(report, dependencyDefinition, json);
156
- }
157
- }
158
- }
159
- }
160
- // ---------------------------------------------------------------------------
161
- // dependentSchemas
162
- // ---------------------------------------------------------------------------
163
- export function dependentSchemasValidator(report, schema, json) {
164
- if (!supportsDependentKeywords(schema, this.options.version)) {
165
- return;
166
- }
167
- if (!isObject(json) || !isObject(schema.dependentSchemas)) {
168
- return;
169
- }
170
- const keys = Object.keys(schema.dependentSchemas);
171
- for (const dependencyName of keys) {
172
- if (Object.hasOwn(json, dependencyName)) {
173
- const dependencySchema = schema.dependentSchemas[dependencyName];
174
- this._jsonValidate(report, dependencySchema, json);
175
- }
176
- }
177
- }
178
- // ---------------------------------------------------------------------------
179
- // dependentRequired
180
- // ---------------------------------------------------------------------------
181
- export function dependentRequiredValidator(report, schema, json) {
182
- if (!supportsDependentKeywords(schema, this.options.version)) {
183
- return;
184
- }
185
- if (shouldSkipValidate(this.validateOptions, ['OBJECT_DEPENDENCY_KEY'])) {
186
- return;
187
- }
188
- if (!isObject(json) || !isObject(schema.dependentRequired)) {
189
- return;
190
- }
191
- const keys = Object.keys(schema.dependentRequired);
192
- for (const dependencyName of keys) {
193
- if (!Object.hasOwn(json, dependencyName)) {
194
- continue;
195
- }
196
- const requiredProperties = schema.dependentRequired[dependencyName];
197
- if (!Array.isArray(requiredProperties)) {
198
- continue;
199
- }
200
- for (const requiredPropertyName of requiredProperties) {
201
- if (!Object.hasOwn(json, requiredPropertyName)) {
202
- report.addError('OBJECT_DEPENDENCY_KEY', [requiredPropertyName, dependencyName], undefined, schema, 'dependentRequired');
203
- }
204
- }
205
- }
206
- }
207
- // ---------------------------------------------------------------------------
208
- // propertyNames
209
- // ---------------------------------------------------------------------------
210
- export function propertyNamesValidator(report, schema, json) {
211
- if (shouldSkipValidate(this.validateOptions, ['PROPERTY_NAMES'])) {
212
- return;
213
- }
214
- if (!isObject(json)) {
215
- return;
216
- }
217
- const propertyNamesSchema = schema.propertyNames;
218
- if (propertyNamesSchema === undefined) {
219
- return;
220
- }
221
- const Report_ = report.constructor;
222
- const keys = Object.keys(json);
223
- const subReports = [];
224
- for (const key of keys) {
225
- const subReport = new Report_(report);
226
- subReports.push(subReport);
227
- this._jsonValidate(subReport, propertyNamesSchema, key);
228
- }
229
- const addPropertyNameErrors = () => {
230
- for (let idx = 0; idx < keys.length; idx++) {
231
- if (subReports[idx].errors.length > 0) {
232
- report.addError('PROPERTY_NAMES', [keys[idx]], subReports[idx], schema, undefined);
233
- }
234
- }
235
- };
236
- deferOrRunSync(report, subReports, addPropertyNameErrors);
237
- }
@@ -1,70 +0,0 @@
1
- import { findId, getId } from '../json-schema.js';
2
- import { getRemotePath } from '../utils/uri.js';
3
- // ---------------------------------------------------------------------------
4
- // $dynamicRef helpers
5
- // ---------------------------------------------------------------------------
6
- export const getDynamicRefAnchorName = (dynamicRef) => {
7
- const hashIdx = dynamicRef.indexOf('#');
8
- if (hashIdx === -1) {
9
- return undefined;
10
- }
11
- const fragment = dynamicRef.slice(hashIdx + 1);
12
- if (!fragment || fragment[0] === '/') {
13
- return undefined;
14
- }
15
- return fragment;
16
- };
17
- export const findDynamicAnchorInScope = (scopeSchema, anchorName) => {
18
- const scopeId = getId(scopeSchema);
19
- const scopeBaseUri = scopeId ? getRemotePath(scopeId) : undefined;
20
- const found = findId(scopeSchema, anchorName, scopeBaseUri, scopeBaseUri);
21
- if (found && found.$dynamicAnchor === anchorName) {
22
- return found;
23
- }
24
- return undefined;
25
- };
26
- // ---------------------------------------------------------------------------
27
- // $recursiveRef resolution
28
- // ---------------------------------------------------------------------------
29
- /**
30
- * Resolves the effective target for a $recursiveRef, walking the recursive anchor stack.
31
- */
32
- export const resolveRecursiveRef = (schema, recursiveAnchorStack) => {
33
- const resolved = schema.__$recursiveRefResolved;
34
- if (!resolved) {
35
- return undefined;
36
- }
37
- let target = resolved;
38
- if (typeof target === 'object' && target.$recursiveAnchor === true) {
39
- const dynamicTarget = recursiveAnchorStack[0];
40
- if (dynamicTarget) {
41
- target = dynamicTarget;
42
- }
43
- }
44
- return target;
45
- };
46
- // ---------------------------------------------------------------------------
47
- // $dynamicRef resolution
48
- // ---------------------------------------------------------------------------
49
- /**
50
- * Resolves the effective target for a $dynamicRef, walking the dynamic scope stack.
51
- */
52
- export const resolveDynamicRef = (schema, dynamicScopeStack) => {
53
- const resolved = schema.__$dynamicRefResolved;
54
- if (typeof resolved === 'undefined' || !schema.$dynamicRef) {
55
- return resolved;
56
- }
57
- let target = resolved;
58
- const anchorName = getDynamicRefAnchorName(schema.$dynamicRef);
59
- if (anchorName && typeof target === 'object' && target.$dynamicAnchor === anchorName) {
60
- for (let scopeIdx = 0; scopeIdx < dynamicScopeStack.length; scopeIdx++) {
61
- const scopeSchema = dynamicScopeStack[scopeIdx];
62
- const scopedTarget = findDynamicAnchorInScope(scopeSchema, anchorName);
63
- if (scopedTarget) {
64
- target = scopedTarget;
65
- break;
66
- }
67
- }
68
- }
69
- return target;
70
- };
@@ -1,136 +0,0 @@
1
- import { isObject } from '../utils/what-is.js';
2
- // ---------------------------------------------------------------------------
3
- // Draft / vocabulary helpers
4
- // ---------------------------------------------------------------------------
5
- export const shouldSkipValidate = function (options, errors) {
6
- return (options &&
7
- Array.isArray(options.includeErrors) &&
8
- options.includeErrors.length > 0 &&
9
- !errors.some(function (err) {
10
- return options.includeErrors.includes(err);
11
- }));
12
- };
13
- export const supportsDependentKeywords = (schema, version) => {
14
- if (typeof schema.$schema === 'string') {
15
- return !/draft-04|draft-06|draft-07/.test(schema.$schema);
16
- }
17
- return !(version === 'draft-04' || version === 'draft-06' || version === 'draft-07');
18
- };
19
- // ---------------------------------------------------------------------------
20
- // Vocabulary constants
21
- // ---------------------------------------------------------------------------
22
- const VOCAB_VALIDATION_2019_09 = 'https://json-schema.org/draft/2019-09/vocab/validation';
23
- const VOCAB_VALIDATION_2020_12 = 'https://json-schema.org/draft/2020-12/vocab/validation';
24
- const VOCAB_FORMAT_2019_09 = 'https://json-schema.org/draft/2019-09/vocab/format';
25
- const VOCAB_FORMAT_ASSERTION_2020_12 = 'https://json-schema.org/draft/2020-12/vocab/format-assertion';
26
- export const VALIDATION_VOCAB_KEYWORDS = new Set([
27
- 'type',
28
- 'multipleOf',
29
- 'maximum',
30
- 'exclusiveMaximum',
31
- 'minimum',
32
- 'exclusiveMinimum',
33
- 'maxLength',
34
- 'minLength',
35
- 'pattern',
36
- 'maxItems',
37
- 'minItems',
38
- 'uniqueItems',
39
- 'maxContains',
40
- 'minContains',
41
- 'maxProperties',
42
- 'minProperties',
43
- 'required',
44
- 'dependentRequired',
45
- 'enum',
46
- 'const',
47
- 'contentEncoding',
48
- 'contentMediaType',
49
- ]);
50
- export const isValidationVocabularyEnabled = (schema, report, version) => {
51
- if (version !== 'draft2019-09' && version !== 'draft2020-12') {
52
- return true;
53
- }
54
- const currentSchemaMeta = schema.__$schemaResolved;
55
- const rootSchemaMeta = report.rootSchema && typeof report.rootSchema !== 'boolean' ? report.rootSchema.__$schemaResolved : undefined;
56
- const metaSchema = (currentSchemaMeta || rootSchemaMeta);
57
- if (!metaSchema || typeof metaSchema !== 'object' || !isObject(metaSchema.$vocabulary)) {
58
- return true;
59
- }
60
- const vocabulary = metaSchema.$vocabulary;
61
- const has2019 = Object.hasOwn(vocabulary, VOCAB_VALIDATION_2019_09);
62
- const has2020 = Object.hasOwn(vocabulary, VOCAB_VALIDATION_2020_12);
63
- if (has2019 || has2020) {
64
- return vocabulary[VOCAB_VALIDATION_2019_09] === true || vocabulary[VOCAB_VALIDATION_2020_12] === true;
65
- }
66
- return false;
67
- };
68
- /**
69
- * Checks whether the format-assertion vocabulary is enabled in the meta-schema.
70
- * For draft 2019-09: checks if the format vocabulary is set to true.
71
- * For draft 2020-12: checks if the format-assertion vocabulary is present and true.
72
- * Returns true for older drafts (format was always an assertion).
73
- */
74
- export const isFormatAssertionVocabEnabled = (schema, report, version) => {
75
- if (version !== 'draft2019-09' && version !== 'draft2020-12') {
76
- return true; // older drafts always assert format
77
- }
78
- const currentSchemaMeta = schema.__$schemaResolved;
79
- const rootSchemaMeta = report.rootSchema && typeof report.rootSchema !== 'boolean' ? report.rootSchema.__$schemaResolved : undefined;
80
- const metaSchema = (currentSchemaMeta || rootSchemaMeta);
81
- if (!metaSchema || typeof metaSchema !== 'object' || !isObject(metaSchema.$vocabulary)) {
82
- return false; // no vocabulary info, default to annotation-only for modern drafts
83
- }
84
- const vocabulary = metaSchema.$vocabulary;
85
- // For draft 2020-12, only the format-assertion vocabulary enables format as assertion
86
- if (Object.hasOwn(vocabulary, VOCAB_FORMAT_ASSERTION_2020_12)) {
87
- return vocabulary[VOCAB_FORMAT_ASSERTION_2020_12] === true;
88
- }
89
- // For draft 2019-09, check if the format vocabulary is enabled (true)
90
- if (Object.hasOwn(vocabulary, VOCAB_FORMAT_2019_09)) {
91
- return vocabulary[VOCAB_FORMAT_2019_09] === true;
92
- }
93
- return false; // default to annotation-only for modern drafts
94
- };
95
- // ---------------------------------------------------------------------------
96
- // Validation result caching
97
- // ---------------------------------------------------------------------------
98
- export function cacheValidationResult(report, schema, json, passed) {
99
- let schemaMap = report.__validationResultCache.get(schema);
100
- if (!schemaMap) {
101
- schemaMap = new Map();
102
- report.__validationResultCache.set(schema, schemaMap);
103
- }
104
- schemaMap.set(json, passed);
105
- }
106
- export function getCachedValidationResult(report, schema, json) {
107
- return report.__validationResultCache.get(schema)?.get(json);
108
- }
109
- // ---------------------------------------------------------------------------
110
- // Async task aggregation
111
- // ---------------------------------------------------------------------------
112
- /**
113
- * Shared async-task aggregation pattern.
114
- *
115
- * 1. Collects async tasks from `subReports` into `report`.
116
- * 2. If new async tasks were added, defers `decisionFn` via `report.addAsyncTask`
117
- * with proper path save/restore so error paths are correct.
118
- * 3. Otherwise, runs `decisionFn` synchronously.
119
- */
120
- export function deferOrRunSync(report, subReports, decisionFn) {
121
- const asyncTasksBefore = report.asyncTasks.length;
122
- for (const subReport of subReports) {
123
- report.asyncTasks.push(...subReport.asyncTasks);
124
- }
125
- const hasAsyncTasks = report.asyncTasks.length > asyncTasksBefore;
126
- if (hasAsyncTasks) {
127
- report.addAsyncTaskWithPath((callback) => {
128
- setTimeout(() => callback(null), 0);
129
- }, [], () => {
130
- decisionFn();
131
- });
132
- }
133
- else {
134
- decisionFn();
135
- }
136
- }
@@ -1,170 +0,0 @@
1
- import { getFormatValidators } from '../format-validators.js';
2
- import { decodeBase64, isValidBase64 } from '../utils/base64.js';
3
- import { compileSchemaRegex } from '../utils/schema-regex.js';
4
- import { unicodeLength } from '../utils/unicode.js';
5
- import { whatIs } from '../utils/what-is.js';
6
- import { isFormatAssertionVocabEnabled, shouldSkipValidate } from './shared.js';
7
- // ---------------------------------------------------------------------------
8
- // minLength
9
- // ---------------------------------------------------------------------------
10
- export function minLengthValidator(report, schema, json) {
11
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.2.2
12
- if (shouldSkipValidate(this.validateOptions, ['MIN_LENGTH'])) {
13
- return;
14
- }
15
- if (typeof json !== 'string') {
16
- return;
17
- }
18
- if (unicodeLength(json) < schema.minLength) {
19
- report.addError('MIN_LENGTH', [json.length, schema.minLength], undefined, schema, 'minLength');
20
- }
21
- }
22
- // ---------------------------------------------------------------------------
23
- // maxLength
24
- // ---------------------------------------------------------------------------
25
- export function maxLengthValidator(report, schema, json) {
26
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1.2
27
- if (shouldSkipValidate(this.validateOptions, ['MAX_LENGTH'])) {
28
- return;
29
- }
30
- if (typeof json !== 'string') {
31
- return;
32
- }
33
- if (unicodeLength(json) > schema.maxLength) {
34
- report.addError('MAX_LENGTH', [json.length, schema.maxLength], undefined, schema, 'maxLength');
35
- }
36
- }
37
- // ---------------------------------------------------------------------------
38
- // pattern
39
- // ---------------------------------------------------------------------------
40
- export function patternValidator(report, schema, json) {
41
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.3.2
42
- if (shouldSkipValidate(this.validateOptions, ['PATTERN'])) {
43
- return;
44
- }
45
- if (typeof json !== 'string') {
46
- return;
47
- }
48
- const result = compileSchemaRegex(schema.pattern);
49
- if (!result.ok) {
50
- // Should not happen: schema should have been validated already
51
- report.addError('PATTERN', [schema.pattern, json, result.error.message], undefined, schema, 'pattern');
52
- return;
53
- }
54
- if (!result.value.test(json)) {
55
- report.addError('PATTERN', [schema.pattern, json], undefined, schema, 'pattern');
56
- }
57
- }
58
- // ---------------------------------------------------------------------------
59
- // format
60
- // ---------------------------------------------------------------------------
61
- export function formatValidator(report, schema, json) {
62
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.2
63
- if (this.options.formatAssertions === false) {
64
- return;
65
- }
66
- // When formatAssertions is explicitly true, respect the meta-schema vocabulary:
67
- // for draft 2019-09/2020-12, format is annotation-only unless the format-assertion
68
- // vocabulary is enabled in the meta-schema.
69
- if (this.options.formatAssertions === true) {
70
- if (!isFormatAssertionVocabEnabled(schema, report, this.options.version)) {
71
- return;
72
- }
73
- }
74
- const isModernDraft = this.options.version === 'draft2019-09' || this.options.version === 'draft2020-12';
75
- const formatValidators = getFormatValidators(this.options);
76
- const formatValidatorFn = formatValidators[schema.format];
77
- if (typeof formatValidatorFn === 'function') {
78
- if (shouldSkipValidate(this.validateOptions, ['INVALID_FORMAT'])) {
79
- return;
80
- }
81
- if (report.hasError('INVALID_TYPE', [schema.type, whatIs(json)])) {
82
- return;
83
- }
84
- if (formatValidatorFn.length === 2) {
85
- // callback-based async
86
- report.addAsyncTaskWithPath(formatValidatorFn, [json], function (result) {
87
- if (result !== true) {
88
- report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema, 'format');
89
- }
90
- });
91
- }
92
- else {
93
- const result = formatValidatorFn.call(this, json);
94
- if (result instanceof Promise) {
95
- // Promise-based async
96
- const promiseResult = result;
97
- report.addAsyncTaskWithPath(async (callback) => {
98
- try {
99
- const resolved = await promiseResult;
100
- callback(resolved);
101
- }
102
- catch (_error) {
103
- callback(false);
104
- }
105
- }, [], function (resolvedResult) {
106
- if (resolvedResult !== true) {
107
- report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema, 'format');
108
- }
109
- });
110
- }
111
- else {
112
- // sync
113
- if (result !== true) {
114
- report.addError('INVALID_FORMAT', [schema.format, JSON.stringify(json)], undefined, schema, 'format');
115
- }
116
- }
117
- }
118
- }
119
- else if (this.options.ignoreUnknownFormats !== true && !isModernDraft) {
120
- report.addError('UNKNOWN_FORMAT', [schema.format], undefined, schema, 'format');
121
- }
122
- }
123
- // ---------------------------------------------------------------------------
124
- // contentEncoding
125
- // ---------------------------------------------------------------------------
126
- export function contentEncodingValidator(report, schema, json) {
127
- if (this.options.version !== 'draft-07') {
128
- return;
129
- }
130
- if (typeof json !== 'string') {
131
- return;
132
- }
133
- const contentEncoding = schema.contentEncoding;
134
- if (contentEncoding !== 'base64') {
135
- return;
136
- }
137
- if (!isValidBase64(json)) {
138
- report.addError('INVALID_FORMAT', ['contentEncoding:base64', JSON.stringify(json)], undefined, schema, 'contentEncoding');
139
- }
140
- }
141
- // ---------------------------------------------------------------------------
142
- // contentMediaType
143
- // ---------------------------------------------------------------------------
144
- export function contentMediaTypeValidator(report, schema, json) {
145
- if (this.options.version !== 'draft-07') {
146
- return;
147
- }
148
- if (typeof json !== 'string') {
149
- return;
150
- }
151
- const contentMediaType = schema.contentMediaType;
152
- if (contentMediaType !== 'application/json') {
153
- return;
154
- }
155
- let payload = json;
156
- if (schema.contentEncoding === 'base64') {
157
- const decoded = decodeBase64(json);
158
- if (decoded === undefined) {
159
- report.addError('INVALID_FORMAT', ['contentEncoding:base64', JSON.stringify(json)], undefined, schema, 'contentEncoding');
160
- return;
161
- }
162
- payload = decoded;
163
- }
164
- try {
165
- JSON.parse(payload);
166
- }
167
- catch {
168
- report.addError('INVALID_FORMAT', ['contentMediaType:application/json', JSON.stringify(json)], undefined, schema, 'contentMediaType');
169
- }
170
- }
@@ -1,55 +0,0 @@
1
- import { areEqual } from '../utils/json.js';
2
- import { whatIs } from '../utils/what-is.js';
3
- import { shouldSkipValidate } from './shared.js';
4
- // ---------------------------------------------------------------------------
5
- // type
6
- // ---------------------------------------------------------------------------
7
- export function typeValidator(report, schema, json) {
8
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.2.2
9
- if (shouldSkipValidate(this.validateOptions, ['INVALID_TYPE'])) {
10
- return;
11
- }
12
- const jsonType = whatIs(json);
13
- if (typeof schema.type === 'string') {
14
- if (jsonType !== schema.type && (jsonType !== 'integer' || schema.type !== 'number')) {
15
- report.addError('INVALID_TYPE', [schema.type, jsonType], undefined, schema, 'type');
16
- }
17
- }
18
- else {
19
- if (!schema.type.includes(jsonType) && (jsonType !== 'integer' || !schema.type.includes('number'))) {
20
- report.addError('INVALID_TYPE', [JSON.stringify(schema.type), jsonType], undefined, schema, 'type');
21
- }
22
- }
23
- }
24
- // ---------------------------------------------------------------------------
25
- // enum
26
- // ---------------------------------------------------------------------------
27
- export function enumValidator(report, schema, json) {
28
- // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.5.1.2
29
- if (shouldSkipValidate(this.validateOptions, ['ENUM_CASE_MISMATCH', 'ENUM_MISMATCH'])) {
30
- return;
31
- }
32
- let match = false, caseInsensitiveMatch = false;
33
- for (const enumVal of schema.enum) {
34
- if (areEqual(json, enumVal, { maxDepth: this.options.maxRecursionDepth })) {
35
- match = true;
36
- break;
37
- }
38
- else if (areEqual(json, enumVal, { caseInsensitiveComparison: true, maxDepth: this.options.maxRecursionDepth })) {
39
- caseInsensitiveMatch = true;
40
- }
41
- }
42
- if (match === false) {
43
- const error = caseInsensitiveMatch && this.options.enumCaseInsensitiveComparison ? 'ENUM_CASE_MISMATCH' : 'ENUM_MISMATCH';
44
- report.addError(error, [JSON.stringify(json)], undefined, schema, 'enum');
45
- }
46
- }
47
- // ---------------------------------------------------------------------------
48
- // const
49
- // ---------------------------------------------------------------------------
50
- export function constValidator(report, schema, json) {
51
- const constValue = schema.const;
52
- if (areEqual(json, constValue, { maxDepth: this.options.maxRecursionDepth }) === false) {
53
- report.addError('CONST', [JSON.stringify(constValue)], undefined, schema, undefined);
54
- }
55
- }