@hyperjump/json-schema 1.13.0 → 1.14.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 +14 -20
- package/annotations/index.js +27 -7
- package/bundle/index.js +39 -227
- package/draft-04/additionalItems.js +13 -19
- package/draft-04/items.js +26 -14
- package/draft-2020-12/dynamicRef.js +20 -8
- package/lib/core.js +19 -4
- package/lib/evaluation-plugins/annotations.js +32 -0
- package/lib/evaluation-plugins/basic-output.js +34 -0
- package/lib/evaluation-plugins/detailed-output.js +36 -0
- package/lib/experimental.d.ts +18 -5
- package/lib/experimental.js +3 -0
- package/lib/instance.js +12 -3
- package/lib/keywords/additionalProperties.js +8 -22
- package/lib/keywords/allOf.js +1 -29
- package/lib/keywords/anyOf.js +1 -27
- package/lib/keywords/conditional.js +1 -27
- package/lib/keywords/contains.js +14 -18
- package/lib/keywords/dependentSchemas.js +1 -21
- package/lib/keywords/dynamicRef.js +19 -6
- package/lib/keywords/else.js +2 -19
- package/lib/keywords/if.js +1 -9
- package/lib/keywords/itemPattern.js +5 -9
- package/lib/keywords/items.js +5 -14
- package/lib/keywords/oneOf.js +1 -33
- package/lib/keywords/patternProperties.js +7 -25
- package/lib/keywords/prefixItems.js +2 -5
- package/lib/keywords/properties.js +6 -22
- package/lib/keywords/propertyDependencies.js +1 -20
- package/lib/keywords/propertyNames.js +1 -1
- package/lib/keywords/ref.js +1 -3
- package/lib/keywords/then.js +2 -19
- package/lib/keywords/unevaluatedItems.js +44 -20
- package/lib/keywords/unevaluatedProperties.js +40 -26
- package/lib/keywords/validation.js +31 -129
- package/lib/keywords.js +30 -30
- package/package.json +1 -1
|
@@ -18,36 +18,20 @@ const interpret = (properties, instance, context) => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
let isValid = true;
|
|
21
|
-
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
22
|
-
const propertyName = Instance.value(propertyNameNode);
|
|
23
|
-
if (propertyName in properties && !Validation.interpret(properties[propertyName], property, context)) {
|
|
24
|
-
isValid = false;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return isValid;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const simpleApplicator = true;
|
|
32
|
-
|
|
33
|
-
const collectEvaluatedProperties = (properties, instance, context) => {
|
|
34
|
-
if (Instance.typeOf(instance) !== "object") {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const evaluatedPropertyNames = new Set();
|
|
39
21
|
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
40
22
|
const propertyName = Instance.value(propertyNameNode);
|
|
41
23
|
if (propertyName in properties) {
|
|
42
24
|
if (!Validation.interpret(properties[propertyName], property, context)) {
|
|
43
|
-
|
|
25
|
+
isValid = false;
|
|
44
26
|
}
|
|
45
27
|
|
|
46
|
-
|
|
28
|
+
context.evaluatedProperties?.add(propertyName);
|
|
47
29
|
}
|
|
48
30
|
}
|
|
49
31
|
|
|
50
|
-
return
|
|
32
|
+
return isValid;
|
|
51
33
|
};
|
|
52
34
|
|
|
53
|
-
|
|
35
|
+
const simpleApplicator = true;
|
|
36
|
+
|
|
37
|
+
export default { id, compile, interpret, simpleApplicator };
|
|
@@ -43,23 +43,4 @@ const interpret = (propertyDependencies, instance, context) => {
|
|
|
43
43
|
|
|
44
44
|
const simpleApplicator = true;
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
const evaluatedPropertyNames = new Set();
|
|
48
|
-
for (const propertyName in propertyDependencies) {
|
|
49
|
-
const propertyValue = Instance.value(instance)[propertyName];
|
|
50
|
-
|
|
51
|
-
const valueMappings = propertyDependencies[propertyName];
|
|
52
|
-
if (Instance.has(propertyName, instance) && propertyValue in valueMappings) {
|
|
53
|
-
const propertyNames = Validation.collectEvaluatedProperties(valueMappings[propertyValue], instance, context);
|
|
54
|
-
if (!propertyNames) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
propertyNames.forEach(evaluatedPropertyNames.add, evaluatedPropertyNames);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return evaluatedPropertyNames;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties };
|
|
46
|
+
export default { id, compile, interpret, simpleApplicator };
|
|
@@ -13,7 +13,7 @@ const interpret = (propertyNames, instance, context) => {
|
|
|
13
13
|
|
|
14
14
|
let isValid = true;
|
|
15
15
|
for (const key of Instance.keys(instance)) {
|
|
16
|
-
if (!Validation.interpret(propertyNames, key,
|
|
16
|
+
if (!Validation.interpret(propertyNames, key, context)) {
|
|
17
17
|
isValid = false;
|
|
18
18
|
}
|
|
19
19
|
}
|
package/lib/keywords/ref.js
CHANGED
|
@@ -5,9 +5,7 @@ const id = "https://json-schema.org/keyword/ref";
|
|
|
5
5
|
|
|
6
6
|
const compile = (...args) => Validation.compile(...args);
|
|
7
7
|
const interpret = (...args) => Validation.interpret(...args);
|
|
8
|
-
const collectEvaluatedProperties = (...args) => Validation.collectEvaluatedProperties(...args);
|
|
9
|
-
const collectEvaluatedItems = (...args) => Validation.collectEvaluatedItems(...args);
|
|
10
8
|
|
|
11
9
|
const simpleApplicator = true;
|
|
12
10
|
|
|
13
|
-
export default { id, compile, interpret, simpleApplicator
|
|
11
|
+
export default { id, compile, interpret, simpleApplicator };
|
package/lib/keywords/then.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import { FLAG } from "../index.js";
|
|
3
2
|
import { getKeywordName, Validation } from "../experimental.js";
|
|
4
3
|
|
|
5
4
|
|
|
@@ -17,26 +16,10 @@ const compile = async (schema, ast, parentSchema) => {
|
|
|
17
16
|
|
|
18
17
|
const interpret = ([ifSchema, thenSchema], instance, context) => {
|
|
19
18
|
return ifSchema === undefined
|
|
20
|
-
|| !Validation.interpret(ifSchema, instance, { ...context,
|
|
19
|
+
|| !Validation.interpret(ifSchema, instance, { ...context, plugins: context.ast.plugins })
|
|
21
20
|
|| Validation.interpret(thenSchema, instance, context);
|
|
22
21
|
};
|
|
23
22
|
|
|
24
23
|
const simpleApplicator = true;
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
if (ifSchema === undefined || !Validation.interpret(ifSchema, instance, context)) {
|
|
28
|
-
return new Set();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return Validation.collectEvaluatedProperties(thenSchema, instance, context);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const collectEvaluatedItems = ([ifSchema, thenSchema], instance, context) => {
|
|
35
|
-
if (ifSchema === undefined || !Validation.interpret(ifSchema, instance, context)) {
|
|
36
|
-
return new Set();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return Validation.collectEvaluatedItems(thenSchema, instance, context);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties, collectEvaluatedItems };
|
|
25
|
+
export default { id, compile, interpret, simpleApplicator };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { zip, range } from "@hyperjump/pact";
|
|
2
|
-
import { FLAG } from "../index.js";
|
|
3
1
|
import { canonicalUri, Validation } from "../experimental.js";
|
|
4
2
|
import * as Instance from "../instance.js";
|
|
5
3
|
|
|
@@ -15,17 +13,33 @@ const interpret = ([schemaUrl, unevaluatedItems], instance, context) => {
|
|
|
15
13
|
return true;
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
if (context.rootSchema === schemaUrl) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Because order matters, we re-evaluate this schema skipping this keyword
|
|
21
|
+
// just to collect all the evalauted items.
|
|
22
|
+
const keywordContext = {
|
|
23
|
+
...context,
|
|
24
|
+
plugins: [...context.ast.plugins, unevaluatedPlugin],
|
|
25
|
+
rootSchema: schemaUrl
|
|
26
|
+
};
|
|
27
|
+
if (!Validation.interpret(schemaUrl, instance, keywordContext)) {
|
|
21
28
|
return true;
|
|
22
29
|
}
|
|
23
30
|
|
|
24
31
|
let isValid = true;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
let index = 0;
|
|
33
|
+
for (const item of Instance.iter(instance)) {
|
|
34
|
+
if (!keywordContext.evaluatedItems.has(index)) {
|
|
35
|
+
if (!Validation.interpret(unevaluatedItems, item, context)) {
|
|
36
|
+
isValid = false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
context.evaluatedItems?.add(index);
|
|
28
40
|
}
|
|
41
|
+
|
|
42
|
+
index++;
|
|
29
43
|
}
|
|
30
44
|
|
|
31
45
|
return isValid;
|
|
@@ -33,19 +47,29 @@ const interpret = ([schemaUrl, unevaluatedItems], instance, context) => {
|
|
|
33
47
|
|
|
34
48
|
const simpleApplicator = true;
|
|
35
49
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
const unevaluatedPlugin = {
|
|
51
|
+
beforeSchema(_url, _instance, context) {
|
|
52
|
+
context.evaluatedItems ??= new Set();
|
|
53
|
+
context.schemaEvaluatedItems ??= new Set();
|
|
54
|
+
},
|
|
55
|
+
beforeKeyword(_node, _instance, context, schemaContext) {
|
|
56
|
+
context.rootSchema = schemaContext.rootSchema;
|
|
57
|
+
context.evaluatedItems = new Set();
|
|
58
|
+
},
|
|
59
|
+
afterKeyword(_node, _instance, context, valid, schemaContext) {
|
|
60
|
+
if (valid) {
|
|
61
|
+
for (const index of context.evaluatedItems) {
|
|
62
|
+
schemaContext.schemaEvaluatedItems.add(index);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
afterSchema(_url, _instance, context, valid) {
|
|
67
|
+
if (valid) {
|
|
68
|
+
for (const index of context.schemaEvaluatedItems) {
|
|
69
|
+
context.evaluatedItems.add(index);
|
|
70
|
+
}
|
|
46
71
|
}
|
|
47
72
|
}
|
|
48
|
-
return evaluatedIndexes;
|
|
49
73
|
};
|
|
50
74
|
|
|
51
|
-
export default { id, compile, interpret, simpleApplicator
|
|
75
|
+
export default { id, compile, interpret, simpleApplicator };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { FLAG } from "../index.js";
|
|
2
1
|
import { Validation, canonicalUri } from "../experimental.js";
|
|
3
2
|
import * as Instance from "../instance.js";
|
|
4
3
|
|
|
@@ -14,18 +13,33 @@ const interpret = ([schemaUrl, unevaluatedProperties], instance, context) => {
|
|
|
14
13
|
return true;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
if (context.rootSchema === schemaUrl) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Because order matters, we re-evaluate this schema skipping this keyword
|
|
21
|
+
// just to collect all the evalauted properties.
|
|
22
|
+
const keywordContext = {
|
|
23
|
+
...context,
|
|
24
|
+
plugins: [...context.ast.plugins, unevaluatedPlugin],
|
|
25
|
+
rootSchema: schemaUrl
|
|
26
|
+
};
|
|
27
|
+
if (!Validation.interpret(schemaUrl, instance, keywordContext)) {
|
|
20
28
|
return true;
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
let isValid = true;
|
|
24
32
|
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
25
33
|
const propertyName = Instance.value(propertyNameNode);
|
|
26
|
-
if (
|
|
34
|
+
if (keywordContext.evaluatedProperties.has(propertyName)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!Validation.interpret(unevaluatedProperties, property, context)) {
|
|
27
39
|
isValid = false;
|
|
28
40
|
}
|
|
41
|
+
|
|
42
|
+
context.evaluatedProperties?.add(propertyName);
|
|
29
43
|
}
|
|
30
44
|
|
|
31
45
|
return isValid;
|
|
@@ -33,29 +47,29 @@ const interpret = ([schemaUrl, unevaluatedProperties], instance, context) => {
|
|
|
33
47
|
|
|
34
48
|
const simpleApplicator = true;
|
|
35
49
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const unevaluatedPlugin = {
|
|
51
|
+
beforeSchema(_url, _instance, context) {
|
|
52
|
+
context.evaluatedProperties ??= new Set();
|
|
53
|
+
context.schemaEvaluatedProperties ??= new Set();
|
|
54
|
+
},
|
|
55
|
+
beforeKeyword(_node, _instance, context, schemaContext) {
|
|
56
|
+
context.rootSchema = schemaContext.rootSchema;
|
|
57
|
+
context.evaluatedProperties = new Set();
|
|
58
|
+
},
|
|
59
|
+
afterKeyword(_node, _instance, context, valid, schemaContext) {
|
|
60
|
+
if (valid) {
|
|
61
|
+
for (const property of context.evaluatedProperties) {
|
|
62
|
+
schemaContext.schemaEvaluatedProperties.add(property);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
afterSchema(_url, _instance, context, valid) {
|
|
67
|
+
if (valid) {
|
|
68
|
+
for (const property of context.schemaEvaluatedProperties) {
|
|
69
|
+
context.evaluatedProperties.add(property);
|
|
52
70
|
}
|
|
53
|
-
|
|
54
|
-
evaluatedPropertyNames.add(propertyName);
|
|
55
71
|
}
|
|
56
72
|
}
|
|
57
|
-
|
|
58
|
-
return evaluatedPropertyNames;
|
|
59
73
|
};
|
|
60
74
|
|
|
61
|
-
export default { id, compile, interpret, simpleApplicator
|
|
75
|
+
export default { id, compile, interpret, simpleApplicator };
|
|
@@ -2,10 +2,7 @@ import { value, entries } from "@hyperjump/browser";
|
|
|
2
2
|
import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
|
|
3
3
|
import { append as pointerAppend } from "@hyperjump/json-pointer";
|
|
4
4
|
import { publishAsync } from "../pubsub.js";
|
|
5
|
-
import
|
|
6
|
-
import { toAbsoluteUri } from "../common.js";
|
|
7
|
-
import { canonicalUri, getKeyword, getKeywordByName, BASIC, DETAILED } from "../experimental.js";
|
|
8
|
-
import { FLAG } from "../index.js";
|
|
5
|
+
import { canonicalUri, getKeyword, getKeywordByName } from "../experimental.js";
|
|
9
6
|
|
|
10
7
|
|
|
11
8
|
const id = "https://json-schema.org/evaluation/validate";
|
|
@@ -35,6 +32,9 @@ const compile = async (schema, ast) => {
|
|
|
35
32
|
entries(schema),
|
|
36
33
|
asyncMap(async ([keyword, keywordSchema]) => {
|
|
37
34
|
const keywordHandler = getKeywordByName(keyword, schema.document.dialectId);
|
|
35
|
+
if (keywordHandler.plugin) {
|
|
36
|
+
ast.plugins.add(keywordHandler.plugin);
|
|
37
|
+
}
|
|
38
38
|
const keywordAst = await keywordHandler.compile(keywordSchema, ast, schema);
|
|
39
39
|
return [keywordHandler.id, pointerAppend(keyword, canonicalUri(schema)), keywordAst];
|
|
40
40
|
}),
|
|
@@ -45,140 +45,42 @@ const compile = async (schema, ast) => {
|
|
|
45
45
|
return url;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
-
const interpret = (url, instance,
|
|
49
|
-
|
|
48
|
+
const interpret = (url, instance, context) => {
|
|
49
|
+
let valid = true;
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
} else {
|
|
55
|
-
errors.push({
|
|
56
|
-
keyword: id,
|
|
57
|
-
absoluteKeywordLocation: url,
|
|
58
|
-
instanceLocation: Instance.uri(instance)
|
|
59
|
-
});
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
} else {
|
|
63
|
-
const schemaAnnotations = [];
|
|
51
|
+
for (const plugin of context.plugins) {
|
|
52
|
+
plugin.beforeSchema(url, instance, context);
|
|
53
|
+
}
|
|
64
54
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
55
|
+
if (typeof context.ast[url] === "boolean") {
|
|
56
|
+
valid = context.ast[url];
|
|
57
|
+
} else {
|
|
58
|
+
for (const node of context.ast[url]) {
|
|
59
|
+
const [keywordId, , keywordValue] = node;
|
|
60
|
+
const keyword = getKeyword(keywordId);
|
|
61
|
+
|
|
62
|
+
const keywordContext = {
|
|
63
|
+
ast: context.ast,
|
|
64
|
+
plugins: context.plugins
|
|
65
|
+
};
|
|
66
|
+
for (const plugin of context.plugins) {
|
|
67
|
+
plugin.beforeKeyword(node, instance, keywordContext, context, keyword);
|
|
68
|
+
}
|
|
69
|
+
const isKeywordValid = keyword.interpret(keywordValue, instance, keywordContext);
|
|
70
70
|
if (!isKeywordValid) {
|
|
71
|
-
|
|
71
|
+
valid = false;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
break;
|
|
77
|
-
case BASIC:
|
|
78
|
-
if (!isKeywordValid) {
|
|
79
|
-
if (!keywordHandler.simpleApplicator) {
|
|
80
|
-
errors.push({
|
|
81
|
-
keyword: keywordId,
|
|
82
|
-
absoluteKeywordLocation: schemaUri,
|
|
83
|
-
instanceLocation: Instance.uri(instance)
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
errors.push(...context.errors);
|
|
87
|
-
} else {
|
|
88
|
-
const annotation = keywordHandler.annotation?.(keywordValue, instance);
|
|
89
|
-
if (annotation !== undefined) {
|
|
90
|
-
schemaAnnotations.unshift({
|
|
91
|
-
keyword: keywordId,
|
|
92
|
-
absoluteKeywordLocation: schemaUri,
|
|
93
|
-
instanceLocation: Instance.uri(instance),
|
|
94
|
-
annotation: annotation
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
for (const contextAnnotation of context.annotations) {
|
|
98
|
-
schemaAnnotations.unshift(contextAnnotation);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
break;
|
|
102
|
-
case DETAILED: {
|
|
103
|
-
if (!isKeywordValid) {
|
|
104
|
-
const outputUnit = {
|
|
105
|
-
keyword: keywordId,
|
|
106
|
-
absoluteKeywordLocation: schemaUri,
|
|
107
|
-
instanceLocation: Instance.uri(instance)
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
errors.push(outputUnit);
|
|
111
|
-
if (context.errors.length > 0) {
|
|
112
|
-
outputUnit.errors = context.errors;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
default:
|
|
118
|
-
throw Error(`Unsupported output format '${outputFormat}'`);
|
|
74
|
+
for (const plugin of context.plugins) {
|
|
75
|
+
plugin.afterKeyword(node, instance, keywordContext, isKeywordValid, context, keyword);
|
|
119
76
|
}
|
|
120
77
|
}
|
|
121
|
-
|
|
122
|
-
if (outputFormat === BASIC && isSchemaValid) {
|
|
123
|
-
annotations.push(...schemaAnnotations);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return isSchemaValid;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const emptyPropertyNames = new Set();
|
|
131
|
-
const collectEvaluatedProperties = (url, instance, context, isTop = false) => {
|
|
132
|
-
if (typeof context.ast[url] === "boolean") {
|
|
133
|
-
return context.ast[url] ? emptyPropertyNames : false;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const accumulatedPropertyNames = new Set();
|
|
137
|
-
for (const [keywordId, , keywordValue] of context.ast[url]) {
|
|
138
|
-
if (isTop && keywordId === "https://json-schema.org/keyword/unevaluatedProperties") {
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const keywordHandler = getKeyword(keywordId);
|
|
143
|
-
const propertyNames = "collectEvaluatedProperties" in keywordHandler
|
|
144
|
-
? keywordHandler.collectEvaluatedProperties(keywordValue, instance, context, isTop)
|
|
145
|
-
: keywordHandler.interpret(keywordValue, instance, context) && emptyPropertyNames;
|
|
146
|
-
|
|
147
|
-
if (propertyNames === false) {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
propertyNames.forEach(accumulatedPropertyNames.add, accumulatedPropertyNames);
|
|
152
78
|
}
|
|
153
79
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const emptyItemIndexes = new Set();
|
|
158
|
-
const collectEvaluatedItems = (url, instance, context, isTop = false) => {
|
|
159
|
-
if (typeof context.ast[url] === "boolean") {
|
|
160
|
-
return context.ast[url] ? emptyItemIndexes : false;
|
|
80
|
+
for (const plugin of context.plugins) {
|
|
81
|
+
plugin.afterSchema(url, instance, context, valid);
|
|
161
82
|
}
|
|
162
|
-
|
|
163
|
-
const accumulatedItemIndexes = new Set();
|
|
164
|
-
for (const [keywordId, , keywordValue] of context.ast[url]) {
|
|
165
|
-
if (isTop && keywordId === "https://json-schema.org/keyword/unevaluatedItems") {
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const keywordHandler = getKeyword(keywordId);
|
|
170
|
-
const itemIndexes = "collectEvaluatedItems" in keywordHandler
|
|
171
|
-
? keywordHandler.collectEvaluatedItems(keywordValue, instance, context, isTop)
|
|
172
|
-
: keywordHandler.interpret(keywordValue, instance, context) && emptyItemIndexes;
|
|
173
|
-
|
|
174
|
-
if (itemIndexes === false) {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
itemIndexes.forEach(accumulatedItemIndexes.add, accumulatedItemIndexes);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return accumulatedItemIndexes;
|
|
83
|
+
return valid;
|
|
182
84
|
};
|
|
183
85
|
|
|
184
|
-
export default { id, compile, interpret
|
|
86
|
+
export default { id, compile, interpret };
|
package/lib/keywords.js
CHANGED
|
@@ -35,17 +35,19 @@ export const defineVocabulary = (id, keywords) => {
|
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
const _dialects = {};
|
|
38
|
-
const _allowUnknownKeywords = {};
|
|
39
|
-
const _persistentDialects = {};
|
|
40
38
|
|
|
41
|
-
export const getKeywordId = (keyword, dialectId) =>
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
export const getKeywordId = (keyword, dialectId) => {
|
|
40
|
+
const dialect = getDialect(dialectId);
|
|
41
|
+
return dialect.keywords[keyword]
|
|
42
|
+
?? ((dialect.allowUnknownKeywords || keyword.startsWith("x-"))
|
|
43
|
+
? `https://json-schema.org/keyword/unknown#${keyword}`
|
|
44
|
+
: undefined);
|
|
45
|
+
};
|
|
44
46
|
|
|
45
47
|
export const getKeywordName = (dialectId, keywordId) => {
|
|
46
48
|
const dialect = getDialect(dialectId);
|
|
47
|
-
for (const keyword in dialect) {
|
|
48
|
-
if (dialect[keyword] === keywordId) {
|
|
49
|
+
for (const keyword in dialect.keywords) {
|
|
50
|
+
if (dialect.keywords[keyword] === keywordId) {
|
|
49
51
|
return keyword;
|
|
50
52
|
}
|
|
51
53
|
}
|
|
@@ -62,33 +64,31 @@ const getDialect = (dialectId) => {
|
|
|
62
64
|
export const hasDialect = (dialectId) => dialectId in _dialects;
|
|
63
65
|
|
|
64
66
|
export const loadDialect = (dialectId, dialect, allowUnknownKeywords = false, isPersistent = true) => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} else if (!allowUnknownKeywords || isRequired) {
|
|
81
|
-
delete _dialects[dialectId];
|
|
82
|
-
delete _allowUnknownKeywords[dialectId];
|
|
83
|
-
delete _persistentDialects[dialectId];
|
|
84
|
-
throw Error(`Unrecognized vocabulary: ${vocabularyId}. You can define this vocabulary with the 'defineVocabulary' function.`);
|
|
67
|
+
_dialects[dialectId] = {
|
|
68
|
+
keywords: {},
|
|
69
|
+
allowUnknownKeywords: allowUnknownKeywords,
|
|
70
|
+
persistentDialects: _dialects[dialectId]?.persistentDialects || isPersistent
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
for (const vocabularyId in dialect) {
|
|
74
|
+
if (vocabularyId in _vocabularies) {
|
|
75
|
+
for (const keyword in _vocabularies[vocabularyId]) {
|
|
76
|
+
let keywordId = _vocabularies[vocabularyId][keyword];
|
|
77
|
+
if (!(keywordId in _keywords) && !dialect[vocabularyId]) {
|
|
78
|
+
// Allow keyword to be ignored
|
|
79
|
+
keywordId = `https://json-schema.org/keyword/unknown#${keyword}`;
|
|
80
|
+
}
|
|
81
|
+
_dialects[dialectId].keywords[keyword] = keywordId;
|
|
85
82
|
}
|
|
86
|
-
})
|
|
83
|
+
} else if (!allowUnknownKeywords || dialect[vocabularyId]) {
|
|
84
|
+
delete _dialects[dialectId];
|
|
85
|
+
throw Error(`Unrecognized vocabulary: ${vocabularyId}. You can define this vocabulary with the 'defineVocabulary' function.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
87
88
|
};
|
|
88
89
|
|
|
89
90
|
export const unloadDialect = (dialectId) => {
|
|
90
|
-
if (!
|
|
91
|
-
delete _allowUnknownKeywords[dialectId];
|
|
91
|
+
if (!_dialects[dialectId]?.persistentDialects) {
|
|
92
92
|
delete _dialects[dialectId];
|
|
93
93
|
}
|
|
94
94
|
};
|
package/package.json
CHANGED