@hyperjump/json-schema 1.13.0 → 1.14.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 +14 -20
- package/annotations/index.js +27 -7
- package/annotations/test-utils.d.ts +1 -0
- package/annotations/test-utils.js +38 -0
- package/bundle/index.js +39 -227
- package/draft-04/additionalItems.js +13 -19
- package/draft-04/dependencies.js +7 -7
- 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/contentSchema.js +6 -3
- 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
package/lib/core.js
CHANGED
|
@@ -11,6 +11,8 @@ import { InvalidSchemaError } from "./invalid-schema-error.js";
|
|
|
11
11
|
import { getSchema, registerSchema, unregisterSchema as schemaUnregister } from "./schema.js";
|
|
12
12
|
import { getKeywordName } from "./keywords.js";
|
|
13
13
|
import Validation from "./keywords/validation.js";
|
|
14
|
+
import { basicOutputPlugin } from "./evaluation-plugins/basic-output.js";
|
|
15
|
+
import { detailedOutputPlugin } from "./evaluation-plugins/detailed-output.js";
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
export const FLAG = "FLAG", BASIC = "BASIC", DETAILED = "DETAILED";
|
|
@@ -25,16 +27,29 @@ export const validate = async (url, value = undefined, outputFormat = undefined)
|
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
export const compile = async (schema) => {
|
|
28
|
-
const ast = { metaData: {} };
|
|
30
|
+
const ast = { metaData: {}, plugins: new Set() };
|
|
29
31
|
const schemaUri = await Validation.compile(schema, ast);
|
|
30
32
|
return { ast, schemaUri };
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
export const interpret = curry(({ ast, schemaUri }, instance, outputFormat = FLAG) => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
+
const context = { ast, plugins: [...ast.plugins] };
|
|
37
|
+
|
|
38
|
+
switch (outputFormat) {
|
|
39
|
+
case FLAG:
|
|
40
|
+
break;
|
|
41
|
+
case BASIC:
|
|
42
|
+
context.plugins.push(basicOutputPlugin);
|
|
43
|
+
break;
|
|
44
|
+
case DETAILED:
|
|
45
|
+
context.plugins.push(detailedOutputPlugin);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
throw Error(`Unsupported output format '${outputFormat}'`);
|
|
49
|
+
}
|
|
50
|
+
|
|
36
51
|
const valid = Validation.interpret(schemaUri, instance, context);
|
|
37
|
-
return
|
|
52
|
+
return !valid && "errors" in context ? { valid, errors: context.errors } : { valid };
|
|
38
53
|
});
|
|
39
54
|
|
|
40
55
|
const metaValidators = {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as Instance from "../instance.js";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const annotationsPlugin = {
|
|
5
|
+
beforeSchema(_url, _instance, context) {
|
|
6
|
+
context.annotations ??= [];
|
|
7
|
+
context.schemaAnnotations = [];
|
|
8
|
+
},
|
|
9
|
+
beforeKeyword(_node, _instance, context) {
|
|
10
|
+
context.annotations = [];
|
|
11
|
+
},
|
|
12
|
+
afterKeyword(node, instance, context, valid, schemaContext, keyword) {
|
|
13
|
+
if (valid) {
|
|
14
|
+
const [keywordId, schemaUri, keywordValue] = node;
|
|
15
|
+
const annotation = keyword.annotation?.(keywordValue, instance, context);
|
|
16
|
+
if (annotation !== undefined) {
|
|
17
|
+
schemaContext.schemaAnnotations.push({
|
|
18
|
+
keyword: keywordId,
|
|
19
|
+
absoluteKeywordLocation: schemaUri,
|
|
20
|
+
instanceLocation: Instance.uri(instance),
|
|
21
|
+
annotation: annotation
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
schemaContext.schemaAnnotations.push(...context.annotations);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
afterSchema(_schemaNode, _instanceNode, context, valid) {
|
|
28
|
+
if (valid) {
|
|
29
|
+
context.annotations.push(...context.schemaAnnotations);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Validation } from "../experimental.js";
|
|
2
|
+
import * as Instance from "../instance.js";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const basicOutputPlugin = {
|
|
6
|
+
beforeSchema(_url, _intance, context) {
|
|
7
|
+
context.errors ??= [];
|
|
8
|
+
},
|
|
9
|
+
beforeKeyword(_node, _instance, context) {
|
|
10
|
+
context.errors = [];
|
|
11
|
+
},
|
|
12
|
+
afterKeyword(node, instance, context, valid, schemaContext, keyword) {
|
|
13
|
+
if (!valid) {
|
|
14
|
+
if (!keyword.simpleApplicator) {
|
|
15
|
+
const [keywordId, schemaUri] = node;
|
|
16
|
+
schemaContext.errors.push({
|
|
17
|
+
keyword: keywordId,
|
|
18
|
+
absoluteKeywordLocation: schemaUri,
|
|
19
|
+
instanceLocation: Instance.uri(instance)
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
schemaContext.errors.push(...context.errors);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
afterSchema(url, instance, context, valid) {
|
|
26
|
+
if (typeof context.ast[url] === "boolean" && !valid) {
|
|
27
|
+
context.errors.push({
|
|
28
|
+
keyword: Validation.id,
|
|
29
|
+
absoluteKeywordLocation: url,
|
|
30
|
+
instanceLocation: Instance.uri(instance)
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Validation } from "../experimental.js";
|
|
2
|
+
import * as Instance from "../instance.js";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const detailedOutputPlugin = {
|
|
6
|
+
beforeSchema(_url, _instance, context) {
|
|
7
|
+
context.errors ??= [];
|
|
8
|
+
},
|
|
9
|
+
beforeKeyword(_node, _instance, context) {
|
|
10
|
+
context.errors = [];
|
|
11
|
+
},
|
|
12
|
+
afterKeyword(node, instance, context, valid, schemaContext) {
|
|
13
|
+
if (!valid) {
|
|
14
|
+
const [keywordId, schemaUri] = node;
|
|
15
|
+
const outputUnit = {
|
|
16
|
+
keyword: keywordId,
|
|
17
|
+
absoluteKeywordLocation: schemaUri,
|
|
18
|
+
instanceLocation: Instance.uri(instance)
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
schemaContext.errors.push(outputUnit);
|
|
22
|
+
if (context.errors.length > 0) {
|
|
23
|
+
outputUnit.errors = context.errors;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
afterSchema(url, instance, context, valid) {
|
|
28
|
+
if (typeof context.ast[url] === "boolean" && !valid) {
|
|
29
|
+
context.errors.push({
|
|
30
|
+
keyword: Validation.id,
|
|
31
|
+
absoluteKeywordLocation: url,
|
|
32
|
+
instanceLocation: Instance.uri(instance)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
package/lib/experimental.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type CompiledSchema = {
|
|
|
18
18
|
|
|
19
19
|
type AST = {
|
|
20
20
|
metaData: Record<string, MetaData>;
|
|
21
|
+
plugins: Set<EvaluationPlugin<unknown>>;
|
|
21
22
|
} & Record<string, Node<unknown>[] | boolean>;
|
|
22
23
|
|
|
23
24
|
type Node<A> = [keywordId: string, schemaUri: string, keywordValue: A];
|
|
@@ -70,18 +71,30 @@ export type Keyword<A> = {
|
|
|
70
71
|
compile: (schema: Browser<SchemaDocument>, ast: AST, parentSchema: Browser<SchemaDocument>) => Promise<A>;
|
|
71
72
|
interpret: (compiledKeywordValue: A, instance: JsonNode, context: ValidationContext) => boolean;
|
|
72
73
|
simpleApplicator: boolean;
|
|
73
|
-
collectEvaluatedProperties?: (compiledKeywordValue: A, instance: JsonNode, context: ValidationContext, isTop?: boolean) => Set<string> | false;
|
|
74
|
-
collectEvaluatedItems?: (compiledKeywordValue: A, instance: JsonNode, context: ValidationContext, isTop?: boolean) => Set<number> | false;
|
|
75
|
-
collectExternalIds?: (visited: Set<string>, parentSchema: Browser<SchemaDocument>, schema: Browser<SchemaDocument>) => Promise<Set<string>>;
|
|
76
74
|
annotation?: <B>(compiledKeywordValue: A, instance: JsonNode) => B | undefined;
|
|
77
75
|
};
|
|
78
76
|
|
|
79
77
|
export type ValidationContext = {
|
|
80
78
|
ast: AST;
|
|
81
|
-
|
|
79
|
+
plugins: EvaluationPlugin<unknown>[];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type EvaluationPlugin<Context> = {
|
|
83
|
+
beforeSchema(url: string, instance: JsonNode, context: Context): void;
|
|
84
|
+
beforeKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: Context, schemaContext: Context, keyword: Keyword): void;
|
|
85
|
+
afterKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: Context, valid: boolean, schemaContext: Context, keyword: Keyword): void;
|
|
86
|
+
afterSchema(url: string, instance: JsonNode, context: Context, valid: boolean): void;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const basicOutputPlugin: EvaluationPlugin<ErrorsContext>;
|
|
90
|
+
export const detailedOutputPlugin: EvaluationPlugin<ErrorsContext>;
|
|
91
|
+
export type ErrorsContext = {
|
|
82
92
|
errors: OutputUnit[];
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const annotationsPlugin: EvaluationPlugin<AnnotationsContext>;
|
|
96
|
+
export type AnnotationsContext = {
|
|
83
97
|
annotations: OutputUnit[];
|
|
84
|
-
outputFormat: OutputFormat;
|
|
85
98
|
};
|
|
86
99
|
|
|
87
100
|
export const Validation: Keyword<string>;
|
package/lib/experimental.js
CHANGED
|
@@ -6,3 +6,6 @@ export {
|
|
|
6
6
|
} from "./keywords.js";
|
|
7
7
|
export { getSchema, toSchema, canonicalUri, buildSchemaDocument } from "./schema.js";
|
|
8
8
|
export { default as Validation } from "./keywords/validation.js";
|
|
9
|
+
export { basicOutputPlugin } from "./evaluation-plugins/basic-output.js";
|
|
10
|
+
export { detailedOutputPlugin } from "./evaluation-plugins/detailed-output.js";
|
|
11
|
+
export { annotationsPlugin } from "./evaluation-plugins/annotations.js";
|
package/lib/instance.js
CHANGED
|
@@ -27,7 +27,8 @@ export const fromJs = (value, uri = "", pointer = "", parent = undefined) => {
|
|
|
27
27
|
objectNode.children = Object.entries(value).map((entry) => {
|
|
28
28
|
const propertyPointer = JsonPointer.append(entry[0], pointer);
|
|
29
29
|
const propertyNode = cons(uri, propertyPointer, undefined, "property", [], objectNode);
|
|
30
|
-
propertyNode.children =
|
|
30
|
+
propertyNode.children[0] = fromJs(entry[0], uri, "*" + propertyPointer, propertyNode);
|
|
31
|
+
propertyNode.children[1] = fromJs(entry[1], uri, propertyPointer, propertyNode);
|
|
31
32
|
return propertyNode;
|
|
32
33
|
});
|
|
33
34
|
return objectNode;
|
|
@@ -62,11 +63,19 @@ export const get = (uri, instance) => {
|
|
|
62
63
|
throw Error(`Reference '${uri}' is not local to '${instance.baseUri}'`);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
let isPropertyNamePointer = false;
|
|
67
|
+
let pointer = uriFragment(uri);
|
|
68
|
+
if (pointer.startsWith("*")) {
|
|
69
|
+
pointer = pointer.slice(1);
|
|
70
|
+
isPropertyNamePointer = true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const result = reduce((node, segment) => {
|
|
67
74
|
segment = segment === "-" && typeOf(node) === "array" ? length(node) : segment;
|
|
68
75
|
return step(segment, node);
|
|
69
76
|
}, instance.root, JsonPointer.pointerSegments(pointer));
|
|
77
|
+
|
|
78
|
+
return isPropertyNamePointer ? result.parent.children[0] : result;
|
|
70
79
|
};
|
|
71
80
|
|
|
72
81
|
export const uri = (node) => `${node.baseUri}#${encodeURI(node.pointer)}`;
|
|
@@ -39,9 +39,15 @@ const interpret = ([isDefinedProperty, additionalProperties], instance, context)
|
|
|
39
39
|
let isValid = true;
|
|
40
40
|
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
41
41
|
const propertyName = Instance.value(propertyNameNode);
|
|
42
|
-
if (
|
|
42
|
+
if (isDefinedProperty.test(propertyName)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!Validation.interpret(additionalProperties, property, context)) {
|
|
43
47
|
isValid = false;
|
|
44
48
|
}
|
|
49
|
+
|
|
50
|
+
context.evaluatedProperties?.add(propertyName);
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
return isValid;
|
|
@@ -49,24 +55,4 @@ const interpret = ([isDefinedProperty, additionalProperties], instance, context)
|
|
|
49
55
|
|
|
50
56
|
const simpleApplicator = true;
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
if (Instance.typeOf(instance) !== "object") {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const evaluatedPropertyNames = new Set();
|
|
58
|
-
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
59
|
-
const propertyName = Instance.value(propertyNameNode);
|
|
60
|
-
if (!isDefinedProperty.test(propertyName)) {
|
|
61
|
-
if (!Validation.interpret(additionalProperties, property, context)) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
evaluatedPropertyNames.add(propertyName);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return evaluatedPropertyNames;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties };
|
|
58
|
+
export default { id, compile, interpret, simpleApplicator };
|
package/lib/keywords/allOf.js
CHANGED
|
@@ -23,32 +23,4 @@ const interpret = (allOf, instance, ast, dynamicAnchors, quiet) => {
|
|
|
23
23
|
|
|
24
24
|
const simpleApplicator = true;
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const evaluatedPropertyNames = new Set();
|
|
28
|
-
for (const schemaUrl of allOf) {
|
|
29
|
-
const propertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, context);
|
|
30
|
-
if (!propertyNames) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
propertyNames.forEach(evaluatedPropertyNames.add, evaluatedPropertyNames);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return evaluatedPropertyNames;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const collectEvaluatedItems = (allOf, instance, context) => {
|
|
41
|
-
const evaluatedItemIndexes = new Set();
|
|
42
|
-
for (const schemaUrl of allOf) {
|
|
43
|
-
const itemIndexes = Validation.collectEvaluatedItems(schemaUrl, instance, context);
|
|
44
|
-
if (!itemIndexes) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
itemIndexes.forEach(evaluatedItemIndexes.add, evaluatedItemIndexes);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return evaluatedItemIndexes;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties, collectEvaluatedItems };
|
|
26
|
+
export default { id, compile, interpret, simpleApplicator };
|
package/lib/keywords/anyOf.js
CHANGED
|
@@ -16,30 +16,4 @@ const interpret = (anyOf, instance, ast, dynamicAnchors, quiet) => {
|
|
|
16
16
|
return matches.length > 0;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
let evaluatedPropertyNames = false;
|
|
21
|
-
for (const schemaUrl of anyOf) {
|
|
22
|
-
const propertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, context);
|
|
23
|
-
if (propertyNames) {
|
|
24
|
-
evaluatedPropertyNames ||= new Set();
|
|
25
|
-
propertyNames.forEach(evaluatedPropertyNames.add, evaluatedPropertyNames);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return evaluatedPropertyNames;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const collectEvaluatedItems = (anyOf, instance, context) => {
|
|
33
|
-
let evaluatedItemIndexes = false;
|
|
34
|
-
for (const schemaUrl of anyOf) {
|
|
35
|
-
const itemIndexes = Validation.collectEvaluatedItems(schemaUrl, instance, context);
|
|
36
|
-
if (itemIndexes) {
|
|
37
|
-
evaluatedItemIndexes ||= new Set();
|
|
38
|
-
itemIndexes.forEach(evaluatedItemIndexes.add, evaluatedItemIndexes);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return evaluatedItemIndexes;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export default { id, compile, interpret, collectEvaluatedProperties, collectEvaluatedItems };
|
|
19
|
+
export default { id, compile, interpret };
|
|
@@ -25,32 +25,6 @@ const interpret = (conditional, instance, context) => {
|
|
|
25
25
|
return true;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const collectEvaluatedProperties = (conditional, instance, context) => {
|
|
29
|
-
for (let index = 0; index < conditional.length; index += 2) {
|
|
30
|
-
const unevaluatedProperties = Validation.collectEvaluatedProperties(conditional[index], instance, context);
|
|
31
|
-
if (index + 1 === conditional.length) {
|
|
32
|
-
return unevaluatedProperties;
|
|
33
|
-
} else if (unevaluatedProperties !== false) {
|
|
34
|
-
return Validation.collectEvaluatedProperties(conditional[index + 1], instance, context);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return new Set();
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
const collectEvaluatedItems = (conditional, instance, context) => {
|
|
42
|
-
for (let index = 0; index < conditional.length; index += 2) {
|
|
43
|
-
const unevaluatedItems = Validation.collectEvaluatedItems(conditional[index], instance, context);
|
|
44
|
-
if (index + 1 === conditional.length) {
|
|
45
|
-
return unevaluatedItems;
|
|
46
|
-
} else if (unevaluatedItems !== false) {
|
|
47
|
-
return Validation.collectEvaluatedItems(conditional[index + 1], instance, context);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return new Set();
|
|
52
|
-
};
|
|
53
|
-
|
|
54
28
|
const schemaFlatten = async function* (iter, depth = 1) {
|
|
55
29
|
for await (const n of iter) {
|
|
56
30
|
if (depth > 0 && Browser.typeOf(n) === "array") {
|
|
@@ -61,4 +35,4 @@ const schemaFlatten = async function* (iter, depth = 1) {
|
|
|
61
35
|
}
|
|
62
36
|
};
|
|
63
37
|
|
|
64
|
-
export default { id, compile, interpret
|
|
38
|
+
export default { id, compile, interpret };
|
package/lib/keywords/contains.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { pipe, filter, reduce, zip, range, map, collectSet } from "@hyperjump/pact";
|
|
2
1
|
import * as Browser from "@hyperjump/browser";
|
|
3
2
|
import * as Instance from "../instance.js";
|
|
4
3
|
import { getKeywordName, Validation } from "../experimental.js";
|
|
@@ -21,23 +20,20 @@ const compile = async (schema, ast, parentSchema) => {
|
|
|
21
20
|
};
|
|
22
21
|
|
|
23
22
|
const interpret = ({ contains, minContains, maxContains }, instance, context) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
if (Instance.typeOf(instance) !== "array") {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let matches = 0;
|
|
28
|
+
let index = 0;
|
|
29
|
+
for (const item of Instance.iter(instance)) {
|
|
30
|
+
if (Validation.interpret(contains, item, context)) {
|
|
31
|
+
matches++;
|
|
32
|
+
context.evaluatedItems?.add(index);
|
|
33
|
+
}
|
|
34
|
+
index++;
|
|
35
|
+
}
|
|
29
36
|
return matches >= minContains && matches <= maxContains;
|
|
30
37
|
};
|
|
31
38
|
|
|
32
|
-
|
|
33
|
-
return interpret(keywordValue, instance, context)
|
|
34
|
-
&& Instance.typeOf(instance) === "array"
|
|
35
|
-
&& pipe(
|
|
36
|
-
zip(Instance.iter(instance), range(0)),
|
|
37
|
-
filter(([item]) => Validation.interpret(keywordValue.contains, item, context)),
|
|
38
|
-
map(([, itemIndex]) => itemIndex),
|
|
39
|
-
collectSet
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export default { id, compile, interpret, collectEvaluatedItems };
|
|
39
|
+
export default { id, compile, interpret };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { canonicalUri } from "../schema.js";
|
|
2
1
|
import * as Browser from "@hyperjump/browser";
|
|
3
2
|
import * as Instance from "../instance.js";
|
|
4
3
|
import { getKeywordName } from "../keywords.js";
|
|
@@ -9,13 +8,17 @@ const id = "https://json-schema.org/keyword/contentSchema";
|
|
|
9
8
|
const compile = async (contentSchema, _ast, parentSchema) => {
|
|
10
9
|
const contentMediaTypeKeyword = getKeywordName(contentSchema.document.dialectId, "https://json-schema.org/keyword/contentMediaType");
|
|
11
10
|
const contentMediaType = await Browser.step(contentMediaTypeKeyword, parentSchema);
|
|
12
|
-
|
|
11
|
+
if (Browser.value(contentMediaType) === undefined) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return Browser.value(contentSchema);
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
const interpret = () => true;
|
|
16
19
|
|
|
17
20
|
const annotation = (contentSchema, instance) => {
|
|
18
|
-
if (Instance.typeOf(instance) !== "string") {
|
|
21
|
+
if (!contentSchema || Instance.typeOf(instance) !== "string") {
|
|
19
22
|
return;
|
|
20
23
|
}
|
|
21
24
|
|
|
@@ -29,24 +29,4 @@ const interpret = (dependentSchemas, instance, context) => {
|
|
|
29
29
|
|
|
30
30
|
const simpleApplicator = true;
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
if (Instance.typeOf(instance) !== "object") {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const evaluatedPropertyNames = new Set();
|
|
38
|
-
for (const [propertyName, dependentSchema] of dependentSchemas) {
|
|
39
|
-
if (Instance.has(propertyName, instance)) {
|
|
40
|
-
const propertyNames = Validation.collectEvaluatedProperties(dependentSchema, instance, context);
|
|
41
|
-
if (propertyNames === false) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
propertyNames.forEach(Set.prototype.add.bind(evaluatedPropertyNames));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return evaluatedPropertyNames;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties };
|
|
32
|
+
export default { id, compile, interpret, simpleApplicator };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
2
|
import { Validation } from "../experimental.js";
|
|
3
|
+
import { toAbsoluteUri } from "../common.js";
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
const id = "https://json-schema.org/keyword/dynamicRef";
|
|
@@ -12,17 +13,29 @@ const compile = async (schema, ast) => {
|
|
|
12
13
|
return reference;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
|
-
const
|
|
16
|
+
const interpret = (fragment, instance, context) => {
|
|
16
17
|
if (!(fragment in context.dynamicAnchors)) {
|
|
17
18
|
throw Error(`No dynamic anchor found for "${fragment}"`);
|
|
18
19
|
}
|
|
19
|
-
return
|
|
20
|
+
return Validation.interpret(context.dynamicAnchors[fragment], instance, context);
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const simpleApplicator = true;
|
|
23
24
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const plugin = {
|
|
26
|
+
beforeSchema(url, _instance, context) {
|
|
27
|
+
context.dynamicAnchors = {
|
|
28
|
+
...context.ast.metaData[toAbsoluteUri(url)].dynamicAnchors,
|
|
29
|
+
...context.dynamicAnchors
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
beforeKeyword(_url, _instance, context, schemaContext) {
|
|
33
|
+
context.dynamicAnchors = schemaContext.dynamicAnchors;
|
|
34
|
+
},
|
|
35
|
+
afterKeyword() {
|
|
36
|
+
},
|
|
37
|
+
afterSchema() {
|
|
38
|
+
}
|
|
39
|
+
};
|
|
27
40
|
|
|
28
|
-
export default { id, compile, interpret, simpleApplicator,
|
|
41
|
+
export default { id, compile, interpret, simpleApplicator, plugin };
|
package/lib/keywords/else.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, elseSchema], 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(elseSchema, 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(elseSchema, instance, context);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const collectEvaluatedItems = ([ifSchema, elseSchema], instance, context) => {
|
|
35
|
-
if (ifSchema === undefined || Validation.interpret(ifSchema, instance, context)) {
|
|
36
|
-
return new Set();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return Validation.collectEvaluatedItems(elseSchema, instance, context);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties, collectEvaluatedItems };
|
|
25
|
+
export default { id, compile, interpret, simpleApplicator };
|
package/lib/keywords/if.js
CHANGED
|
@@ -10,12 +10,4 @@ const interpret = (ifSchema, instance, context) => {
|
|
|
10
10
|
return true;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
return Validation.collectEvaluatedProperties(ifSchema, instance, context) || new Set();
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const collectEvaluatedItems = (ifSchema, instance, context) => {
|
|
18
|
-
return Validation.collectEvaluatedItems(ifSchema, instance, context) || new Set();
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default { id, compile, interpret, collectEvaluatedProperties, collectEvaluatedItems };
|
|
13
|
+
export default { id, compile, interpret };
|
|
@@ -39,7 +39,7 @@ const compile = async (schema, ast) => {
|
|
|
39
39
|
.reduce(union);
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
const
|
|
42
|
+
const interpret = (nfa, instance, context) => {
|
|
43
43
|
if (Instance.typeOf(instance) !== "array") {
|
|
44
44
|
return true;
|
|
45
45
|
}
|
|
@@ -51,7 +51,7 @@ const evaluate = (strategy, nfa, instance, context) => {
|
|
|
51
51
|
const nextStates = [];
|
|
52
52
|
|
|
53
53
|
for (const state of currentStates) {
|
|
54
|
-
const nextState = transition(
|
|
54
|
+
const nextState = transition(state.transition, item, context);
|
|
55
55
|
if (nextState) {
|
|
56
56
|
addNextState(nextState, nextStates, []);
|
|
57
57
|
}
|
|
@@ -76,16 +76,12 @@ const addNextState = (state, nextStates, visited) => {
|
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
-
const transition = (
|
|
79
|
+
const transition = (transitions, instance, context) => {
|
|
80
80
|
for (const schema in transitions) {
|
|
81
|
-
if (
|
|
81
|
+
if (Validation.interpret(schema, instance, context)) {
|
|
82
82
|
return transitions[schema];
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
const collectEvalatedProperties = (...args) => evaluate(Validation.collectEvaluatedProperties, ...args);
|
|
89
|
-
const collectEvalatedItems = (...args) => evaluate(Validation.collectEvaluatedItems, ...args);
|
|
90
|
-
|
|
91
|
-
export default { id, compile, interpret, collectEvalatedProperties, collectEvalatedItems };
|
|
87
|
+
export default { id, compile, interpret };
|
package/lib/keywords/items.js
CHANGED
|
@@ -20,10 +20,14 @@ const interpret = ([numberOfPrefixItems, items], instance, context) => {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
let isValid = true;
|
|
23
|
+
let index = numberOfPrefixItems;
|
|
23
24
|
for (const item of drop(numberOfPrefixItems, Instance.iter(instance))) {
|
|
24
25
|
if (!Validation.interpret(items, item, context)) {
|
|
25
26
|
isValid = false;
|
|
26
27
|
}
|
|
28
|
+
|
|
29
|
+
context.evaluatedItems?.add(index);
|
|
30
|
+
index++;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
return isValid;
|
|
@@ -31,17 +35,4 @@ const interpret = ([numberOfPrefixItems, items], instance, context) => {
|
|
|
31
35
|
|
|
32
36
|
const simpleApplicator = true;
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
if (!interpret(keywordValue, instance, context)) {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const evaluatedIndexes = new Set();
|
|
40
|
-
for (let ndx = keywordValue[0]; ndx < Instance.length(instance); ndx++) {
|
|
41
|
-
evaluatedIndexes.add(ndx);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return evaluatedIndexes;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export default { id, compile, interpret, simpleApplicator, collectEvaluatedItems };
|
|
38
|
+
export default { id, compile, interpret, simpleApplicator };
|