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/package.json
DELETED
package/dist/report.js
DELETED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { Errors, getValidateError } from './errors.js';
|
|
2
|
-
import { shallowClone } from './utils/clone.js';
|
|
3
|
-
import { MAX_ASYNC_TIMEOUT } from './utils/constants.js';
|
|
4
|
-
import { get } from './utils/json.js';
|
|
5
|
-
import { jsonSymbol, schemaSymbol } from './utils/symbols.js';
|
|
6
|
-
import { isAbsoluteUri } from './utils/uri.js';
|
|
7
|
-
import { isObject } from './utils/what-is.js';
|
|
8
|
-
const ASYNC_TIMEOUT_POLL_MS = 10;
|
|
9
|
-
export class Report {
|
|
10
|
-
asyncTasks = [];
|
|
11
|
-
commonErrorMessage;
|
|
12
|
-
__$recursiveAnchorStack = [];
|
|
13
|
-
__$dynamicScopeStack = [];
|
|
14
|
-
__validationResultCache = new Map();
|
|
15
|
-
errors = [];
|
|
16
|
-
json;
|
|
17
|
-
path = [];
|
|
18
|
-
schemaPath = [];
|
|
19
|
-
rootSchema;
|
|
20
|
-
parentReport;
|
|
21
|
-
options;
|
|
22
|
-
reportOptions;
|
|
23
|
-
validateOptions = {};
|
|
24
|
-
constructor(parentOrOptions, reportOptionsOrValidate, validateOptions) {
|
|
25
|
-
this.parentReport = parentOrOptions instanceof Report ? parentOrOptions : undefined;
|
|
26
|
-
this.options = parentOrOptions instanceof Report ? parentOrOptions.options : parentOrOptions || {};
|
|
27
|
-
if (parentOrOptions instanceof Report) {
|
|
28
|
-
// subreport
|
|
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
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
// primary
|
|
37
|
-
this.reportOptions = {};
|
|
38
|
-
this.validateOptions = reportOptionsOrValidate || {};
|
|
39
|
-
this.__$recursiveAnchorStack = [];
|
|
40
|
-
this.__$dynamicScopeStack = [];
|
|
41
|
-
this.__validationResultCache = new Map();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
isValid() {
|
|
45
|
-
if (this.asyncTasks.length > 0) {
|
|
46
|
-
throw new Error("Async tasks pending, can't answer isValid");
|
|
47
|
-
}
|
|
48
|
-
return this.errors.length === 0;
|
|
49
|
-
}
|
|
50
|
-
addAsyncTask(fn, args, asyncTaskResultProcessFn) {
|
|
51
|
-
this.asyncTasks.push([fn, args, asyncTaskResultProcessFn]);
|
|
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) {
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
if (this.parentReport.getSchemaId() === id) {
|
|
77
|
-
return this.parentReport;
|
|
78
|
-
}
|
|
79
|
-
return this.parentReport.getAncestor(id);
|
|
80
|
-
}
|
|
81
|
-
processAsyncTasks(timeout, callback) {
|
|
82
|
-
const validationTimeout = Math.min(Math.max(timeout || 2000, 0), MAX_ASYNC_TIMEOUT);
|
|
83
|
-
const timeoutAt = Date.now() + validationTimeout;
|
|
84
|
-
let tasksCount = this.asyncTasks.length;
|
|
85
|
-
let timedOut = false;
|
|
86
|
-
const finish = () => {
|
|
87
|
-
setTimeout(() => {
|
|
88
|
-
const valid = this.errors.length === 0;
|
|
89
|
-
const err = valid ? undefined : getValidateError({ details: this.errors });
|
|
90
|
-
callback(err, valid);
|
|
91
|
-
}, 0);
|
|
92
|
-
};
|
|
93
|
-
const respond = (asyncTaskResultProcessFn) => (asyncTaskResult) => {
|
|
94
|
-
if (timedOut) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
asyncTaskResultProcessFn(asyncTaskResult);
|
|
98
|
-
if (--tasksCount === 0) {
|
|
99
|
-
finish();
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
// finish if tasks are completed or there are any errors and breaking on first error was requested
|
|
103
|
-
if (tasksCount === 0 || (this.errors.length > 0 && this.options.breakOnFirstError)) {
|
|
104
|
-
finish();
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
for (let i = 0; i < this.asyncTasks.length; i++) {
|
|
108
|
-
const [fn, fnArgs, processFn] = this.asyncTasks[i];
|
|
109
|
-
const respondCallback = respond(processFn);
|
|
110
|
-
fn(...fnArgs, respondCallback);
|
|
111
|
-
}
|
|
112
|
-
const checkTimeout = () => {
|
|
113
|
-
if (timedOut || tasksCount <= 0) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (Date.now() >= timeoutAt) {
|
|
117
|
-
timedOut = true;
|
|
118
|
-
this.addError('ASYNC_TIMEOUT', [tasksCount, validationTimeout]);
|
|
119
|
-
callback(getValidateError({ details: this.errors }), false);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
setTimeout(checkTimeout, ASYNC_TIMEOUT_POLL_MS);
|
|
123
|
-
};
|
|
124
|
-
setTimeout(checkTimeout, ASYNC_TIMEOUT_POLL_MS);
|
|
125
|
-
}
|
|
126
|
-
getPath(returnPathAsString) {
|
|
127
|
-
let path = [];
|
|
128
|
-
if (this.parentReport) {
|
|
129
|
-
path = path.concat(this.parentReport.path);
|
|
130
|
-
}
|
|
131
|
-
path = path.concat(this.path);
|
|
132
|
-
if (returnPathAsString !== true) {
|
|
133
|
-
// Sanitize the path segments (http://tools.ietf.org/html/rfc6901#section-4)
|
|
134
|
-
return ('#/' +
|
|
135
|
-
path
|
|
136
|
-
.map(function (segment) {
|
|
137
|
-
segment = segment.toString();
|
|
138
|
-
if (isAbsoluteUri(segment)) {
|
|
139
|
-
return 'uri(' + segment + ')';
|
|
140
|
-
}
|
|
141
|
-
return segment.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
142
|
-
})
|
|
143
|
-
.join('/'));
|
|
144
|
-
}
|
|
145
|
-
return path;
|
|
146
|
-
}
|
|
147
|
-
getSchemaPath() {
|
|
148
|
-
let schemaPath = [];
|
|
149
|
-
if (this.parentReport) {
|
|
150
|
-
schemaPath = schemaPath.concat(this.parentReport.schemaPath);
|
|
151
|
-
}
|
|
152
|
-
schemaPath = schemaPath.concat(this.schemaPath);
|
|
153
|
-
return schemaPath;
|
|
154
|
-
}
|
|
155
|
-
getSchemaId() {
|
|
156
|
-
if (!this.rootSchema) {
|
|
157
|
-
return undefined;
|
|
158
|
-
}
|
|
159
|
-
// get the error path as an array
|
|
160
|
-
let path = [];
|
|
161
|
-
if (this.parentReport) {
|
|
162
|
-
path = path.concat(this.parentReport.path);
|
|
163
|
-
}
|
|
164
|
-
path = path.concat(this.path);
|
|
165
|
-
// try to find id in the error path
|
|
166
|
-
while (path.length > 0) {
|
|
167
|
-
const obj = get(this.rootSchema, path);
|
|
168
|
-
if (obj && obj.id) {
|
|
169
|
-
return obj.id;
|
|
170
|
-
}
|
|
171
|
-
path.pop();
|
|
172
|
-
}
|
|
173
|
-
// return id of the root
|
|
174
|
-
return this.rootSchema.id;
|
|
175
|
-
}
|
|
176
|
-
hasError(errCode, errParams) {
|
|
177
|
-
for (let idx = 0; idx < this.errors.length; idx++) {
|
|
178
|
-
if (this.errors[idx].code === errCode) {
|
|
179
|
-
// assume match
|
|
180
|
-
let match = true;
|
|
181
|
-
// check the params too
|
|
182
|
-
for (let idx2 = 0; idx2 < this.errors[idx].params.length; idx2++) {
|
|
183
|
-
if (this.errors[idx].params[idx2] !== errParams[idx2]) {
|
|
184
|
-
match = false;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
// if match, return true
|
|
188
|
-
if (match) {
|
|
189
|
-
return match;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
addError(errCode, errParams, subReports, schema, keyword) {
|
|
196
|
-
if (!errCode) {
|
|
197
|
-
throw new Error('No errorCode passed into addError()');
|
|
198
|
-
}
|
|
199
|
-
this.addCustomError(errCode, Errors[errCode], errParams, subReports, schema, keyword);
|
|
200
|
-
}
|
|
201
|
-
// this returns the root object being validated (the one passed into validator.validate)
|
|
202
|
-
getJson() {
|
|
203
|
-
if (this.json) {
|
|
204
|
-
return this.json;
|
|
205
|
-
}
|
|
206
|
-
if (this.parentReport) {
|
|
207
|
-
return this.parentReport.getJson();
|
|
208
|
-
}
|
|
209
|
-
return undefined;
|
|
210
|
-
}
|
|
211
|
-
addCustomError(errorCode, errorMessage, params, subReports, schema, keyword) {
|
|
212
|
-
if (typeof this.reportOptions.maxErrors === 'number' && this.errors.length >= this.reportOptions.maxErrors) {
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
if (!errorMessage) {
|
|
216
|
-
throw new Error('No errorMessage known for code ' + errorCode);
|
|
217
|
-
}
|
|
218
|
-
params = params || [];
|
|
219
|
-
for (let idx = 0; idx < params.length; idx++) {
|
|
220
|
-
const param = params[idx] === null || isObject(params[idx]) ? JSON.stringify(params[idx]) : params[idx];
|
|
221
|
-
errorMessage = errorMessage.replace('{' + idx + '}', param.toString());
|
|
222
|
-
}
|
|
223
|
-
const err = {
|
|
224
|
-
code: errorCode,
|
|
225
|
-
params: params,
|
|
226
|
-
message: errorMessage,
|
|
227
|
-
path: this.getPath(this.options.reportPathAsArray),
|
|
228
|
-
schemaPath: this.getSchemaPath(),
|
|
229
|
-
schemaId: this.getSchemaId(),
|
|
230
|
-
keyword: keyword,
|
|
231
|
-
};
|
|
232
|
-
err[schemaSymbol] = schema;
|
|
233
|
-
err[jsonSymbol] = this.getJson();
|
|
234
|
-
if (schema && typeof schema === 'string') {
|
|
235
|
-
err.description = schema;
|
|
236
|
-
}
|
|
237
|
-
else if (schema && typeof schema === 'object') {
|
|
238
|
-
if (schema.title) {
|
|
239
|
-
err.title = schema.title;
|
|
240
|
-
}
|
|
241
|
-
if (schema.description) {
|
|
242
|
-
err.description = schema.description;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (subReports != null) {
|
|
246
|
-
if (!Array.isArray(subReports)) {
|
|
247
|
-
subReports = [subReports];
|
|
248
|
-
}
|
|
249
|
-
err.inner = [];
|
|
250
|
-
for (const subReport of subReports) {
|
|
251
|
-
for (const error of subReport.errors) {
|
|
252
|
-
err.inner.push(error);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (err.inner.length === 0) {
|
|
256
|
-
err.inner = undefined;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
// Check if this error code should be excluded
|
|
260
|
-
if (Array.isArray(this.validateOptions.excludeErrors) && this.validateOptions.excludeErrors.includes(errorCode)) {
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
this.errors.push(err);
|
|
264
|
-
}
|
|
265
|
-
}
|
package/dist/schema-cache.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { findId, getId } from './json-schema.js';
|
|
2
|
-
import { Report } from './report.js';
|
|
3
|
-
import { deepClone } from './utils/clone.js';
|
|
4
|
-
import { decodeJSONPointer } from './utils/json.js';
|
|
5
|
-
import { getQueryPath, getRemotePath, isAbsoluteUri } from './utils/uri.js';
|
|
6
|
-
import { normalizeOptions } from './z-schema-options.js';
|
|
7
|
-
// Normalize a URI into a cache key, rejecting keys that could pollute Object.prototype.
|
|
8
|
-
function getSafeRemotePath(uri) {
|
|
9
|
-
const remotePath = getRemotePath(uri);
|
|
10
|
-
if (!remotePath) {
|
|
11
|
-
return undefined;
|
|
12
|
-
}
|
|
13
|
-
if (remotePath === '__proto__' || remotePath === 'constructor' || remotePath === 'prototype') {
|
|
14
|
-
return undefined;
|
|
15
|
-
}
|
|
16
|
-
return remotePath;
|
|
17
|
-
}
|
|
18
|
-
const getEffectiveId = (schema) => {
|
|
19
|
-
let id = getId(schema);
|
|
20
|
-
if ((!id || !isAbsoluteUri(id)) && typeof schema.id === 'string' && isAbsoluteUri(schema.id)) {
|
|
21
|
-
id = schema.id;
|
|
22
|
-
}
|
|
23
|
-
return id;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Shared logic for registering a remote reference schema.
|
|
27
|
-
* Used by both the static `ZSchema.setRemoteReference()` (global cache) and
|
|
28
|
-
* the instance `validator.setRemoteReference()` (instance cache).
|
|
29
|
-
*/
|
|
30
|
-
export function prepareRemoteSchema(schema, uri, validationOptions, maxCloneDepth) {
|
|
31
|
-
let _schema;
|
|
32
|
-
if (typeof schema === 'string') {
|
|
33
|
-
_schema = JSON.parse(schema);
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
_schema = deepClone(schema, maxCloneDepth);
|
|
37
|
-
}
|
|
38
|
-
if (!_schema.id) {
|
|
39
|
-
_schema.id = uri;
|
|
40
|
-
}
|
|
41
|
-
if (validationOptions) {
|
|
42
|
-
_schema.__$validationOptions = normalizeOptions(validationOptions);
|
|
43
|
-
}
|
|
44
|
-
return _schema;
|
|
45
|
-
}
|
|
46
|
-
export class SchemaCache {
|
|
47
|
-
validator;
|
|
48
|
-
static global_cache = Object.create(null);
|
|
49
|
-
cache = Object.create(null);
|
|
50
|
-
constructor(validator) {
|
|
51
|
-
this.validator = validator;
|
|
52
|
-
}
|
|
53
|
-
static cacheSchemaByUri(uri, schema) {
|
|
54
|
-
const remotePath = getSafeRemotePath(uri);
|
|
55
|
-
if (remotePath) {
|
|
56
|
-
this.global_cache[remotePath] = schema;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
cacheSchemaByUri(uri, schema) {
|
|
60
|
-
const remotePath = getSafeRemotePath(uri);
|
|
61
|
-
if (remotePath) {
|
|
62
|
-
this.cache[remotePath] = schema;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
removeFromCacheByUri(uri) {
|
|
66
|
-
const remotePath = getSafeRemotePath(uri);
|
|
67
|
-
if (remotePath) {
|
|
68
|
-
delete this.cache[remotePath];
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
checkCacheForUri(uri) {
|
|
72
|
-
const remotePath = getSafeRemotePath(uri);
|
|
73
|
-
return remotePath ? this.cache[remotePath] != null : false;
|
|
74
|
-
}
|
|
75
|
-
getSchema(report, refOrSchema) {
|
|
76
|
-
if (Array.isArray(refOrSchema)) {
|
|
77
|
-
return refOrSchema.map((i) => this.getSchema(report, i));
|
|
78
|
-
}
|
|
79
|
-
if (typeof refOrSchema === 'string') {
|
|
80
|
-
// ref input
|
|
81
|
-
return this.getSchemaByUri(report, refOrSchema);
|
|
82
|
-
}
|
|
83
|
-
// no caching done on this, but we need to return a clone so we can mutate it
|
|
84
|
-
return deepClone(refOrSchema, this.validator.options.maxRecursionDepth);
|
|
85
|
-
}
|
|
86
|
-
fromCache(path) {
|
|
87
|
-
if (path === '__proto__' || path === 'constructor' || path === 'prototype') {
|
|
88
|
-
return undefined;
|
|
89
|
-
}
|
|
90
|
-
let found = this.cache[path];
|
|
91
|
-
if (found) {
|
|
92
|
-
return found;
|
|
93
|
-
}
|
|
94
|
-
found = SchemaCache.global_cache[path];
|
|
95
|
-
if (found) {
|
|
96
|
-
// Clone once from global cache into instance cache so subsequent lookups
|
|
97
|
-
// never deep-clone again for the same path on this instance.
|
|
98
|
-
const clone = deepClone(found, this.validator.options.maxRecursionDepth);
|
|
99
|
-
if (!clone.id || (!isAbsoluteUri(clone.id) && isAbsoluteUri(path))) {
|
|
100
|
-
clone.id = path;
|
|
101
|
-
}
|
|
102
|
-
this.cache[path] = clone;
|
|
103
|
-
return clone;
|
|
104
|
-
}
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
getSchemaByUri(report, uri, root) {
|
|
108
|
-
if (root && !isAbsoluteUri(uri)) {
|
|
109
|
-
const rootId = getEffectiveId(root);
|
|
110
|
-
if (rootId && isAbsoluteUri(rootId)) {
|
|
111
|
-
const hashIndex = rootId.indexOf('#');
|
|
112
|
-
const rootBase = hashIndex === -1 ? rootId : rootId.slice(0, hashIndex);
|
|
113
|
-
try {
|
|
114
|
-
uri = new URL(uri, rootBase).toString();
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
// keep original uri when URL construction fails
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
const remotePath = getSafeRemotePath(uri);
|
|
122
|
-
const queryPath = getQueryPath(uri);
|
|
123
|
-
let result;
|
|
124
|
-
let resolvedFromAncestor = false;
|
|
125
|
-
if (remotePath) {
|
|
126
|
-
const ancestorReport = report.getAncestor(remotePath);
|
|
127
|
-
if (ancestorReport?.rootSchema) {
|
|
128
|
-
result = ancestorReport.rootSchema;
|
|
129
|
-
resolvedFromAncestor = true;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if (!result && root && remotePath) {
|
|
133
|
-
const rootId = getEffectiveId(root);
|
|
134
|
-
const rootRemotePath = rootId ? getRemotePath(rootId) : undefined;
|
|
135
|
-
if (rootRemotePath && rootRemotePath === remotePath) {
|
|
136
|
-
result = root;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (!result) {
|
|
140
|
-
result = remotePath ? this.fromCache(remotePath) : root;
|
|
141
|
-
}
|
|
142
|
-
if (result && remotePath && isAbsoluteUri(remotePath) && (!result.id || !isAbsoluteUri(result.id))) {
|
|
143
|
-
result.id = remotePath;
|
|
144
|
-
}
|
|
145
|
-
if (result && remotePath) {
|
|
146
|
-
// we need to avoid compiling schemas in a recursive loop
|
|
147
|
-
const compileRemote = result !== root && !resolvedFromAncestor;
|
|
148
|
-
// now we need to compile and validate resolved schema (in case it's not already)
|
|
149
|
-
if (compileRemote) {
|
|
150
|
-
report.path.push(remotePath);
|
|
151
|
-
let remoteReport;
|
|
152
|
-
let usesAncestorReport = false;
|
|
153
|
-
const anscestorReport = result.id ? report.getAncestor(result.id) : undefined;
|
|
154
|
-
if (anscestorReport) {
|
|
155
|
-
remoteReport = anscestorReport;
|
|
156
|
-
usesAncestorReport = true;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
remoteReport = new Report(report);
|
|
160
|
-
const noCache = result.id && isAbsoluteUri(result.id) ? false : true;
|
|
161
|
-
if (this.validator.sc.compileSchema(remoteReport, result, { noCache })) {
|
|
162
|
-
const savedOptions = this.validator.options;
|
|
163
|
-
try {
|
|
164
|
-
// If custom validationOptions were provided to setRemoteReference(),
|
|
165
|
-
// use them instead of the default options
|
|
166
|
-
this.validator.options = result.__$validationOptions || this.validator.options;
|
|
167
|
-
const parentSchemaUri = typeof result.$schema === 'string' ? getRemotePath(result.$schema) : undefined;
|
|
168
|
-
const currentSchemaUri = report.getSchemaId();
|
|
169
|
-
const parentSchemaIsCompiling = !!parentSchemaUri &&
|
|
170
|
-
parentSchemaUri.length > 0 &&
|
|
171
|
-
(currentSchemaUri === parentSchemaUri || !!report.getAncestor(parentSchemaUri));
|
|
172
|
-
if (!parentSchemaIsCompiling) {
|
|
173
|
-
this.validator.sv.validateSchema(remoteReport, result);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
finally {
|
|
177
|
-
this.validator.options = savedOptions;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const remoteReportIsValid = usesAncestorReport ? true : remoteReport.isValid();
|
|
182
|
-
if (!remoteReportIsValid) {
|
|
183
|
-
report.addError('REMOTE_NOT_VALID', [uri], remoteReport);
|
|
184
|
-
}
|
|
185
|
-
report.path.pop();
|
|
186
|
-
if (!remoteReportIsValid) {
|
|
187
|
-
return undefined;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
const resourceRoot = result;
|
|
192
|
-
if (result && queryPath) {
|
|
193
|
-
const parts = queryPath.split('/');
|
|
194
|
-
for (let idx = 0, lim = parts.length; result && idx < lim; idx++) {
|
|
195
|
-
const key = decodeJSONPointer(parts[idx]);
|
|
196
|
-
if (idx === 0) {
|
|
197
|
-
// it's an id
|
|
198
|
-
result = findId(result, key, remotePath, remotePath, this.validator.options.maxRecursionDepth);
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
// it's a path behind id
|
|
202
|
-
result = result[key];
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (result && typeof result === 'object' && resourceRoot && typeof resourceRoot === 'object') {
|
|
207
|
-
result.__$resourceRoot = resourceRoot;
|
|
208
|
-
}
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
|
-
}
|