z-schema 9.0.1 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +123 -191
  2. package/cjs/index.d.ts +33 -9
  3. package/cjs/index.js +4799 -3984
  4. package/dist/errors.js +5 -0
  5. package/dist/format-validators.js +65 -0
  6. package/dist/json-schema-versions.js +5 -0
  7. package/dist/json-schema.js +11 -4
  8. package/dist/json-validation.js +151 -10
  9. package/dist/report.js +2 -3
  10. package/dist/schema-cache.js +23 -2
  11. package/dist/schema-compiler.js +25 -10
  12. package/dist/schema-validator.js +66 -45
  13. package/dist/schemas/draft-06-hyper-schema.json +132 -0
  14. package/dist/schemas/draft-06-links.json +43 -0
  15. package/dist/schemas/draft-06-schema.json +155 -0
  16. package/dist/types/errors.d.ts +4 -0
  17. package/dist/types/index.d.ts +2 -1
  18. package/dist/types/json-schema-versions.d.ts +23 -0
  19. package/dist/types/json-schema.d.ts +5 -9
  20. package/dist/types/json-validation.d.ts +3 -3
  21. package/dist/types/report.d.ts +3 -3
  22. package/dist/types/schema-cache.d.ts +1 -1
  23. package/dist/types/schema-compiler.d.ts +1 -1
  24. package/dist/types/schema-validator.d.ts +1 -1
  25. package/dist/types/utils/what-is.d.ts +1 -0
  26. package/dist/types/z-schema-base.d.ts +1 -1
  27. package/dist/types/z-schema-options.d.ts +1 -1
  28. package/dist/types/z-schema-reader.d.ts +1 -1
  29. package/dist/types/z-schema-versions.d.ts +1 -0
  30. package/dist/types/z-schema.d.ts +10 -1
  31. package/dist/utils/schema-regex.js +4 -3
  32. package/dist/utils/what-is.js +4 -1
  33. package/dist/z-schema-base.js +4 -5
  34. package/dist/z-schema-options.js +3 -1
  35. package/dist/z-schema-versions.js +27 -0
  36. package/dist/z-schema.js +21 -7
  37. package/package.json +2 -2
  38. package/src/errors.ts +6 -0
  39. package/src/format-validators.ts +65 -0
  40. package/src/index.ts +2 -1
  41. package/src/json-schema-versions.ts +34 -0
  42. package/src/json-schema.ts +22 -16
  43. package/src/json-validation.ts +183 -13
  44. package/src/report.ts +5 -6
  45. package/src/schema-cache.ts +25 -3
  46. package/src/schema-compiler.ts +25 -11
  47. package/src/schema-validator.ts +128 -62
  48. package/src/schemas/draft-06-hyper-schema.json +133 -0
  49. package/src/schemas/draft-06-links.json +43 -0
  50. package/src/schemas/draft-06-schema.json +155 -0
  51. package/src/utils/schema-regex.ts +5 -3
  52. package/src/utils/what-is.ts +5 -1
  53. package/src/z-schema-base.ts +5 -6
  54. package/src/z-schema-options.ts +3 -2
  55. package/src/z-schema-reader.ts +1 -1
  56. package/src/z-schema-versions.ts +38 -0
  57. package/src/z-schema.ts +27 -11
  58. package/umd/ZSchema.js +5100 -4285
  59. package/umd/ZSchema.min.js +1 -1
package/dist/errors.js CHANGED
@@ -47,6 +47,11 @@ export const Errors = {
47
47
  ASYNC_TIMEOUT: '{0} asynchronous task(s) have timed out after {1} ms',
48
48
  PARENT_SCHEMA_VALIDATION_FAILED: 'Schema failed to validate against its parent schema, see inner errors for details.',
49
49
  REMOTE_NOT_VALID: "Remote reference didn't compile successfully: {0}",
50
+ // Draft-06 errors
51
+ SCHEMA_IS_FALSE: 'Boolean schema "false" is always invalid.',
52
+ CONST: 'Value does not match const: {0}',
53
+ CONTAINS: 'Array does not contain an item matching the schema',
54
+ PROPERTY_NAMES: 'Property name {0} does not match the propertyNames schema',
50
55
  };
