@hyperjump/json-schema 1.11.0 → 1.12.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 +24 -7
- package/annotations/annotated-instance.d.ts +0 -1
- package/annotations/annotated-instance.js +0 -7
- package/annotations/index.js +19 -3
- package/draft-04/additionalItems.js +4 -4
- package/draft-04/dependencies.js +2 -2
- package/draft-04/items.js +5 -5
- package/draft-06/contains.js +3 -2
- package/draft-2020-12/dynamicRef.js +5 -5
- package/lib/core.js +5 -4
- package/lib/experimental.d.ts +12 -3
- package/lib/experimental.js +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/instance.d.ts +0 -2
- package/lib/instance.js +0 -2
- package/lib/keywords/additionalProperties.js +7 -5
- package/lib/keywords/allOf.js +7 -5
- package/lib/keywords/anyOf.js +4 -4
- package/lib/keywords/conditional.js +9 -9
- package/lib/keywords/contains.js +5 -5
- package/lib/keywords/contentEncoding.js +3 -7
- package/lib/keywords/contentMediaType.js +3 -7
- package/lib/keywords/contentSchema.js +3 -7
- package/lib/keywords/default.js +3 -7
- package/lib/keywords/dependentSchemas.js +7 -5
- package/lib/keywords/deprecated.js +3 -7
- package/lib/keywords/description.js +3 -7
- package/lib/keywords/dynamicRef.js +6 -4
- package/lib/keywords/else.js +13 -10
- package/lib/keywords/examples.js +3 -7
- package/lib/keywords/format.js +3 -7
- package/lib/keywords/if.js +6 -6
- package/lib/keywords/itemPattern.js +7 -7
- package/lib/keywords/items.js +7 -5
- package/lib/keywords/oneOf.js +6 -6
- package/lib/keywords/patternProperties.js +7 -5
- package/lib/keywords/prefixItems.js +7 -5
- package/lib/keywords/properties.js +7 -5
- package/lib/keywords/propertyDependencies.js +7 -5
- package/lib/keywords/propertyNames.js +5 -3
- package/lib/keywords/readOnly.js +3 -7
- package/lib/keywords/ref.js +3 -1
- package/lib/keywords/then.js +14 -12
- package/lib/keywords/title.js +3 -7
- package/lib/keywords/unevaluatedItems.js +11 -8
- package/lib/keywords/unevaluatedProperties.js +11 -7
- package/lib/keywords/unknown.js +3 -7
- package/lib/keywords/validation.js +83 -28
- package/lib/keywords/writeOnly.js +3 -7
- package/openapi-3-0/discriminator.js +3 -7
- package/openapi-3-0/example.js +3 -7
- package/openapi-3-0/externalDocs.js +3 -7
- package/openapi-3-0/index.d.ts +1 -1
- package/openapi-3-0/xml.js +3 -7
- package/package.json +1 -1
- package/lib/output.js +0 -41
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FLAG } from "../index.js";
|
|
1
2
|
import { Validation, canonicalUri } from "../experimental.js";
|
|
2
3
|
import * as Instance from "../instance.js";
|
|
3
4
|
|
|
@@ -8,12 +9,13 @@ const compile = async (schema, ast, parentSchema) => {
|
|
|
8
9
|
return [canonicalUri(parentSchema), await Validation.compile(schema, ast)];
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
const interpret = ([schemaUrl, unevaluatedProperties], instance,
|
|
12
|
+
const interpret = ([schemaUrl, unevaluatedProperties], instance, context) => {
|
|
12
13
|
if (Instance.typeOf(instance) !== "object") {
|
|
13
14
|
return true;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const keywordContext = { ...context, errors: [], annotations: [], outputFormat: FLAG };
|
|
18
|
+
const evaluatedPropertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, keywordContext, true);
|
|
17
19
|
if (evaluatedPropertyNames === false) {
|
|
18
20
|
return true;
|
|
19
21
|
}
|
|
@@ -21,7 +23,7 @@ const interpret = ([schemaUrl, unevaluatedProperties], instance, ast, dynamicAnc
|
|
|
21
23
|
let isValid = true;
|
|
22
24
|
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
23
25
|
const propertyName = Instance.value(propertyNameNode);
|
|
24
|
-
if (!evaluatedPropertyNames.has(propertyName) && !Validation.interpret(unevaluatedProperties, property,
|
|
26
|
+
if (!evaluatedPropertyNames.has(propertyName) && !Validation.interpret(unevaluatedProperties, property, context)) {
|
|
25
27
|
isValid = false;
|
|
26
28
|
}
|
|
27
29
|
}
|
|
@@ -29,12 +31,14 @@ const interpret = ([schemaUrl, unevaluatedProperties], instance, ast, dynamicAnc
|
|
|
29
31
|
return isValid;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
|
-
const
|
|
34
|
+
const simpleApplicator = true;
|
|
35
|
+
|
|
36
|
+
const collectEvaluatedProperties = ([schemaUrl, unevaluatedProperties], instance, context) => {
|
|
33
37
|
if (Instance.typeOf(instance) !== "object") {
|
|
34
38
|
return true;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
const evaluatedPropertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance,
|
|
41
|
+
const evaluatedPropertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, context, true);
|
|
38
42
|
|
|
39
43
|
if (!evaluatedPropertyNames) {
|
|
40
44
|
return false;
|
|
@@ -43,7 +47,7 @@ const collectEvaluatedProperties = ([schemaUrl, unevaluatedProperties], instance
|
|
|
43
47
|
for (const [propertyNameNode, property] of Instance.entries(instance)) {
|
|
44
48
|
const propertyName = Instance.value(propertyNameNode);
|
|
45
49
|
if (!evaluatedPropertyNames.has(propertyName)) {
|
|
46
|
-
if (!Validation.interpret(unevaluatedProperties, property,
|
|
50
|
+
if (!Validation.interpret(unevaluatedProperties, property, context)) {
|
|
47
51
|
return false;
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -54,4 +58,4 @@ const collectEvaluatedProperties = ([schemaUrl, unevaluatedProperties], instance
|
|
|
54
58
|
return evaluatedPropertyNames;
|
|
55
59
|
};
|
|
56
60
|
|
|
57
|
-
export default { id, compile, interpret, collectEvaluatedProperties };
|
|
61
|
+
export default { id, compile, interpret, simpleApplicator, collectEvaluatedProperties };
|
package/lib/keywords/unknown.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import * as Instance from "../../annotations/annotated-instance.js";
|
|
3
2
|
import { pointerSegments } from "@hyperjump/json-pointer";
|
|
4
3
|
|
|
5
4
|
|
|
@@ -10,10 +9,7 @@ const compile = (schema) => {
|
|
|
10
9
|
return [keywordName, Browser.value(schema)];
|
|
11
10
|
};
|
|
12
11
|
|
|
13
|
-
const interpret = (
|
|
14
|
-
|
|
15
|
-
Instance.setAnnotation(instance, keywordId, schemaLocation, value);
|
|
16
|
-
return true;
|
|
17
|
-
};
|
|
12
|
+
const interpret = () => true;
|
|
13
|
+
const annotation = ([, value]) => value;
|
|
18
14
|
|
|
19
|
-
export default { id, compile, interpret };
|
|
15
|
+
export default { id, compile, interpret, annotation };
|
|
@@ -2,8 +2,10 @@ 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 * as Instance from "../instance.js";
|
|
5
6
|
import { toAbsoluteUri } from "../common.js";
|
|
6
|
-
import { canonicalUri, getKeyword, getKeywordByName } from "../experimental.js";
|
|
7
|
+
import { canonicalUri, getKeyword, getKeywordByName, BASIC, DETAILED } from "../experimental.js";
|
|
8
|
+
import { FLAG } from "../index.js";
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
const id = "https://json-schema.org/evaluation/validate";
|
|
@@ -43,48 +45,101 @@ const compile = async (schema, ast) => {
|
|
|
43
45
|
return url;
|
|
44
46
|
};
|
|
45
47
|
|
|
46
|
-
const interpret = (url, instance, ast, dynamicAnchors,
|
|
48
|
+
const interpret = (url, instance, { ast, dynamicAnchors, errors, annotations, outputFormat }) => {
|
|
47
49
|
dynamicAnchors = { ...ast.metaData[toAbsoluteUri(url)].dynamicAnchors, ...dynamicAnchors };
|
|
48
50
|
|
|
49
|
-
let isSchemaValid = true;
|
|
50
51
|
if (typeof ast[url] === "boolean") {
|
|
51
|
-
|
|
52
|
+
if (ast[url]) {
|
|
53
|
+
return true;
|
|
54
|
+
} else {
|
|
55
|
+
errors.push({
|
|
56
|
+
keyword: id,
|
|
57
|
+
absoluteKeywordLocation: url,
|
|
58
|
+
instanceLocation: Instance.uri(instance)
|
|
59
|
+
});
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
52
62
|
} else {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
const schemaAnnotations = [];
|
|
64
|
+
|
|
65
|
+
let isSchemaValid = true;
|
|
66
|
+
for (const [keywordId, schemaUri, keywordValue] of ast[url]) {
|
|
67
|
+
const context = { ast, dynamicAnchors, errors: [], annotations: [], outputFormat };
|
|
68
|
+
const keywordHandler = getKeyword(keywordId);
|
|
69
|
+
const isKeywordValid = keywordHandler.interpret(keywordValue, instance, context);
|
|
70
|
+
if (!isKeywordValid) {
|
|
59
71
|
isSchemaValid = false;
|
|
60
72
|
}
|
|
73
|
+
|
|
74
|
+
switch (outputFormat) {
|
|
75
|
+
case FLAG:
|
|
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
|
+
if (keywordHandler.annotation) {
|
|
89
|
+
schemaAnnotations.push({
|
|
90
|
+
keyword: keywordId,
|
|
91
|
+
absoluteKeywordLocation: schemaUri,
|
|
92
|
+
instanceLocation: Instance.uri(instance),
|
|
93
|
+
annotation: keywordHandler.annotation(keywordValue)
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
schemaAnnotations.push(...context.annotations);
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
case DETAILED: {
|
|
100
|
+
if (!isKeywordValid) {
|
|
101
|
+
const outputUnit = {
|
|
102
|
+
keyword: keywordId,
|
|
103
|
+
absoluteKeywordLocation: schemaUri,
|
|
104
|
+
instanceLocation: Instance.uri(instance)
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
errors.push(outputUnit);
|
|
108
|
+
if (context.errors.length > 0) {
|
|
109
|
+
outputUnit.errors = context.errors;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
default:
|
|
115
|
+
throw Error(`Unsupported output format '${outputFormat}'`);
|
|
116
|
+
}
|
|
61
117
|
}
|
|
62
|
-
}
|
|
63
118
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
119
|
+
if (outputFormat === BASIC && isSchemaValid) {
|
|
120
|
+
annotations.push(...schemaAnnotations);
|
|
121
|
+
}
|
|
67
122
|
|
|
68
|
-
|
|
69
|
-
|
|
123
|
+
return isSchemaValid;
|
|
124
|
+
}
|
|
70
125
|
};
|
|
71
126
|
|
|
72
127
|
const emptyPropertyNames = new Set();
|
|
73
|
-
const collectEvaluatedProperties = (url, instance,
|
|
74
|
-
if (typeof ast[url] === "boolean") {
|
|
75
|
-
return ast[url] ?
|
|
128
|
+
const collectEvaluatedProperties = (url, instance, context, isTop = false) => {
|
|
129
|
+
if (typeof context.ast[url] === "boolean") {
|
|
130
|
+
return context.ast[url] ? emptyPropertyNames : false;
|
|
76
131
|
}
|
|
77
132
|
|
|
78
133
|
const accumulatedPropertyNames = new Set();
|
|
79
|
-
for (const [keywordId, , keywordValue] of ast[url]) {
|
|
134
|
+
for (const [keywordId, , keywordValue] of context.ast[url]) {
|
|
80
135
|
if (isTop && keywordId === "https://json-schema.org/keyword/unevaluatedProperties") {
|
|
81
136
|
continue;
|
|
82
137
|
}
|
|
83
138
|
|
|
84
139
|
const keywordHandler = getKeyword(keywordId);
|
|
85
140
|
const propertyNames = "collectEvaluatedProperties" in keywordHandler
|
|
86
|
-
? keywordHandler.collectEvaluatedProperties(keywordValue, instance,
|
|
87
|
-
: keywordHandler.interpret(keywordValue, instance,
|
|
141
|
+
? keywordHandler.collectEvaluatedProperties(keywordValue, instance, context, isTop)
|
|
142
|
+
: keywordHandler.interpret(keywordValue, instance, context) && emptyPropertyNames;
|
|
88
143
|
|
|
89
144
|
if (propertyNames === false) {
|
|
90
145
|
return false;
|
|
@@ -97,21 +152,21 @@ const collectEvaluatedProperties = (url, instance, ast, dynamicAnchors, isTop =
|
|
|
97
152
|
};
|
|
98
153
|
|
|
99
154
|
const emptyItemIndexes = new Set();
|
|
100
|
-
const collectEvaluatedItems = (url, instance,
|
|
101
|
-
if (typeof ast[url] === "boolean") {
|
|
102
|
-
return ast[url] ?
|
|
155
|
+
const collectEvaluatedItems = (url, instance, context, isTop = false) => {
|
|
156
|
+
if (typeof context.ast[url] === "boolean") {
|
|
157
|
+
return context.ast[url] ? emptyItemIndexes : false;
|
|
103
158
|
}
|
|
104
159
|
|
|
105
160
|
const accumulatedItemIndexes = new Set();
|
|
106
|
-
for (const [keywordId, , keywordValue] of ast[url]) {
|
|
161
|
+
for (const [keywordId, , keywordValue] of context.ast[url]) {
|
|
107
162
|
if (isTop && keywordId === "https://json-schema.org/keyword/unevaluatedItems") {
|
|
108
163
|
continue;
|
|
109
164
|
}
|
|
110
165
|
|
|
111
166
|
const keywordHandler = getKeyword(keywordId);
|
|
112
167
|
const itemIndexes = "collectEvaluatedItems" in keywordHandler
|
|
113
|
-
? keywordHandler.collectEvaluatedItems(keywordValue, instance,
|
|
114
|
-
: keywordHandler.interpret(keywordValue, instance,
|
|
168
|
+
? keywordHandler.collectEvaluatedItems(keywordValue, instance, context, isTop)
|
|
169
|
+
: keywordHandler.interpret(keywordValue, instance, context) && emptyItemIndexes;
|
|
115
170
|
|
|
116
171
|
if (itemIndexes === false) {
|
|
117
172
|
return false;
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import * as Instance from "../../annotations/annotated-instance.js";
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
const id = "https://json-schema.org/keyword/writeOnly";
|
|
6
5
|
|
|
7
6
|
const compile = (schema) => Browser.value(schema);
|
|
7
|
+
const interpret = () => true;
|
|
8
|
+
const annotation = (writeOnly) => writeOnly;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
Instance.setAnnotation(instance, id, schemaLocation, writeOnly);
|
|
11
|
-
return true;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default { id, compile, interpret };
|
|
10
|
+
export default { id, compile, interpret, annotation };
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import * as Instance from "../annotations/annotated-instance.js";
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
const id = "https://spec.openapis.org/oas/3.0/keyword/discriminator";
|
|
6
5
|
|
|
7
6
|
const compile = (schema) => Browser.value(schema);
|
|
7
|
+
const interpret = () => true;
|
|
8
|
+
const annotation = (discriminator) => discriminator;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
Instance.setAnnotation(instance, id, schemaLocation, discriminator);
|
|
11
|
-
return true;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default { id, compile, interpret };
|
|
10
|
+
export default { id, compile, interpret, annotation };
|
package/openapi-3-0/example.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import * as Instance from "../annotations/annotated-instance.js";
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
const id = "https://spec.openapis.org/oas/3.0/keyword/example";
|
|
6
5
|
|
|
7
6
|
const compile = (schema) => Browser.value(schema);
|
|
7
|
+
const interpret = () => true;
|
|
8
|
+
const annotation = (example) => example;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
Instance.setAnnotation(instance, id, schemaLocation, example);
|
|
11
|
-
return true;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default { id, compile, interpret };
|
|
10
|
+
export default { id, compile, interpret, annotation };
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import * as Instance from "../annotations/annotated-instance.js";
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
const id = "https://spec.openapis.org/oas/3.0/keyword/externalDocs";
|
|
6
5
|
|
|
7
6
|
const compile = (schema) => Browser.value(schema);
|
|
7
|
+
const interpret = () => true;
|
|
8
|
+
const annotation = (externalDocs) => externalDocs;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
Instance.setAnnotation(instance, id, schemaLocation, externalDocs);
|
|
11
|
-
return true;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default { id, compile, interpret };
|
|
10
|
+
export default { id, compile, interpret, annotation };
|
package/openapi-3-0/index.d.ts
CHANGED
package/openapi-3-0/xml.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import * as Browser from "@hyperjump/browser";
|
|
2
|
-
import * as Instance from "../annotations/annotated-instance.js";
|
|
3
2
|
|
|
4
3
|
|
|
5
4
|
const id = "https://spec.openapis.org/oas/3.0/keyword/xml";
|
|
6
5
|
|
|
7
6
|
const compile = (schema) => Browser.value(schema);
|
|
7
|
+
const interpret = () => true;
|
|
8
|
+
const annotation = (xml) => xml;
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
Instance.setAnnotation(instance, id, schemaLocation, xml);
|
|
11
|
-
return true;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export default { id, compile, interpret };
|
|
10
|
+
export default { id, compile, interpret, annotation };
|
package/package.json
CHANGED
package/lib/output.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import * as Instance from "./instance.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const outputFormats = {};
|
|
5
|
-
|
|
6
|
-
export const toOutputFormat = (node, outputFormat) => {
|
|
7
|
-
if (outputFormat in outputFormats) {
|
|
8
|
-
return outputFormats[outputFormat](node);
|
|
9
|
-
} else {
|
|
10
|
-
throw Error(`The '${outputFormat}' error format is not supported`);
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
outputFormats.FLAG = (instance) => {
|
|
15
|
-
return { valid: instance.valid };
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
outputFormats.BASIC = (instance) => {
|
|
19
|
-
const output = {
|
|
20
|
-
valid: instance.valid
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
if (!instance.valid) {
|
|
24
|
-
output.errors = [];
|
|
25
|
-
|
|
26
|
-
for (const child of Instance.allNodes(instance)) {
|
|
27
|
-
for (const [absoluteKeywordLocation, keyword] of Object.entries(child.errors).reverse()) {
|
|
28
|
-
if (keyword !== "https://json-schema.org/evaluation/validate" && !child.valid) {
|
|
29
|
-
output.errors.unshift({
|
|
30
|
-
keyword,
|
|
31
|
-
absoluteKeywordLocation,
|
|
32
|
-
instanceLocation: Instance.uri(child),
|
|
33
|
-
valid: child.valid
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return output;
|
|
41
|
-
};
|