@hyperjump/json-schema 1.6.7 → 1.7.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 +247 -255
- package/annotations/annotated-instance.js +3 -3
- package/annotations/index.d.ts +7 -1
- package/annotations/index.js +3 -3
- package/bundle/index.d.ts +1 -5
- package/bundle/index.js +112 -156
- package/draft-04/additionalItems.js +6 -7
- package/draft-04/dependencies.js +5 -5
- package/draft-04/index.js +2 -2
- package/draft-04/items.js +5 -5
- package/draft-04/maximum.js +8 -8
- package/draft-04/minimum.js +8 -8
- package/draft-06/contains.js +2 -2
- package/draft-06/index.js +3 -2
- package/draft-07/index.js +3 -2
- package/draft-2019-09/index.js +9 -11
- package/draft-2020-12/dynamicRef.js +5 -5
- package/draft-2020-12/index.js +11 -13
- package/lib/common.d.ts +1 -1
- package/lib/common.js +44 -60
- package/lib/configuration.js +0 -6
- package/lib/core.js +32 -30
- package/lib/experimental.d.ts +75 -5
- package/lib/experimental.js +2 -2
- package/lib/index.d.ts +43 -11
- package/lib/index.js +11 -11
- package/lib/instance.d.ts +1 -17
- package/lib/instance.js +3 -3
- package/lib/keywords/additionalProperties.js +12 -13
- package/lib/keywords/allOf.js +3 -3
- package/lib/keywords/anyOf.js +3 -3
- package/lib/keywords/conditional.js +6 -7
- package/lib/keywords/const.js +2 -2
- package/lib/keywords/contains.js +14 -35
- package/lib/keywords/contentSchema.js +1 -1
- package/lib/keywords/definitions.js +2 -2
- package/lib/keywords/dependentRequired.js +4 -4
- package/lib/keywords/dependentSchemas.js +5 -5
- package/lib/keywords/dynamicRef.js +10 -5
- package/lib/keywords/else.js +5 -6
- package/lib/keywords/enum.js +4 -4
- package/lib/keywords/exclusiveMaximum.js +3 -3
- package/lib/keywords/exclusiveMinimum.js +3 -3
- package/lib/keywords/if.js +1 -1
- package/lib/keywords/itemPattern.js +17 -14
- package/lib/keywords/items.js +6 -7
- package/lib/keywords/maxItems.js +3 -3
- package/lib/keywords/maxLength.js +3 -3
- package/lib/keywords/maxProperties.js +3 -3
- package/lib/keywords/maximum.js +3 -3
- package/lib/keywords/meta-data.js +1 -1
- package/lib/keywords/minItems.js +3 -3
- package/lib/keywords/minLength.js +3 -3
- package/lib/keywords/minProperties.js +3 -3
- package/lib/keywords/minimum.js +3 -3
- package/lib/keywords/multipleOf.js +3 -3
- package/lib/keywords/not.js +1 -1
- package/lib/keywords/oneOf.js +3 -3
- package/lib/keywords/pattern.js +3 -3
- package/lib/keywords/patternProperties.js +5 -5
- package/lib/keywords/prefixItems.js +5 -5
- package/lib/keywords/properties.js +5 -5
- package/lib/keywords/propertyDependencies.js +6 -7
- package/lib/keywords/propertyNames.js +2 -2
- package/lib/keywords/ref.js +2 -7
- package/lib/keywords/requireAllExcept.js +8 -9
- package/lib/keywords/required.js +3 -3
- package/lib/keywords/then.js +5 -5
- package/lib/keywords/type.js +9 -3
- package/lib/keywords/unevaluatedItems.js +4 -4
- package/lib/keywords/unevaluatedProperties.js +4 -5
- package/lib/keywords/uniqueItems.js +3 -3
- package/lib/keywords/validation.js +11 -23
- package/lib/keywords.js +27 -14
- package/lib/openapi.js +19 -6
- package/lib/schema.js +236 -227
- package/openapi-3-0/index.js +5 -5
- package/openapi-3-0/type.js +13 -7
- package/openapi-3-1/index.js +22 -21
- package/openapi-3-1/{schema-base/2022-10-07.js → schema-base.js} +12 -2
- package/openapi-3-1/schema-draft-04.js +33 -0
- package/openapi-3-1/schema-draft-06.js +33 -0
- package/openapi-3-1/schema-draft-07.js +33 -0
- package/openapi-3-1/schema-draft-2019-09.js +33 -0
- package/openapi-3-1/schema-draft-2020-12.js +33 -0
- package/package.json +11 -11
- package/stable/index.js +10 -10
- package/annotations/validation-error.d.ts +0 -8
- package/draft-2019-09/contains.js +0 -44
- package/lib/configuration.d.ts +0 -9
- package/lib/context-uri.browser.js +0 -1
- package/lib/context-uri.js +0 -4
- package/lib/core.d.ts +0 -48
- package/lib/fetch.browser.js +0 -1
- package/lib/fetch.js +0 -20
- package/lib/invalid-schema-error.d.ts +0 -8
- package/lib/keywords.d.ts +0 -19
- package/lib/media-types.d.ts +0 -11
- package/lib/media-types.js +0 -48
- package/lib/reference.d.ts +0 -11
- package/lib/reference.js +0 -11
- package/lib/schema.d.ts +0 -60
- /package/openapi-3-0/{schema/2021-09-28.js → schema.js} +0 -0
- /package/openapi-3-1/{schema/2022-10-07.js → schema.js} +0 -0
package/draft-06/contains.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { some } from "@hyperjump/pact";
|
|
2
2
|
import * as Instance from "../lib/instance.js";
|
|
3
|
-
import Validation from "../lib/
|
|
3
|
+
import { Validation } from "../lib/experimental.js";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
const id = "https://json-schema.org/keyword/draft-06/contains";
|
|
@@ -8,7 +8,7 @@ const id = "https://json-schema.org/keyword/draft-06/contains";
|
|
|
8
8
|
const compile = (schema, ast) => Validation.compile(schema, ast);
|
|
9
9
|
|
|
10
10
|
const interpret = (contains, instance, ast, dynamicAnchors, quiet) => {
|
|
11
|
-
return
|
|
11
|
+
return Instance.typeOf(instance) !== "array" || some((item) => Validation.interpret(contains, item, ast, dynamicAnchors, quiet), Instance.iter(instance));
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export default { id, compile, interpret };
|
package/draft-06/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { addKeyword, defineVocabulary, loadDialect } from "../lib/keywords.js";
|
|
2
|
-
import {
|
|
2
|
+
import { registerSchema } from "../lib/index.js";
|
|
3
|
+
|
|
3
4
|
import metaSchema from "./schema.js";
|
|
4
5
|
import additionalItems from "../draft-04/additionalItems.js";
|
|
5
6
|
import contains from "./contains.js";
|
|
@@ -61,6 +62,6 @@ loadDialect(jsonSchemaVersion, {
|
|
|
61
62
|
[jsonSchemaVersion]: true
|
|
62
63
|
}, true);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
registerSchema(metaSchema);
|
|
65
66
|
|
|
66
67
|
export * from "../lib/index.js";
|
package/draft-07/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { addKeyword, defineVocabulary, loadDialect } from "../lib/keywords.js";
|
|
2
|
-
import {
|
|
2
|
+
import { registerSchema } from "../lib/index.js";
|
|
3
|
+
|
|
3
4
|
import metaSchema from "./schema.js";
|
|
4
5
|
import additionalItems from "../draft-04/additionalItems.js";
|
|
5
6
|
import contains from "../draft-06/contains.js";
|
|
@@ -67,6 +68,6 @@ loadDialect(jsonSchemaVersion, {
|
|
|
67
68
|
[jsonSchemaVersion]: true
|
|
68
69
|
}, true);
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
registerSchema(metaSchema);
|
|
71
72
|
|
|
72
73
|
export * from "../lib/index.js";
|
package/draft-2019-09/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { addKeyword, defineVocabulary, loadDialect } from "../lib/keywords.js";
|
|
2
|
-
import {
|
|
2
|
+
import { registerSchema } from "../lib/index.js";
|
|
3
3
|
|
|
4
4
|
import metaSchema from "./schema.js";
|
|
5
5
|
import coreMetaSchema from "./meta/core.js";
|
|
@@ -10,14 +10,12 @@ import formatMetaSchema from "./meta/format.js";
|
|
|
10
10
|
import contentMetaSchema from "./meta/content.js";
|
|
11
11
|
|
|
12
12
|
import additionalItems from "../draft-04/additionalItems.js";
|
|
13
|
-
import contains from "./contains.js";
|
|
14
13
|
import items from "../draft-04/items.js";
|
|
15
14
|
import recursiveAnchor from "./recursiveAnchor.js";
|
|
16
15
|
import recursiveRef from "../draft-2020-12/dynamicRef.js";
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
addKeyword(additionalItems);
|
|
20
|
-
addKeyword(contains);
|
|
21
19
|
addKeyword(items);
|
|
22
20
|
addKeyword(recursiveAnchor);
|
|
23
21
|
addKeyword(recursiveRef);
|
|
@@ -38,7 +36,7 @@ defineVocabulary("https://json-schema.org/draft/2019-09/vocab/applicator", {
|
|
|
38
36
|
"additionalProperties": "https://json-schema.org/keyword/additionalProperties",
|
|
39
37
|
"allOf": "https://json-schema.org/keyword/allOf",
|
|
40
38
|
"anyOf": "https://json-schema.org/keyword/anyOf",
|
|
41
|
-
"contains": "https://json-schema.org/keyword/
|
|
39
|
+
"contains": "https://json-schema.org/keyword/contains",
|
|
42
40
|
"dependentSchemas": "https://json-schema.org/keyword/dependentSchemas",
|
|
43
41
|
"if": "https://json-schema.org/keyword/if",
|
|
44
42
|
"then": "https://json-schema.org/keyword/then",
|
|
@@ -105,12 +103,12 @@ loadDialect("https://json-schema.org/draft/2019-09/schema", {
|
|
|
105
103
|
"https://json-schema.org/draft/2019-09/vocab/content": true
|
|
106
104
|
}, true);
|
|
107
105
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
106
|
+
registerSchema(metaSchema);
|
|
107
|
+
registerSchema(coreMetaSchema);
|
|
108
|
+
registerSchema(applicatorMetaSchema);
|
|
109
|
+
registerSchema(validationMetaSchema);
|
|
110
|
+
registerSchema(metaDataMetaSchema);
|
|
111
|
+
registerSchema(formatMetaSchema);
|
|
112
|
+
registerSchema(contentMetaSchema);
|
|
115
113
|
|
|
116
114
|
export * from "../lib/index.js";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import * as Browser from "@hyperjump/browser";
|
|
2
|
+
import { Validation, canonicalUri } from "../lib/experimental.js";
|
|
3
3
|
import { uriFragment } from "../lib/common.js";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
const id = "https://json-schema.org/keyword/draft-2020-12/dynamicRef";
|
|
7
7
|
|
|
8
8
|
const compile = async (dynamicRef, ast) => {
|
|
9
|
-
const fragment = uriFragment(
|
|
10
|
-
const referencedSchema = await
|
|
9
|
+
const fragment = uriFragment(Browser.value(dynamicRef));
|
|
10
|
+
const referencedSchema = await Browser.get(Browser.value(dynamicRef), dynamicRef);
|
|
11
11
|
await Validation.compile(referencedSchema, ast);
|
|
12
|
-
return [referencedSchema.
|
|
12
|
+
return [referencedSchema.document.baseUri, fragment, canonicalUri(referencedSchema)];
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const evaluate = (strategy) => ([id, fragment, ref], instance, ast, dynamicAnchors, quiet) => {
|
package/draft-2020-12/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { addKeyword, defineVocabulary, loadDialect } from "../lib/keywords.js";
|
|
2
|
-
import {
|
|
2
|
+
import { registerSchema } from "../lib/index.js";
|
|
3
3
|
|
|
4
4
|
import metaSchema from "./schema.js";
|
|
5
5
|
import coreMetaSchema from "./meta/core.js";
|
|
@@ -11,12 +11,10 @@ import formatAssertionMetaSchema from "./meta/format-assertion.js";
|
|
|
11
11
|
import contentMetaSchema from "./meta/content.js";
|
|
12
12
|
import unevaluatedMetaSchema from "./meta/unevaluated.js";
|
|
13
13
|
|
|
14
|
-
import contains from "../draft-2019-09/contains.js";
|
|
15
14
|
import dynamicAnchor from "./dynamicAnchor.js";
|
|
16
15
|
import dynamicRef from "./dynamicRef.js";
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
addKeyword(contains);
|
|
20
18
|
addKeyword(dynamicRef);
|
|
21
19
|
addKeyword(dynamicAnchor);
|
|
22
20
|
|
|
@@ -35,7 +33,7 @@ defineVocabulary("https://json-schema.org/draft/2020-12/vocab/applicator", {
|
|
|
35
33
|
"additionalProperties": "https://json-schema.org/keyword/additionalProperties",
|
|
36
34
|
"allOf": "https://json-schema.org/keyword/allOf",
|
|
37
35
|
"anyOf": "https://json-schema.org/keyword/anyOf",
|
|
38
|
-
"contains": "https://json-schema.org/keyword/
|
|
36
|
+
"contains": "https://json-schema.org/keyword/contains",
|
|
39
37
|
"dependentSchemas": "https://json-schema.org/keyword/dependentSchemas",
|
|
40
38
|
"if": "https://json-schema.org/keyword/if",
|
|
41
39
|
"then": "https://json-schema.org/keyword/then",
|
|
@@ -111,14 +109,14 @@ loadDialect("https://json-schema.org/draft/2020-12/schema", {
|
|
|
111
109
|
"https://json-schema.org/draft/2020-12/vocab/unevaluated": true
|
|
112
110
|
}, true);
|
|
113
111
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
112
|
+
registerSchema(metaSchema);
|
|
113
|
+
registerSchema(coreMetaSchema);
|
|
114
|
+
registerSchema(applicatorMetaSchema);
|
|
115
|
+
registerSchema(validationMetaSchema);
|
|
116
|
+
registerSchema(metaDataMetaSchema);
|
|
117
|
+
registerSchema(formatAnnotationMetaSchema);
|
|
118
|
+
registerSchema(formatAssertionMetaSchema);
|
|
119
|
+
registerSchema(contentMetaSchema);
|
|
120
|
+
registerSchema(unevaluatedMetaSchema);
|
|
123
121
|
|
|
124
122
|
export * from "../lib/index.js";
|
package/lib/common.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type JsonType = "object" | "array" | "string" | "number" | "boolean" | "null";
|
|
2
2
|
export type JsonSchemaType = JsonType | "integer";
|
|
3
3
|
|
|
4
|
-
export const
|
|
4
|
+
export const toRelativeIri: (from: string, to: string) => string;
|
|
5
5
|
|
|
6
6
|
export type Replacer = (key: string, value: unknown) => unknown;
|
|
7
7
|
export const jsonStringify: (value: unknown, replacer?: Replacer, space?: string) => string;
|
package/lib/common.js
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
|
-
import { resolveIri, parseIriReference } from "@hyperjump/uri";
|
|
1
|
+
import { resolveIri, parseIriReference, parseAbsoluteIri } from "@hyperjump/uri";
|
|
2
2
|
import * as JsonPointer from "@hyperjump/json-pointer";
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
export const jsonTypeOf = (value) => {
|
|
6
|
+
const jsType = typeof value;
|
|
7
|
+
|
|
8
|
+
switch (jsType) {
|
|
9
|
+
case "number":
|
|
10
|
+
case "string":
|
|
11
|
+
case "boolean":
|
|
12
|
+
case "undefined":
|
|
13
|
+
return jsType;
|
|
14
|
+
case "object":
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
return "array";
|
|
17
|
+
} else if (value === null) {
|
|
18
|
+
return "null";
|
|
19
|
+
} else if (Object.getPrototypeOf(value) === Object.prototype) {
|
|
20
|
+
return "object";
|
|
21
|
+
}
|
|
22
|
+
default:
|
|
23
|
+
const type = jsType === "object" ? Object.getPrototypeOf(value).constructor.name || "anonymous" : jsType;
|
|
24
|
+
throw Error(`Not a JSON compatible type: ${type}`);
|
|
25
|
+
}
|
|
14
26
|
};
|
|
15
|
-
export const jsonTypeOf = (value, type) => isType[type](value);
|
|
16
27
|
|
|
17
28
|
export const resolveUri = (uri, baseUri) => {
|
|
18
29
|
const resolved = resolveIri(uri, baseUri);
|
|
@@ -30,70 +41,43 @@ export const toAbsoluteUri = (uri) => {
|
|
|
30
41
|
|
|
31
42
|
export const uriFragment = (uri) => decodeURIComponent(parseIriReference(uri).fragment || "");
|
|
32
43
|
|
|
33
|
-
const
|
|
44
|
+
export const toRelativeIri = (from, to) => {
|
|
45
|
+
const fromUri = parseAbsoluteIri(from);
|
|
46
|
+
const toUri = parseAbsoluteIri(to);
|
|
34
47
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return "";
|
|
48
|
+
if (toUri.scheme !== fromUri.scheme) {
|
|
49
|
+
return to;
|
|
38
50
|
}
|
|
39
51
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const toLen = to.length - toStart;
|
|
43
|
-
|
|
44
|
-
// Compare paths to find the longest common path from root
|
|
45
|
-
const length = fromLen < toLen ? fromLen : toLen;
|
|
46
|
-
let lastCommonSep = -1;
|
|
47
|
-
let i = 0;
|
|
48
|
-
for (; i < length; i++) {
|
|
49
|
-
const fromCode = from.charCodeAt(i + 1);
|
|
50
|
-
if (fromCode !== to.charCodeAt(toStart + i)) {
|
|
51
|
-
break;
|
|
52
|
-
} else if (fromCode === CHAR_BACKWARD_SLASH) {
|
|
53
|
-
lastCommonSep = i;
|
|
54
|
-
}
|
|
52
|
+
if (toUri.authority !== fromUri.authority) {
|
|
53
|
+
return to;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
return to.slice(toStart + i + 1);
|
|
60
|
-
}
|
|
61
|
-
if (i === 0) {
|
|
62
|
-
return to.slice(toStart + i);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (fromLen > length) {
|
|
66
|
-
if (from.charCodeAt(i + 1) === CHAR_BACKWARD_SLASH) {
|
|
67
|
-
lastCommonSep = i;
|
|
68
|
-
} else if (length === 0) {
|
|
69
|
-
lastCommonSep = 0;
|
|
70
|
-
}
|
|
56
|
+
if (from === to) {
|
|
57
|
+
return "";
|
|
71
58
|
}
|
|
72
59
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for (i = lastCommonSep + 2; i <= from.length; ++i) {
|
|
76
|
-
if (i === from.length || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {
|
|
77
|
-
out += out.length === 0 ? ".." : "/..";
|
|
78
|
-
}
|
|
79
|
-
}
|
|
60
|
+
const fromSegments = fromUri.path.split("/");
|
|
61
|
+
const toSegments = toUri.path.split("/");
|
|
80
62
|
|
|
81
|
-
|
|
63
|
+
let position = 0;
|
|
64
|
+
while (fromSegments[position] === toSegments[position] && position < fromSegments.length - 1 && position < toSegments.length - 1) {
|
|
65
|
+
position++;
|
|
66
|
+
}
|
|
82
67
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return `${out}${to.slice(toStart, to.length)}`;
|
|
68
|
+
const segments = [];
|
|
69
|
+
for (let index = position + 1; index < fromSegments.length; index++) {
|
|
70
|
+
segments.push("..");
|
|
87
71
|
}
|
|
88
72
|
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
for (let index = position; index < toSegments.length; index++) {
|
|
74
|
+
segments.push(toSegments[index]);
|
|
91
75
|
}
|
|
92
76
|
|
|
93
|
-
return
|
|
77
|
+
return segments.join("/");
|
|
94
78
|
};
|
|
95
79
|
|
|
96
|
-
const defaultReplacer = (
|
|
80
|
+
const defaultReplacer = (_key, value) => value;
|
|
97
81
|
export const jsonStringify = (value, replacer = defaultReplacer, space = "") => {
|
|
98
82
|
return stringifyValue(value, replacer, space, "", JsonPointer.nil, 1);
|
|
99
83
|
};
|
package/lib/configuration.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
let metaSchemaOutputFormat;
|
|
2
2
|
let shouldValidateSchema = true;
|
|
3
|
-
const enabledExperimentalKeywords = {};
|
|
4
3
|
|
|
5
4
|
export const getMetaSchemaOutputFormat = () => metaSchemaOutputFormat;
|
|
6
5
|
export const setMetaSchemaOutputFormat = (format) => {
|
|
@@ -11,8 +10,3 @@ export const getShouldValidateSchema = () => shouldValidateSchema;
|
|
|
11
10
|
export const setShouldValidateSchema = (isEnabled) => {
|
|
12
11
|
shouldValidateSchema = isEnabled;
|
|
13
12
|
};
|
|
14
|
-
|
|
15
|
-
export const isExperimentalKeywordEnabled = (keywordId) => enabledExperimentalKeywords[keywordId];
|
|
16
|
-
export const setExperimentalKeywordEnabled = (keywordId, isEnabled) => {
|
|
17
|
-
enabledExperimentalKeywords[keywordId] = isEnabled;
|
|
18
|
-
};
|
package/lib/core.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import curry from "just-curry-it";
|
|
2
|
+
import { resolveIri, toAbsoluteIri } from "@hyperjump/uri";
|
|
2
3
|
import { subscribe, unsubscribe } from "./pubsub.js";
|
|
3
4
|
import {
|
|
4
5
|
setMetaSchemaOutputFormat,
|
|
5
6
|
getShouldValidateSchema,
|
|
6
|
-
isExperimentalKeywordEnabled,
|
|
7
|
-
setExperimentalKeywordEnabled,
|
|
8
7
|
getMetaSchemaOutputFormat
|
|
9
8
|
} from "./configuration.js";
|
|
10
9
|
import * as Instance from "./instance.js";
|
|
11
10
|
import { InvalidSchemaError } from "./invalid-schema-error.js";
|
|
12
|
-
import
|
|
11
|
+
import { getSchema, registerSchema, unregisterSchema as schemaUnregister } from "./schema.js";
|
|
12
|
+
import { getKeywordName } from "./keywords.js";
|
|
13
13
|
import Validation from "./keywords/validation.js";
|
|
14
14
|
|
|
15
15
|
|
|
@@ -17,14 +17,14 @@ export const FLAG = "FLAG", BASIC = "BASIC", DETAILED = "DETAILED", VERBOSE = "V
|
|
|
17
17
|
setMetaSchemaOutputFormat(FLAG);
|
|
18
18
|
|
|
19
19
|
export const validate = async (url, value = undefined, outputFormat = undefined) => {
|
|
20
|
-
const
|
|
20
|
+
const schema = await getSchema(url);
|
|
21
|
+
const compiled = await compile(schema);
|
|
21
22
|
const interpretAst = (value, outputFormat) => interpret(compiled, Instance.cons(value), outputFormat);
|
|
22
23
|
|
|
23
24
|
return value === undefined ? interpretAst : interpretAst(value, outputFormat);
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
export const compile = async (
|
|
27
|
-
const schema = await Schema.get(url);
|
|
27
|
+
export const compile = async (schema) => {
|
|
28
28
|
const ast = { metaData: {} };
|
|
29
29
|
const schemaUri = await Validation.compile(schema, ast);
|
|
30
30
|
return { ast, schemaUri };
|
|
@@ -79,39 +79,41 @@ const outputHandler = (outputFormat, output) => {
|
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
const metaValidators = {};
|
|
82
|
-
subscribe("validate.metaValidate", async (
|
|
83
|
-
if (getShouldValidateSchema() && !schema.validated) {
|
|
84
|
-
|
|
82
|
+
subscribe("validate.metaValidate", async (_message, schema) => {
|
|
83
|
+
if (getShouldValidateSchema() && !schema.document.validated) {
|
|
84
|
+
schema.document.validated = true;
|
|
85
85
|
|
|
86
86
|
// Compile
|
|
87
|
-
if (!(schema.dialectId in metaValidators)) {
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
setExperimentalKeywordEnabled(dyanmicRefKeywordId, true);
|
|
92
|
-
|
|
93
|
-
// itemPattern is experimental, but is necessary for meta-validation
|
|
94
|
-
const itemPatternKeywordId = "https://json-schema.org/keyword/itemPattern";
|
|
95
|
-
const isItemPatternEnabled = isExperimentalKeywordEnabled(itemPatternKeywordId);
|
|
96
|
-
setExperimentalKeywordEnabled(itemPatternKeywordId, true);
|
|
97
|
-
|
|
98
|
-
const compiledSchema = await compile(schema.dialectId);
|
|
99
|
-
metaValidators[schema.dialectId] = interpret(compiledSchema);
|
|
100
|
-
|
|
101
|
-
setExperimentalKeywordEnabled(itemPatternKeywordId, isItemPatternEnabled);
|
|
102
|
-
setExperimentalKeywordEnabled(dyanmicRefKeywordId, isDynamicRefEnabled);
|
|
87
|
+
if (!(schema.document.dialectId in metaValidators)) {
|
|
88
|
+
const metaSchema = await getSchema(schema.document.dialectId);
|
|
89
|
+
const compiledSchema = await compile(metaSchema);
|
|
90
|
+
metaValidators[schema.document.dialectId] = interpret(compiledSchema);
|
|
103
91
|
}
|
|
104
92
|
|
|
105
93
|
// Interpret
|
|
106
|
-
const schemaInstance = Instance.cons(schema.
|
|
107
|
-
const metaResults = metaValidators[schema.dialectId](schemaInstance, getMetaSchemaOutputFormat());
|
|
94
|
+
const schemaInstance = Instance.cons(schema.document.root, schema.document.baseUri);
|
|
95
|
+
const metaResults = metaValidators[schema.document.dialectId](schemaInstance, getMetaSchemaOutputFormat());
|
|
108
96
|
if (!metaResults.valid) {
|
|
109
97
|
throw new InvalidSchemaError(metaResults);
|
|
110
98
|
}
|
|
111
99
|
}
|
|
112
100
|
});
|
|
113
101
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
102
|
+
/**
|
|
103
|
+
* @deprecated since 1.7.0. Use registerSchema instead.
|
|
104
|
+
*/
|
|
105
|
+
export const addSchema = (schema, retrievalUri = undefined, contextDialectId = undefined) => {
|
|
106
|
+
const dialectId = typeof schema.$schema === "string" ? toAbsoluteIri(schema.$schema) : contextDialectId;
|
|
107
|
+
const idToken = getKeywordName(dialectId, "https://json-schema.org/keyword/id")
|
|
108
|
+
|| getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id");
|
|
109
|
+
const id = typeof schema[idToken] === "string" ? resolveIri(schema[idToken], retrievalUri) : retrievalUri;
|
|
110
|
+
|
|
111
|
+
unregisterSchema(id);
|
|
112
|
+
|
|
113
|
+
registerSchema(schema, retrievalUri, contextDialectId);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const unregisterSchema = (uri) => {
|
|
117
|
+
schemaUnregister(uri);
|
|
118
|
+
delete metaValidators[uri];
|
|
117
119
|
};
|
package/lib/experimental.d.ts
CHANGED
|
@@ -1,8 +1,78 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Browser, Document } from "@hyperjump/browser";
|
|
2
|
+
import type { Validator, OutputUnit, OutputFormat, SchemaObject } from "./index.js";
|
|
3
|
+
import type { JsonDocument } from "./instance.js";
|
|
2
4
|
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
export
|
|
7
|
-
|
|
6
|
+
// Compile/interpret
|
|
7
|
+
export const compile: (url: string) => Promise<CompiledSchema>;
|
|
8
|
+
export const interpret: (
|
|
9
|
+
(compiledSchema: CompiledSchema, value: unknown, outputFormat?: OutputFormat) => OutputUnit
|
|
10
|
+
) & (
|
|
11
|
+
(compiledSchema: CompiledSchema) => Validator
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export type CompiledSchema = {
|
|
15
|
+
schemaUri: string;
|
|
16
|
+
ast: AST;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type AST = {
|
|
20
|
+
metaData: Record<string, MetaData>;
|
|
21
|
+
} & Record<string, Node<Node<unknown>[] | boolean>>;
|
|
22
|
+
|
|
23
|
+
type Node<A> = [keywordId: string, schemaUri: string, keywordValue: A];
|
|
24
|
+
|
|
25
|
+
type MetaData = {
|
|
26
|
+
id: string;
|
|
27
|
+
dynamicAnchors: Anchors;
|
|
28
|
+
anchors: Anchors;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type Anchors = Record<string, string>;
|
|
32
|
+
|
|
33
|
+
// Output Formats
|
|
34
|
+
export const BASIC: "BASIC";
|
|
35
|
+
export const DETAILED: "DETAILED";
|
|
36
|
+
export const VERBOSE: "VERBOSE";
|
|
37
|
+
|
|
38
|
+
// Schema
|
|
39
|
+
export const getSchema: (uri: string, browser?: Browser) => Promise<Browser<SchemaDocument>>;
|
|
40
|
+
export const buildSchemaDocument: (schema: SchemaObject | boolean, retrievalUri?: string, contextDialectId?: string) => SchemaDocument;
|
|
41
|
+
export const canonicalUri: (browser: Browser<SchemaDocument>) => string;
|
|
42
|
+
export const toSchema: (browser: Browser<SchemaDocument>, options?: ToSchemaOptions) => SchemaObject;
|
|
43
|
+
|
|
44
|
+
export type ToSchemaOptions = {
|
|
45
|
+
contextDialectId?: string;
|
|
46
|
+
includeDialect?: "auto" | "always" | "never";
|
|
47
|
+
selfIdentify?: boolean;
|
|
48
|
+
contextUri?: string;
|
|
49
|
+
includeEmbedded?: boolean;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type SchemaDocument = Document & {
|
|
53
|
+
dialectId: string;
|
|
54
|
+
anchors: Record<string, string>;
|
|
55
|
+
dynamicAnchors: Record<string, string>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Vocabulary System
|
|
59
|
+
export const addKeyword: <A>(keywordHandler: Keyword<A>) => void;
|
|
60
|
+
export const getKeywordName: (dialectId: string, keywordId: string) => string;
|
|
61
|
+
export const getKeyword: <A>(id: string) => Keyword<A>;
|
|
62
|
+
export const getKeywordByName: <A>(keywordName: string, dialectId: string) => Keyword<A>;
|
|
63
|
+
export const getKeywordId: (keywordName: string, dialectId: string) => string;
|
|
64
|
+
export const defineVocabulary: (id: string, keywords: { [keyword: string]: string }) => void;
|
|
65
|
+
export const loadDialect: (dialectId: string, dialect: { [vocabularyId: string]: boolean }, allowUnknownKeywords?: boolean) => void;
|
|
66
|
+
export const hasDialect: (dialectId: string) => boolean;
|
|
67
|
+
|
|
68
|
+
export type Keyword<A> = {
|
|
69
|
+
id: string;
|
|
70
|
+
compile: (schema: Browser<SchemaDocument>, ast: AST, parentSchema: Browser<SchemaDocument>) => Promise<A>;
|
|
71
|
+
interpret: (compiledKeywordValue: A, instance: JsonDocument, ast: AST, dynamicAnchors: Anchors) => boolean;
|
|
72
|
+
collectEvaluatedProperties?: (compiledKeywordValue: A, instance: JsonDocument, ast: AST, dynamicAnchors: Anchors, isTop?: boolean) => Set<string> | false;
|
|
73
|
+
collectEvaluatedItems?: (compiledKeywordValue: A, instance: JsonDocument, ast: AST, dynamicAnchors: Anchors, isTop?: boolean) => Set<number> | false;
|
|
74
|
+
collectExternalIds?: (visited: Set<string>, parentSchema: Browser<SchemaDocument>, schema: Browser<SchemaDocument>) => Promise<Set<string>>;
|
|
75
|
+
annotation?: <B>(compiledKeywordValue: A) => B;
|
|
76
|
+
};
|
|
77
|
+
|
|
8
78
|
export const Validation: Keyword<string>;
|
package/lib/experimental.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { compile, interpret, BASIC, DETAILED, VERBOSE } from "./core.js";
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
2
|
+
export { getKeyword, getKeywordByName, addKeyword, defineVocabulary, getKeywordName, getKeywordId, loadDialect, hasDialect } from "./keywords.js";
|
|
3
|
+
export { getSchema, toSchema, canonicalUri, buildSchemaDocument } from "./schema.js";
|
|
4
4
|
export { default as Validation } from "./keywords/validation.js";
|
package/lib/index.d.ts
CHANGED
|
@@ -1,11 +1,43 @@
|
|
|
1
|
-
export
|
|
2
|
-
export type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
export type SchemaFragment = string | number | boolean | null | SchemaObject | SchemaFragment[];
|
|
2
|
+
export type SchemaObject = {
|
|
3
|
+
[keyword: string]: SchemaFragment;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export const registerSchema: (schema: SchemaObject | boolean, retrievalUri?: string, contextDialectId?: string) => void;
|
|
7
|
+
export const unregisterSchema: (retrievalUri: string) => void;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated since 1.7.0. Use registerSchema instead.
|
|
11
|
+
*/
|
|
12
|
+
export const addSchema: typeof registerSchema;
|
|
13
|
+
|
|
14
|
+
export const validate: (
|
|
15
|
+
(url: string, value: unknown, outputFormat?: OutputFormat) => Promise<OutputUnit>
|
|
16
|
+
) & (
|
|
17
|
+
(url: string) => Promise<Validator>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export type Validator = (value: unknown, outputFormat?: OutputFormat) => OutputUnit;
|
|
21
|
+
|
|
22
|
+
export type OutputUnit = {
|
|
23
|
+
keyword: string;
|
|
24
|
+
absoluteKeywordLocation: string;
|
|
25
|
+
instanceLocation: string;
|
|
26
|
+
valid: boolean;
|
|
27
|
+
errors?: OutputUnit[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const FLAG: "FLAG";
|
|
31
|
+
|
|
32
|
+
export type OutputFormat = "FLAG" | "BASIC" | "DETAILED" | "VERBOSE";
|
|
33
|
+
|
|
34
|
+
export const setMetaSchemaOutputFormat: (format: OutputFormat) => void;
|
|
35
|
+
export const getMetaSchemaOutputFormat: () => OutputFormat;
|
|
36
|
+
export const setShouldValidateSchema: (isEnabled: boolean) => void;
|
|
37
|
+
export const getShouldValidateSchema: () => boolean;
|
|
38
|
+
|
|
39
|
+
export class InvalidSchemaError extends Error {
|
|
40
|
+
public output: OutputUnit;
|
|
41
|
+
|
|
42
|
+
public constructor(output: OutputUnit);
|
|
43
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { addMediaTypePlugin } from "@hyperjump/browser";
|
|
1
2
|
import { addKeyword } from "./keywords.js";
|
|
2
|
-
import {
|
|
3
|
+
import { schemaPlugin } from "./schema.js";
|
|
3
4
|
|
|
4
5
|
import additionalProperties from "./keywords/additionalProperties.js";
|
|
5
6
|
import allOf from "./keywords/allOf.js";
|
|
@@ -64,13 +65,7 @@ import vocabulary from "./keywords/vocabulary.js";
|
|
|
64
65
|
import writeOnly from "./keywords/writeOnly.js";
|
|
65
66
|
|
|
66
67
|
|
|
67
|
-
addMediaTypePlugin("application/schema+json",
|
|
68
|
-
parse: async (response, contentTypeParameters) => [
|
|
69
|
-
await response.json(),
|
|
70
|
-
contentTypeParameters.schema || contentTypeParameters.profile
|
|
71
|
-
],
|
|
72
|
-
matcher: (path) => path.endsWith(".schema.json")
|
|
73
|
-
});
|
|
68
|
+
addMediaTypePlugin("application/schema+json", schemaPlugin);
|
|
74
69
|
|
|
75
70
|
addKeyword(additionalProperties);
|
|
76
71
|
addKeyword(allOf);
|
|
@@ -134,7 +129,12 @@ addKeyword(unknown);
|
|
|
134
129
|
addKeyword(vocabulary);
|
|
135
130
|
addKeyword(writeOnly);
|
|
136
131
|
|
|
137
|
-
export { addSchema, validate, FLAG } from "./core.js";
|
|
138
|
-
export {
|
|
132
|
+
export { addSchema, unregisterSchema, validate, FLAG } from "./core.js";
|
|
133
|
+
export { registerSchema } from "./schema.js";
|
|
134
|
+
export {
|
|
135
|
+
getMetaSchemaOutputFormat,
|
|
136
|
+
setMetaSchemaOutputFormat,
|
|
137
|
+
getShouldValidateSchema,
|
|
138
|
+
setShouldValidateSchema
|
|
139
|
+
} from "./configuration.js";
|
|
139
140
|
export { InvalidSchemaError } from "./invalid-schema-error.js";
|
|
140
|
-
export { addMediaTypePlugin } from "./media-types.js";
|
package/lib/instance.d.ts
CHANGED
|
@@ -8,23 +8,7 @@ export const get: (url: string, context?: JsonDocument) => JsonDocument;
|
|
|
8
8
|
export const uri: (doc: JsonDocument) => string;
|
|
9
9
|
export const value: <A extends Json>(doc: JsonDocument<A>) => A;
|
|
10
10
|
export const has: (key: string, doc: JsonDocument<JsonObject>) => boolean;
|
|
11
|
-
export const typeOf: (
|
|
12
|
-
(doc: JsonDocument, type: "null") => doc is JsonDocument<null>
|
|
13
|
-
) & (
|
|
14
|
-
(doc: JsonDocument, type: "boolean") => doc is JsonDocument<boolean>
|
|
15
|
-
) & (
|
|
16
|
-
(doc: JsonDocument, type: "object") => doc is JsonDocument<JsonObject>
|
|
17
|
-
) & (
|
|
18
|
-
(doc: JsonDocument, type: "array") => doc is JsonDocument<Json[]>
|
|
19
|
-
) & (
|
|
20
|
-
(doc: JsonDocument, type: "number" | "integer") => doc is JsonDocument<number>
|
|
21
|
-
) & (
|
|
22
|
-
(doc: JsonDocument, type: "string") => doc is JsonDocument<string>
|
|
23
|
-
) & (
|
|
24
|
-
(doc: JsonDocument, type: JsonType) => boolean
|
|
25
|
-
) & (
|
|
26
|
-
(doc: JsonDocument) => (type: JsonType) => boolean
|
|
27
|
-
);
|
|
11
|
+
export const typeOf: (doc: JsonDocument) => JsonType;
|
|
28
12
|
export const step: (key: string, doc: JsonDocument<JsonObject | Json[]>) => JsonDocument<typeof doc.value>;
|
|
29
13
|
export const iter: (doc: JsonDocument<JsonObject>) => Generator<JsonDocument>;
|
|
30
14
|
export const keys: (doc: JsonDocument<JsonObject>) => Generator<string>;
|