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,194 @@
1
+ import { isAbsoluteUri } from "./utils/uri.mjs";
2
+ import { MAX_ASYNC_TIMEOUT } from "./utils/constants.mjs";
3
+ import { isObject } from "./utils/what-is.mjs";
4
+ import { Errors, getValidateError } from "./errors.mjs";
5
+ import { shallowClone } from "./utils/clone.mjs";
6
+ import { get } from "./utils/json.mjs";
7
+ import { jsonSymbol, schemaSymbol } from "./utils/symbols.mjs";
8
+ //#region src/report.ts
9
+ const ASYNC_TIMEOUT_POLL_MS = 10;
10
+ var Report = class Report {
11
+ asyncTasks = [];
12
+ commonErrorMessage;
13
+ __$recursiveAnchorStack = [];
14
+ __$dynamicScopeStack = [];
15
+ __validationResultCache = /* @__PURE__ */ new Map();
16
+ errors = [];
17
+ json;
18
+ path = [];
19
+ schemaPath = [];
20
+ rootSchema;
21
+ parentReport;
22
+ options;
23
+ reportOptions;
24
+ validateOptions = {};
25
+ constructor(parentOrOptions, reportOptionsOrValidate, validateOptions) {
26
+ this.parentReport = parentOrOptions instanceof Report ? parentOrOptions : void 0;
27
+ this.options = parentOrOptions instanceof Report ? parentOrOptions.options : parentOrOptions || {};
28
+ if (parentOrOptions instanceof Report) {
29
+ this.reportOptions = reportOptionsOrValidate || {};
30
+ this.validateOptions = validateOptions || parentOrOptions.validateOptions;
31
+ this.__$recursiveAnchorStack = [...parentOrOptions.__$recursiveAnchorStack];
32
+ this.__$dynamicScopeStack = [...parentOrOptions.__$dynamicScopeStack];
33
+ this.__validationResultCache = parentOrOptions.__validationResultCache;
34
+ } else {
35
+ this.reportOptions = {};
36
+ this.validateOptions = reportOptionsOrValidate || {};
37
+ this.__$recursiveAnchorStack = [];
38
+ this.__$dynamicScopeStack = [];
39
+ this.__validationResultCache = /* @__PURE__ */ new Map();
40
+ }
41
+ }
42
+ isValid() {
43
+ if (this.asyncTasks.length > 0) throw new Error("Async tasks pending, can't answer isValid");
44
+ return this.errors.length === 0;
45
+ }
46
+ addAsyncTask(fn, args, asyncTaskResultProcessFn) {
47
+ this.asyncTasks.push([
48
+ fn,
49
+ args,
50
+ asyncTaskResultProcessFn
51
+ ]);
52
+ }
53
+ /**
54
+ * Like {@link addAsyncTask}, but automatically saves the current `path` and
55
+ * restores it around `processFn`. This eliminates the manual
56
+ * path-save/restore boilerplate that every async-aware validator would
57
+ * otherwise need.
58
+ */
59
+ addAsyncTaskWithPath(fn, args, processFn) {
60
+ const pathBefore = shallowClone(this.path);
61
+ this.asyncTasks.push([
62
+ fn,
63
+ args,
64
+ (result) => {
65
+ const backup = this.path;
66
+ this.path = pathBefore;
67
+ processFn(result);
68
+ this.path = backup;
69
+ }
70
+ ]);
71
+ }
72
+ getAncestor(id) {
73
+ if (!this.parentReport) return;
74
+ if (this.parentReport.getSchemaId() === id) return this.parentReport;
75
+ return this.parentReport.getAncestor(id);
76
+ }
77
+ processAsyncTasks(timeout, callback) {
78
+ const validationTimeout = Math.min(Math.max(timeout || 2e3, 0), MAX_ASYNC_TIMEOUT);
79
+ const timeoutAt = Date.now() + validationTimeout;
80
+ let tasksCount = this.asyncTasks.length;
81
+ let timedOut = false;
82
+ const finish = () => {
83
+ setTimeout(() => {
84
+ const valid = this.errors.length === 0;
85
+ callback(valid ? void 0 : getValidateError({ details: this.errors }), valid);
86
+ }, 0);
87
+ };
88
+ const respond = (asyncTaskResultProcessFn) => (asyncTaskResult) => {
89
+ if (timedOut) return;
90
+ asyncTaskResultProcessFn(asyncTaskResult);
91
+ if (--tasksCount === 0) finish();
92
+ };
93
+ if (tasksCount === 0 || this.errors.length > 0 && this.options.breakOnFirstError) {
94
+ finish();
95
+ return;
96
+ }
97
+ for (let i = 0; i < this.asyncTasks.length; i++) {
98
+ const [fn, fnArgs, processFn] = this.asyncTasks[i];
99
+ const respondCallback = respond(processFn);
100
+ fn(...fnArgs, respondCallback);
101
+ }
102
+ const checkTimeout = () => {
103
+ if (timedOut || tasksCount <= 0) return;
104
+ if (Date.now() >= timeoutAt) {
105
+ timedOut = true;
106
+ this.addError("ASYNC_TIMEOUT", [tasksCount, validationTimeout]);
107
+ callback(getValidateError({ details: this.errors }), false);
108
+ return;
109
+ }
110
+ setTimeout(checkTimeout, ASYNC_TIMEOUT_POLL_MS);
111
+ };
112
+ setTimeout(checkTimeout, ASYNC_TIMEOUT_POLL_MS);
113
+ }
114
+ getPath(returnPathAsString) {
115
+ let path = [];
116
+ if (this.parentReport) path = path.concat(this.parentReport.path);
117
+ path = path.concat(this.path);
118
+ if (returnPathAsString !== true) return "#/" + path.map(function(segment) {
119
+ segment = segment.toString();
120
+ if (isAbsoluteUri(segment)) return "uri(" + segment + ")";
121
+ return segment.replace(/~/g, "~0").replace(/\//g, "~1");
122
+ }).join("/");
123
+ return path;
124
+ }
125
+ getSchemaPath() {
126
+ let schemaPath = [];
127
+ if (this.parentReport) schemaPath = schemaPath.concat(this.parentReport.schemaPath);
128
+ schemaPath = schemaPath.concat(this.schemaPath);
129
+ return schemaPath;
130
+ }
131
+ getSchemaId() {
132
+ if (!this.rootSchema) return;
133
+ let path = [];
134
+ if (this.parentReport) path = path.concat(this.parentReport.path);
135
+ path = path.concat(this.path);
136
+ while (path.length > 0) {
137
+ const obj = get(this.rootSchema, path);
138
+ if (obj && obj.id) return obj.id;
139
+ path.pop();
140
+ }
141
+ return this.rootSchema.id;
142
+ }
143
+ hasError(errCode, errParams) {
144
+ for (let idx = 0; idx < this.errors.length; idx++) if (this.errors[idx].code === errCode) {
145
+ let match = true;
146
+ for (let idx2 = 0; idx2 < this.errors[idx].params.length; idx2++) if (this.errors[idx].params[idx2] !== errParams[idx2]) match = false;
147
+ if (match) return match;
148
+ }
149
+ return false;
150
+ }
151
+ addError(errCode, errParams, subReports, schema, keyword) {
152
+ if (!errCode) throw new Error("No errorCode passed into addError()");
153
+ this.addCustomError(errCode, Errors[errCode], errParams, subReports, schema, keyword);
154
+ }
155
+ getJson() {
156
+ if (this.json) return this.json;
157
+ if (this.parentReport) return this.parentReport.getJson();
158
+ }
159
+ addCustomError(errorCode, errorMessage, params, subReports, schema, keyword) {
160
+ if (typeof this.reportOptions.maxErrors === "number" && this.errors.length >= this.reportOptions.maxErrors) return;
161
+ if (!errorMessage) throw new Error("No errorMessage known for code " + errorCode);
162
+ params = params || [];
163
+ for (let idx = 0; idx < params.length; idx++) {
164
+ const param = params[idx] === null || isObject(params[idx]) ? JSON.stringify(params[idx]) : params[idx];
165
+ errorMessage = errorMessage.replace("{" + idx + "}", param.toString());
166
+ }
167
+ const err = {
168
+ code: errorCode,
169
+ params,
170
+ message: errorMessage,
171
+ path: this.getPath(this.options.reportPathAsArray),
172
+ schemaPath: this.getSchemaPath(),
173
+ schemaId: this.getSchemaId(),
174
+ keyword
175
+ };
176
+ err[schemaSymbol] = schema;
177
+ err[jsonSymbol] = this.getJson();
178
+ if (schema && typeof schema === "string") err.description = schema;
179
+ else if (schema && typeof schema === "object") {
180
+ if (schema.title) err.title = schema.title;
181
+ if (schema.description) err.description = schema.description;
182
+ }
183
+ if (subReports != null) {
184
+ if (!Array.isArray(subReports)) subReports = [subReports];
185
+ err.inner = [];
186
+ for (const subReport of subReports) for (const error of subReport.errors) err.inner.push(error);
187
+ if (err.inner.length === 0) err.inner = void 0;
188
+ }
189
+ if (Array.isArray(this.validateOptions.excludeErrors) && this.validateOptions.excludeErrors.includes(errorCode)) return;
190
+ this.errors.push(err);
191
+ }
192
+ };
193
+ //#endregion
194
+ export { Report };
@@ -0,0 +1,23 @@
1
+ import { Report } from "./report.mjs";
2
+ import { ZSchemaBase } from "./z-schema-base.mjs";
3
+ import { JsonSchema, JsonSchemaInternal } from "./json-schema-versions.mjs";
4
+
5
+ //#region src/schema-cache.d.ts
6
+ type SchemaCacheStorage = Record<string, JsonSchemaInternal>;
7
+ declare class SchemaCache {
8
+ private validator;
9
+ static global_cache: SchemaCacheStorage;
10
+ cache: SchemaCacheStorage;
11
+ constructor(validator: ZSchemaBase);
12
+ static cacheSchemaByUri(uri: string, schema: JsonSchemaInternal): void;
13
+ cacheSchemaByUri(uri: string, schema: JsonSchemaInternal): void;
14
+ removeFromCacheByUri(uri: string): void;
15
+ checkCacheForUri(uri: string): boolean;
16
+ getSchema(report: Report, refOrSchema: string): JsonSchemaInternal | undefined;
17
+ getSchema(report: Report, refOrSchema: JsonSchema): JsonSchemaInternal;
18
+ getSchema(report: Report, refOrSchema: JsonSchema[]): JsonSchemaInternal[];
19
+ fromCache(path: string): JsonSchemaInternal | undefined;
20
+ getSchemaByUri(report: Report, uri: string, root?: JsonSchemaInternal): JsonSchemaInternal | undefined;
21
+ }
22
+ //#endregion
23
+ export { SchemaCache };
@@ -0,0 +1,144 @@
1
+ import { getQueryPath, getRemotePath, isAbsoluteUri } from "./utils/uri.mjs";
2
+ import { findId, getId } from "./json-schema.mjs";
3
+ import { deepClone } from "./utils/clone.mjs";
4
+ import { decodeJSONPointer } from "./utils/json.mjs";
5
+ import { Report } from "./report.mjs";
6
+ import { normalizeOptions } from "./z-schema-options.mjs";
7
+ //#region src/schema-cache.ts
8
+ function getSafeRemotePath(uri) {
9
+ const remotePath = getRemotePath(uri);
10
+ if (!remotePath) return;
11
+ if (remotePath === "__proto__" || remotePath === "constructor" || remotePath === "prototype") return;
12
+ return remotePath;
13
+ }
14
+ const getEffectiveId = (schema) => {
15
+ let id = getId(schema);
16
+ if ((!id || !isAbsoluteUri(id)) && typeof schema.id === "string" && isAbsoluteUri(schema.id)) id = schema.id;
17
+ return id;
18
+ };
19
+ /**
20
+ * Shared logic for registering a remote reference schema.
21
+ * Used by both the static `ZSchema.setRemoteReference()` (global cache) and
22
+ * the instance `validator.setRemoteReference()` (instance cache).
23
+ */
24
+ function prepareRemoteSchema(schema, uri, validationOptions, maxCloneDepth) {
25
+ let _schema;
26
+ if (typeof schema === "string") _schema = JSON.parse(schema);
27
+ else _schema = deepClone(schema, maxCloneDepth);
28
+ if (!_schema.id) _schema.id = uri;
29
+ if (validationOptions) _schema.__$validationOptions = normalizeOptions(validationOptions);
30
+ return _schema;
31
+ }
32
+ var SchemaCache = class SchemaCache {
33
+ static global_cache = Object.create(null);
34
+ cache = Object.create(null);
35
+ constructor(validator) {
36
+ this.validator = validator;
37
+ }
38
+ static cacheSchemaByUri(uri, schema) {
39
+ const remotePath = getSafeRemotePath(uri);
40
+ if (remotePath) this.global_cache[remotePath] = schema;
41
+ }
42
+ cacheSchemaByUri(uri, schema) {
43
+ const remotePath = getSafeRemotePath(uri);
44
+ if (remotePath) this.cache[remotePath] = schema;
45
+ }
46
+ removeFromCacheByUri(uri) {
47
+ const remotePath = getSafeRemotePath(uri);
48
+ if (remotePath) delete this.cache[remotePath];
49
+ }
50
+ checkCacheForUri(uri) {
51
+ const remotePath = getSafeRemotePath(uri);
52
+ return remotePath ? this.cache[remotePath] != null : false;
53
+ }
54
+ getSchema(report, refOrSchema) {
55
+ if (Array.isArray(refOrSchema)) return refOrSchema.map((i) => this.getSchema(report, i));
56
+ if (typeof refOrSchema === "string") return this.getSchemaByUri(report, refOrSchema);
57
+ return deepClone(refOrSchema, this.validator.options.maxRecursionDepth);
58
+ }
59
+ fromCache(path) {
60
+ if (path === "__proto__" || path === "constructor" || path === "prototype") return;
61
+ let found = this.cache[path];
62
+ if (found) return found;
63
+ found = SchemaCache.global_cache[path];
64
+ if (found) {
65
+ const clone = deepClone(found, this.validator.options.maxRecursionDepth);
66
+ if (!clone.id || !isAbsoluteUri(clone.id) && isAbsoluteUri(path)) clone.id = path;
67
+ this.cache[path] = clone;
68
+ return clone;
69
+ }
70
+ }
71
+ getSchemaByUri(report, uri, root) {
72
+ if (root && !isAbsoluteUri(uri)) {
73
+ const rootId = getEffectiveId(root);
74
+ if (rootId && isAbsoluteUri(rootId)) {
75
+ const hashIndex = rootId.indexOf("#");
76
+ const rootBase = hashIndex === -1 ? rootId : rootId.slice(0, hashIndex);
77
+ try {
78
+ uri = new URL(uri, rootBase).toString();
79
+ } catch {}
80
+ }
81
+ }
82
+ const remotePath = getSafeRemotePath(uri);
83
+ const queryPath = getQueryPath(uri);
84
+ let result;
85
+ let resolvedFromAncestor = false;
86
+ if (remotePath) {
87
+ const ancestorReport = report.getAncestor(remotePath);
88
+ if (ancestorReport?.rootSchema) {
89
+ result = ancestorReport.rootSchema;
90
+ resolvedFromAncestor = true;
91
+ }
92
+ }
93
+ if (!result && root && remotePath) {
94
+ const rootId = getEffectiveId(root);
95
+ const rootRemotePath = rootId ? getRemotePath(rootId) : void 0;
96
+ if (rootRemotePath && rootRemotePath === remotePath) result = root;
97
+ }
98
+ if (!result) result = remotePath ? this.fromCache(remotePath) : root;
99
+ if (result && remotePath && isAbsoluteUri(remotePath) && (!result.id || !isAbsoluteUri(result.id))) result.id = remotePath;
100
+ if (result && remotePath) {
101
+ if (result !== root && !resolvedFromAncestor) {
102
+ report.path.push(remotePath);
103
+ let remoteReport;
104
+ let usesAncestorReport = false;
105
+ const anscestorReport = result.id ? report.getAncestor(result.id) : void 0;
106
+ if (anscestorReport) {
107
+ remoteReport = anscestorReport;
108
+ usesAncestorReport = true;
109
+ } else {
110
+ remoteReport = new Report(report);
111
+ const noCache = result.id && isAbsoluteUri(result.id) ? false : true;
112
+ if (this.validator.sc.compileSchema(remoteReport, result, { noCache })) {
113
+ const savedOptions = this.validator.options;
114
+ try {
115
+ this.validator.options = result.__$validationOptions || this.validator.options;
116
+ const parentSchemaUri = typeof result.$schema === "string" ? getRemotePath(result.$schema) : void 0;
117
+ const currentSchemaUri = report.getSchemaId();
118
+ if (!(!!parentSchemaUri && parentSchemaUri.length > 0 && (currentSchemaUri === parentSchemaUri || !!report.getAncestor(parentSchemaUri)))) this.validator.sv.validateSchema(remoteReport, result);
119
+ } finally {
120
+ this.validator.options = savedOptions;
121
+ }
122
+ }
123
+ }
124
+ const remoteReportIsValid = usesAncestorReport ? true : remoteReport.isValid();
125
+ if (!remoteReportIsValid) report.addError("REMOTE_NOT_VALID", [uri], remoteReport);
126
+ report.path.pop();
127
+ if (!remoteReportIsValid) return;
128
+ }
129
+ }
130
+ const resourceRoot = result;
131
+ if (result && queryPath) {
132
+ const parts = queryPath.split("/");
133
+ for (let idx = 0, lim = parts.length; result && idx < lim; idx++) {
134
+ const key = decodeJSONPointer(parts[idx]);
135
+ if (idx === 0) result = findId(result, key, remotePath, remotePath, this.validator.options.maxRecursionDepth);
136
+ else result = result[key];
137
+ }
138
+ }
139
+ if (result && typeof result === "object" && resourceRoot && typeof resourceRoot === "object") result.__$resourceRoot = resourceRoot;
140
+ return result;
141
+ }
142
+ };
143
+ //#endregion
144
+ export { SchemaCache, prepareRemoteSchema };
@@ -0,0 +1,23 @@
1
+ import { Report } from "./report.mjs";
2
+ import { ZSchemaBase } from "./z-schema-base.mjs";
3
+ import { JsonSchemaInternal } from "./json-schema-versions.mjs";
4
+
5
+ //#region src/schema-compiler.d.ts
6
+ interface Reference {
7
+ ref: string;
8
+ key: '$ref' | '$schema' | '$recursiveRef' | '$dynamicRef';
9
+ obj: JsonSchemaInternal;
10
+ path: Array<string | number>;
11
+ }
12
+ declare class SchemaCompiler {
13
+ private validator;
14
+ constructor(validator: ZSchemaBase);
15
+ collectAndCacheIds(schema: JsonSchemaInternal): void;
16
+ compileSchema(report: Report, schema: JsonSchemaInternal | JsonSchemaInternal[], options?: {
17
+ noCache?: boolean;
18
+ }): boolean;
19
+ compileArrayOfSchemas(report: Report, arr: JsonSchemaInternal[]): boolean;
20
+ compileArrayOfSchemasLoop(mainReport: Report, arr: JsonSchemaInternal[]): number;
21
+ }
22
+ //#endregion
23
+ export { Reference, SchemaCompiler };
@@ -0,0 +1,265 @@
1
+ import { getRemotePath, isAbsoluteUri } from "./utils/uri.mjs";
2
+ import { NON_SCHEMA_KEYWORDS, getId, isInternalKey } from "./json-schema.mjs";
3
+ import { Report } from "./report.mjs";
4
+ import { getSchemaReader } from "./z-schema-reader.mjs";
5
+ //#region src/schema-compiler.ts
6
+ const UNSAFE_TARGETS = [
7
+ Object.prototype,
8
+ Function.prototype,
9
+ Array.prototype
10
+ ];
11
+ /** Returns true if `obj` is a built-in prototype that must not be mutated. */
12
+ function isUnsafeTarget(obj) {
13
+ return UNSAFE_TARGETS.includes(obj);
14
+ }
15
+ /** Safely assign a property on `obj`, refusing prototype-polluting keys. */
16
+ function safeSetProperty(obj, key, value) {
17
+ if (isUnsafeTarget(obj)) return;
18
+ /** Reject property names that could pollute Object.prototype (CWE-1321). */
19
+ if (key !== "__proto__" && key !== "constructor" && key !== "prototype") obj[key] = value;
20
+ }
21
+ /** Safely delete a property from `obj`, refusing to mutate built-in prototypes (CWE-1321). */
22
+ function safeDeleteProperty(obj, key) {
23
+ if (isUnsafeTarget(obj)) return;
24
+ if (key !== "__proto__" && key !== "constructor" && key !== "prototype") delete obj[key];
25
+ }
26
+ const collectIds = (obj, maxDepth = 100) => {
27
+ const ids = [];
28
+ function walk(node, scope, _depth = 0) {
29
+ if (typeof node !== "object" || node == null) return;
30
+ if (_depth >= maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded in collectIds. If your schema is deeply nested and valid, increase the maxRecursionDepth option.`);
31
+ let addedScope = false;
32
+ const nodeId = getId(node);
33
+ if (typeof nodeId === "string") {
34
+ let type = isAbsoluteUri(nodeId) ? "absolute" : "relative";
35
+ if (scope.length === 0) type = "root";
36
+ const id = {
37
+ id: nodeId,
38
+ type,
39
+ obj: node
40
+ };
41
+ if (type === "absolute" || type === "root" && isAbsoluteUri(nodeId)) id.absoluteUri = nodeId;
42
+ else if (type === "root" && typeof node.id === "string" && isAbsoluteUri(node.id) && node.id !== nodeId) id.absoluteUri = resolveSchemaScopeId(node.id, node, nodeId);
43
+ else if (type === "relative") {
44
+ id.absoluteParent = scope.filter((x) => x.type === "absolute" || x.type === "root" && x.absoluteUri).slice(-1)[0];
45
+ if (id.absoluteParent) id.absoluteUri = resolveSchemaScopeId(id.absoluteParent.absoluteUri || id.absoluteParent.id, node, id.id);
46
+ }
47
+ ids.push(id);
48
+ scope.push(id);
49
+ addedScope = true;
50
+ }
51
+ if (Array.isArray(node)) for (const item of node) walk(item, scope, _depth + 1);
52
+ else for (const key of Object.keys(node)) {
53
+ if (isInternalKey(key) || NON_SCHEMA_KEYWORDS.includes(key)) continue;
54
+ walk(node[key], scope, _depth + 1);
55
+ }
56
+ if (addedScope) scope.pop();
57
+ }
58
+ walk(obj, []);
59
+ return ids;
60
+ };
61
+ const collectReferences = (obj, results, scope, path, options, maxDepth = 100, _depth = 0) => {
62
+ results = results || [];
63
+ scope = scope || [];
64
+ path = path || [];
65
+ options = options || {};
66
+ if (typeof obj !== "object" || obj === null) return results;
67
+ if (_depth >= maxDepth) throw new Error(`Maximum recursion depth (${maxDepth}) exceeded in collectReferences. If your schema is deeply nested and valid, increase the maxRecursionDepth option.`);
68
+ const hasRef = typeof obj.$ref === "string" && typeof obj.__$refResolved === "undefined";
69
+ let addedScope = false;
70
+ const isRootScope = scope.length === 0;
71
+ let scopeId = getId(obj);
72
+ if (typeof obj.id === "string" && isAbsoluteUri(obj.id) && (!scopeId || !isAbsoluteUri(scopeId))) scopeId = obj.id;
73
+ if (typeof scopeId === "string" && (isRootScope || !hasRef || options.useRefObjectScope === true)) {
74
+ const base = scope.length > 0 ? scope[scope.length - 1] : void 0;
75
+ scope.push(resolveSchemaScopeId(base, obj, scopeId));
76
+ addedScope = true;
77
+ }
78
+ if (hasRef) results.push({
79
+ ref: resolveReference(scope[scope.length - 1], obj.$ref),
80
+ key: "$ref",
81
+ obj,
82
+ path: path.slice(0)
83
+ });
84
+ if (typeof obj.$recursiveRef === "string" && typeof obj.__$recursiveRefResolved === "undefined") results.push({
85
+ ref: resolveReference(scope[scope.length - 1], obj.$recursiveRef),
86
+ key: "$recursiveRef",
87
+ obj,
88
+ path: path.slice(0)
89
+ });
90
+ if (typeof obj.$dynamicRef === "string" && typeof obj.__$dynamicRefResolved === "undefined") results.push({
91
+ ref: resolveReference(scope[scope.length - 1], obj.$dynamicRef),
92
+ key: "$dynamicRef",
93
+ obj,
94
+ path: path.slice(0)
95
+ });
96
+ if (typeof obj.$schema === "string" && typeof obj.__$schemaResolved === "undefined") results.push({
97
+ ref: resolveReference(scope[scope.length - 1], obj.$schema),
98
+ key: "$schema",
99
+ obj,
100
+ path: path.slice(0)
101
+ });
102
+ if (Array.isArray(obj)) for (let i = 0; i < obj.length; i++) {
103
+ path.push(i);
104
+ collectReferences(obj[i], results, scope, path, options, maxDepth, _depth + 1);
105
+ path.pop();
106
+ }
107
+ else {
108
+ const keys = Object.keys(obj);
109
+ for (const key of keys) {
110
+ if (isInternalKey(key) || NON_SCHEMA_KEYWORDS.includes(key)) continue;
111
+ path.push(key);
112
+ collectReferences(obj[key], results, scope, path, options, maxDepth, _depth + 1);
113
+ path.pop();
114
+ }
115
+ }
116
+ if (addedScope) scope.pop();
117
+ return results;
118
+ };
119
+ const resolveReference = (base, ref) => {
120
+ if (isAbsoluteUri(ref)) return ref;
121
+ const baseStr = base ?? "";
122
+ if (ref[0] === "#") {
123
+ const hashIndex = baseStr.indexOf("#");
124
+ return (hashIndex === -1 ? baseStr : baseStr.slice(0, hashIndex)) + ref;
125
+ }
126
+ if (!baseStr) return ref;
127
+ const hashIndex = baseStr.indexOf("#");
128
+ const baseNoFrag = hashIndex === -1 ? baseStr : baseStr.slice(0, hashIndex);
129
+ if (isAbsoluteUri(baseNoFrag)) try {
130
+ return new URL(ref, baseNoFrag).toString();
131
+ } catch {}
132
+ let baseDir = baseNoFrag;
133
+ if (!baseDir.endsWith("/")) {
134
+ const lastSlash = baseDir.lastIndexOf("/");
135
+ baseDir = lastSlash === -1 ? "" : baseDir.slice(0, lastSlash + 1);
136
+ }
137
+ return baseDir + ref;
138
+ };
139
+ const isSimpleIdentifier = (id) => id[0] !== "#" && !id.includes("/") && !id.includes(".") && !id.includes("#");
140
+ const resolveIdScope = (base, id) => {
141
+ if (isAbsoluteUri(id)) return id;
142
+ const baseStr = base ?? "";
143
+ if (isSimpleIdentifier(id)) {
144
+ const hashIndex = baseStr.indexOf("#");
145
+ return (hashIndex === -1 ? baseStr : baseStr.slice(0, hashIndex)) + "#" + id;
146
+ }
147
+ return resolveReference(base, id);
148
+ };
149
+ const resolveSchemaScopeId = (base, schema, id) => {
150
+ if (typeof schema.$id === "string") return resolveReference(base, id);
151
+ return resolveIdScope(base, id);
152
+ };
153
+ var SchemaCompiler = class {
154
+ constructor(validator) {
155
+ this.validator = validator;
156
+ }
157
+ collectAndCacheIds(schema) {
158
+ const ids = collectIds(schema, this.validator.options.maxRecursionDepth);
159
+ for (const item of ids) if (item.absoluteUri) {
160
+ this.validator.scache.cacheSchemaByUri(item.absoluteUri, item.obj);
161
+ if (item.type === "relative" && item.absoluteParent && isSimpleIdentifier(item.id)) {
162
+ const altAbsoluteUri = resolveReference(item.absoluteParent.absoluteUri || item.absoluteParent.id, item.id);
163
+ this.validator.scache.cacheSchemaByUri(altAbsoluteUri, item.obj);
164
+ }
165
+ } else if (item.type === "root") this.validator.scache.cacheSchemaByUri(item.id, item.obj);
166
+ }
167
+ compileSchema(report, schema, options) {
168
+ report.commonErrorMessage = "SCHEMA_COMPILATION_FAILED";
169
+ if (typeof schema === "string") {
170
+ const loadedSchema = this.validator.scache.getSchemaByUri(report, schema);
171
+ if (typeof loadedSchema === "undefined") {
172
+ report.addError("SCHEMA_NOT_REACHABLE", [schema]);
173
+ return false;
174
+ }
175
+ schema = loadedSchema;
176
+ }
177
+ if (Array.isArray(schema)) {
178
+ if (!options?.noCache) schema.forEach((s) => this.collectAndCacheIds(s));
179
+ return this.compileArrayOfSchemas(report, schema);
180
+ } else if (typeof schema === "boolean") return true;
181
+ else if (!options?.noCache) this.collectAndCacheIds(schema);
182
+ const canMutateSchemaObject = schema !== Object.prototype && schema !== Function.prototype && schema !== Array.prototype;
183
+ if (canMutateSchemaObject && schema.__$compiled && schema.id && this.validator.scache.checkCacheForUri(schema.id) === false) schema.__$compiled = void 0;
184
+ if (schema.__$compiled) return true;
185
+ if (canMutateSchemaObject && !schema.$schema && this.validator.options.version !== "none") schema.$schema = this.validator.getDefaultSchemaId();
186
+ if (schema.id && typeof schema.id === "string" && !options?.noCache) this.validator.scache.cacheSchemaByUri(schema.id, schema);
187
+ let isRoot = false;
188
+ if (!report.rootSchema) {
189
+ report.rootSchema = schema;
190
+ isRoot = true;
191
+ }
192
+ const isValidExceptReferences = report.isValid();
193
+ if (canMutateSchemaObject) safeDeleteProperty(schema, "__$missingReferences");
194
+ const useRefObjectScope = this.validator.options.version === "draft2019-09" || this.validator.options.version === "draft2020-12";
195
+ const refs = collectReferences(schema, void 0, void 0, void 0, { useRefObjectScope }, this.validator.options.maxRecursionDepth);
196
+ for (const refObj of refs) {
197
+ let response = this.validator.scache.getSchemaByUri(report, refObj.ref, schema);
198
+ if (typeof response === "undefined") {
199
+ const schemaReader = getSchemaReader();
200
+ if (schemaReader) {
201
+ const remotePath = getRemotePath(refObj.ref);
202
+ const s = schemaReader(remotePath);
203
+ if (s) {
204
+ s.id = remotePath;
205
+ const subreport = new Report(report);
206
+ if (!this.compileSchema(subreport, s)) report.errors = report.errors.concat(subreport.errors);
207
+ else response = this.validator.scache.getSchemaByUri(report, refObj.ref, schema);
208
+ }
209
+ }
210
+ }
211
+ if (typeof response === "undefined") {
212
+ const hasNotValid = report.hasError("REMOTE_NOT_VALID", [refObj.ref]);
213
+ const isAbsolute = isAbsoluteUri(refObj.ref);
214
+ let isDownloaded = false;
215
+ const ignoreUnresolvableRemotes = this.validator.options.ignoreUnresolvableReferences === true;
216
+ if (isAbsolute) isDownloaded = this.validator.scache.checkCacheForUri(refObj.ref);
217
+ if (hasNotValid) {} else if (ignoreUnresolvableRemotes && isAbsolute) {} else if (isDownloaded) {} else {
218
+ report.path.push(...refObj.path);
219
+ report.addError("UNRESOLVABLE_REFERENCE", [refObj.ref]);
220
+ report.path = report.path.slice(0, -refObj.path.length);
221
+ if (isValidExceptReferences && canMutateSchemaObject && !isUnsafeTarget(schema)) {
222
+ schema.__$missingReferences = schema.__$missingReferences || [];
223
+ schema.__$missingReferences.push(refObj);
224
+ }
225
+ }
226
+ }
227
+ safeSetProperty(refObj.obj, `__${refObj.key}Resolved`, response);
228
+ }
229
+ const isValid = report.isValid();
230
+ if (isValid && canMutateSchemaObject) schema.__$compiled = true;
231
+ if (isRoot) report.rootSchema = void 0;
232
+ return isValid;
233
+ }
234
+ compileArrayOfSchemas(report, arr) {
235
+ let compiled = 0, lastLoopCompiled;
236
+ do {
237
+ report.errors = report.errors.filter((e) => e.code !== "UNRESOLVABLE_REFERENCE");
238
+ lastLoopCompiled = compiled;
239
+ compiled = this.compileArrayOfSchemasLoop(report, arr);
240
+ for (const sch of arr) if (sch.__$missingReferences) {
241
+ for (let idx2 = sch.__$missingReferences.length - 1; idx2 >= 0; idx2--) {
242
+ const refObj = sch.__$missingReferences[idx2];
243
+ const response = arr.find((x) => x.id === refObj.ref);
244
+ if (response) {
245
+ safeSetProperty(refObj.obj, `__${refObj.key}Resolved`, response);
246
+ sch.__$missingReferences.splice(idx2, 1);
247
+ }
248
+ }
249
+ if (sch.__$missingReferences.length === 0) safeDeleteProperty(sch, "__$missingReferences");
250
+ }
251
+ } while (compiled !== arr.length && compiled !== lastLoopCompiled);
252
+ return report.isValid();
253
+ }
254
+ compileArrayOfSchemasLoop(mainReport, arr) {
255
+ let compiledCount = 0;
256
+ for (const schema of arr) {
257
+ const report = new Report(mainReport);
258
+ if (this.compileSchema(report, schema)) compiledCount++;
259
+ mainReport.errors = mainReport.errors.concat(report.errors);
260
+ }
261
+ return compiledCount;
262
+ }
263
+ };
264
+ //#endregion
265
+ export { SchemaCompiler };
@@ -0,0 +1,15 @@
1
+ import { ZSchemaOptions } from "./z-schema-options.mjs";
2
+ import { Report } from "./report.mjs";
3
+ import { ZSchemaBase } from "./z-schema-base.mjs";
4
+ import { JsonSchemaInternal } from "./json-schema-versions.mjs";
5
+
6
+ //#region src/schema-validator.d.ts
7
+ declare class SchemaValidator {
8
+ private validator;
9
+ constructor(validator: ZSchemaBase);
10
+ get options(): ZSchemaOptions;
11
+ validateArrayOfSchemas(report: Report, arr: Array<JsonSchemaInternal | boolean>): boolean;
12
+ validateSchema(report: Report, schema: JsonSchemaInternal | boolean | Array<JsonSchemaInternal | boolean>): boolean;
13
+ }
14
+ //#endregion
15
+ export { SchemaValidator };