51
56
  export class ValidateError extends Error {
52
57
  name;
@@ -191,6 +191,65 @@ const uriValidator = function (uri) {
191
191
  }
192
192
  return /^[a-zA-Z][a-zA-Z0-9+.-]*:[^"\\<>^{}^`| ]*$/.test(uri);
193
193
  };
194
+ const uriReferenceValidator = (uri) => {
195
+ if (typeof uri !== 'string')
196
+ return true;
197
+ // eslint-disable-next-line no-control-regex
198
+ if (/[^\x00-\x7F]/.test(uri))
199
+ return false;
200
+ // URI-reference allows relative URIs
201
+ return /^([a-zA-Z][a-zA-Z0-9+.-]*:)?[^"\\<>^{}^`| ]*$/.test(uri);
202
+ };
203
+ const uriTemplateValidator = (uri) => {
204
+ if (typeof uri !== 'string')
205
+ return true;
206
+ // URI template allows braces for expressions.
207
+ if (!/^([a-zA-Z][a-zA-Z0-9+.-]*:)?[^"\\<>^`| ]*$/.test(uri)) {
208
+ return false;
209
+ }
210
+ let inExpression = false;
211
+ for (let idx = 0; idx < uri.length; idx++) {
212
+ const ch = uri[idx];
213
+ if (ch === '{') {
214
+ if (inExpression) {
215
+ return false;
216
+ }
217
+ inExpression = true;
218
+ }
219
+ else if (ch === '}') {
220
+ if (!inExpression) {
221
+ return false;
222
+ }
223
+ inExpression = false;
224
+ }
225
+ }
226
+ return !inExpression;
227
+ };
228
+ const jsonPointerValidator = (pointer) => {
229
+ if (typeof pointer !== 'string')
230
+ return true;
231
+ // JSON Pointer: empty, or a sequence of '/'-prefixed reference tokens.
232
+ // In each token, '~' must be escaped as '~0' or '~1'.
233
+ return pointer === '' || /^(?:\/(?:[^~]|~0|~1)*)+$/.test(pointer);
234
+ };
235
+ const relativeJsonPointerValidator = (pointer) => {
236
+ if (typeof pointer !== 'string')
237
+ return true;
238
+ // Relative JSON Pointer: number#path or empty
239
+ return /^\d+(#.*)?$/.test(pointer) || pointer === '';
240
+ };
241
+ const timeValidator = (time) => {
242
+ if (typeof time !== 'string')
243
+ return true;
244
+ // time: hh:mm:ss[.fraction]
245
+ return /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)(\.\d+)?$/.test(time);
246
+ };
247
+ const idnEmailValidator = (email) => {
248
+ if (typeof email !== 'string')
249
+ return true;
250
+ // Simple email check, allowing international chars
251
+ return /^[^\s@]+@[^\s@]+$/.test(email);
252
+ };
194
253
  const inbuiltValidators = {
195
254
  date: dateValidator,
196
255
  'date-time': dateTimeValidator,
@@ -202,6 +261,12 @@ const inbuiltValidators = {
202
261
  regex: regexValidator,
203
262
  uri: uriValidator,
204
263
  'strict-uri': strictUriValidator,
264
+ 'uri-reference': uriReferenceValidator,
265
+ 'uri-template': uriTemplateValidator,
266
+ 'json-pointer': jsonPointerValidator,
267
+ 'relative-json-pointer': relativeJsonPointerValidator,
268
+ time: timeValidator,
269
+ 'idn-email': idnEmailValidator,
205
270
  };
206
271
  const customValidators = {};
207
272
  export function getFormatValidators(options) {
@@ -0,0 +1,5 @@
1
+ export const CURRENT_DEFAULT_SCHEMA_VERSION = 'draft-06';
2
+ export const VERSION_SCHEMA_URL_MAPPING = {
3
+ 'draft-04': 'http://json-schema.org/draft-04/schema#',
4
+ 'draft-06': 'http://json-schema.org/draft-06/schema#',
5
+ };
@@ -1,6 +1,12 @@
1
1
  import { isObject } from './utils/what-is.js';
2
- export const VERSION_SCHEMA_URL_MAPPING = {
3
- 'draft-04': 'http://json-schema.org/draft-04/schema#',
2
+ export const getId = (schema) => {
3
+ if (schema.$id) {
4
+ return schema.$id;
5
+ }
6
+ if (schema.id) {
7
+ return schema.id;
8
+ }
9
+ return undefined;
4
10
  };
5
11
  export const findId = (schema, id) => {
6
12
  // process only arrays and objects
@@ -11,8 +17,9 @@ export const findId = (schema, id) => {
11
17
  if (!id) {
12
18
  return schema;
13
19
  }
14
- if (schema.id) {
15
- if (schema.id === id || (schema.id[0] === '#' && schema.id.substring(1) === id)) {
20
+ const schemaId = getId(schema);
21
+ if (schemaId) {
22
+ if (schemaId === id || (schemaId[0] === '#' && schemaId.substring(1) === id)) {
16
23
  return schema;
17
24
  }
18
25
  }
@@ -54,8 +54,20 @@ export const JsonValidators = {
54
54
  }
55
55
  }
56
56
  },
57
- exclusiveMaximum: function () {
58
- // covered in maximum
57
+ exclusiveMaximum: function (report, schema, json) {
58
+ // In draft-06+, exclusiveMaximum is a standalone number
59
+ if (typeof schema.exclusiveMaximum === 'number') {
60
+ if (shouldSkipValidate(this.validateOptions, ['MAXIMUM_EXCLUSIVE'])) {
61
+ return;
62
+ }
63
+ if (typeof json !== 'number') {
64
+ return;
65
+ }
66
+ if (json >= schema.exclusiveMaximum) {
67
+ report.addError('MAXIMUM_EXCLUSIVE', [json, schema.exclusiveMaximum], undefined, schema, 'exclusiveMaximum');
68
+ }
69
+ }
70
+ // In draft-04, exclusiveMaximum is a boolean handled inside the `maximum` validator
59
71
  },
60
72
  minimum: function (report, schema, json) {
61
73
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.3.2
@@ -76,8 +88,20 @@ export const JsonValidators = {
76
88
  }
77
89
  }
78
90
  },
79
- exclusiveMinimum: function () {
80
- // covered in minimum
91
+ exclusiveMinimum: function (report, schema, json) {
92
+ // In draft-06+, exclusiveMinimum is a standalone number
93
+ if (typeof schema.exclusiveMinimum === 'number') {
94
+ if (shouldSkipValidate(this.validateOptions, ['MINIMUM_EXCLUSIVE'])) {
95
+ return;
96
+ }
97
+ if (typeof json !== 'number') {
98
+ return;
99
+ }
100
+ if (json <= schema.exclusiveMinimum) {
101
+ report.addError('MINIMUM_EXCLUSIVE', [json, schema.exclusiveMinimum], undefined, schema, 'exclusiveMinimum');
102
+ }
103
+ }
104
+ // In draft-04, exclusiveMinimum is a boolean handled inside the `minimum` validator
81
105
  },
82
106
  maxLength: function (report, schema, json) {
83
107
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1.2
@@ -256,7 +280,11 @@ export const JsonValidators = {
256
280
  // for each regex in "pp", remove all elements of "s" which this regex matches.
257
281
  let idx = pp.length;
258
282
  while (idx--) {
259
- const regExp = RegExp(pp[idx]);
283
+ const result = compileSchemaRegex(pp[idx]);
284
+ if (!result.ok) {
285
+ continue;
286
+ }
287
+ const regExp = result.value;
260
288
  let idx2 = s.length;
261
289
  while (idx2--) {
262
290
  if (regExp.test(s[idx2]) === true) {
@@ -549,6 +577,112 @@ export const JsonValidators = {
549
577
  report.addError('UNKNOWN_FORMAT', [schema.format], undefined, schema, 'format');
550
578
  }
551
579
  },
580
+ // draft-06 additions
581
+ $id: () => {
582
+ // TODO: implement
583
+ },
584
+ const: function (report, schema, json) {
585
+ const constValue = schema.const;
586
+ if (areEqual(json, constValue) === false) {
587
+ report.addError('CONST', [JSON.stringify(constValue)], undefined, schema, undefined);
588
+ }
589
+ },
590
+ contains: function (report, schema, json) {
591
+ if (shouldSkipValidate(this.validateOptions, ['CONTAINS'])) {
592
+ return;
593
+ }
594
+ if (!Array.isArray(json)) {
595
+ return;
596
+ }
597
+ const containsSchema = schema.contains;
598
+ if (containsSchema === undefined) {
599
+ return;
600
+ }
601
+ const subReports = [];
602
+ let idx = json.length;
603
+ while (idx--) {
604
+ const subReport = new Report(report);
605
+ subReports.push(subReport);
606
+ validate.call(this, subReport, containsSchema, json[idx]);
607
+ }
608
+ const asyncTasksBefore = report.asyncTasks.length;
609
+ for (const subReport of subReports) {
610
+ report.asyncTasks.push(...subReport.asyncTasks);
611
+ }
612
+ const hasAsyncTasks = report.asyncTasks.length > asyncTasksBefore;
613
+ const addContainsErrorIfNeeded = () => {
614
+ let hasValidItem = false;
615
+ for (const subReport of subReports) {
616
+ if (subReport.errors.length === 0) {
617
+ hasValidItem = true;
618
+ break;
619
+ }
620
+ }
621
+ if (!hasValidItem) {
622
+ report.addError('CONTAINS', undefined, subReports, schema, undefined);
623
+ }
624
+ };
625
+ if (hasAsyncTasks) {
626
+ const pathBeforeAsync = shallowClone(report.path);
627
+ report.addAsyncTask((callback) => {
628
+ setTimeout(() => callback(null), 0);
629
+ }, [], () => {
630
+ const backup = report.path;
631
+ report.path = pathBeforeAsync;
632
+ addContainsErrorIfNeeded();
633
+ report.path = backup;
634
+ });
635
+ return;
636
+ }
637
+ addContainsErrorIfNeeded();
638
+ },
639
+ examples: () => {
640
+ // TODO: implement
641
+ },
642
+ propertyNames: function (report, schema, json) {
643
+ if (shouldSkipValidate(this.validateOptions, ['PROPERTY_NAMES'])) {
644
+ return;
645
+ }
646
+ if (!isObject(json)) {
647
+ return;
648
+ }
649
+ const propertyNamesSchema = schema.propertyNames;
650
+ if (propertyNamesSchema === undefined) {
651
+ return;
652
+ }
653
+ const keys = Object.keys(json);
654
+ const subReports = [];
655
+ for (const key of keys) {
656
+ const subReport = new Report(report);
657
+ subReports.push(subReport);
658
+ validate.call(this, subReport, propertyNamesSchema, key);
659
+ }
660
+ const asyncTasksBefore = report.asyncTasks.length;
661
+ for (const subReport of subReports) {
662
+ report.asyncTasks.push(...subReport.asyncTasks);
663
+ }
664
+ const hasAsyncTasks = report.asyncTasks.length > asyncTasksBefore;
665
+ const addPropertyNameErrors = () => {
666
+ for (let idx = 0; idx < keys.length; idx++) {
667
+ if (subReports[idx].errors.length > 0) {
668
+ report.addError('PROPERTY_NAMES', [keys[idx]], subReports[idx], schema, undefined);
669
+ }
670
+ }
671
+ };
672
+ if (hasAsyncTasks) {
673
+ const pathBeforeAsync = shallowClone(report.path);
674
+ report.addAsyncTask((callback) => {
675
+ setTimeout(() => callback(null), 0);
676
+ }, [], () => {
677
+ const backup = report.path;
678
+ report.path = pathBeforeAsync;
679
+ addPropertyNameErrors();
680
+ report.path = backup;
681
+ });
682
+ return;
683
+ }
684
+ addPropertyNameErrors();
685
+ },
552
686
  };
553
687
  const recurseArray = function (report, schema, json) {
554
688
  // http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.2
@@ -575,7 +709,7 @@ const recurseArray = function (report, schema, json) {
575
709
  }
576
710
  }
577
711
  }
578
- else if (typeof schema.items === 'object') {
712
+ else if (typeof schema.items === 'object' || typeof schema.items === 'boolean') {
579
713
  // If items is a schema, then the child instance must be valid against this schema,
580
714
  // regardless of its index, and regardless of the value of "additionalItems".
581
715
  while (idx--) {
@@ -615,7 +749,8 @@ const recurseObject = function (report, schema, json) {
615
749
  let idx2 = pp.length;
616
750
  while (idx2--) {
617
751
  const regexString = pp[idx2];
618
- if (RegExp(regexString).test(m) === true) {
752
+ const result = compileSchemaRegex(regexString);
753
+ if (result.ok && result.value.test(m) === true) {
619
754
  s.push(schema.patternProperties[regexString]);
620
755
  }
621
756
  }
@@ -651,10 +786,16 @@ const recurseObject = function (report, schema, json) {
651
786
  };
652
787
  export function validate(report, schema, json) {
653
788
  report.commonErrorMessage = 'JSON_OBJECT_VALIDATION_FAILED';
789
+ if (schema === true) {
790
+ return true;
791
+ }
792
+ if (schema === false) {
793
+ report.addError('SCHEMA_IS_FALSE', [], undefined, schema);
794
+ return false;
795
+ }
654
796
  // check if schema is an object
655
- const to = whatIs(schema);
656
- if (to !== 'object') {
657
- report.addError('SCHEMA_NOT_AN_OBJECT', [to], undefined, schema);
797
+ if (!isObject(schema)) {
798
+ report.addError('SCHEMA_NOT_AN_OBJECT', [whatIs(schema)], undefined, schema);
658
799
  return false;
659
800
  }
660
801
  // check if schema is empty, everything is valid against empty schema
package/dist/report.js CHANGED
@@ -2,7 +2,7 @@ import { Errors, getValidateError } from './errors.js';
2
2
  import { get } from './utils/json.js';
3
3
  import { jsonSymbol, schemaSymbol } from './utils/symbols.js';
4
4
  import { isAbsoluteUri } from './utils/uri.js';
5
- import { whatIs } from './utils/what-is.js';
5
+ import { isObject } from './utils/what-is.js';
6
6
  export class Report {
7
7
  asyncTasks = [];
8
8
  commonErrorMessage;
@@ -183,8 +183,7 @@ export class Report {
183
183
  params = params || [];
184
184
  let idx = params.length;
185
185
  while (idx--) {
186
- const paramType = whatIs(params[idx]);
187
- const param = paramType === 'object' || paramType === 'null' ? JSON.stringify(params[idx]) : params[idx];
186
+ const param = params[idx] === null || isObject(params[idx]) ? JSON.stringify(params[idx]) : params[idx];
188
187
  errorMessage = errorMessage.replace('{' + idx + '}', param.toString());
189
188
  }
190
189
  const err = {
@@ -1,4 +1,4 @@
1
- import { findId } from './json-schema.js';
1
+ import { findId, getId } from './json-schema.js';
2
2
  import { Report } from './report.js';
3
3
  import { deepClone } from './utils/clone.js';
4
4
  import { decodeJSONPointer } from './utils/json.js';
@@ -49,7 +49,9 @@ export class SchemaCache {
49
49
  return this.cache[path];
50
50
  }
51
51
  const asClone = (s) => {
52
- s.id ??= path;
52
+ if (!s.id || (!isAbsoluteUri(s.id) && isAbsoluteUri(path))) {
53
+ s.id = path;
54
+ }
53
55
  return deepClone(s);
54
56
  };
55
57
  found = SchemaCache.global_cache[path];
@@ -59,9 +61,28 @@ export class SchemaCache {
59
61
  return undefined;
60
62
  }
61
63
  getSchemaByUri(report, uri, root) {
64
+ if (root && !isAbsoluteUri(uri)) {
65
+ let rootId = getId(root);
66
+ if ((!rootId || !isAbsoluteUri(rootId)) && typeof root.id === 'string' && isAbsoluteUri(root.id)) {
67
+ rootId = root.id;
68
+ }
69
+ if (rootId && isAbsoluteUri(rootId)) {
70
+ const hashIndex = rootId.indexOf('#');
71
+ const rootBase = hashIndex === -1 ? rootId : rootId.slice(0, hashIndex);
72
+ try {
73
+ uri = new URL(uri, rootBase).toString();
74
+ }
75
+ catch {
76
+ // keep original uri when URL construction fails
77
+ }
78
+ }
79
+ }
62
80
  const remotePath = getRemotePath(uri);
63
81
  const queryPath = getQueryPath(uri);
64
82
  let result = remotePath ? this.fromCache(remotePath) : root;
83
+ if (result && remotePath && isAbsoluteUri(remotePath) && (!result.id || !isAbsoluteUri(result.id))) {
84
+ result.id = remotePath;
85
+ }
65
86
  if (result && remotePath) {
66
87
  // we need to avoid compiling schemas in a recursive loop
67
88
  const compileRemote = result !== root;
@@ -1,31 +1,38 @@
1
+ import { getId } from './json-schema.js';
1
2
  import { Report } from './report.js';
2
3
  import { getRemotePath, isAbsoluteUri } from './utils/uri.js';
3
4
  import { getSchemaReader } from './z-schema-reader.js';
4
5
  export const collectIds = (obj) => {
5
6
  const ids = [];
7
+ const doNotCollectIdsFrom = ['enum', 'const', 'default', 'examples'];
6
8
  function walk(node, scope) {
7
9
  if (typeof node !== 'object' || node == null)
8
10
  return;
9
11
  let addedScope = false;
10
- if (node.id && typeof node.id === 'string') {
11
- let type = isAbsoluteUri(node.id) ? 'absolute' : 'relative';
12
+ const nodeId = getId(node);
13
+ if (typeof nodeId === 'string') {
14
+ let type = isAbsoluteUri(nodeId) ? 'absolute' : 'relative';
12
15
  if (scope.length === 0) {
13
16
  type = 'root';
14
17
  }
15
18
  const id = {
16
- id: node.id,
19
+ id: nodeId,
17
20
  type,
18
21
  obj: node,
19
22
  };
20
- if (type === 'absolute' || (type === 'root' && isAbsoluteUri(node.id))) {
21
- id.absoluteUri = node.id;
23
+ if (type === 'absolute' || (type === 'root' && isAbsoluteUri(nodeId))) {
24
+ id.absoluteUri = nodeId;
25
+ }
26
+ else if (type === 'root' && typeof node.id === 'string' && isAbsoluteUri(node.id) && node.id !== nodeId) {
27
+ id.absoluteUri = resolveIdScope(node.id, nodeId);
22
28
  }
23
29
  else if (type === 'relative') {
24
30
  id.absoluteParent = scope
25
31
  .filter((x) => x.type === 'absolute' || (x.type === 'root' && x.absoluteUri))
26
32
  .slice(-1)[0];
27
33
  if (id.absoluteParent) {
28
- id.absoluteUri = id.absoluteParent.id.split('/').slice(0, -1).concat(id.id).join('/');
34
+ const parentUri = id.absoluteParent.absoluteUri || id.absoluteParent.id;
35
+ id.absoluteUri = parentUri.split('/').slice(0, -1).concat(id.id).join('/');
29
36
  }
30
37
  }
31
38
  ids.push(id);
@@ -39,7 +46,7 @@ export const collectIds = (obj) => {
39
46
  }
40
47
  else {
41
48
  for (const key of Object.keys(node)) {
42
- if (key.indexOf('__$') === 0)
49
+ if (key.indexOf('__$') === 0 || doNotCollectIdsFrom.includes(key))
43
50
  continue;
44
51
  walk(node[key], scope);
45
52
  }
@@ -51,7 +58,7 @@ export const collectIds = (obj) => {
51
58
  walk(obj, []);
52
59
  return ids;
53
60
  };
54
- const doNotCollectReferencesFrom = ['enum'];
61
+ const doNotCollectReferencesFrom = ['enum', 'const', 'default', 'examples'];
55
62
  export const collectReferences = (obj, results, scope, path) => {
56
63
  results = results || [];
57
64
  scope = scope || [];
@@ -62,9 +69,14 @@ export const collectReferences = (obj, results, scope, path) => {
62
69
  const hasRef = typeof obj.$ref === 'string' && typeof obj.__$refResolved === 'undefined';
63
70
  let addedScope = false;
64
71
  const isRootScope = scope.length === 0;
65
- if (typeof obj.id === 'string' && (isRootScope || !hasRef)) {
72
+ const objId = getId(obj);
73
+ let scopeId = objId;
74
+ if (typeof obj.id === 'string' && isAbsoluteUri(obj.id) && (!scopeId || !isAbsoluteUri(scopeId))) {
75
+ scopeId = obj.id;
76
+ }
77
+ if (typeof scopeId === 'string' && (isRootScope || !hasRef)) {
66
78
  const base = scope.length > 0 ? scope[scope.length - 1] : undefined;
67
- scope.push(resolveIdScope(base, obj.id));
79
+ scope.push(resolveIdScope(base, scopeId));
68
80
  addedScope = true;
69
81
  }
70
82
  if (hasRef) {
@@ -186,6 +198,9 @@ export class SchemaCompiler {
186
198
  }
187
199
  return this.compileArrayOfSchemas(report, schema);
188
200
  }
201
+ else if (typeof schema === 'boolean') {
202
+ return true;
203
+ }
189
204
  else {
190
205
  if (!options?.noCache) {
191
206
  this.collectAndCacheIds(schema);