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.
- package/bin/z-schema +7 -2
- package/cjs/index.d.ts +541 -530
- package/cjs/index.js +3963 -7740
- package/dist/errors.d.mts +64 -0
- package/dist/errors.mjs +67 -0
- package/dist/format-validators.d.mts +14 -0
- package/dist/format-validators.mjs +261 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +7 -0
- package/dist/json-schema-versions.d.mts +137 -0
- package/dist/json-schema-versions.mjs +11 -0
- package/dist/json-schema.d.mts +61 -0
- package/dist/json-schema.mjs +53 -0
- package/dist/json-validation.mjs +441 -0
- package/dist/report.d.mts +97 -0
- package/dist/report.mjs +194 -0
- package/dist/schema-cache.d.mts +23 -0
- package/dist/schema-cache.mjs +144 -0
- package/dist/schema-compiler.d.mts +23 -0
- package/dist/schema-compiler.mjs +265 -0
- package/dist/schema-validator.d.mts +15 -0
- package/dist/schema-validator.mjs +446 -0
- package/dist/schemas/draft-04-schema.mjs +125 -0
- package/dist/schemas/draft-06-schema.mjs +126 -0
- package/dist/schemas/draft-07-schema.mjs +141 -0
- package/dist/schemas/draft-2019-09-meta-applicator.mjs +46 -0
- package/dist/schemas/draft-2019-09-meta-content.mjs +15 -0
- package/dist/schemas/draft-2019-09-meta-core.mjs +52 -0
- package/dist/schemas/draft-2019-09-meta-format.mjs +11 -0
- package/dist/schemas/draft-2019-09-meta-meta-data.mjs +31 -0
- package/dist/schemas/draft-2019-09-meta-validation.mjs +80 -0
- package/dist/schemas/draft-2019-09-schema.mjs +39 -0
- package/dist/schemas/draft-2020-12-meta-applicator.mjs +45 -0
- package/dist/schemas/draft-2020-12-meta-content.mjs +15 -0
- package/dist/schemas/draft-2020-12-meta-core.mjs +46 -0
- package/dist/schemas/draft-2020-12-meta-format-annotation.mjs +11 -0
- package/dist/schemas/draft-2020-12-meta-format-assertion.mjs +11 -0
- package/dist/schemas/draft-2020-12-meta-meta-data.mjs +31 -0
- package/dist/schemas/draft-2020-12-meta-unevaluated.mjs +14 -0
- package/dist/schemas/draft-2020-12-meta-validation.mjs +80 -0
- package/dist/schemas/draft-2020-12-schema.mjs +55 -0
- package/dist/utils/array.mjs +54 -0
- package/dist/utils/base64.mjs +21 -0
- package/dist/utils/clone.mjs +42 -0
- package/dist/utils/constants.mjs +16 -0
- package/dist/utils/date.mjs +19 -0
- package/dist/utils/hostname.mjs +73 -0
- package/dist/utils/json.mjs +34 -0
- package/dist/utils/properties.mjs +11 -0
- package/dist/utils/schema-regex.mjs +49 -0
- package/dist/utils/symbols.mjs +5 -0
- package/dist/utils/time.mjs +42 -0
- package/dist/utils/unicode.mjs +12 -0
- package/dist/utils/uri.mjs +12 -0
- package/dist/utils/what-is.mjs +23 -0
- package/dist/validation/array.mjs +57 -0
- package/dist/validation/combinators.mjs +62 -0
- package/dist/validation/numeric.mjs +38 -0
- package/dist/validation/object.mjs +109 -0
- package/dist/validation/ref.mjs +49 -0
- package/dist/validation/shared.mjs +97 -0
- package/dist/validation/string.mjs +88 -0
- package/dist/validation/type.mjs +32 -0
- package/dist/z-schema-base.d.mts +85 -0
- package/dist/z-schema-base.mjs +230 -0
- package/dist/z-schema-options.d.mts +35 -0
- package/dist/z-schema-options.mjs +55 -0
- package/dist/z-schema-reader.d.mts +6 -0
- package/dist/z-schema-reader.mjs +10 -0
- package/dist/z-schema-versions.mjs +67 -0
- package/dist/z-schema.d.mts +193 -0
- package/dist/z-schema.mjs +300 -0
- package/package.json +49 -64
- package/src/index.ts +3 -3
- package/src/schema-compiler.ts +30 -10
- package/src/schema-validator.ts +1 -1
- package/src/utils/schema-regex.ts +13 -2
- package/src/z-schema-base.ts +1 -1
- package/src/z-schema-versions.ts +1 -2
- package/src/z-schema.ts +0 -1
- package/umd/ZSchema.js +5934 -8110
- package/umd/ZSchema.min.js +2 -1
- package/dist/errors.js +0 -72
- package/dist/format-validators.js +0 -392
- package/dist/index.js +0 -5
- package/dist/json-schema-versions.js +0 -8
- package/dist/json-schema.js +0 -84
- package/dist/json-validation.js +0 -728
- package/dist/package.json +0 -3
- package/dist/report.js +0 -265
- package/dist/schema-cache.js +0 -211
- package/dist/schema-compiler.js +0 -415
- package/dist/schema-validator.js +0 -721
- package/dist/schemas/draft-04-schema.json +0 -149
- package/dist/schemas/draft-06-schema.json +0 -155
- package/dist/schemas/draft-07-schema.json +0 -172
- package/dist/schemas/draft-2019-09-meta-applicator.json +0 -52
- package/dist/schemas/draft-2019-09-meta-content.json +0 -12
- package/dist/schemas/draft-2019-09-meta-core.json +0 -53
- package/dist/schemas/draft-2019-09-meta-format.json +0 -10
- package/dist/schemas/draft-2019-09-meta-meta-data.json +0 -32
- package/dist/schemas/draft-2019-09-meta-validation.json +0 -94
- package/dist/schemas/draft-2019-09-schema.json +0 -41
- package/dist/schemas/draft-2020-12-meta-applicator.json +0 -44
- package/dist/schemas/draft-2020-12-meta-content.json +0 -12
- package/dist/schemas/draft-2020-12-meta-core.json +0 -47
- package/dist/schemas/draft-2020-12-meta-format-annotation.json +0 -10
- package/dist/schemas/draft-2020-12-meta-format-assertion.json +0 -10
- package/dist/schemas/draft-2020-12-meta-meta-data.json +0 -32
- package/dist/schemas/draft-2020-12-meta-unevaluated.json +0 -11
- package/dist/schemas/draft-2020-12-meta-validation.json +0 -94
- package/dist/schemas/draft-2020-12-schema.json +0 -57
- package/dist/types/errors.d.ts +0 -64
- package/dist/types/format-validators.d.ts +0 -11
- package/dist/types/index.d.ts +0 -14
- package/dist/types/json-schema-versions.d.ts +0 -142
- package/dist/types/json-schema.d.ts +0 -66
- package/dist/types/json-validation.d.ts +0 -6
- package/dist/types/report.d.ts +0 -94
- package/dist/types/schema-cache.d.ts +0 -27
- package/dist/types/schema-compiler.d.ts +0 -31
- package/dist/types/schema-validator.d.ts +0 -10
- package/dist/types/utils/array.d.ts +0 -9
- package/dist/types/utils/base64.d.ts +0 -2
- package/dist/types/utils/clone.d.ts +0 -2
- package/dist/types/utils/constants.d.ts +0 -19
- package/dist/types/utils/date.d.ts +0 -1
- package/dist/types/utils/hostname.d.ts +0 -2
- package/dist/types/utils/json.d.ts +0 -9
- package/dist/types/utils/properties.d.ts +0 -1
- package/dist/types/utils/schema-regex.d.ts +0 -10
- package/dist/types/utils/symbols.d.ts +0 -2
- package/dist/types/utils/time.d.ts +0 -12
- package/dist/types/utils/unicode.d.ts +0 -5
- package/dist/types/utils/uri.d.ts +0 -4
- package/dist/types/utils/what-is.d.ts +0 -4
- package/dist/types/validation/array.d.ts +0 -12
- package/dist/types/validation/combinators.d.ts +0 -10
- package/dist/types/validation/numeric.d.ts +0 -8
- package/dist/types/validation/object.d.ts +0 -13
- package/dist/types/validation/ref.d.ts +0 -11
- package/dist/types/validation/shared.d.ts +0 -26
- package/dist/types/validation/string.d.ts +0 -9
- package/dist/types/validation/type.d.ts +0 -6
- package/dist/types/z-schema-base.d.ts +0 -87
- package/dist/types/z-schema-options.d.ts +0 -35
- package/dist/types/z-schema-reader.d.ts +0 -4
- package/dist/types/z-schema-versions.d.ts +0 -1
- package/dist/types/z-schema.d.ts +0 -191
- package/dist/utils/array.js +0 -69
- package/dist/utils/base64.js +0 -29
- package/dist/utils/clone.js +0 -59
- package/dist/utils/constants.js +0 -19
- package/dist/utils/date.js +0 -21
- package/dist/utils/hostname.js +0 -146
- package/dist/utils/json.js +0 -70
- package/dist/utils/properties.js +0 -10
- package/dist/utils/schema-regex.js +0 -52
- package/dist/utils/symbols.js +0 -2
- package/dist/utils/time.js +0 -50
- package/dist/utils/unicode.js +0 -12
- package/dist/utils/uri.js +0 -15
- package/dist/utils/what-is.js +0 -32
- package/dist/validation/array.js +0 -127
- package/dist/validation/combinators.js +0 -106
- package/dist/validation/numeric.js +0 -97
- package/dist/validation/object.js +0 -237
- package/dist/validation/ref.js +0 -70
- package/dist/validation/shared.js +0 -136
- package/dist/validation/string.js +0 -170
- package/dist/validation/type.js +0 -55
- package/dist/z-schema-base.js +0 -286
- package/dist/z-schema-options.js +0 -99
- package/dist/z-schema-reader.js +0 -7
- package/dist/z-schema-versions.js +0 -110
- package/dist/z-schema.js +0 -287
package/dist/report.mjs
ADDED
|
@@ -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 };
|