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
@@ -0,0 +1,53 @@
1
+ import { getRemotePath, isAbsoluteUri } from "./utils/uri.mjs";
2
+ import { isObject } from "./utils/what-is.mjs";
3
+ //#region src/json-schema.ts
4
+ /**
5
+ * Keywords whose values are not JSON Schema sub-schemas and must not be
6
+ * traversed during schema walking (id collection, reference collection, etc.).
7
+ */
8
+ const NON_SCHEMA_KEYWORDS = [
9
+ "enum",
10
+ "const",
11
+ "default",
12
+ "examples"
13
+ ];
14
+ /** Returns true if the key is an internal z-schema property (prefixed with `__$`). */
15
+ const isInternalKey = (key) => key.startsWith("__$");
16
+ const getId = (schema) => {
17
+ if (typeof schema.$schema === "string" && schema.$schema.includes("draft-04")) return schema.id;
18
+ return schema.$id ?? schema.id;
19
+ };
20
+ const findId = (schema, id, targetBaseUri, currentBaseUri, maxDepth = 100, _depth = 0) => {
21
+ if (typeof schema !== "object" || schema === null) return;
22
+ if (!id) return schema;
23
+ if (_depth >= maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded in findId. If your schema is deeply nested and valid, increase the maxRecursionDepth option.`);
24
+ const baseUri = currentBaseUri ?? targetBaseUri;
25
+ const schemaId = getId(schema);
26
+ let nextBaseUri = baseUri;
27
+ if (schemaId) {
28
+ if (isAbsoluteUri(schemaId)) nextBaseUri = getRemotePath(schemaId);
29
+ else if (baseUri && isAbsoluteUri(baseUri)) try {
30
+ nextBaseUri = getRemotePath(new URL(schemaId, baseUri).toString());
31
+ } catch {}
32
+ }
33
+ if (!targetBaseUri || nextBaseUri === targetBaseUri) {
34
+ if (schemaId && (schemaId === id || schemaId[0] === "#" && schemaId.substring(1) === id)) return schema;
35
+ if (schema.$anchor === id || schema.$dynamicAnchor === id) return schema;
36
+ }
37
+ let result;
38
+ if (Array.isArray(schema)) for (let i = 0; i < schema.length; i++) {
39
+ result = findId(schema[i], id, targetBaseUri, nextBaseUri, maxDepth, _depth + 1);
40
+ if (result) return result;
41
+ }
42
+ if (isObject(schema)) {
43
+ const keys = Object.keys(schema);
44
+ for (let i = keys.length - 1; i >= 0; i--) {
45
+ const k = keys[i];
46
+ if (isInternalKey(k) || NON_SCHEMA_KEYWORDS.includes(k)) continue;
47
+ result = findId(schema[k], id, targetBaseUri, nextBaseUri, maxDepth, _depth + 1);
48
+ if (result) return result;
49
+ }
50
+ }
51
+ };
52
+ //#endregion
53
+ export { NON_SCHEMA_KEYWORDS, findId, getId, isInternalKey };
@@ -0,0 +1,441 @@
1
+ import { isObject, whatIs } from "./utils/what-is.mjs";
2
+ import { getId } from "./json-schema.mjs";
3
+ import { Report } from "./report.mjs";
4
+ import { compileSchemaRegex } from "./utils/schema-regex.mjs";
5
+ import { VALIDATION_VOCAB_KEYWORDS, getCachedValidationResult, isValidationVocabularyEnabled } from "./validation/shared.mjs";
6
+ import { additionalItemsValidator, containsValidator, itemsValidator, maxContainsValidator, maxItemsValidator, minContainsValidator, minItemsValidator, prefixItemsValidator, uniqueItemsValidator } from "./validation/array.mjs";
7
+ import { allOfValidator, anyOfValidator, elseValidator, ifValidator, notValidator, oneOfValidator, thenValidator } from "./validation/combinators.mjs";
8
+ import { exclusiveMaximumValidator, exclusiveMinimumValidator, maximumValidator, minimumValidator, multipleOfValidator } from "./validation/numeric.mjs";
9
+ import { additionalPropertiesValidator, dependenciesValidator, dependentRequiredValidator, dependentSchemasValidator, maxPropertiesValidator, minPropertiesValidator, patternPropertiesValidator, propertiesValidator, propertyNamesValidator, requiredValidator } from "./validation/object.mjs";
10
+ import { resolveDynamicRef, resolveRecursiveRef } from "./validation/ref.mjs";
11
+ import { contentEncodingValidator, contentMediaTypeValidator, formatValidator, maxLengthValidator, minLengthValidator, patternValidator } from "./validation/string.mjs";
12
+ import { constValidator, enumValidator, typeValidator } from "./validation/type.mjs";
13
+ //#region src/json-validation.ts
14
+ function collectEvaluated(args) {
15
+ const { report, currentSchema, json, mode, depth } = args;
16
+ if (!currentSchema || typeof currentSchema === "boolean") return /* @__PURE__ */ new Set();
17
+ if (depth > (this.options.maxRecursionDepth ?? 100)) {
18
+ report.addError("COLLECT_EVALUATED_DEPTH_EXCEEDED", [depth]);
19
+ return /* @__PURE__ */ new Set();
20
+ }
21
+ const evaluated = /* @__PURE__ */ new Set();
22
+ const merge = (other) => {
23
+ if (other === "all") return true;
24
+ for (const v of other) evaluated.add(v);
25
+ return false;
26
+ };
27
+ const recurse = (subSchema) => {
28
+ if (mode === "items") return collectEvaluated.call(this, {
29
+ report,
30
+ currentSchema: subSchema,
31
+ json,
32
+ mode: "items",
33
+ jsonArr: args.jsonArr,
34
+ depth: depth + 1
35
+ });
36
+ return collectEvaluated.call(this, {
37
+ report,
38
+ currentSchema: subSchema,
39
+ json,
40
+ mode: "properties",
41
+ jsonData: args.jsonData,
42
+ depth: depth + 1
43
+ });
44
+ };
45
+ if (mode === "items") {
46
+ const jsonArr = args.jsonArr;
47
+ if (Array.isArray(currentSchema.prefixItems)) {
48
+ const len = Math.min(currentSchema.prefixItems.length, jsonArr.length);
49
+ for (let i = 0; i < len; i++) evaluated.add(i);
50
+ }
51
+ if (currentSchema.items !== void 0) {
52
+ if (Array.isArray(currentSchema.items)) {
53
+ const len = Math.min(currentSchema.items.length, jsonArr.length);
54
+ for (let i = 0; i < len; i++) evaluated.add(i);
55
+ } else if (currentSchema.items !== false) return "all";
56
+ }
57
+ if (currentSchema.additionalItems !== void 0 && currentSchema.additionalItems !== false && Array.isArray(currentSchema.items)) return "all";
58
+ if (currentSchema.contains !== void 0) for (let i = 0; i < jsonArr.length; i++) {
59
+ let passed = getCachedValidationResult(report, currentSchema.contains, jsonArr[i]);
60
+ if (passed === void 0) {
61
+ const subReport = new Report(report);
62
+ validate.call(this, subReport, currentSchema.contains, jsonArr[i]);
63
+ passed = subReport.errors.length === 0;
64
+ }
65
+ if (passed) evaluated.add(i);
66
+ }
67
+ if (currentSchema.unevaluatedItems === true) return "all";
68
+ } else {
69
+ const jsonData = args.jsonData;
70
+ if (isObject(currentSchema.properties)) {
71
+ for (const key of Object.keys(currentSchema.properties)) if (Object.hasOwn(jsonData, key)) evaluated.add(key);
72
+ }
73
+ if (isObject(currentSchema.patternProperties)) for (const pattern of Object.keys(currentSchema.patternProperties)) {
74
+ const result = compileSchemaRegex(pattern);
75
+ if (result.ok) {
76
+ for (const key of Object.keys(jsonData)) if (result.value.test(key)) evaluated.add(key);
77
+ }
78
+ }
79
+ if (currentSchema.additionalProperties !== void 0) {
80
+ const propKeys = isObject(currentSchema.properties) ? Object.keys(currentSchema.properties) : [];
81
+ const patternRegexes = [];
82
+ if (isObject(currentSchema.patternProperties)) for (const pattern of Object.keys(currentSchema.patternProperties)) {
83
+ const result = compileSchemaRegex(pattern);
84
+ if (result.ok) patternRegexes.push(result.value);
85
+ }
86
+ for (const key of Object.keys(jsonData)) {
87
+ if (propKeys.includes(key)) continue;
88
+ if (patternRegexes.some((re) => re.test(key))) continue;
89
+ evaluated.add(key);
90
+ }
91
+ }
92
+ if (isObject(currentSchema.dependentSchemas)) {
93
+ for (const [depKey, depSchema] of Object.entries(currentSchema.dependentSchemas)) if (Object.hasOwn(jsonData, depKey)) {
94
+ if (merge(recurse(depSchema))) return "all";
95
+ }
96
+ }
97
+ if (currentSchema.unevaluatedProperties === true) return "all";
98
+ }
99
+ if (Array.isArray(currentSchema.allOf)) {
100
+ for (const subSchema of currentSchema.allOf) if (merge(recurse(subSchema))) return "all";
101
+ }
102
+ if (Array.isArray(currentSchema.anyOf)) for (const subSchema of currentSchema.anyOf) {
103
+ let passed = getCachedValidationResult(report, subSchema, json);
104
+ if (passed === void 0) {
105
+ const subReport = new Report(report);
106
+ validate.call(this, subReport, subSchema, json);
107
+ passed = subReport.errors.length === 0;
108
+ }
109
+ if (passed) {
110
+ if (merge(recurse(subSchema))) return "all";
111
+ }
112
+ }
113
+ if (Array.isArray(currentSchema.oneOf)) for (const subSchema of currentSchema.oneOf) {
114
+ let passed = getCachedValidationResult(report, subSchema, json);
115
+ if (passed === void 0) {
116
+ const subReport = new Report(report);
117
+ validate.call(this, subReport, subSchema, json);
118
+ passed = subReport.errors.length === 0;
119
+ }
120
+ if (passed) {
121
+ if (merge(recurse(subSchema))) return "all";
122
+ }
123
+ }
124
+ if (currentSchema.if !== void 0) {
125
+ let condPassed = getCachedValidationResult(report, currentSchema.if, json);
126
+ if (condPassed === void 0) {
127
+ const condReport = new Report(report);
128
+ validate.call(this, condReport, currentSchema.if, json);
129
+ condPassed = condReport.errors.length === 0;
130
+ }
131
+ if (condPassed) {
132
+ if (merge(recurse(currentSchema.if))) return "all";
133
+ if (currentSchema.then !== void 0) {
134
+ if (merge(recurse(currentSchema.then))) return "all";
135
+ }
136
+ } else if (currentSchema.else !== void 0) {
137
+ if (merge(recurse(currentSchema.else))) return "all";
138
+ }
139
+ }
140
+ if (currentSchema.__$refResolved && currentSchema.__$refResolved !== currentSchema) {
141
+ if (merge(recurse(currentSchema.__$refResolved))) return "all";
142
+ }
143
+ const recursiveTarget = resolveRecursiveRef(currentSchema, report.__$recursiveAnchorStack);
144
+ if (recursiveTarget && recursiveTarget !== currentSchema) {
145
+ if (merge(recurse(recursiveTarget))) return "all";
146
+ }
147
+ const dynamicTarget = resolveDynamicRef(currentSchema, report.__$dynamicScopeStack);
148
+ if (dynamicTarget && dynamicTarget !== currentSchema) {
149
+ if (merge(recurse(dynamicTarget))) return "all";
150
+ }
151
+ return evaluated;
152
+ }
153
+ function unevaluatedItemsValidator(report, schema, json) {
154
+ if (!Array.isArray(json)) return;
155
+ if (schema.unevaluatedItems === true) return;
156
+ const unevalSchema = schema.unevaluatedItems;
157
+ if (unevalSchema === void 0) return;
158
+ if (json.length === 0) return;
159
+ const evaluatedItems = collectEvaluated.call(this, {
160
+ report,
161
+ currentSchema: schema,
162
+ json,
163
+ mode: "items",
164
+ jsonArr: json,
165
+ depth: 0
166
+ });
167
+ if (evaluatedItems === "all") return;
168
+ const unevaluatedIndices = [];
169
+ for (let i = 0; i < json.length; i++) if (!evaluatedItems.has(i)) unevaluatedIndices.push(i);
170
+ if (unevaluatedIndices.length === 0) return;
171
+ if (unevalSchema === false) report.addError("ARRAY_UNEVALUATED_ITEMS", void 0, void 0, schema, "unevaluatedItems");
172
+ else for (const idx of unevaluatedIndices) {
173
+ const subReport = new Report(report);
174
+ validate.call(this, subReport, unevalSchema, json[idx]);
175
+ if (subReport.errors.length > 0) {
176
+ report.addError("ARRAY_UNEVALUATED_ITEMS", void 0, void 0, schema, "unevaluatedItems");
177
+ break;
178
+ }
179
+ }
180
+ }
181
+ function unevaluatedPropertiesValidator(report, schema, json) {
182
+ if (!isObject(json)) return;
183
+ if (schema.unevaluatedProperties === true) return;
184
+ const unevalSchema = schema.unevaluatedProperties;
185
+ if (unevalSchema === void 0) return;
186
+ const allKeys = Object.keys(json);
187
+ if (allKeys.length === 0) return;
188
+ const evaluatedProperties = collectEvaluated.call(this, {
189
+ report,
190
+ currentSchema: schema,
191
+ json,
192
+ mode: "properties",
193
+ jsonData: json,
194
+ depth: 0
195
+ });
196
+ if (evaluatedProperties === "all") return;
197
+ const unevaluatedKeys = allKeys.filter((key) => !evaluatedProperties.has(key));
198
+ if (unevaluatedKeys.length === 0) return;
199
+ if (unevalSchema === false) report.addError("OBJECT_UNEVALUATED_PROPERTIES", [unevaluatedKeys.join(", ")], void 0, schema, "unevaluatedProperties");
200
+ else for (const key of unevaluatedKeys) {
201
+ const subReport = new Report(report);
202
+ validate.call(this, subReport, unevalSchema, json[key]);
203
+ if (subReport.errors.length > 0) report.addError("OBJECT_UNEVALUATED_PROPERTIES", [key], void 0, schema, "unevaluatedProperties");
204
+ }
205
+ }
206
+ function definitionsValidator() {}
207
+ const JsonValidators = {
208
+ id: () => {},
209
+ $id: () => {},
210
+ $ref: () => {},
211
+ $schema: () => {},
212
+ $dynamicAnchor: () => {},
213
+ $dynamicRef: () => {},
214
+ $anchor: () => {},
215
+ $defs: () => {},
216
+ $vocabulary: () => {},
217
+ $recursiveAnchor: () => {},
218
+ $recursiveRef: () => {},
219
+ examples: () => {},
220
+ title: () => {},
221
+ description: () => {},
222
+ default: () => {},
223
+ type: typeValidator,
224
+ enum: enumValidator,
225
+ const: constValidator,
226
+ multipleOf: multipleOfValidator,
227
+ maximum: maximumValidator,
228
+ exclusiveMaximum: exclusiveMaximumValidator,
229
+ minimum: minimumValidator,
230
+ exclusiveMinimum: exclusiveMinimumValidator,
231
+ maxLength: maxLengthValidator,
232
+ minLength: minLengthValidator,
233
+ pattern: patternValidator,
234
+ format: formatValidator,
235
+ contentEncoding: contentEncodingValidator,
236
+ contentMediaType: contentMediaTypeValidator,
237
+ additionalItems: additionalItemsValidator,
238
+ items: itemsValidator,
239
+ prefixItems: prefixItemsValidator,
240
+ maxItems: maxItemsValidator,
241
+ minItems: minItemsValidator,
242
+ uniqueItems: uniqueItemsValidator,
243
+ contains: containsValidator,
244
+ maxContains: maxContainsValidator,
245
+ minContains: minContainsValidator,
246
+ unevaluatedItems: unevaluatedItemsValidator,
247
+ maxProperties: maxPropertiesValidator,
248
+ minProperties: minPropertiesValidator,
249
+ required: requiredValidator,
250
+ additionalProperties: additionalPropertiesValidator,
251
+ patternProperties: patternPropertiesValidator,
252
+ properties: propertiesValidator,
253
+ dependencies: dependenciesValidator,
254
+ dependentSchemas: dependentSchemasValidator,
255
+ dependentRequired: dependentRequiredValidator,
256
+ propertyNames: propertyNamesValidator,
257
+ unevaluatedProperties: unevaluatedPropertiesValidator,
258
+ allOf: allOfValidator,
259
+ anyOf: anyOfValidator,
260
+ oneOf: oneOfValidator,
261
+ not: notValidator,
262
+ if: ifValidator,
263
+ then: thenValidator,
264
+ else: elseValidator,
265
+ definitions: definitionsValidator
266
+ };
267
+ const recurseArray = function(report, schema, json) {
268
+ const schemaUri = typeof schema.$schema === "string" ? schema.$schema : void 0;
269
+ const prefixItems = (schemaUri === "https://json-schema.org/draft/2020-12/schema" || !schemaUri && this.options.version === "draft2020-12") && Array.isArray(schema.prefixItems) ? schema.prefixItems : void 0;
270
+ if (prefixItems) {
271
+ for (let idx = 0; idx < json.length; idx++) if (idx < prefixItems.length) {
272
+ report.path.push(idx);
273
+ validate.call(this, report, prefixItems[idx], json[idx]);
274
+ report.path.pop();
275
+ } else if (schema.items !== void 0 && !Array.isArray(schema.items)) {
276
+ report.path.push(idx);
277
+ report.schemaPath.push("items");
278
+ validate.call(this, report, schema.items, json[idx]);
279
+ report.schemaPath.pop();
280
+ report.path.pop();
281
+ }
282
+ return;
283
+ }
284
+ if (Array.isArray(schema.items)) {
285
+ for (let idx = 0; idx < json.length; idx++) if (idx < schema.items.length) {
286
+ report.path.push(idx);
287
+ validate.call(this, report, schema.items[idx], json[idx]);
288
+ report.path.pop();
289
+ } else if (typeof schema.additionalItems === "object") {
290
+ report.path.push(idx);
291
+ validate.call(this, report, schema.additionalItems, json[idx]);
292
+ report.path.pop();
293
+ }
294
+ } else if (typeof schema.items === "object" || typeof schema.items === "boolean") for (let idx = 0; idx < json.length; idx++) {
295
+ report.path.push(idx);
296
+ report.schemaPath.push("items");
297
+ validate.call(this, report, schema.items, json[idx]);
298
+ report.schemaPath.pop();
299
+ report.path.pop();
300
+ }
301
+ };
302
+ const recurseObject = function(report, schema, json) {
303
+ let additionalProperties = schema.additionalProperties;
304
+ if (additionalProperties === true || additionalProperties === void 0) additionalProperties = {};
305
+ const p = schema.properties ? Object.keys(schema.properties) : [];
306
+ const pp = schema.patternProperties ? Object.keys(schema.patternProperties) : [];
307
+ const keys = Object.keys(json);
308
+ for (const m of keys) {
309
+ const propertyValue = json[m];
310
+ const s = [];
311
+ if (p.includes(m)) s.push(schema.properties[m]);
312
+ for (const regexString of pp) {
313
+ const result = compileSchemaRegex(regexString);
314
+ if (result.ok && result.value.test(m) === true) s.push(schema.patternProperties[regexString]);
315
+ }
316
+ if (s.length === 0 && additionalProperties !== false) s.push(additionalProperties);
317
+ for (const schema_s of s) {
318
+ report.path.push(m);
319
+ if (p.includes(m)) {
320
+ report.schemaPath.push("properties");
321
+ report.schemaPath.push(m);
322
+ } else report.schemaPath.push("additionalProperties");
323
+ validate.call(this, report, schema_s, propertyValue);
324
+ report.path.pop();
325
+ report.schemaPath.pop();
326
+ if (p.includes(m)) report.schemaPath.pop();
327
+ }
328
+ }
329
+ };
330
+ function validate(report, schema, json) {
331
+ report.commonErrorMessage = "JSON_OBJECT_VALIDATION_FAILED";
332
+ if (schema === true) return true;
333
+ if (schema === false) {
334
+ report.addError("SCHEMA_IS_FALSE", [], void 0, schema);
335
+ return false;
336
+ }
337
+ if (!isObject(schema)) {
338
+ report.addError("SCHEMA_NOT_AN_OBJECT", [whatIs(schema)], void 0, schema);
339
+ return false;
340
+ }
341
+ let keys = Object.keys(schema);
342
+ if (keys.length === 0) return true;
343
+ let isRoot = false;
344
+ if (!report.rootSchema) {
345
+ report.rootSchema = schema;
346
+ isRoot = true;
347
+ }
348
+ const recursiveAnchorStack = report.__$recursiveAnchorStack;
349
+ const dynamicScopeStack = report.__$dynamicScopeStack;
350
+ let pushedRecursiveAnchor = false;
351
+ let pushedDynamicScope = false;
352
+ const schemaId = getId(schema);
353
+ const dynamicScopeEntry = schema.__$resourceRoot || (isRoot || typeof schemaId === "string" ? schema : void 0);
354
+ if (dynamicScopeEntry && dynamicScopeStack[dynamicScopeStack.length - 1] !== dynamicScopeEntry) {
355
+ dynamicScopeStack.push(dynamicScopeEntry);
356
+ pushedDynamicScope = true;
357
+ }
358
+ if (schema.$recursiveAnchor === true) {
359
+ recursiveAnchorStack.push(schema);
360
+ pushedRecursiveAnchor = true;
361
+ }
362
+ if (schema.$ref !== void 0) if (this.options.version === "draft2019-09" || this.options.version === "draft2020-12") {
363
+ if (!schema.__$refResolved) report.addError("REF_UNRESOLVED", [schema.$ref], void 0, schema);
364
+ else validate.call(this, report, schema.__$refResolved, json);
365
+ keys = keys.filter((key) => key !== "$ref");
366
+ } else {
367
+ let maxRefs = 99;
368
+ while (schema.$ref && maxRefs > 0) {
369
+ if (!schema.__$refResolved) {
370
+ report.addError("REF_UNRESOLVED", [schema.$ref], void 0, schema);
371
+ break;
372
+ } else if (schema.__$refResolved === schema) break;
373
+ else {
374
+ schema = schema.__$refResolved;
375
+ keys = Object.keys(schema);
376
+ }
377
+ maxRefs--;
378
+ }
379
+ if (maxRefs === 0) throw new Error("Circular dependency by $ref references!");
380
+ report.schemaPath = [];
381
+ }
382
+ if (schema.$recursiveRef !== void 0) {
383
+ if (this.options.version === "draft2019-09" || this.options.version === "draft2020-12") {
384
+ const recursiveRefTarget = resolveRecursiveRef(schema, recursiveAnchorStack);
385
+ if (!recursiveRefTarget) report.addError("REF_UNRESOLVED", [schema.$recursiveRef], void 0, schema);
386
+ else validate.call(this, report, recursiveRefTarget, json);
387
+ keys = keys.filter((key) => key !== "$recursiveRef");
388
+ }
389
+ }
390
+ if (schema.$dynamicRef !== void 0) {
391
+ if (this.options.version === "draft2020-12") {
392
+ const dynamicRefTarget = resolveDynamicRef(schema, dynamicScopeStack);
393
+ if (typeof dynamicRefTarget === "undefined") report.addError("REF_UNRESOLVED", [schema.$dynamicRef], void 0, schema);
394
+ else validate.call(this, report, dynamicRefTarget, json);
395
+ keys = keys.filter((key) => key !== "$dynamicRef");
396
+ }
397
+ }
398
+ const validationVocabularyEnabled = isValidationVocabularyEnabled(schema, report, this.options.version);
399
+ if (!validationVocabularyEnabled) keys = keys.filter((key) => !VALIDATION_VOCAB_KEYWORDS.has(key));
400
+ if (validationVocabularyEnabled && schema.type) {
401
+ keys.splice(keys.indexOf("type"), 1);
402
+ report.schemaPath.push("type");
403
+ JsonValidators.type.call(this, report, schema, json);
404
+ report.schemaPath.pop();
405
+ if (report.errors.length && this.options.breakOnFirstError) {
406
+ if (pushedRecursiveAnchor) recursiveAnchorStack.pop();
407
+ if (pushedDynamicScope) dynamicScopeStack.pop();
408
+ return false;
409
+ }
410
+ }
411
+ const deferredUnevaluatedKeys = [];
412
+ for (const key of keys) {
413
+ if (key === "unevaluatedItems" || key === "unevaluatedProperties") {
414
+ deferredUnevaluatedKeys.push(key);
415
+ continue;
416
+ }
417
+ const validator = JsonValidators[key];
418
+ if (validator) {
419
+ validator.call(this, report, schema, json);
420
+ if (report.errors.length && this.options.breakOnFirstError) break;
421
+ }
422
+ }
423
+ if (deferredUnevaluatedKeys.length > 0 && !(report.errors.length > 0 && this.options.breakOnFirstError)) for (const key of deferredUnevaluatedKeys) {
424
+ const validator = JsonValidators[key];
425
+ if (validator) {
426
+ validator.call(this, report, schema, json);
427
+ if (report.errors.length && this.options.breakOnFirstError) break;
428
+ }
429
+ }
430
+ if (report.errors.length === 0 || this.options.breakOnFirstError === false) {
431
+ if (Array.isArray(json)) recurseArray.call(this, report, schema, json);
432
+ else if (isObject(json)) recurseObject.call(this, report, schema, json);
433
+ }
434
+ if (typeof this.options.customValidator === "function") this.options.customValidator.call(this, report, schema, json);
435
+ if (pushedRecursiveAnchor) recursiveAnchorStack.pop();
436
+ if (pushedDynamicScope) dynamicScopeStack.pop();
437
+ if (isRoot) report.rootSchema = void 0;
438
+ return report.errors.length === 0;
439
+ }
440
+ //#endregion
441
+ export { validate };
@@ -0,0 +1,97 @@
1
+ import { ZSchemaOptions } from "./z-schema-options.mjs";
2
+ import { ErrorCode, ErrorParam } from "./errors.mjs";
3
+ import { ValidateCallback, ValidateOptions } from "./z-schema-base.mjs";
4
+ import { JsonSchema, JsonSchemaAll, JsonSchemaInternal } from "./json-schema-versions.mjs";
5
+
6
+ //#region src/report.d.ts
7
+ interface SchemaErrorDetail {
8
+ /**
9
+ * Example: "Expected type string but found type array"
10
+ */
11
+ message: string;
12
+ /**
13
+ * An error identifier that can be used to format a custom error message.
14
+ * Example: "INVALID_TYPE"
15
+ */
16
+ code: string;
17
+ /**
18
+ * Format parameters that can be used to format a custom error message.
19
+ * Example: ["string","array"]
20
+ */
21
+ params: ErrorParam[];
22
+ /**
23
+ * A JSON path indicating the location of the error.
24
+ * Example: "#/projects/1"
25
+ */
26
+ path: string | Array<string | number>;
27
+ /**
28
+ * A JSON path indicating the location in the schema where the constraint is defined.
29
+ * Example: ["properties", "name", "type"]
30
+ */
31
+ schemaPath?: Array<string | number>;
32
+ /**
33
+ * The schema rule description, which is included for certain errors where
34
+ * this information is useful (e.g. to describe a constraint).
35
+ */
36
+ title?: string;
37
+ description?: string;
38
+ /**
39
+ * Returns details for sub-schemas that failed to match. For example, if the schema
40
+ * uses the "oneOf" constraint to accept several alternative possibilities, each
41
+ * alternative will have its own inner detail object explaining why it failed to match.
42
+ */
43
+ inner?: SchemaErrorDetail[];
44
+ schemaId?: string;
45
+ /**
46
+ * The schema keyword that caused this validation error.
47
+ * Example: "required", "type", "minLength"
48
+ */
49
+ keyword?: keyof JsonSchemaAll;
50
+ }
51
+ interface ReportOptions {
52
+ maxErrors?: number;
53
+ }
54
+ type TaskResult = unknown;
55
+ type TaskFn = (...args: unknown[]) => TaskResult;
56
+ type TaskFnArgs = Parameters<TaskFn>;
57
+ type TaskProcessFn = (result: ReturnType<TaskFn>) => void;
58
+ type AsyncTask = [TaskFn, TaskFnArgs, TaskProcessFn];
59
+ declare class Report {
60
+ asyncTasks: AsyncTask[];
61
+ commonErrorMessage?: string;
62
+ __$recursiveAnchorStack: JsonSchemaInternal[];
63
+ __$dynamicScopeStack: JsonSchemaInternal[];
64
+ __validationResultCache: Map<unknown, Map<unknown, boolean>>;
65
+ errors: SchemaErrorDetail[];
66
+ json?: unknown;
67
+ path: Array<number | string>;
68
+ schemaPath: Array<number | string>;
69
+ rootSchema?: JsonSchemaInternal;
70
+ parentReport?: Report;
71
+ options: ZSchemaOptions;
72
+ reportOptions: ReportOptions;
73
+ validateOptions: ValidateOptions;
74
+ constructor(zschemaOptions: ZSchemaOptions, validateOptions?: ValidateOptions);
75
+ constructor(parentReport: Report, validateOptions?: ValidateOptions);
76
+ constructor(parentReport: Report, reportOptions: ReportOptions, validateOptions?: ValidateOptions);
77
+ isValid(): boolean;
78
+ addAsyncTask<FV, FN extends (...args: any[]) => FV>(fn: FN, args: Parameters<FN>, asyncTaskResultProcessFn: (result: ReturnType<FN>) => void): void;
79
+ /**
80
+ * Like {@link addAsyncTask}, but automatically saves the current `path` and
81
+ * restores it around `processFn`. This eliminates the manual
82
+ * path-save/restore boilerplate that every async-aware validator would
83
+ * otherwise need.
84
+ */
85
+ addAsyncTaskWithPath(fn: (...args: any[]) => any, args: any[], processFn: (result: any) => void): void;
86
+ getAncestor(id: string): Report | undefined;
87
+ processAsyncTasks(timeout: number | undefined, callback: ValidateCallback): void;
88
+ getPath(returnPathAsString?: boolean): string | (string | number)[];
89
+ getSchemaPath(): Array<string | number>;
90
+ getSchemaId(): string | undefined;
91
+ hasError(errCode: string, errParams: Array<any>): boolean;
92
+ addError(errCode: ErrorCode, errParams?: ErrorParam[], subReports?: Report | Report[], schema?: JsonSchema | boolean, keyword?: keyof JsonSchemaAll): void;
93
+ getJson(): unknown;
94
+ addCustomError(errorCode: ErrorCode, errorMessage: string, params?: ErrorParam[], subReports?: Report | Report[], schema?: JsonSchema | boolean, keyword?: keyof JsonSchemaAll): void;
95
+ }
96
+ //#endregion
97
+ export { Report, SchemaErrorDetail };