z-schema 6.0.1 → 7.0.0-beta.1
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/README.md +154 -137
- package/bin/z-schema +128 -124
- package/dist/Errors.js +50 -0
- package/dist/FormatValidators.js +136 -0
- package/{src → dist}/JsonValidation.js +186 -212
- package/dist/Report.js +220 -0
- package/{src → dist}/SchemaCache.js +67 -82
- package/{src → dist}/SchemaCompilation.js +89 -129
- package/dist/SchemaValidation.js +631 -0
- package/{src → dist}/Utils.js +96 -104
- package/dist/ZSchema-umd-min.js +1 -0
- package/dist/ZSchema-umd.js +13791 -0
- package/dist/ZSchema.cjs +13785 -0
- package/dist/ZSchema.js +366 -0
- package/dist/schemas/hyper-schema.json +156 -0
- package/dist/schemas/schema.json +151 -0
- package/dist/types/Errors.d.ts +44 -0
- package/dist/types/FormatValidators.d.ts +12 -0
- package/dist/types/JsonValidation.d.ts +37 -0
- package/dist/types/Report.d.ts +87 -0
- package/dist/types/SchemaCache.d.ts +26 -0
- package/dist/types/SchemaCompilation.d.ts +1 -0
- package/dist/types/SchemaValidation.d.ts +6 -0
- package/dist/types/Utils.d.ts +64 -0
- package/dist/types/ZSchema.d.ts +97 -0
- package/package.json +54 -43
- package/src/Errors.ts +56 -0
- package/src/FormatValidators.ts +136 -0
- package/src/JsonValidation.ts +624 -0
- package/src/Report.ts +337 -0
- package/src/SchemaCache.ts +189 -0
- package/src/SchemaCompilation.ts +293 -0
- package/src/SchemaValidation.ts +629 -0
- package/src/Utils.ts +286 -0
- package/src/ZSchema.ts +469 -0
- package/src/schemas/_ +0 -0
- package/dist/ZSchema-browser-min.js +0 -2
- package/dist/ZSchema-browser-min.js.map +0 -1
- package/dist/ZSchema-browser-test.js +0 -30633
- package/dist/ZSchema-browser.js +0 -13429
- package/index.d.ts +0 -175
- package/src/Errors.js +0 -60
- package/src/FormatValidators.js +0 -129
- package/src/Polyfills.js +0 -16
- package/src/Report.js +0 -299
- package/src/SchemaValidation.js +0 -619
- package/src/ZSchema.js +0 -409
package/src/Report.ts
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import get from 'lodash.get';
|
|
2
|
+
import { Errors } from './Errors.js';
|
|
3
|
+
import * as Utils from './Utils.js';
|
|
4
|
+
import { ZSchemaOptions } from './ZSchema.js';
|
|
5
|
+
|
|
6
|
+
export interface SchemaError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* Implements the Error.name contract. The value is always "z-schema validation error".
|
|
9
|
+
*/
|
|
10
|
+
name: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* An identifier indicating the type of error.
|
|
14
|
+
* Example: "JSON_OBJECT_VALIDATION_FAILED"
|
|
15
|
+
*/
|
|
16
|
+
message: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns details for each error that occurred during validation.
|
|
20
|
+
* See Options.breakOnFirstError.
|
|
21
|
+
*/
|
|
22
|
+
details?: SchemaErrorDetail[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SchemaErrorDetail {
|
|
26
|
+
/**
|
|
27
|
+
* Example: "Expected type string but found type array"
|
|
28
|
+
*/
|
|
29
|
+
message: string;
|
|
30
|
+
/**
|
|
31
|
+
* An error identifier that can be used to format a custom error message.
|
|
32
|
+
* Example: "INVALID_TYPE"
|
|
33
|
+
*/
|
|
34
|
+
code: string;
|
|
35
|
+
/**
|
|
36
|
+
* Format parameters that can be used to format a custom error message.
|
|
37
|
+
* Example: ["string","array"]
|
|
38
|
+
*/
|
|
39
|
+
params: Array<string>;
|
|
40
|
+
/**
|
|
41
|
+
* A JSON path indicating the location of the error.
|
|
42
|
+
* Example: "#/projects/1"
|
|
43
|
+
*/
|
|
44
|
+
path: string | string[];
|
|
45
|
+
/**
|
|
46
|
+
* The schema rule description, which is included for certain errors where
|
|
47
|
+
* this information is useful (e.g. to describe a constraint).
|
|
48
|
+
*/
|
|
49
|
+
title?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns details for sub-schemas that failed to match. For example, if the schema
|
|
54
|
+
* uses the "oneOf" constraint to accept several alternative possibilities, each
|
|
55
|
+
* alternative will have its own inner detail object explaining why it failed to match.
|
|
56
|
+
*/
|
|
57
|
+
inner?: SchemaErrorDetail[];
|
|
58
|
+
|
|
59
|
+
schemaId?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ReportOptions {
|
|
63
|
+
maxErrors?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type TaskResult = unknown;
|
|
67
|
+
type TaskFn = (...args: unknown[]) => TaskResult;
|
|
68
|
+
type TaskFnArgs = Parameters<TaskFn>;
|
|
69
|
+
type TaskProcessFn = (result: ReturnType<TaskFn>) => void;
|
|
70
|
+
type AsyncTask = [TaskFn, TaskFnArgs, TaskProcessFn];
|
|
71
|
+
|
|
72
|
+
export class Report {
|
|
73
|
+
errors: SchemaErrorDetail[];
|
|
74
|
+
parentReport?: Report;
|
|
75
|
+
options: ZSchemaOptions;
|
|
76
|
+
reportOptions: ReportOptions;
|
|
77
|
+
path: string[];
|
|
78
|
+
asyncTasks: AsyncTask[];
|
|
79
|
+
rootSchema?: {
|
|
80
|
+
id?: string;
|
|
81
|
+
};
|
|
82
|
+
commonErrorMessage?: string;
|
|
83
|
+
json?: unknown;
|
|
84
|
+
|
|
85
|
+
constructor(parentOrOptions, reportOptions?) {
|
|
86
|
+
this.parentReport = parentOrOptions instanceof Report ? parentOrOptions : undefined;
|
|
87
|
+
|
|
88
|
+
this.options = parentOrOptions instanceof Report ? parentOrOptions.options : parentOrOptions || {};
|
|
89
|
+
|
|
90
|
+
this.reportOptions = reportOptions || {};
|
|
91
|
+
|
|
92
|
+
this.errors = [];
|
|
93
|
+
/**
|
|
94
|
+
* @type {string[]}
|
|
95
|
+
*/
|
|
96
|
+
this.path = [];
|
|
97
|
+
this.asyncTasks = [];
|
|
98
|
+
|
|
99
|
+
this.rootSchema = undefined;
|
|
100
|
+
this.commonErrorMessage = undefined;
|
|
101
|
+
this.json = undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
isValid(): boolean {
|
|
105
|
+
if (this.asyncTasks.length > 0) {
|
|
106
|
+
throw new Error("Async tasks pending, can't answer isValid");
|
|
107
|
+
}
|
|
108
|
+
return this.errors.length === 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
addAsyncTask(fn, args, asyncTaskResultProcessFn) {
|
|
112
|
+
this.asyncTasks.push([fn, args, asyncTaskResultProcessFn]);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getAncestor(id) {
|
|
116
|
+
if (!this.parentReport) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
if (this.parentReport.getSchemaId() === id) {
|
|
120
|
+
return this.parentReport;
|
|
121
|
+
}
|
|
122
|
+
return this.parentReport.getAncestor(id);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
processAsyncTasks(timeout, callback) {
|
|
126
|
+
const validationTimeout = timeout || 2000;
|
|
127
|
+
let tasksCount = this.asyncTasks.length;
|
|
128
|
+
let idx = tasksCount;
|
|
129
|
+
let timedOut = false;
|
|
130
|
+
|
|
131
|
+
const finish = () => {
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
const valid = this.errors.length === 0,
|
|
134
|
+
err = valid ? null : this.errors;
|
|
135
|
+
callback(err, valid);
|
|
136
|
+
}, 0);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function respond(asyncTaskResultProcessFn: TaskProcessFn) {
|
|
140
|
+
return function (asyncTaskResult) {
|
|
141
|
+
if (timedOut) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
asyncTaskResultProcessFn(asyncTaskResult);
|
|
145
|
+
if (--tasksCount === 0) {
|
|
146
|
+
finish();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// finish if tasks are completed or there are any errors and breaking on first error was requested
|
|
152
|
+
if (tasksCount === 0 || (this.errors.length > 0 && this.options.breakOnFirstError)) {
|
|
153
|
+
finish();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
while (idx--) {
|
|
158
|
+
const [fn, fnArgs, processFn] = this.asyncTasks[idx];
|
|
159
|
+
const respondCallback = respond(processFn);
|
|
160
|
+
fn(...fnArgs, respondCallback);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
setTimeout(() => {
|
|
164
|
+
if (tasksCount > 0) {
|
|
165
|
+
timedOut = true;
|
|
166
|
+
this.addError('ASYNC_TIMEOUT', [tasksCount, validationTimeout]);
|
|
167
|
+
callback(this.errors, false);
|
|
168
|
+
}
|
|
169
|
+
}, validationTimeout);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getPath(returnPathAsString) {
|
|
173
|
+
/**
|
|
174
|
+
* @type {string[]|string}
|
|
175
|
+
*/
|
|
176
|
+
let path = [];
|
|
177
|
+
if (this.parentReport) {
|
|
178
|
+
path = path.concat(this.parentReport.path);
|
|
179
|
+
}
|
|
180
|
+
path = path.concat(this.path);
|
|
181
|
+
|
|
182
|
+
if (returnPathAsString !== true) {
|
|
183
|
+
// Sanitize the path segments (http://tools.ietf.org/html/rfc6901#section-4)
|
|
184
|
+
return (
|
|
185
|
+
'#/' +
|
|
186
|
+
path
|
|
187
|
+
.map(function (segment) {
|
|
188
|
+
segment = segment.toString();
|
|
189
|
+
|
|
190
|
+
if (Utils.isAbsoluteUri(segment)) {
|
|
191
|
+
return 'uri(' + segment + ')';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return segment.replace(/~/g, '~0').replace(/\//g, '~1');
|
|
195
|
+
})
|
|
196
|
+
.join('/')
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return path;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getSchemaId() {
|
|
203
|
+
if (!this.rootSchema) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// get the error path as an array
|
|
208
|
+
let path = [];
|
|
209
|
+
if (this.parentReport) {
|
|
210
|
+
path = path.concat(this.parentReport.path);
|
|
211
|
+
}
|
|
212
|
+
path = path.concat(this.path);
|
|
213
|
+
|
|
214
|
+
// try to find id in the error path
|
|
215
|
+
while (path.length > 0) {
|
|
216
|
+
const obj = get(this.rootSchema, path);
|
|
217
|
+
if (obj && obj.id) {
|
|
218
|
+
return obj.id;
|
|
219
|
+
}
|
|
220
|
+
path.pop();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// return id of the root
|
|
224
|
+
return this.rootSchema.id;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
hasError(errorCode, params) {
|
|
228
|
+
let idx = this.errors.length;
|
|
229
|
+
while (idx--) {
|
|
230
|
+
if (this.errors[idx].code === errorCode) {
|
|
231
|
+
// assume match
|
|
232
|
+
let match = true;
|
|
233
|
+
|
|
234
|
+
// check the params too
|
|
235
|
+
let idx2 = this.errors[idx].params.length;
|
|
236
|
+
while (idx2--) {
|
|
237
|
+
if (this.errors[idx].params[idx2] !== params[idx2]) {
|
|
238
|
+
match = false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// if match, return true
|
|
243
|
+
if (match) {
|
|
244
|
+
return match;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
addError(errorCode, params, subReports?, schema?) {
|
|
252
|
+
if (!errorCode) {
|
|
253
|
+
throw new Error('No errorCode passed into addError()');
|
|
254
|
+
}
|
|
255
|
+
this.addCustomError(errorCode, Errors[errorCode], params, subReports, schema);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getJson() {
|
|
259
|
+
if (this.json) {
|
|
260
|
+
return this.json;
|
|
261
|
+
}
|
|
262
|
+
if (this.parentReport) {
|
|
263
|
+
return this.parentReport.getJson();
|
|
264
|
+
}
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
addCustomError(
|
|
269
|
+
errorCode: string,
|
|
270
|
+
errorMessage: string,
|
|
271
|
+
params: string[],
|
|
272
|
+
subReports?: Report[] | Report,
|
|
273
|
+
schema?: {
|
|
274
|
+
title?: string;
|
|
275
|
+
description?: string;
|
|
276
|
+
}
|
|
277
|
+
) {
|
|
278
|
+
if (this.errors.length >= this.reportOptions.maxErrors) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (!errorMessage) {
|
|
283
|
+
throw new Error('No errorMessage known for code ' + errorCode);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
params = params || [];
|
|
287
|
+
|
|
288
|
+
let idx = params.length;
|
|
289
|
+
while (idx--) {
|
|
290
|
+
const whatIs = Utils.whatIs(params[idx]);
|
|
291
|
+
const param = whatIs === 'object' || whatIs === 'null' ? JSON.stringify(params[idx]) : params[idx];
|
|
292
|
+
errorMessage = errorMessage.replace('{' + idx + '}', param);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const err: SchemaErrorDetail = {
|
|
296
|
+
code: errorCode,
|
|
297
|
+
params: params,
|
|
298
|
+
message: errorMessage,
|
|
299
|
+
path: this.getPath(this.options.reportPathAsArray),
|
|
300
|
+
schemaId: this.getSchemaId(),
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
err[Utils.schemaSymbol] = schema;
|
|
304
|
+
err[Utils.jsonSymbol] = this.getJson();
|
|
305
|
+
|
|
306
|
+
if (schema && typeof schema === 'string') {
|
|
307
|
+
err.description = schema;
|
|
308
|
+
} else if (schema && typeof schema === 'object') {
|
|
309
|
+
if (schema.title) {
|
|
310
|
+
err.title = schema.title;
|
|
311
|
+
}
|
|
312
|
+
if (schema.description) {
|
|
313
|
+
err.description = schema.description;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (subReports != null) {
|
|
318
|
+
if (!Array.isArray(subReports)) {
|
|
319
|
+
subReports = [subReports];
|
|
320
|
+
}
|
|
321
|
+
err.inner = [];
|
|
322
|
+
idx = subReports.length;
|
|
323
|
+
while (idx--) {
|
|
324
|
+
const subReport = subReports[idx];
|
|
325
|
+
let idx2 = subReport.errors.length;
|
|
326
|
+
while (idx2--) {
|
|
327
|
+
err.inner.push(subReport.errors[idx2]);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (err.inner.length === 0) {
|
|
331
|
+
err.inner = undefined;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
this.errors.push(err);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import isequal from 'lodash.isequal';
|
|
2
|
+
import { Report } from './Report.js';
|
|
3
|
+
import { compileSchema } from './SchemaCompilation.js';
|
|
4
|
+
import * as SchemaValidation from './SchemaValidation.js';
|
|
5
|
+
import * as Utils from './Utils.js';
|
|
6
|
+
|
|
7
|
+
function decodeJSONPointer(str) {
|
|
8
|
+
// http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07#section-3
|
|
9
|
+
return decodeURIComponent(str).replace(/~[0-1]/g, function (x) {
|
|
10
|
+
return x === '~1' ? '/' : '~';
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getRemotePath(uri) {
|
|
15
|
+
const io = uri.indexOf('#');
|
|
16
|
+
return io === -1 ? uri : uri.slice(0, io);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getQueryPath(uri) {
|
|
20
|
+
const io = uri.indexOf('#');
|
|
21
|
+
const res = io === -1 ? undefined : uri.slice(io + 1);
|
|
22
|
+
// WARN: do not slice slash, #/ means take root and go down from it
|
|
23
|
+
// if (res && res[0] === "/") { res = res.slice(1); }
|
|
24
|
+
return res;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findId(schema, id) {
|
|
28
|
+
// process only arrays and objects
|
|
29
|
+
if (typeof schema !== 'object' || schema === null) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// no id means root so return itself
|
|
34
|
+
if (!id) {
|
|
35
|
+
return schema;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (schema.id) {
|
|
39
|
+
if (schema.id === id || (schema.id[0] === '#' && schema.id.substring(1) === id)) {
|
|
40
|
+
return schema;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let idx, result;
|
|
45
|
+
if (Array.isArray(schema)) {
|
|
46
|
+
idx = schema.length;
|
|
47
|
+
while (idx--) {
|
|
48
|
+
result = findId(schema[idx], id);
|
|
49
|
+
if (result) {
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
const keys = Object.keys(schema);
|
|
55
|
+
idx = keys.length;
|
|
56
|
+
while (idx--) {
|
|
57
|
+
const k = keys[idx];
|
|
58
|
+
if (k.indexOf('__$') === 0) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
result = findId(schema[k], id);
|
|
62
|
+
if (result) {
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
*
|
|
71
|
+
* @param {*} uri
|
|
72
|
+
* @param {*} schema
|
|
73
|
+
*
|
|
74
|
+
* @returns {void}
|
|
75
|
+
*/
|
|
76
|
+
export function cacheSchemaByUri(uri, schema) {
|
|
77
|
+
const remotePath = getRemotePath(uri);
|
|
78
|
+
if (remotePath) {
|
|
79
|
+
this.cache[remotePath] = schema;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
*
|
|
85
|
+
* @param {*} uri
|
|
86
|
+
*
|
|
87
|
+
* @returns {void}
|
|
88
|
+
*/
|
|
89
|
+
export function removeFromCacheByUri(uri) {
|
|
90
|
+
const remotePath = getRemotePath(uri);
|
|
91
|
+
if (remotePath) {
|
|
92
|
+
delete this.cache[remotePath];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {*} uri
|
|
99
|
+
*
|
|
100
|
+
* @returns {boolean}
|
|
101
|
+
*/
|
|
102
|
+
export function checkCacheForUri(uri) {
|
|
103
|
+
const remotePath = getRemotePath(uri);
|
|
104
|
+
return remotePath ? this.cache[remotePath] != null : false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getSchema(report, schema) {
|
|
108
|
+
if (typeof schema === 'object') {
|
|
109
|
+
schema = getSchemaByReference.call(this, report, schema);
|
|
110
|
+
}
|
|
111
|
+
if (typeof schema === 'string') {
|
|
112
|
+
schema = getSchemaByUri.call(this, report, schema);
|
|
113
|
+
}
|
|
114
|
+
return schema;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function getSchemaByReference(report, key) {
|
|
118
|
+
let i = this.referenceCache.length;
|
|
119
|
+
while (i--) {
|
|
120
|
+
if (isequal(this.referenceCache[i][0], key)) {
|
|
121
|
+
return this.referenceCache[i][1];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// not found
|
|
125
|
+
const schema = Utils.cloneDeep(key);
|
|
126
|
+
this.referenceCache.push([key, schema]);
|
|
127
|
+
return schema;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function getSchemaByUri(report, uri, root) {
|
|
131
|
+
const remotePath = getRemotePath(uri);
|
|
132
|
+
const queryPath = getQueryPath(uri);
|
|
133
|
+
let result = remotePath ? this.cache[remotePath] : root;
|
|
134
|
+
|
|
135
|
+
if (result && remotePath) {
|
|
136
|
+
// we need to avoid compiling schemas in a recursive loop
|
|
137
|
+
const compileRemote = result !== root;
|
|
138
|
+
// now we need to compile and validate resolved schema (in case it's not already)
|
|
139
|
+
if (compileRemote) {
|
|
140
|
+
report.path.push(remotePath);
|
|
141
|
+
|
|
142
|
+
let remoteReport;
|
|
143
|
+
|
|
144
|
+
const anscestorReport = report.getAncestor(result.id);
|
|
145
|
+
if (anscestorReport) {
|
|
146
|
+
remoteReport = anscestorReport;
|
|
147
|
+
} else {
|
|
148
|
+
remoteReport = new Report(report);
|
|
149
|
+
if (compileSchema.call(this, remoteReport, result)) {
|
|
150
|
+
const savedOptions = this.options;
|
|
151
|
+
try {
|
|
152
|
+
// If custom validationOptions were provided to setRemoteReference(),
|
|
153
|
+
// use them instead of the default options
|
|
154
|
+
this.options = result.__$validationOptions || this.options;
|
|
155
|
+
SchemaValidation.validateSchema.call(this, remoteReport, result);
|
|
156
|
+
} finally {
|
|
157
|
+
this.options = savedOptions;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const remoteReportIsValid = remoteReport.isValid();
|
|
162
|
+
if (!remoteReportIsValid) {
|
|
163
|
+
report.addError('REMOTE_NOT_VALID', [uri], remoteReport);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
report.path.pop();
|
|
167
|
+
|
|
168
|
+
if (!remoteReportIsValid) {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (result && queryPath) {
|
|
175
|
+
const parts = queryPath.split('/');
|
|
176
|
+
for (let idx = 0, lim = parts.length; result && idx < lim; idx++) {
|
|
177
|
+
const key = decodeJSONPointer(parts[idx]);
|
|
178
|
+
if (idx === 0) {
|
|
179
|
+
// it's an id
|
|
180
|
+
result = findId(result, key);
|
|
181
|
+
} else {
|
|
182
|
+
// it's a path behind id
|
|
183
|
+
result = result[key];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return result;
|
|
189
|
+
}
|