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.
- package/README.md +123 -191
- package/cjs/index.d.ts +33 -9
- package/cjs/index.js +4799 -3984
- package/dist/errors.js +5 -0
- package/dist/format-validators.js +65 -0
- package/dist/json-schema-versions.js +5 -0
- package/dist/json-schema.js +11 -4
- package/dist/json-validation.js +151 -10
- package/dist/report.js +2 -3
- package/dist/schema-cache.js +23 -2
- package/dist/schema-compiler.js +25 -10
- package/dist/schema-validator.js +66 -45
- package/dist/schemas/draft-06-hyper-schema.json +132 -0
- package/dist/schemas/draft-06-links.json +43 -0
- package/dist/schemas/draft-06-schema.json +155 -0
- package/dist/types/errors.d.ts +4 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/json-schema-versions.d.ts +23 -0
- package/dist/types/json-schema.d.ts +5 -9
- package/dist/types/json-validation.d.ts +3 -3
- package/dist/types/report.d.ts +3 -3
- package/dist/types/schema-cache.d.ts +1 -1
- package/dist/types/schema-compiler.d.ts +1 -1
- package/dist/types/schema-validator.d.ts +1 -1
- package/dist/types/utils/what-is.d.ts +1 -0
- package/dist/types/z-schema-base.d.ts +1 -1
- package/dist/types/z-schema-options.d.ts +1 -1
- package/dist/types/z-schema-reader.d.ts +1 -1
- package/dist/types/z-schema-versions.d.ts +1 -0
- package/dist/types/z-schema.d.ts +10 -1
- package/dist/utils/schema-regex.js +4 -3
- package/dist/utils/what-is.js +4 -1
- package/dist/z-schema-base.js +4 -5
- package/dist/z-schema-options.js +3 -1
- package/dist/z-schema-versions.js +27 -0
- package/dist/z-schema.js +21 -7
- package/package.json +2 -2
- package/src/errors.ts +6 -0
- package/src/format-validators.ts +65 -0
- package/src/index.ts +2 -1
- package/src/json-schema-versions.ts +34 -0
- package/src/json-schema.ts +22 -16
- package/src/json-validation.ts +183 -13
- package/src/report.ts +5 -6
- package/src/schema-cache.ts +25 -3
- package/src/schema-compiler.ts +25 -11
- package/src/schema-validator.ts +128 -62
- package/src/schemas/draft-06-hyper-schema.json +133 -0
- package/src/schemas/draft-06-links.json +43 -0
- package/src/schemas/draft-06-schema.json +155 -0
- package/src/utils/schema-regex.ts +5 -3
- package/src/utils/what-is.ts +5 -1
- package/src/z-schema-base.ts +5 -6
- package/src/z-schema-options.ts +3 -2
- package/src/z-schema-reader.ts +1 -1
- package/src/z-schema-versions.ts +38 -0
- package/src/z-schema.ts +27 -11
- package/umd/ZSchema.js +5100 -4285
- package/umd/ZSchema.min.js +1 -1
package/src/json-validation.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { JsonSchema, JsonSchemaInternal } from './json-schema.js';
|
|
1
|
+
import type { JsonSchema, JsonSchemaAll, JsonSchemaInternal } from './json-schema-versions.js';
|
|
2
2
|
import type { ValidateOptions, ZSchemaBase } from './z-schema-base.js';
|
|
3
3
|
|
|
4
4
|
import { getFormatValidators } from './format-validators.js';
|
|
@@ -24,7 +24,7 @@ const shouldSkipValidate = function (options: ValidateOptions, errors: any) {
|
|
|
24
24
|
|
|
25
25
|
type JsonValidatorFn = (this: ZSchemaBase, report: Report, schema: JsonSchema, json: unknown) => void;
|
|
26
26
|
|
|
27
|
-
export const JsonValidators: Record<keyof
|
|
27
|
+
export const JsonValidators: Record<keyof JsonSchemaAll, JsonValidatorFn> = {
|
|
28
28
|
id: () => {},
|
|
29
29
|
$ref: () => {},
|
|
30
30
|
$schema: () => {},
|
|
@@ -63,8 +63,20 @@ export const JsonValidators: Record<keyof JsonSchema, JsonValidatorFn> = {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
|
-
exclusiveMaximum: function () {
|
|
67
|
-
//
|
|
66
|
+
exclusiveMaximum: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
67
|
+
// In draft-06+, exclusiveMaximum is a standalone number
|
|
68
|
+
if (typeof schema.exclusiveMaximum === 'number') {
|
|
69
|
+
if (shouldSkipValidate(this.validateOptions, ['MAXIMUM_EXCLUSIVE'])) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (typeof json !== 'number') {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (json >= schema.exclusiveMaximum) {
|
|
76
|
+
report.addError('MAXIMUM_EXCLUSIVE', [json, schema.exclusiveMaximum], undefined, schema, 'exclusiveMaximum');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// In draft-04, exclusiveMaximum is a boolean handled inside the `maximum` validator
|
|
68
80
|
},
|
|
69
81
|
minimum: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
70
82
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.1.3.2
|
|
@@ -84,8 +96,20 @@ export const JsonValidators: Record<keyof JsonSchema, JsonValidatorFn> = {
|
|
|
84
96
|
}
|
|
85
97
|
}
|
|
86
98
|
},
|
|
87
|
-
exclusiveMinimum: function () {
|
|
88
|
-
//
|
|
99
|
+
exclusiveMinimum: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
100
|
+
// In draft-06+, exclusiveMinimum is a standalone number
|
|
101
|
+
if (typeof schema.exclusiveMinimum === 'number') {
|
|
102
|
+
if (shouldSkipValidate(this.validateOptions, ['MINIMUM_EXCLUSIVE'])) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (typeof json !== 'number') {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (json <= schema.exclusiveMinimum) {
|
|
109
|
+
report.addError('MINIMUM_EXCLUSIVE', [json, schema.exclusiveMinimum], undefined, schema, 'exclusiveMinimum');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// In draft-04, exclusiveMinimum is a boolean handled inside the `minimum` validator
|
|
89
113
|
},
|
|
90
114
|
maxLength: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
91
115
|
// http://json-schema.org/latest/json-schema-validation.html#rfc.section.5.2.1.2
|
|
@@ -276,7 +300,11 @@ export const JsonValidators: Record<keyof JsonSchema, JsonValidatorFn> = {
|
|
|
276
300
|
// for each regex in "pp", remove all elements of "s" which this regex matches.
|
|
277
301
|
let idx = pp.length;
|
|
278
302
|
while (idx--) {
|
|
279
|
-
const
|
|
303
|
+
const result = compileSchemaRegex(pp[idx]);
|
|
304
|
+
if (!result.ok) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const regExp = result.value;
|
|
280
308
|
let idx2 = s.length;
|
|
281
309
|
while (idx2--) {
|
|
282
310
|
if (regExp.test(s[idx2]) === true) {
|
|
@@ -596,6 +624,134 @@ export const JsonValidators: Record<keyof JsonSchema, JsonValidatorFn> = {
|
|
|
596
624
|
report.addError('UNKNOWN_FORMAT', [schema.format!], undefined, schema, 'format');
|
|
597
625
|
}
|
|
598
626
|
},
|
|
627
|
+
// draft-06 additions
|
|
628
|
+
$id: () => {
|
|
629
|
+
// TODO: implement
|
|
630
|
+
},
|
|
631
|
+
const: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
632
|
+
const constValue = (schema as JsonSchemaAll).const;
|
|
633
|
+
if (areEqual(json, constValue) === false) {
|
|
634
|
+
report.addError('CONST', [JSON.stringify(constValue)], undefined, schema, undefined);
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
contains: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
638
|
+
if (shouldSkipValidate(this.validateOptions, ['CONTAINS'])) {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (!Array.isArray(json)) {
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const containsSchema = (schema as JsonSchemaAll).contains;
|
|
647
|
+
if (containsSchema === undefined) {
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
const subReports: Report[] = [];
|
|
652
|
+
let idx = json.length;
|
|
653
|
+
while (idx--) {
|
|
654
|
+
const subReport = new Report(report);
|
|
655
|
+
subReports.push(subReport);
|
|
656
|
+
validate.call(this, subReport, containsSchema as any, json[idx]);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
const asyncTasksBefore = report.asyncTasks.length;
|
|
660
|
+
for (const subReport of subReports) {
|
|
661
|
+
report.asyncTasks.push(...subReport.asyncTasks);
|
|
662
|
+
}
|
|
663
|
+
const hasAsyncTasks = report.asyncTasks.length > asyncTasksBefore;
|
|
664
|
+
|
|
665
|
+
const addContainsErrorIfNeeded = () => {
|
|
666
|
+
let hasValidItem = false;
|
|
667
|
+
for (const subReport of subReports) {
|
|
668
|
+
if (subReport.errors.length === 0) {
|
|
669
|
+
hasValidItem = true;
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
if (!hasValidItem) {
|
|
674
|
+
report.addError('CONTAINS', undefined, subReports, schema, undefined);
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
if (hasAsyncTasks) {
|
|
679
|
+
const pathBeforeAsync = shallowClone(report.path);
|
|
680
|
+
report.addAsyncTask(
|
|
681
|
+
(callback) => {
|
|
682
|
+
setTimeout(() => callback(null), 0);
|
|
683
|
+
},
|
|
684
|
+
[] as any,
|
|
685
|
+
() => {
|
|
686
|
+
const backup = report.path;
|
|
687
|
+
report.path = pathBeforeAsync;
|
|
688
|
+
addContainsErrorIfNeeded();
|
|
689
|
+
report.path = backup;
|
|
690
|
+
}
|
|
691
|
+
);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
addContainsErrorIfNeeded();
|
|
696
|
+
},
|
|
697
|
+
examples: () => {
|
|
698
|
+
// TODO: implement
|
|
699
|
+
},
|
|
700
|
+
propertyNames: function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: unknown) {
|
|
701
|
+
if (shouldSkipValidate(this.validateOptions, ['PROPERTY_NAMES'])) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (!isObject(json)) {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const propertyNamesSchema = (schema as JsonSchemaAll).propertyNames;
|
|
710
|
+
if (propertyNamesSchema === undefined) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const keys = Object.keys(json);
|
|
715
|
+
const subReports: Report[] = [];
|
|
716
|
+
for (const key of keys) {
|
|
717
|
+
const subReport = new Report(report);
|
|
718
|
+
subReports.push(subReport);
|
|
719
|
+
validate.call(this, subReport, propertyNamesSchema as any, key);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const asyncTasksBefore = report.asyncTasks.length;
|
|
723
|
+
for (const subReport of subReports) {
|
|
724
|
+
report.asyncTasks.push(...subReport.asyncTasks);
|
|
725
|
+
}
|
|
726
|
+
const hasAsyncTasks = report.asyncTasks.length > asyncTasksBefore;
|
|
727
|
+
|
|
728
|
+
const addPropertyNameErrors = () => {
|
|
729
|
+
for (let idx = 0; idx < keys.length; idx++) {
|
|
730
|
+
if (subReports[idx].errors.length > 0) {
|
|
731
|
+
report.addError('PROPERTY_NAMES', [keys[idx]], subReports[idx], schema, undefined);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
|
|
736
|
+
if (hasAsyncTasks) {
|
|
737
|
+
const pathBeforeAsync = shallowClone(report.path);
|
|
738
|
+
report.addAsyncTask(
|
|
739
|
+
(callback) => {
|
|
740
|
+
setTimeout(() => callback(null), 0);
|
|
741
|
+
},
|
|
742
|
+
[] as any,
|
|
743
|
+
() => {
|
|
744
|
+
const backup = report.path;
|
|
745
|
+
report.path = pathBeforeAsync;
|
|
746
|
+
addPropertyNameErrors();
|
|
747
|
+
report.path = backup;
|
|
748
|
+
}
|
|
749
|
+
);
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
addPropertyNameErrors();
|
|
754
|
+
},
|
|
599
755
|
};
|
|
600
756
|
|
|
601
757
|
const recurseArray = function (this: ZSchemaBase, report: Report, schema: JsonSchemaInternal, json: Array<unknown>) {
|
|
@@ -623,7 +779,7 @@ const recurseArray = function (this: ZSchemaBase, report: Report, schema: JsonSc
|
|
|
623
779
|
}
|
|
624
780
|
}
|
|
625
781
|
}
|
|
626
|
-
} else if (typeof schema.items === 'object') {
|
|
782
|
+
} else if (typeof schema.items === 'object' || typeof schema.items === 'boolean') {
|
|
627
783
|
// If items is a schema, then the child instance must be valid against this schema,
|
|
628
784
|
// regardless of its index, and regardless of the value of "additionalItems".
|
|
629
785
|
while (idx--) {
|
|
@@ -673,7 +829,8 @@ const recurseObject = function (this: ZSchemaBase, report: Report, schema: JsonS
|
|
|
673
829
|
let idx2 = pp.length;
|
|
674
830
|
while (idx2--) {
|
|
675
831
|
const regexString = pp[idx2];
|
|
676
|
-
|
|
832
|
+
const result = compileSchemaRegex(regexString);
|
|
833
|
+
if (result.ok && result.value.test(m) === true) {
|
|
677
834
|
s.push(schema.patternProperties![regexString]);
|
|
678
835
|
}
|
|
679
836
|
}
|
|
@@ -710,13 +867,26 @@ const recurseObject = function (this: ZSchemaBase, report: Report, schema: JsonS
|
|
|
710
867
|
}
|
|
711
868
|
};
|
|
712
869
|
|
|
713
|
-
export function validate(
|
|
870
|
+
export function validate(
|
|
871
|
+
this: ZSchemaBase,
|
|
872
|
+
report: Report,
|
|
873
|
+
schema: boolean | JsonSchemaInternal,
|
|
874
|
+
json: unknown
|
|
875
|
+
): boolean {
|
|
714
876
|
report.commonErrorMessage = 'JSON_OBJECT_VALIDATION_FAILED';
|
|
715
877
|
|
|
878
|
+
if (schema === true) {
|
|
879
|
+
return true;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (schema === false) {
|
|
883
|
+
report.addError('SCHEMA_IS_FALSE', [], undefined, schema);
|
|
884
|
+
return false;
|
|
885
|
+
}
|
|
886
|
+
|
|
716
887
|
// check if schema is an object
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
report.addError('SCHEMA_NOT_AN_OBJECT', [to], undefined, schema);
|
|
888
|
+
if (!isObject(schema)) {
|
|
889
|
+
report.addError('SCHEMA_NOT_AN_OBJECT', [whatIs(schema)], undefined, schema);
|
|
720
890
|
return false;
|
|
721
891
|
}
|
|
722
892
|
|
package/src/report.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ErrorCode, ErrorParam } from './errors.js';
|
|
2
|
-
import type { JsonSchema, JsonSchemaInternal } from './json-schema.js';
|
|
2
|
+
import type { JsonSchema, JsonSchemaInternal } from './json-schema-versions.js';
|
|
3
3
|
import type { ValidateCallback, ValidateOptions } from './z-schema-base.js';
|
|
4
4
|
import type { ZSchemaOptions } from './z-schema-options.js';
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ import { Errors, getValidateError } from './errors.js';
|
|
|
7
7
|
import { get } from './utils/json.js';
|
|
8
8
|
import { jsonSymbol, schemaSymbol } from './utils/symbols.js';
|
|
9
9
|
import { isAbsoluteUri } from './utils/uri.js';
|
|
10
|
-
import {
|
|
10
|
+
import { isObject } from './utils/what-is.js';
|
|
11
11
|
|
|
12
12
|
export interface SchemaErrorDetail {
|
|
13
13
|
/**
|
|
@@ -261,7 +261,7 @@ export class Report {
|
|
|
261
261
|
errCode: ErrorCode,
|
|
262
262
|
errParams?: ErrorParam[],
|
|
263
263
|
subReports?: Report | Report[],
|
|
264
|
-
schema?: JsonSchema,
|
|
264
|
+
schema?: JsonSchema | boolean,
|
|
265
265
|
keyword?: keyof JsonSchema
|
|
266
266
|
) {
|
|
267
267
|
if (!errCode) {
|
|
@@ -286,7 +286,7 @@ export class Report {
|
|
|
286
286
|
errorMessage: string,
|
|
287
287
|
params?: ErrorParam[],
|
|
288
288
|
subReports?: Report | Report[],
|
|
289
|
-
schema?: JsonSchema,
|
|
289
|
+
schema?: JsonSchema | boolean,
|
|
290
290
|
keyword?: keyof JsonSchema
|
|
291
291
|
) {
|
|
292
292
|
if (typeof this.reportOptions.maxErrors === 'number' && this.errors.length >= this.reportOptions.maxErrors) {
|
|
@@ -301,8 +301,7 @@ export class Report {
|
|
|
301
301
|
|
|
302
302
|
let idx = params.length;
|
|
303
303
|
while (idx--) {
|
|
304
|
-
const
|
|
305
|
-
const param = paramType === 'object' || paramType === 'null' ? JSON.stringify(params[idx]) : params[idx];
|
|
304
|
+
const param = params[idx] === null || isObject(params[idx]) ? JSON.stringify(params[idx]) : params[idx];
|
|
306
305
|
errorMessage = errorMessage.replace('{' + idx + '}', param.toString());
|
|
307
306
|
}
|
|
308
307
|
|
package/src/schema-cache.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { JsonSchema, JsonSchemaInternal } from './json-schema.js';
|
|
1
|
+
import type { JsonSchema, JsonSchemaInternal } from './json-schema-versions.js';
|
|
2
2
|
import type { ZSchemaBase } from './z-schema-base.js';
|
|
3
3
|
|
|
4
|
-
import { findId } from './json-schema.js';
|
|
4
|
+
import { findId, getId } from './json-schema.js';
|
|
5
5
|
import { Report } from './report.js';
|
|
6
6
|
import { deepClone } from './utils/clone.js';
|
|
7
7
|
import { decodeJSONPointer } from './utils/json.js';
|
|
@@ -63,7 +63,9 @@ export class SchemaCache {
|
|
|
63
63
|
return this.cache[path];
|
|
64
64
|
}
|
|
65
65
|
const asClone = (s: JsonSchema) => {
|
|
66
|
-
s.id
|
|
66
|
+
if (!s.id || (!isAbsoluteUri(s.id) && isAbsoluteUri(path))) {
|
|
67
|
+
s.id = path;
|
|
68
|
+
}
|
|
67
69
|
return deepClone(s);
|
|
68
70
|
};
|
|
69
71
|
found = SchemaCache.global_cache[path];
|
|
@@ -74,10 +76,30 @@ export class SchemaCache {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
getSchemaByUri(report: Report, uri: string, root?: JsonSchemaInternal) {
|
|
79
|
+
if (root && !isAbsoluteUri(uri)) {
|
|
80
|
+
let rootId = getId(root);
|
|
81
|
+
if ((!rootId || !isAbsoluteUri(rootId)) && typeof root.id === 'string' && isAbsoluteUri(root.id)) {
|
|
82
|
+
rootId = root.id;
|
|
83
|
+
}
|
|
84
|
+
if (rootId && isAbsoluteUri(rootId)) {
|
|
85
|
+
const hashIndex = rootId.indexOf('#');
|
|
86
|
+
const rootBase = hashIndex === -1 ? rootId : rootId.slice(0, hashIndex);
|
|
87
|
+
try {
|
|
88
|
+
uri = new URL(uri, rootBase).toString();
|
|
89
|
+
} catch {
|
|
90
|
+
// keep original uri when URL construction fails
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
77
95
|
const remotePath = getRemotePath(uri);
|
|
78
96
|
const queryPath = getQueryPath(uri);
|
|
79
97
|
let result = remotePath ? this.fromCache(remotePath) : root;
|
|
80
98
|
|
|
99
|
+
if (result && remotePath && isAbsoluteUri(remotePath) && (!result.id || !isAbsoluteUri(result.id))) {
|
|
100
|
+
result.id = remotePath;
|
|
101
|
+
}
|
|
102
|
+
|
|
81
103
|
if (result && remotePath) {
|
|
82
104
|
// we need to avoid compiling schemas in a recursive loop
|
|
83
105
|
const compileRemote = result !== root;
|
package/src/schema-compiler.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { JsonSchemaInternal } from './json-schema.js';
|
|
1
|
+
import type { JsonSchemaInternal } from './json-schema-versions.js';
|
|
2
2
|
import type { ZSchemaBase } from './z-schema-base.js';
|
|
3
3
|
|
|
4
|
+
import { getId } from './json-schema.js';
|
|
4
5
|
import { Report } from './report.js';
|
|
5
6
|
import { getRemotePath, isAbsoluteUri } from './utils/uri.js';
|
|
6
7
|
import { getSchemaReader } from './z-schema-reader.js';
|
|
@@ -15,29 +16,34 @@ interface Id {
|
|
|
15
16
|
|
|
16
17
|
export const collectIds = (obj: JsonSchemaInternal) => {
|
|
17
18
|
const ids: Id[] = [];
|
|
19
|
+
const doNotCollectIdsFrom = ['enum', 'const', 'default', 'examples'];
|
|
18
20
|
function walk(node: any, scope: Id[]) {
|
|
19
21
|
if (typeof node !== 'object' || node == null) return;
|
|
20
22
|
|
|
21
23
|
let addedScope = false;
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
const nodeId = getId(node as JsonSchemaInternal);
|
|
26
|
+
if (typeof nodeId === 'string') {
|
|
27
|
+
let type: Id['type'] = isAbsoluteUri(nodeId) ? 'absolute' : 'relative';
|
|
25
28
|
if (scope.length === 0) {
|
|
26
29
|
type = 'root';
|
|
27
30
|
}
|
|
28
31
|
const id: Id = {
|
|
29
|
-
id:
|
|
32
|
+
id: nodeId,
|
|
30
33
|
type,
|
|
31
34
|
obj: node,
|
|
32
35
|
};
|
|
33
|
-
if (type === 'absolute' || (type === 'root' && isAbsoluteUri(
|
|
34
|
-
id.absoluteUri =
|
|
36
|
+
if (type === 'absolute' || (type === 'root' && isAbsoluteUri(nodeId))) {
|
|
37
|
+
id.absoluteUri = nodeId;
|
|
38
|
+
} else if (type === 'root' && typeof node.id === 'string' && isAbsoluteUri(node.id) && node.id !== nodeId) {
|
|
39
|
+
id.absoluteUri = resolveIdScope(node.id, nodeId);
|
|
35
40
|
} else if (type === 'relative') {
|
|
36
41
|
id.absoluteParent = scope
|
|
37
42
|
.filter((x) => x.type === 'absolute' || (x.type === 'root' && x.absoluteUri))
|
|
38
43
|
.slice(-1)[0];
|
|
39
44
|
if (id.absoluteParent) {
|
|
40
|
-
|
|
45
|
+
const parentUri = id.absoluteParent.absoluteUri || id.absoluteParent.id;
|
|
46
|
+
id.absoluteUri = parentUri.split('/').slice(0, -1).concat(id.id).join('/');
|
|
41
47
|
}
|
|
42
48
|
}
|
|
43
49
|
ids.push(id);
|
|
@@ -51,7 +57,7 @@ export const collectIds = (obj: JsonSchemaInternal) => {
|
|
|
51
57
|
}
|
|
52
58
|
} else {
|
|
53
59
|
for (const key of Object.keys(node)) {
|
|
54
|
-
if (key.indexOf('__$') === 0) continue;
|
|
60
|
+
if (key.indexOf('__$') === 0 || doNotCollectIdsFrom.includes(key)) continue;
|
|
55
61
|
walk(node[key], scope);
|
|
56
62
|
}
|
|
57
63
|
}
|
|
@@ -71,7 +77,7 @@ export interface Reference {
|
|
|
71
77
|
path: Array<string | number>;
|
|
72
78
|
}
|
|
73
79
|
|
|
74
|
-
const doNotCollectReferencesFrom = ['enum'];
|
|
80
|
+
const doNotCollectReferencesFrom = ['enum', 'const', 'default', 'examples'];
|
|
75
81
|
|
|
76
82
|
export const collectReferences = (
|
|
77
83
|
obj: JsonSchemaInternal,
|
|
@@ -90,9 +96,15 @@ export const collectReferences = (
|
|
|
90
96
|
const hasRef = typeof obj.$ref === 'string' && typeof obj.__$refResolved === 'undefined';
|
|
91
97
|
let addedScope = false;
|
|
92
98
|
const isRootScope = scope.length === 0;
|
|
93
|
-
|
|
99
|
+
const objId = getId(obj);
|
|
100
|
+
let scopeId = objId;
|
|
101
|
+
if (typeof obj.id === 'string' && isAbsoluteUri(obj.id) && (!scopeId || !isAbsoluteUri(scopeId))) {
|
|
102
|
+
scopeId = obj.id;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (typeof scopeId === 'string' && (isRootScope || !hasRef)) {
|
|
94
106
|
const base = scope.length > 0 ? scope[scope.length - 1] : undefined;
|
|
95
|
-
scope.push(resolveIdScope(base,
|
|
107
|
+
scope.push(resolveIdScope(base, scopeId));
|
|
96
108
|
addedScope = true;
|
|
97
109
|
}
|
|
98
110
|
|
|
@@ -227,6 +239,8 @@ export class SchemaCompiler {
|
|
|
227
239
|
schema.forEach((s) => this.collectAndCacheIds(s));
|
|
228
240
|
}
|
|
229
241
|
return this.compileArrayOfSchemas(report, schema);
|
|
242
|
+
} else if (typeof schema === 'boolean') {
|
|
243
|
+
return true;
|
|
230
244
|
} else {
|
|
231
245
|
if (!options?.noCache) {
|
|
232
246
|
this.collectAndCacheIds(schema);
|