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.
Files changed (47) hide show
  1. package/README.md +154 -137
  2. package/bin/z-schema +128 -124
  3. package/dist/Errors.js +50 -0
  4. package/dist/FormatValidators.js +136 -0
  5. package/{src → dist}/JsonValidation.js +186 -212
  6. package/dist/Report.js +220 -0
  7. package/{src → dist}/SchemaCache.js +67 -82
  8. package/{src → dist}/SchemaCompilation.js +89 -129
  9. package/dist/SchemaValidation.js +631 -0
  10. package/{src → dist}/Utils.js +96 -104
  11. package/dist/ZSchema-umd-min.js +1 -0
  12. package/dist/ZSchema-umd.js +13791 -0
  13. package/dist/ZSchema.cjs +13785 -0
  14. package/dist/ZSchema.js +366 -0
  15. package/dist/schemas/hyper-schema.json +156 -0
  16. package/dist/schemas/schema.json +151 -0
  17. package/dist/types/Errors.d.ts +44 -0
  18. package/dist/types/FormatValidators.d.ts +12 -0
  19. package/dist/types/JsonValidation.d.ts +37 -0
  20. package/dist/types/Report.d.ts +87 -0
  21. package/dist/types/SchemaCache.d.ts +26 -0
  22. package/dist/types/SchemaCompilation.d.ts +1 -0
  23. package/dist/types/SchemaValidation.d.ts +6 -0
  24. package/dist/types/Utils.d.ts +64 -0
  25. package/dist/types/ZSchema.d.ts +97 -0
  26. package/package.json +54 -43
  27. package/src/Errors.ts +56 -0
  28. package/src/FormatValidators.ts +136 -0
  29. package/src/JsonValidation.ts +624 -0
  30. package/src/Report.ts +337 -0
  31. package/src/SchemaCache.ts +189 -0
  32. package/src/SchemaCompilation.ts +293 -0
  33. package/src/SchemaValidation.ts +629 -0
  34. package/src/Utils.ts +286 -0
  35. package/src/ZSchema.ts +469 -0
  36. package/src/schemas/_ +0 -0
  37. package/dist/ZSchema-browser-min.js +0 -2
  38. package/dist/ZSchema-browser-min.js.map +0 -1
  39. package/dist/ZSchema-browser-test.js +0 -30633
  40. package/dist/ZSchema-browser.js +0 -13429
  41. package/index.d.ts +0 -175
  42. package/src/Errors.js +0 -60
  43. package/src/FormatValidators.js +0 -129
  44. package/src/Polyfills.js +0 -16
  45. package/src/Report.js +0 -299
  46. package/src/SchemaValidation.js +0 -619
  47. package/src/ZSchema.js +0 -409
