json-schema-library 11.2.0 → 11.3.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/CHANGELOG.md +5 -0
- package/bowtie/BOWTIE.md +4 -4
- package/bowtie/Dockerfile +1 -1
- package/bowtie/{bowtie.ts → bowtie-jlib.ts} +11 -17
- package/bowtie/bowtie.test.ts +207 -16
- package/bowtie/package.json +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +75 -4
- package/dist/index.d.mts +75 -4
- package/dist/index.mjs +1 -1
- package/dist/jlib.js +2 -2
- package/package.json +2 -2
- package/src/compileSchema.test.ts +52 -0
- package/src/compileSchema.ts +51 -4
- package/src/draft04.ts +2 -2
- package/src/draft06.ts +2 -2
- package/src/draft07.ts +2 -2
- package/src/draft2019-09/keywords/$ref.ts +4 -14
- package/src/draft2019.ts +1 -1
- package/src/draft2020.ts +1 -1
- package/src/keywords/$ref.ts +3 -4
- package/src/keywords/oneOf.test.ts +3 -3
- package/src/settings.ts +27 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-schema-library",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.0",
|
|
4
4
|
"description": "Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"test:7:ci": "DISABLE_LOG=true mocha -R json 'src/tests/spec/draft07.spec.ts' > test-result-spec7.json; exit 0",
|
|
40
40
|
"test:inspect": "NODE_OPTIONS='--inspect-brk' mocha 'src/**/*.test.ts'",
|
|
41
41
|
"test:spec": "mocha 'src/tests/spec/*.spec.ts'",
|
|
42
|
-
"test:unit": "mocha 'src/**/*.test.ts' 'bowtie
|
|
42
|
+
"test:unit": "mocha 'src/**/*.test.ts' 'bowtie/*.test.ts'",
|
|
43
43
|
"test:unit:ci": "DISABLE_LOG=true mocha -R json 'src/**/*.test.ts' -R json > test-result-unit.json; exit 0"
|
|
44
44
|
},
|
|
45
45
|
"repository": {
|
|
@@ -2,6 +2,9 @@ import { compileSchema } from "./compileSchema";
|
|
|
2
2
|
import { strict as assert } from "assert";
|
|
3
3
|
import { draftEditor } from "./draftEditor";
|
|
4
4
|
import { SchemaNode } from "./SchemaNode";
|
|
5
|
+
import { draft04 } from "./draft04";
|
|
6
|
+
import { draft07 } from "./draft07";
|
|
7
|
+
import { draft2020 } from "./draft2020";
|
|
5
8
|
|
|
6
9
|
describe("compileSchema vocabulary", () => {
|
|
7
10
|
let root: SchemaNode;
|
|
@@ -33,6 +36,54 @@ describe("compileSchema vocabulary", () => {
|
|
|
33
36
|
});
|
|
34
37
|
});
|
|
35
38
|
|
|
39
|
+
describe("compileSchema draft-version", () => {
|
|
40
|
+
it("should select last draft", () => {
|
|
41
|
+
const node = compileSchema({}, { drafts: [draft04, draft07, draft2020] });
|
|
42
|
+
assert(node.getDraftVersion(), "draft-2020");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should select draft specified by $schema", () => {
|
|
46
|
+
const node = compileSchema(
|
|
47
|
+
{ $schema: "http://json-schema.org/draft-07/schema#" },
|
|
48
|
+
{ drafts: [draft04, draft07, draft2020] }
|
|
49
|
+
);
|
|
50
|
+
assert(node.getDraftVersion(), "draft-07");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should select fallback draft specified by `draft`", () => {
|
|
54
|
+
const node = compileSchema(
|
|
55
|
+
{},
|
|
56
|
+
{
|
|
57
|
+
draft: "http://json-schema.org/draft-07/schema#",
|
|
58
|
+
drafts: [draft04, draft07, draft2020]
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
assert(node.getDraftVersion(), "draft-07");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should prefer `$schema` over `draft` options", () => {
|
|
65
|
+
const node = compileSchema(
|
|
66
|
+
{ $schema: "http://json-schema.org/draft-04/schema#" },
|
|
67
|
+
{
|
|
68
|
+
draft: "http://json-schema.org/draft-07/schema#",
|
|
69
|
+
drafts: [draft04, draft07, draft2020]
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
assert(node.getDraftVersion(), "draft-04");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should always fallback to last draft if nothing matches", () => {
|
|
76
|
+
const node = compileSchema(
|
|
77
|
+
{ $schema: "http://json-schema.org/draft-A/schema#" },
|
|
78
|
+
{
|
|
79
|
+
draft: "http://json-schema.org/draft-B/schema#",
|
|
80
|
+
drafts: [draft04, draft07, draft2020]
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
assert(node.getDraftVersion(), "draft-2020");
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
36
87
|
describe("compileSchema vocabulary", () => {
|
|
37
88
|
it("should add remote schema on compile", () => {
|
|
38
89
|
const remote = compileSchema({
|
|
@@ -150,6 +201,7 @@ describe("compileSchema `schemaLocation`", () => {
|
|
|
150
201
|
$defs: { asset: { type: "string" } }
|
|
151
202
|
});
|
|
152
203
|
|
|
204
|
+
assert(node.if && node.then && node.properties && node.$defs);
|
|
153
205
|
assert.deepEqual(node.schemaLocation, "#");
|
|
154
206
|
assert.deepEqual(node.if.schemaLocation, "#/if");
|
|
155
207
|
assert.deepEqual(node.then.schemaLocation, "#/then");
|
package/src/compileSchema.ts
CHANGED
|
@@ -25,15 +25,62 @@ import sanitizeErrors from "./utils/sanitizeErrors";
|
|
|
25
25
|
const { REGEX_FLAGS } = settings;
|
|
26
26
|
|
|
27
27
|
export type CompileOptions = {
|
|
28
|
+
/**
|
|
29
|
+
* List of drafts to support.
|
|
30
|
+
*
|
|
31
|
+
* Drafts are selected by testing the passed `schema.$schema` for a matching id, which
|
|
32
|
+
* is tested by each draft's `Draft.$schemaRegEx`. In case no draft matches `schema.$schema`
|
|
33
|
+
* the last draft in the list will be used.
|
|
34
|
+
*
|
|
35
|
+
* @default [draft04, draft06, draft07, draft2019, draft2020]
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* import { draft04, draft07, draft2020 } from "json-schema-library"
|
|
39
|
+
* compileSchema({ $schema: "draft-04" }, { drafts: [draft04, draft07, draft2020] })
|
|
40
|
+
*/
|
|
28
41
|
drafts?: Draft[];
|
|
42
|
+
/**
|
|
43
|
+
* Fallback _draft_ version in case no _draft_ is specified by `schema.$schema`.
|
|
44
|
+
*
|
|
45
|
+
* Drafts are selected by given `schema.$schema` or the last draft from `drafts` as a fallback.
|
|
46
|
+
* Specifying `draft` will workthe same as a specifying `schema.$schema` in case no $schema is
|
|
47
|
+
* defined. When no match can be found, the last _draft_ from `drafts` will be used.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // uses draft-04
|
|
51
|
+
* compileSchema({ $schema: "draft-04" }, { drafts: [draft04, draft07, draft2020] })
|
|
52
|
+
*
|
|
53
|
+
* // uses draft-2020-12
|
|
54
|
+
* compileSchema({}, { drafts: [draft04, draft07, draft2020] })
|
|
55
|
+
*
|
|
56
|
+
* // uses draft-07
|
|
57
|
+
* compileSchema({}, { draft: "draft-07", drafts: [draft04, draft07, draft2020] })
|
|
58
|
+
|
|
59
|
+
* // uses draft-04
|
|
60
|
+
* compileSchema({ $schema: "draft-04" }, { draft: "draft-07", drafts: [draft04, draft07, draft2020] })
|
|
61
|
+
*
|
|
62
|
+
* // uses draft-2020
|
|
63
|
+
* compileSchema({ $schema: "draft-04" }, { draft: "draft-07", drafts: [draft2020] })
|
|
64
|
+
*/
|
|
65
|
+
draft?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Set node and its remote schemata as remote schemata for this node and schema to resolve $ref
|
|
68
|
+
*/
|
|
29
69
|
remote?: SchemaNode;
|
|
70
|
+
/**
|
|
71
|
+
* Enables `format`-keyword assertions when this is set tor `true` or sets assertion as defined by
|
|
72
|
+
* the given meta-schema. Set to `false` to deactivate format validation.
|
|
73
|
+
*
|
|
74
|
+
* @default true
|
|
75
|
+
*/
|
|
30
76
|
formatAssertion?: boolean | "meta-schema" | undefined;
|
|
77
|
+
/** Set default options for all `node.getData` requests */
|
|
31
78
|
getDataDefaultOptions?: TemplateOptions;
|
|
32
|
-
/**
|
|
79
|
+
/** Set to true to throw an Error on errors in input schema. Defaults to false */
|
|
33
80
|
throwOnInvalidSchema?: boolean;
|
|
34
|
-
/**
|
|
81
|
+
/** Set to true to collect unknown keywords of input schema in `node.schemaAnnotations`. Defaults to false */
|
|
35
82
|
withSchemaAnnotations?: boolean;
|
|
36
|
-
/**
|
|
83
|
+
/** Set to true to throw an Error when encountering an unresolvable ref */
|
|
37
84
|
throwOnInvalidRef?: boolean;
|
|
38
85
|
};
|
|
39
86
|
|
|
@@ -51,7 +98,7 @@ function getDraft(drafts: Draft[], $schema: string) {
|
|
|
51
98
|
export function compileSchema(schema: JsonSchema | BooleanSchema, options: CompileOptions = {}) {
|
|
52
99
|
let formatAssertion = options.formatAssertion ?? true;
|
|
53
100
|
const drafts = options.drafts ?? defaultDrafts;
|
|
54
|
-
const draft = getDraft(drafts, isJsonSchema(schema) ? schema.$schema : undefined);
|
|
101
|
+
const draft = getDraft(drafts, isJsonSchema(schema) ? (options.draft ?? schema.$schema) : undefined);
|
|
55
102
|
const node: SchemaNode & { schemaErrors?: JsonError[]; schemaAnnotations: JsonAnnotation[] } = {
|
|
56
103
|
evaluationPath: "#",
|
|
57
104
|
lastIdPointer: "#",
|
package/src/draft04.ts
CHANGED
|
@@ -61,8 +61,8 @@ import { uniqueItemsKeyword } from "./keywords/uniqueItems";
|
|
|
61
61
|
*/
|
|
62
62
|
export const draft04 = sanitizeKeywords({
|
|
63
63
|
version: "draft-04",
|
|
64
|
-
$schemaRegEx: "draft
|
|
65
|
-
$schema: "http://json-schema.org/draft-04/schema",
|
|
64
|
+
$schemaRegEx: "draft-?0?4",
|
|
65
|
+
$schema: "http://json-schema.org/draft-04/schema#",
|
|
66
66
|
errors,
|
|
67
67
|
formats,
|
|
68
68
|
methods: {
|
package/src/draft06.ts
CHANGED
|
@@ -62,8 +62,8 @@ import { uniqueItemsKeyword } from "./keywords/uniqueItems";
|
|
|
62
62
|
*/
|
|
63
63
|
export const draft06 = sanitizeKeywords({
|
|
64
64
|
version: "draft-06",
|
|
65
|
-
$schemaRegEx: "draft
|
|
66
|
-
$schema: "http://json-schema.org/draft-06/schema",
|
|
65
|
+
$schemaRegEx: "draft-?0?6",
|
|
66
|
+
$schema: "http://json-schema.org/draft-06/schema#",
|
|
67
67
|
errors,
|
|
68
68
|
formats,
|
|
69
69
|
methods: {
|
package/src/draft07.ts
CHANGED
|
@@ -53,8 +53,8 @@ import { uniqueItemsKeyword } from "./keywords/uniqueItems";
|
|
|
53
53
|
*/
|
|
54
54
|
export const draft07 = sanitizeKeywords({
|
|
55
55
|
version: "draft-07",
|
|
56
|
-
$schemaRegEx: "draft
|
|
57
|
-
$schema: "http://json-schema.org/draft-07/schema",
|
|
56
|
+
$schemaRegEx: "draft-?0?7",
|
|
57
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
58
58
|
errors,
|
|
59
59
|
formats,
|
|
60
60
|
methods: {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Keyword, JsonSchemaValidatorParams, ValidationPath } from "../../Keyword";
|
|
2
2
|
import { resolveUri } from "../../utils/resolveUri";
|
|
3
3
|
import splitRef from "../../utils/splitRef";
|
|
4
|
-
import { omit } from "../../utils/omit";
|
|
5
|
-
import { isObject } from "../../utils/isObject";
|
|
6
4
|
import { validateNode } from "../../validateNode";
|
|
7
5
|
import { isSchemaNode, JsonError, SchemaNode } from "../../types";
|
|
8
6
|
import { get, split } from "@sagold/json-pointer";
|
|
9
|
-
import { reduceRef } from "../../keywords/$ref";
|
|
7
|
+
import { reduceRef, compileNext } from "../../keywords/$ref";
|
|
10
8
|
|
|
11
9
|
export const $refKeyword: Keyword = {
|
|
12
10
|
id: "$ref",
|
|
@@ -132,14 +130,6 @@ function resolveRecursiveRef(node: SchemaNode, path: ValidationPath): SchemaNode
|
|
|
132
130
|
return nextNode;
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
function compileNext(referencedNode: SchemaNode, evaluationPath = referencedNode.evaluationPath) {
|
|
136
|
-
const referencedSchema = isObject(referencedNode.schema)
|
|
137
|
-
? omit(referencedNode.schema, "$id")
|
|
138
|
-
: referencedNode.schema;
|
|
139
|
-
|
|
140
|
-
return referencedNode.compileSchema(referencedSchema, `${evaluationPath}/$ref`, referencedNode.schemaLocation);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
133
|
export default function getRef(node: SchemaNode, $ref = node?.$ref): SchemaNode | JsonError {
|
|
144
134
|
if ($ref == null) {
|
|
145
135
|
return node;
|
|
@@ -147,11 +137,11 @@ export default function getRef(node: SchemaNode, $ref = node?.$ref): SchemaNode
|
|
|
147
137
|
|
|
148
138
|
// resolve $ref by json-evaluationPath
|
|
149
139
|
if (node.context.refs[$ref]) {
|
|
150
|
-
return compileNext(node.context.refs[$ref], node
|
|
140
|
+
return compileNext(node.context.refs[$ref], node);
|
|
151
141
|
}
|
|
152
142
|
// resolve $ref from $anchor
|
|
153
143
|
if (node.context.anchors[$ref]) {
|
|
154
|
-
return compileNext(node.context.anchors[$ref], node
|
|
144
|
+
return compileNext(node.context.anchors[$ref], node);
|
|
155
145
|
}
|
|
156
146
|
|
|
157
147
|
// check for remote-host + pointer pair to switch rootSchema
|
|
@@ -171,7 +161,7 @@ export default function getRef(node: SchemaNode, $ref = node?.$ref): SchemaNode
|
|
|
171
161
|
const $ref = fragments[0];
|
|
172
162
|
// this is a reference to remote-host root node
|
|
173
163
|
if (node.context.remotes[$ref]) {
|
|
174
|
-
return compileNext(node.context.remotes[$ref], node
|
|
164
|
+
return compileNext(node.context.remotes[$ref], node);
|
|
175
165
|
}
|
|
176
166
|
if ($ref[0] === "#") {
|
|
177
167
|
// @todo there is a bug joining multiple fragments to e.g. #/base#/examples/0
|
package/src/draft2019.ts
CHANGED
|
@@ -60,7 +60,7 @@ import { uniqueItemsKeyword } from "./keywords/uniqueItems";
|
|
|
60
60
|
*/
|
|
61
61
|
export const draft2019 = sanitizeKeywords({
|
|
62
62
|
version: "draft-2019-09",
|
|
63
|
-
$schemaRegEx: "draft[/-]2019
|
|
63
|
+
$schemaRegEx: "draft[/-]2019-?(09)?",
|
|
64
64
|
$schema: "https://json-schema.org/draft/2019-09/schema",
|
|
65
65
|
errors,
|
|
66
66
|
formats,
|
package/src/draft2020.ts
CHANGED
|
@@ -70,7 +70,7 @@ import { uniqueItemsKeyword } from "./keywords/uniqueItems";
|
|
|
70
70
|
*/
|
|
71
71
|
export const draft2020 = sanitizeKeywords({
|
|
72
72
|
version: "draft-2020-12",
|
|
73
|
-
$schemaRegEx: "draft[/-]2020
|
|
73
|
+
$schemaRegEx: "draft[/-]2020-?(12)?",
|
|
74
74
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
75
75
|
errors,
|
|
76
76
|
formats,
|
package/src/keywords/$ref.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { validateNode } from "../validateNode";
|
|
|
8
8
|
import { get, split } from "@sagold/json-pointer";
|
|
9
9
|
import { mergeNode } from "../mergeNode";
|
|
10
10
|
import { pick } from "../utils/pick";
|
|
11
|
+
import settings from "src/settings";
|
|
11
12
|
|
|
12
13
|
export const $refKeyword: Keyword = {
|
|
13
14
|
id: "$ref",
|
|
@@ -177,14 +178,12 @@ function resolveRecursiveRef(node: SchemaNode, path: ValidationPath): SchemaNode
|
|
|
177
178
|
return getRef(node, refInCurrentScope);
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
function compileNext(referencedNode: SchemaNode, sourceNode: SchemaNode) {
|
|
181
|
+
export function compileNext(referencedNode: SchemaNode, sourceNode: SchemaNode) {
|
|
183
182
|
let referencedSchema = referencedNode.schema;
|
|
184
183
|
if (isObject(referencedNode.schema)) {
|
|
185
184
|
referencedSchema = {
|
|
186
185
|
...omit(referencedNode.schema, "$id"),
|
|
187
|
-
...pick(sourceNode.schema, ...PROPERTIES_TO_MERGE)
|
|
186
|
+
...pick(sourceNode.schema, ...settings.PROPERTIES_TO_MERGE)
|
|
188
187
|
};
|
|
189
188
|
}
|
|
190
189
|
return referencedNode.compileSchema(
|
|
@@ -483,7 +483,7 @@ describe("keyword : oneof-fuzzy : validate", () => {
|
|
|
483
483
|
required: ["type", "children"],
|
|
484
484
|
properties: {
|
|
485
485
|
type: {
|
|
486
|
-
options: { hidden: true },
|
|
486
|
+
"x-options": { hidden: true },
|
|
487
487
|
type: "string",
|
|
488
488
|
const: "parent"
|
|
489
489
|
},
|
|
@@ -500,7 +500,7 @@ describe("keyword : oneof-fuzzy : validate", () => {
|
|
|
500
500
|
required: ["type"],
|
|
501
501
|
properties: {
|
|
502
502
|
type: {
|
|
503
|
-
options: { hidden: true },
|
|
503
|
+
"x-options": { hidden: true },
|
|
504
504
|
type: "string",
|
|
505
505
|
const: "one"
|
|
506
506
|
}
|
|
@@ -512,7 +512,7 @@ describe("keyword : oneof-fuzzy : validate", () => {
|
|
|
512
512
|
required: ["type"],
|
|
513
513
|
properties: {
|
|
514
514
|
type: {
|
|
515
|
-
options: { hidden: true },
|
|
515
|
+
"x-options": { hidden: true },
|
|
516
516
|
type: "string",
|
|
517
517
|
const: "two"
|
|
518
518
|
}
|
package/src/settings.ts
CHANGED
|
@@ -17,5 +17,31 @@ export default {
|
|
|
17
17
|
"patternProperties",
|
|
18
18
|
"propertyDependencies"
|
|
19
19
|
],
|
|
20
|
-
REGEX_FLAGS: "u"
|
|
20
|
+
REGEX_FLAGS: "u",
|
|
21
|
+
/**
|
|
22
|
+
* properties to keep from a $ref-schema when resolving a $ref (recursively)
|
|
23
|
+
* this allows to overwrite specified properties locally on a $ref-definition
|
|
24
|
+
*
|
|
25
|
+
* - draft 2019-09
|
|
26
|
+
* - draft 2020-12
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* {
|
|
30
|
+
* title: "custom component",
|
|
31
|
+
* $ref: "#/$defs/component",
|
|
32
|
+
*
|
|
33
|
+
* $defs: {
|
|
34
|
+
* component: {
|
|
35
|
+
* title: "component",
|
|
36
|
+
* type: "object"
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* // results in
|
|
41
|
+
* {
|
|
42
|
+
* title: "custom component"
|
|
43
|
+
* type: "object"
|
|
44
|
+
* }
|
|
45
|
+
*/
|
|
46
|
+
PROPERTIES_TO_MERGE: ["title", "description", "options", "x-options", "readOnly", "writeOnly"]
|
|
21
47
|
};
|