@@ -0,0 +1,293 @@
1
+ import { Report } from './Report.js';
2
+ import { getSchemaByUri, checkCacheForUri, cacheSchemaByUri, removeFromCacheByUri } from './SchemaCache.js';
3
+ import * as Utils from './Utils.js';
4
+
5
+ function mergeReference(scope, ref) {
6
+ if (Utils.isAbsoluteUri(ref)) {
7
+ return ref;
8
+ }
9
+
10
+ let joinedScope = scope.join('');
11
+ const isScopeAbsolute = Utils.isAbsoluteUri(joinedScope);
12
+ const isScopeRelative = Utils.isRelativeUri(joinedScope);
13
+ const isRefRelative = Utils.isRelativeUri(ref);
14
+ let toRemove;
15
+
16
+ if (isScopeAbsolute && isRefRelative) {
17
+ toRemove = joinedScope.match(/\/[^/]*$/);
18
+ if (toRemove) {
19
+ joinedScope = joinedScope.slice(0, toRemove.index + 1);
20
+ }
21
+ } else if (isScopeRelative && isRefRelative) {
22
+ joinedScope = '';
23
+ } else {
24
+ toRemove = joinedScope.match(/[^#/]+$/);
25
+ if (toRemove) {
26
+ joinedScope = joinedScope.slice(0, toRemove.index);
27
+ }
28
+ }
29
+
30
+ let res = joinedScope + ref;
31
+ res = res.replace(/##/, '#');
32
+ return res;
33
+ }
34
+
35
+ function collectReferences(obj, results, scope, path) {
36
+ results = results || [];
37
+ scope = scope || [];
38
+ path = path || [];
39
+
40
+ if (typeof obj !== 'object' || obj === null) {
41
+ return results;
42
+ }
43
+
44
+ if (typeof obj.id === 'string') {
45
+ scope.push(obj.id);
46
+ }
47
+
48
+ if (typeof obj.$ref === 'string' && typeof obj.__$refResolved === 'undefined') {
49
+ results.push({
50
+ ref: mergeReference(scope, obj.$ref),
51
+ key: '$ref',
52
+ obj: obj,
53
+ path: path.slice(0),
54
+ });
55
+ }
56
+ if (typeof obj.$schema === 'string' && typeof obj.__$schemaResolved === 'undefined') {
57
+ results.push({
58
+ ref: mergeReference(scope, obj.$schema),
59
+ key: '$schema',
60
+ obj: obj,
61
+ path: path.slice(0),
62
+ });
63
+ }
64
+
65
+ let idx;
66
+ if (Array.isArray(obj)) {
67
+ idx = obj.length;
68
+ while (idx--) {
69
+ path.push(idx.toString());
70
+ collectReferences(obj[idx], results, scope, path);
71
+ path.pop();
72
+ }
73
+ } else {
74
+ const keys = Object.keys(obj);
75
+ idx = keys.length;
76
+ while (idx--) {
77
+ // do not recurse through resolved references and other z-schema props
78
+ if (keys[idx].indexOf('__$') === 0) {
79
+ continue;
80
+ }
81
+ path.push(keys[idx]);
82
+ collectReferences(obj[keys[idx]], results, scope, path);
83
+ path.pop();
84
+ }
85
+ }
86
+
87
+ if (typeof obj.id === 'string') {
88
+ scope.pop();
89
+ }
90
+
91
+ return results;
92
+ }
93
+
94
+ const compileArrayOfSchemasLoop = function (mainReport, arr) {
95
+ let idx = arr.length,
96
+ compiledCount = 0;
97
+
98
+ while (idx--) {
99
+ // try to compile each schema separately
100
+ const report = new Report(mainReport);
101
+ const isValid = compileSchema.call(this, report, arr[idx]);
102
+ if (isValid) {
103
+ compiledCount++;
104
+ }
105
+
106
+ // copy errors to report
107
+ mainReport.errors = mainReport.errors.concat(report.errors);
108
+ }
109
+
110
+ return compiledCount;
111
+ };
112
+
113
+ function findId(arr, id) {
114
+ let idx = arr.length;
115
+ while (idx--) {
116
+ if (arr[idx].id === id) {
117
+ return arr[idx];
118
+ }
119
+ }
120
+ return null;
121
+ }
122
+
123
+ const compileArrayOfSchemas = function (report, arr) {
124
+ let compiled = 0,
125
+ lastLoopCompiled;
126
+
127
+ do {
128
+ // remove all UNRESOLVABLE_REFERENCE errors before compiling array again
129
+ let idx = report.errors.length;
130
+ while (idx--) {
131
+ if (report.errors[idx].code === 'UNRESOLVABLE_REFERENCE') {
132
+ report.errors.splice(idx, 1);
133
+ }
134
+ }
135
+
136
+ // remember how many were compiled in the last loop
137
+ lastLoopCompiled = compiled;
138
+
139
+ // count how many are compiled now
140
+ compiled = compileArrayOfSchemasLoop.call(this, report, arr);
141
+
142
+ // fix __$missingReferences if possible
143
+ idx = arr.length;
144
+ while (idx--) {
145
+ const sch = arr[idx];
146
+ if (sch.__$missingReferences) {
147
+ let idx2 = sch.__$missingReferences.length;
148
+ while (idx2--) {
149
+ const refObj = sch.__$missingReferences[idx2];
150
+ const response = findId(arr, refObj.ref);
151
+ if (response) {
152
+ // this might create circular references
153
+ refObj.obj['__' + refObj.key + 'Resolved'] = response;
154
+ // it's resolved now so delete it
155
+ sch.__$missingReferences.splice(idx2, 1);
156
+ }
157
+ }
158
+ if (sch.__$missingReferences.length === 0) {
159
+ delete sch.__$missingReferences;
160
+ }
161
+ }
162
+ }
163
+
164
+ // keep repeating if not all compiled and at least one more was compiled in the last loop
165
+ } while (compiled !== arr.length && compiled !== lastLoopCompiled);
166
+
167
+ return report.isValid();
168
+ };
169
+
170
+ export function compileSchema(report, schema) {
171
+ report.commonErrorMessage = 'SCHEMA_COMPILATION_FAILED';
172
+
173
+ // if schema is a string, assume it's a uri
174
+ if (typeof schema === 'string') {
175
+ const loadedSchema = getSchemaByUri.call(this, report, schema);
176
+ if (!loadedSchema) {
177
+ report.addError('SCHEMA_NOT_REACHABLE', [schema]);
178
+ return false;
179
+ }
180
+ schema = loadedSchema;
181
+ }
182
+
183
+ // if schema is an array, assume it's an array of schemas
184
+ if (Array.isArray(schema)) {
185
+ return compileArrayOfSchemas.call(this, report, schema);
186
+ }
187
+
188
+ // if we have an id than it should be cached already (if this instance has compiled it)
189
+ if (schema.__$compiled && schema.id && checkCacheForUri.call(this, schema.id) === false) {
190
+ schema.__$compiled = undefined;
191
+ }
192
+
193
+ // do not re-compile schemas
194
+ if (schema.__$compiled) {
195
+ return true;
196
+ }
197
+
198
+ if (schema.id && typeof schema.id === 'string') {
199
+ // add this to our schemaCache (before compilation in case we have references including id)
200
+ cacheSchemaByUri.call(this, schema.id, schema);
201
+ }
202
+
203
+ // this method can be called recursively, so we need to remember our root
204
+ let isRoot = false;
205
+ if (!report.rootSchema) {
206
+ report.rootSchema = schema;
207
+ isRoot = true;
208
+ }
209
+
210
+ // delete all __$missingReferences from previous compilation attempts
211
+ const isValidExceptReferences = report.isValid();
212
+ delete schema.__$missingReferences;
213
+
214
+ // collect all references that need to be resolved - $ref and $schema
215
+ const refs = collectReferences.call(this, schema);
216
+ let idx = refs.length;
217
+ while (idx--) {
218
+ // resolve all the collected references into __xxxResolved pointer
219
+ const refObj = refs[idx];
220
+ let response = getSchemaByUri.call(this, report, refObj.ref, schema);
221
+
222
+ // we can try to use custom schemaReader if available
223
+ if (!response) {
224
+ const schemaReader = this.getSchemaReader();
225
+ if (schemaReader) {
226
+ // it's supposed to return a valid schema
227
+ const s = schemaReader(refObj.ref);
228
+ if (s) {
229
+ // it needs to have the id
230
+ s.id = refObj.ref;
231
+ // try to compile the schema
232
+ const subreport = new Report(report);
233
+ if (!compileSchema.call(this, subreport, s)) {
234
+ // copy errors to report
235
+ report.errors = report.errors.concat(subreport.errors);
236
+ } else {
237
+ response = getSchemaByUri.call(this, report, refObj.ref, schema);
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ if (!response) {
244
+ const hasNotValid = report.hasError('REMOTE_NOT_VALID', [refObj.ref]);
245
+ const isAbsolute = Utils.isAbsoluteUri(refObj.ref);
246
+ let isDownloaded = false;
247
+ const ignoreUnresolvableRemotes = this.options.ignoreUnresolvableReferences === true;
248
+
249
+ if (isAbsolute) {
250
+ // we shouldn't add UNRESOLVABLE_REFERENCE for schemas we already have downloaded
251
+ // and set through setRemoteReference method
252
+ isDownloaded = checkCacheForUri.call(this, refObj.ref);
253
+ }
254
+
255
+ if (hasNotValid) {
256
+ // already has REMOTE_NOT_VALID error for this one
257
+ } else if (ignoreUnresolvableRemotes && isAbsolute) {
258
+ // ignoreUnresolvableRemotes is on and remote isAbsolute
259
+ } else if (isDownloaded) {
260
+ // remote is downloaded, so no UNRESOLVABLE_REFERENCE
261
+ } else {
262
+ Array.prototype.push.apply(report.path, refObj.path);
263
+ report.addError('UNRESOLVABLE_REFERENCE', [refObj.ref]);
264
+ report.path = report.path.slice(0, -refObj.path.length);
265
+
266
+ // pusblish unresolved references out
267
+ if (isValidExceptReferences) {
268
+ schema.__$missingReferences = schema.__$missingReferences || [];
269
+ schema.__$missingReferences.push(refObj);
270
+ }
271
+ }
272
+ }
273
+ // this might create circular references
274
+ refObj.obj['__' + refObj.key + 'Resolved'] = response;
275
+ }
276
+
277
+ const isValid = report.isValid();
278
+ if (isValid) {
279
+ schema.__$compiled = true;
280
+ } else {
281
+ if (schema.id && typeof schema.id === 'string') {
282
+ // remove this schema from schemaCache because it failed to compile
283
+ removeFromCacheByUri.call(this, schema.id);
284
+ }
285
+ }
286
+
287
+ // we don't need the root pointer anymore
288
+ if (isRoot) {
289
+ report.rootSchema = undefined;
290
+ }
291
+
292
+ return isValid;
293
+ }