json-schema-library 11.0.0 → 11.0.2
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/.vscode/launch.json +37 -0
- package/README.md +4 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +27 -3
- package/dist/index.d.mts +27 -3
- package/dist/index.mjs +1 -1
- package/dist/jlib.js +2 -2
- package/package.json +2 -2
- package/src/SchemaNode.ts +26 -4
- package/src/draftEditor.ts +4 -4
- package/src/errors/errors.ts +3 -2
- package/src/getNode.oneOfProperty.test.ts +43 -0
- package/src/{compileSchema.getNode.test.ts → getNode.test.ts} +1 -1
- package/src/getNode.ts +16 -3
- package/src/getNodeChild.ts +34 -28
- package/src/keywords/oneOf.test.ts +190 -32
- package/src/keywords/oneOf.ts +83 -8
- package/src/keywords/prefixItems.ts +0 -9
- package/src/methods/getChildSelection.test.ts +18 -0
- package/src/methods/getChildSelection.ts +1 -1
- package/src/methods/getData.test.ts +1779 -1781
- package/src/{compileSchema.reduceSchema.test.ts → reduceNode.test.ts} +0 -1
- package/src/{compileSchema.validate.test.ts → validate.test.ts} +1 -1
- /package/src/{compileSchema.getChild.test.ts → getChildNode.test.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-schema-library",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.2",
|
|
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test:6:ci": "DISABLE_LOG=true mocha -R json 'src/tests/spec/draft06.spec.ts' > test-result-spec6.json; exit 0",
|
|
34
34
|
"test:7": "mocha 'src/tests/spec/draft07.spec.ts'",
|
|
35
35
|
"test:7:ci": "DISABLE_LOG=true mocha -R json 'src/tests/spec/draft07.spec.ts' > test-result-spec7.json; exit 0",
|
|
36
|
-
"test:inspect": "
|
|
36
|
+
"test:inspect": "NODE_OPTIONS='--inspect-brk' mocha 'src/**/*.test.ts'",
|
|
37
37
|
"test:spec": "mocha 'src/tests/spec/*.spec.ts'",
|
|
38
38
|
"test:unit": "mocha 'src/**/*.test.ts'",
|
|
39
39
|
"test:unit:ci": "DISABLE_LOG=true mocha -R json 'src/**/*.test.ts' -R json > test-result-unit.json; exit 0"
|
package/src/SchemaNode.ts
CHANGED
|
@@ -38,7 +38,7 @@ import { getNode } from "./getNode";
|
|
|
38
38
|
import { getNodeChild } from "./getNodeChild";
|
|
39
39
|
import { DataNode } from "./methods/toDataNodes";
|
|
40
40
|
|
|
41
|
-
const { DYNAMIC_PROPERTIES, REGEX_FLAGS } = settings;
|
|
41
|
+
const { DYNAMIC_PROPERTIES, REGEX_FLAGS, DECLARATOR_ONEOF } = settings;
|
|
42
42
|
|
|
43
43
|
export function isSchemaNode(value: unknown): value is SchemaNode {
|
|
44
44
|
return isObject(value) && Array.isArray(value?.reducers) && Array.isArray(value?.resolvers);
|
|
@@ -194,12 +194,34 @@ interface SchemaNodeMethodsType {
|
|
|
194
194
|
createAnnotation<T extends string = DefaultErrors>(code: T, data: AnnotationData, message?: string): JsonAnnotation;
|
|
195
195
|
createSchema(data?: unknown): JsonSchema;
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
/**
|
|
198
|
+
* Returns a node matching the given location (pointer) in data
|
|
199
|
+
*
|
|
200
|
+
* - the returned node will have a **reduced schema** based on given input data
|
|
201
|
+
* - return returned node $ref is resolved
|
|
202
|
+
*
|
|
203
|
+
* To resolve dynamic schema where the type of JSON Schema is evaluated by
|
|
204
|
+
* its value, a data object has to be passed in options.
|
|
205
|
+
*
|
|
206
|
+
* Per default this function will return `undefined` schema for valid properties
|
|
207
|
+
* that do not have a defined schema. Use the option `withSchemaWarning: true` to
|
|
208
|
+
* receive an error with `code: schema-warning` containing the location of its
|
|
209
|
+
* last evaluated json-schema.
|
|
210
|
+
*
|
|
211
|
+
* @returns { node } or { error } where node can also be undefined (valid but undefined)
|
|
212
|
+
*/
|
|
198
213
|
getNode(pointer: string, data: unknown, options: { withSchemaWarning: true } & GetNodeOptions): NodeOrError;
|
|
199
214
|
getNode(pointer: string, data: unknown, options: { createSchema: true } & GetNodeOptions): NodeOrError;
|
|
200
215
|
getNode(pointer: string, data?: unknown, options?: GetNodeOptions): OptionalNodeOrError;
|
|
201
216
|
|
|
202
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Returns the child for the given property-name or array-index
|
|
219
|
+
*
|
|
220
|
+
* - the returned child node is **not reduced**
|
|
221
|
+
* - a child node $ref is resolved
|
|
222
|
+
*
|
|
223
|
+
* @returns { node } or { error } where node can also be undefined (valid but undefined)
|
|
224
|
+
*/
|
|
203
225
|
getNodeChild(
|
|
204
226
|
key: string | number,
|
|
205
227
|
data: unknown,
|
|
@@ -431,7 +453,7 @@ export const SchemaNodeMethods = {
|
|
|
431
453
|
}
|
|
432
454
|
|
|
433
455
|
// remove dynamic properties of node
|
|
434
|
-
workingNode.schema = omit(workingNode.schema, ...DYNAMIC_PROPERTIES);
|
|
456
|
+
workingNode.schema = omit(workingNode.schema, DECLARATOR_ONEOF, ...DYNAMIC_PROPERTIES);
|
|
435
457
|
// @ts-expect-error string accessing schema props
|
|
436
458
|
DYNAMIC_PROPERTIES.forEach((prop) => (workingNode[prop] = undefined));
|
|
437
459
|
return { node: workingNode, error: undefined };
|
package/src/draftEditor.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { extendDraft } from "./Draft";
|
|
2
|
-
import {
|
|
2
|
+
import { draft2020 } from "./draft2020";
|
|
3
3
|
import { oneOfFuzzyKeyword } from "./keywords/oneOf";
|
|
4
4
|
import { render } from "./errors/render";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @draft-editor https://json-schema.org/draft/
|
|
7
|
+
* @draft-editor https://json-schema.org/draft/2020-12/release-notes
|
|
8
8
|
*
|
|
9
|
-
* Uses Draft
|
|
9
|
+
* Uses Draft 2020-12 and changes resolveOneOf to be fuzzy
|
|
10
10
|
*/
|
|
11
|
-
export const draftEditor = extendDraft(
|
|
11
|
+
export const draftEditor = extendDraft(draft2020, {
|
|
12
12
|
$schemaRegEx: ".",
|
|
13
13
|
keywords: [oneOfFuzzyKeyword],
|
|
14
14
|
errors: {
|
package/src/errors/errors.ts
CHANGED
|
@@ -45,12 +45,13 @@ export const errors = {
|
|
|
45
45
|
"min-items-one-error": "At least one item is required in `{{pointer}}`",
|
|
46
46
|
"min-length-error": "Value `{{pointer}}` should have a minimum length of `{{minLength}}`, but got `{{length}}`.",
|
|
47
47
|
"min-length-one-error": "A value is required in `{{pointer}}`",
|
|
48
|
-
"missing-one-of-declarator-error": "Missing oneOf declarator `{{declarator}}` in `{{
|
|
48
|
+
"missing-one-of-declarator-error": "Missing oneOf declarator `{{declarator}}` in schema `{{schemaLocation}}`",
|
|
49
49
|
"min-properties-error":
|
|
50
50
|
"Too few properties in `{{pointer}}`, should be at least `{{minProperties}}`, but got `{{length}}`",
|
|
51
51
|
"missing-array-item-error": "Array at '{{pointer}}' has a missing item at '{{key}}'",
|
|
52
52
|
"missing-dependency-error": "The required propery '{{missingProperty}}' in `{{pointer}}` is missing",
|
|
53
|
-
"missing-one-of-property-error":
|
|
53
|
+
"missing-one-of-property-error":
|
|
54
|
+
"Value at `{{pointer}}` must be object or array and have a property ${oneOfProperty}: ${value}",
|
|
54
55
|
"multiple-of-error": "Expected `{{value}}` in `{{pointer}}` to be multiple of `{{multipleOf}}`",
|
|
55
56
|
"multiple-one-of-error": "Value `{{value}}` should not match multiple schemas in oneOf `{{matches}}`",
|
|
56
57
|
"no-additional-properties-error": "Additional property `{{property}}` in `{{pointer}}` is not allowed",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { compileSchema } from "./compileSchema";
|
|
2
|
+
import { strict as assert } from "assert";
|
|
3
|
+
import { isSchemaNode } from "./types";
|
|
4
|
+
import settings from "./settings";
|
|
5
|
+
const DECLARATOR_ONEOF = settings.DECLARATOR_ONEOF;
|
|
6
|
+
|
|
7
|
+
describe("getNodeChild.oneOfProperty", () => {
|
|
8
|
+
describe("", () => {
|
|
9
|
+
it("should return resolved reference (reduced oneOfNode)", () => {
|
|
10
|
+
const node = compileSchema({
|
|
11
|
+
items: {
|
|
12
|
+
[DECLARATOR_ONEOF]: "name",
|
|
13
|
+
oneOf: [{ $ref: "#/$defs/first" }, { $ref: "#/$defs/second" }]
|
|
14
|
+
},
|
|
15
|
+
$defs: {
|
|
16
|
+
first: {
|
|
17
|
+
properties: { name: { type: "string", const: "first" }, title: { type: "number" } }
|
|
18
|
+
},
|
|
19
|
+
second: {
|
|
20
|
+
properties: { name: { type: "string", const: "second" }, title: { type: "number" } }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// precondition
|
|
26
|
+
const reducedItems = node.items?.reduceNode({ name: "second" });
|
|
27
|
+
assert(reducedItems && reducedItems.node, "should have successfully resolved items schema directly");
|
|
28
|
+
assert.deepEqual(
|
|
29
|
+
reducedItems.node?.schema,
|
|
30
|
+
{
|
|
31
|
+
properties: { name: { type: "string", const: "second" }, title: { type: "number" } }
|
|
32
|
+
},
|
|
33
|
+
"should have correctly resolved items-schema directly"
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const { node: res } = node.getNode("#/0", [{ name: "second" }]);
|
|
37
|
+
assert(isSchemaNode(res), "expected result to a node");
|
|
38
|
+
assert.deepEqual(res.schema, {
|
|
39
|
+
properties: { name: { type: "string", const: "second" }, title: { type: "number" } }
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -520,7 +520,7 @@ describe("compileSchema : getNode", () => {
|
|
|
520
520
|
assert.deepEqual(node.schema, { type: "array", minItems: 2 });
|
|
521
521
|
});
|
|
522
522
|
|
|
523
|
-
it("should
|
|
523
|
+
it("should merge title from local schema", () => {
|
|
524
524
|
const { node } = compileSchema({
|
|
525
525
|
type: "array",
|
|
526
526
|
prefixItems: [{ title: "from ref", $ref: "/$defs/target" }],
|
package/src/getNode.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GetNodeOptions, SchemaNode } from "./SchemaNode";
|
|
1
|
+
import { GetNodeOptions, isSchemaNode, SchemaNode } from "./SchemaNode";
|
|
2
2
|
import { isJsonError, NodeOrError, OptionalNodeOrError } from "./types";
|
|
3
3
|
import { split } from "@sagold/json-pointer";
|
|
4
4
|
import { getValue } from "./utils/getValue";
|
|
@@ -7,9 +7,13 @@ import { getValue } from "./utils/getValue";
|
|
|
7
7
|
export function getNode(pointer: string, data: unknown, options: { withSchemaWarning: true } & GetNodeOptions): NodeOrError;
|
|
8
8
|
export function getNode(pointer: string, data: unknown, options: { createSchema: true } & GetNodeOptions): NodeOrError;
|
|
9
9
|
export function getNode(pointer: string, data?: unknown, options?: GetNodeOptions): OptionalNodeOrError;
|
|
10
|
+
|
|
10
11
|
/**
|
|
11
12
|
* Returns a node containing JSON Schema of a data JSON Pointer.
|
|
12
13
|
*
|
|
14
|
+
* - the returned node will have a reduced schema based on given input data
|
|
15
|
+
* - the returned node $ref is resolved
|
|
16
|
+
*
|
|
13
17
|
* To resolve dynamic schema where the type of JSON Schema is evaluated by
|
|
14
18
|
* its value, a data object has to be passed in options.
|
|
15
19
|
*
|
|
@@ -49,6 +53,15 @@ export function getNode(
|
|
|
49
53
|
currentNode = result.node;
|
|
50
54
|
data = getValue(data, keys[i]);
|
|
51
55
|
}
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
|
|
57
|
+
const { node: reducedNode, error: reduceError } = currentNode.resolveRef(options).reduceNode(data);
|
|
58
|
+
|
|
59
|
+
if (isJsonError(reduceError)) {
|
|
60
|
+
return { node: undefined, error: reduceError };
|
|
61
|
+
}
|
|
62
|
+
if (isSchemaNode(reducedNode)) {
|
|
63
|
+
return { node: reducedNode, error: undefined };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { error: undefined };
|
|
54
67
|
}
|
package/src/getNodeChild.ts
CHANGED
|
@@ -2,67 +2,73 @@ import { GetNodeOptions, isSchemaNode, SchemaNode } from "./SchemaNode";
|
|
|
2
2
|
import { isJsonError, NodeOrError, OptionalNodeOrError } from "./types";
|
|
3
3
|
import { getValue } from "./utils/getValue";
|
|
4
4
|
|
|
5
|
-
// prettier-ignore
|
|
6
|
-
export function getNodeChild(key: string | number, data: unknown, options: {
|
|
7
|
-
// prettier-ignore
|
|
8
|
-
export function getNodeChild(key: string | number, data: unknown, options: { createSchema: true } & GetNodeOptions): NodeOrError;
|
|
5
|
+
export function getNodeChild(key: string | number, data: unknown, options: { withSchemaWarning: true } & GetNodeOptions): NodeOrError; // prettier-ignore
|
|
6
|
+
export function getNodeChild(key: string | number, data: unknown, options: { createSchema: true } & GetNodeOptions): NodeOrError; // prettier-ignore
|
|
9
7
|
export function getNodeChild(key: string | number, data?: unknown, options?: GetNodeOptions): OptionalNodeOrError;
|
|
10
8
|
|
|
11
9
|
/**
|
|
12
|
-
*
|
|
10
|
+
* Returns the child for the given property-name or array-index
|
|
11
|
+
*
|
|
12
|
+
* - the returned child node is **not reduced**
|
|
13
|
+
* - a child node $ref is resolved
|
|
14
|
+
*
|
|
15
|
+
* @returns { node } or { error } where node can also be undefined (valid but undefined)
|
|
13
16
|
*/
|
|
14
17
|
export function getNodeChild(
|
|
15
18
|
key: string | number,
|
|
16
19
|
data?: unknown,
|
|
17
20
|
options: GetNodeOptions = {}
|
|
18
|
-
): OptionalNodeOrError | NodeOrError
|
|
21
|
+
): OptionalNodeOrError | NodeOrError {
|
|
19
22
|
options.path = options.path ?? [];
|
|
20
|
-
|
|
21
23
|
options.withSchemaWarning = options.withSchemaWarning ?? false;
|
|
22
24
|
options.pointer = options.pointer ?? "#";
|
|
23
25
|
const { path, pointer } = options;
|
|
24
26
|
|
|
27
|
+
// reduce parent
|
|
25
28
|
// @ts-expect-error implicitely any
|
|
26
|
-
let
|
|
27
|
-
if (
|
|
28
|
-
const result =
|
|
29
|
+
let parentNode = this as SchemaNode;
|
|
30
|
+
if (parentNode.reducers.length) {
|
|
31
|
+
const result = parentNode.reduceNode(data, { key, path, pointer });
|
|
29
32
|
if (result.error) {
|
|
30
33
|
return result;
|
|
31
34
|
}
|
|
32
35
|
if (isSchemaNode(result.node)) {
|
|
33
|
-
|
|
36
|
+
parentNode = result.node;
|
|
34
37
|
}
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
40
|
+
// find child node
|
|
41
|
+
for (const resolver of parentNode.resolvers) {
|
|
42
|
+
const schemaNode = resolver({ data, key, node: parentNode });
|
|
43
|
+
// a matching resolver found an error, return
|
|
42
44
|
if (isJsonError(schemaNode)) {
|
|
43
45
|
return { node: undefined, error: schemaNode };
|
|
44
46
|
}
|
|
47
|
+
// a matching resolver found a child node, return
|
|
48
|
+
if (isSchemaNode(schemaNode)) {
|
|
49
|
+
return { node: schemaNode.resolveRef({ pointer, path }), error: undefined };
|
|
50
|
+
}
|
|
45
51
|
}
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
if (referencedNode !== node) {
|
|
49
|
-
return referencedNode.getNodeChild(key, data, options);
|
|
50
|
-
}
|
|
51
|
-
|
|
53
|
+
// no child node was found, but the child node is valid
|
|
52
54
|
if (options.createSchema === true) {
|
|
53
|
-
const newNode =
|
|
54
|
-
|
|
55
|
-
`${
|
|
56
|
-
`${
|
|
55
|
+
const newNode = parentNode.compileSchema(
|
|
56
|
+
parentNode.createSchema(getValue(data, key)),
|
|
57
|
+
`${parentNode.evaluationPath}/additional`,
|
|
58
|
+
`${parentNode.schemaLocation}/additional`
|
|
57
59
|
);
|
|
58
60
|
return { node: newNode, error: undefined };
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
if (options.withSchemaWarning === true) {
|
|
62
|
-
const error =
|
|
64
|
+
const error = parentNode.createError("schema-warning", {
|
|
65
|
+
pointer,
|
|
66
|
+
value: data,
|
|
67
|
+
schema: parentNode.schema,
|
|
68
|
+
key
|
|
69
|
+
});
|
|
63
70
|
return { node: undefined, error };
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
return {};
|
|
73
|
+
return { node: undefined };
|
|
68
74
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { strict as assert } from "assert";
|
|
2
2
|
import { compileSchema } from "../compileSchema";
|
|
3
|
-
import { isJsonError } from "../types";
|
|
3
|
+
import { isJsonError, isSchemaNode } from "../types";
|
|
4
4
|
import { reduceOneOfDeclarator, reduceOneOfFuzzy } from "./oneOf";
|
|
5
5
|
import settings from "../settings";
|
|
6
|
+
import { draftEditor } from "../draftEditor";
|
|
6
7
|
const DECLARATOR_ONEOF = settings.DECLARATOR_ONEOF;
|
|
7
8
|
|
|
8
9
|
describe("keyword : oneof : validate", () => {
|
|
@@ -38,7 +39,7 @@ describe("keyword : oneOf : reduce", () => {
|
|
|
38
39
|
]
|
|
39
40
|
}).reduceNode(111);
|
|
40
41
|
|
|
41
|
-
assert.deepEqual(node
|
|
42
|
+
assert.deepEqual(node?.schema, { type: "number", title: "A Number" });
|
|
42
43
|
assert.equal(node.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
43
44
|
});
|
|
44
45
|
|
|
@@ -72,7 +73,7 @@ describe("keyword : oneOf : reduce", () => {
|
|
|
72
73
|
oneOf: [{ required: ["a"], properties: { a: { type: "string" } } }, { $ref: "#/$defs/withData" }]
|
|
73
74
|
}).reduceNode({ b: 111 });
|
|
74
75
|
|
|
75
|
-
assert.deepEqual(node
|
|
76
|
+
assert.deepEqual(node?.schema, { required: ["b"], properties: { b: { type: "number" } } });
|
|
76
77
|
// @note that we override nested oneOfIndex
|
|
77
78
|
assert.equal(node.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
78
79
|
});
|
|
@@ -83,7 +84,7 @@ describe("keyword : oneOf : reduce", () => {
|
|
|
83
84
|
oneOf: [{ required: ["a"], properties: { a: false } }, { $ref: "#/$defs/withData" }]
|
|
84
85
|
}).reduceNode({ b: 111 });
|
|
85
86
|
|
|
86
|
-
assert.deepEqual(node
|
|
87
|
+
assert.deepEqual(node?.schema, { required: ["b"], properties: { b: true } });
|
|
87
88
|
assert.equal(node.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
88
89
|
});
|
|
89
90
|
|
|
@@ -101,7 +102,7 @@ describe("keyword : oneOf : reduce", () => {
|
|
|
101
102
|
]
|
|
102
103
|
}).reduceNode({ title: 4 });
|
|
103
104
|
|
|
104
|
-
assert.deepEqual(node
|
|
105
|
+
assert.deepEqual(node?.schema, { type: "object", properties: { title: { type: "number" } } });
|
|
105
106
|
assert.equal(node.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
106
107
|
});
|
|
107
108
|
|
|
@@ -119,7 +120,7 @@ describe("keyword : oneOf : reduce", () => {
|
|
|
119
120
|
]
|
|
120
121
|
}).reduceNode({ title: 4, test: 2 });
|
|
121
122
|
|
|
122
|
-
assert.deepEqual(node
|
|
123
|
+
assert.deepEqual(node?.schema, { type: "object", additionalProperties: { type: "number" } });
|
|
123
124
|
assert.equal(node.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
124
125
|
});
|
|
125
126
|
});
|
|
@@ -130,7 +131,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
130
131
|
oneOf: [{ type: "string" }, { type: "number" }, { type: "object" }]
|
|
131
132
|
});
|
|
132
133
|
const res = reduceOneOfFuzzy({ node, data: 4, pointer: "#", path: [] });
|
|
133
|
-
assert.deepEqual(res
|
|
134
|
+
assert.deepEqual(res?.schema, { type: "number" });
|
|
134
135
|
assert.equal(res.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
135
136
|
});
|
|
136
137
|
|
|
@@ -142,7 +143,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
142
143
|
]
|
|
143
144
|
});
|
|
144
145
|
const res = reduceOneOfFuzzy({ node, data: "anasterixcame", pointer: "#", path: [] });
|
|
145
|
-
assert.deepEqual(res
|
|
146
|
+
assert.deepEqual(res?.schema, { type: "string", pattern: "asterix" });
|
|
146
147
|
assert.equal(res.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
147
148
|
});
|
|
148
149
|
|
|
@@ -155,7 +156,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
155
156
|
oneOf: [{ $ref: "#/definitions/a" }, { $ref: "#/definitions/b" }]
|
|
156
157
|
});
|
|
157
158
|
const res = reduceOneOfFuzzy({ node, data: "anasterixcame", pointer: "#", path: [] });
|
|
158
|
-
assert.deepEqual(res
|
|
159
|
+
assert.deepEqual(res?.schema, { type: "string", pattern: "asterix" });
|
|
159
160
|
assert.equal(res.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
160
161
|
});
|
|
161
162
|
|
|
@@ -169,7 +170,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
169
170
|
]
|
|
170
171
|
});
|
|
171
172
|
const res = reduceOneOfFuzzy({ node, data: { description: "..." }, pointer: "#", path: [] });
|
|
172
|
-
assert.deepEqual(res
|
|
173
|
+
assert.deepEqual(res?.schema, {
|
|
173
174
|
type: "object",
|
|
174
175
|
properties: { description: { type: "string" } }
|
|
175
176
|
});
|
|
@@ -183,7 +184,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
183
184
|
]
|
|
184
185
|
});
|
|
185
186
|
const res = reduceOneOfFuzzy({ node, data: { title: "asterix" }, pointer: "#", path: [] });
|
|
186
|
-
assert.deepEqual(res
|
|
187
|
+
assert.deepEqual(res?.schema, {
|
|
187
188
|
type: "object",
|
|
188
189
|
properties: { title: { type: "string" } }
|
|
189
190
|
});
|
|
@@ -199,7 +200,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
199
200
|
]
|
|
200
201
|
});
|
|
201
202
|
const res = reduceOneOfFuzzy({ node, data: { a: 0, b: 1 }, pointer: "#", path: [] });
|
|
202
|
-
assert.deepEqual(res
|
|
203
|
+
assert.deepEqual(res?.schema, {
|
|
203
204
|
type: "object",
|
|
204
205
|
properties: { a: t, b: t, c: t }
|
|
205
206
|
});
|
|
@@ -216,7 +217,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
216
217
|
]
|
|
217
218
|
});
|
|
218
219
|
const res = reduceOneOfFuzzy({ node, data: { a: true, b: 1 }, pointer: "#", path: [] });
|
|
219
|
-
assert.deepEqual(res
|
|
220
|
+
assert.deepEqual(res?.schema, {
|
|
220
221
|
type: "object",
|
|
221
222
|
properties: { a: { type: "boolean" }, b: t, d: t }
|
|
222
223
|
});
|
|
@@ -252,7 +253,7 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
252
253
|
node,
|
|
253
254
|
data: { type: "teaser", redirectUrl: "http://example.com/test/pay/article.html" }
|
|
254
255
|
});
|
|
255
|
-
assert.deepEqual(res
|
|
256
|
+
assert.deepEqual(res?.schema, {
|
|
256
257
|
type: "object",
|
|
257
258
|
properties: {
|
|
258
259
|
redirectUrl: { format: "url", type: "string" },
|
|
@@ -284,7 +285,7 @@ describe("keyword : oneof-property : reduce", () => {
|
|
|
284
285
|
]
|
|
285
286
|
});
|
|
286
287
|
const res = reduceOneOfDeclarator({ node, data: { name: "2", title: 123 }, pointer: "#", path: [] });
|
|
287
|
-
assert.deepEqual(res
|
|
288
|
+
assert.deepEqual(res?.schema, {
|
|
288
289
|
type: "object",
|
|
289
290
|
properties: {
|
|
290
291
|
name: { type: "string", pattern: "^2$" },
|
|
@@ -318,7 +319,7 @@ describe("keyword : oneof-property : reduce", () => {
|
|
|
318
319
|
pointer: "#",
|
|
319
320
|
path: []
|
|
320
321
|
});
|
|
321
|
-
assert.deepEqual(res
|
|
322
|
+
assert.deepEqual(res?.schema, {
|
|
322
323
|
type: "object",
|
|
323
324
|
properties: {
|
|
324
325
|
name: { type: "string", pattern: "^2$" },
|
|
@@ -349,31 +350,188 @@ describe("keyword : oneof-property : reduce", () => {
|
|
|
349
350
|
assert(isJsonError(res), "expected result to be an error");
|
|
350
351
|
assert.deepEqual(res.code, "missing-one-of-property-error");
|
|
351
352
|
});
|
|
352
|
-
});
|
|
353
353
|
|
|
354
|
-
|
|
355
|
-
it("should return an error if no oneOfProperty could be matched", () => {
|
|
354
|
+
it("should return correct reference", () => {
|
|
356
355
|
const node = compileSchema({
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
properties: {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
356
|
+
[DECLARATOR_ONEOF]: "name",
|
|
357
|
+
oneOf: [{ $ref: "#/$defs/first" }, { $ref: "#/$defs/second" }],
|
|
358
|
+
$defs: {
|
|
359
|
+
first: {
|
|
360
|
+
properties: { name: { type: "string", const: "first" }, title: { type: "number" } }
|
|
361
|
+
},
|
|
362
|
+
second: {
|
|
363
|
+
properties: { name: { type: "string", const: "second" }, title: { type: "number" } }
|
|
366
364
|
}
|
|
367
|
-
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
const res = reduceOneOfDeclarator({ node, data: { name: "second" }, pointer: "#", path: [] });
|
|
368
|
+
assert(isSchemaNode(res), "expected result to be a node");
|
|
369
|
+
assert.deepEqual(res.schema, {
|
|
370
|
+
properties: { name: { type: "string", const: "second" }, title: { type: "number" } }
|
|
371
|
+
});
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("should return correct reference even if data is not fully valid", () => {
|
|
375
|
+
const node = compileSchema({
|
|
376
|
+
[DECLARATOR_ONEOF]: "name",
|
|
377
|
+
oneOf: [{ $ref: "#/$defs/first" }, { $ref: "#/$defs/second" }],
|
|
378
|
+
$defs: {
|
|
379
|
+
first: {
|
|
380
|
+
properties: { name: { type: "string", const: "first" }, title: { type: "number" } }
|
|
381
|
+
},
|
|
382
|
+
second: {
|
|
383
|
+
properties: { name: { type: "string", const: "second" }, title: { type: "number" } }
|
|
384
|
+
}
|
|
385
|
+
}
|
|
368
386
|
});
|
|
369
387
|
const res = reduceOneOfDeclarator({
|
|
370
388
|
node,
|
|
371
|
-
data: { name: "
|
|
389
|
+
data: { name: "first", title: "not a number" },
|
|
372
390
|
pointer: "#",
|
|
373
391
|
path: []
|
|
374
392
|
});
|
|
375
|
-
assert(
|
|
376
|
-
assert.deepEqual(res.
|
|
393
|
+
assert(isSchemaNode(res), "expected result to be a node");
|
|
394
|
+
assert.deepEqual(res.schema, {
|
|
395
|
+
properties: { name: { type: "string", const: "first" }, title: { type: "number" } }
|
|
396
|
+
});
|
|
377
397
|
});
|
|
378
398
|
});
|
|
399
|
+
|
|
400
|
+
describe("array", () => {
|
|
401
|
+
// TODO test access on array-item as oneOfProperty id (oneOfProperty: "0")
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
describe("keyword : oneof-fuzzy : validate", () => {
|
|
406
|
+
it("should return one-of-error oneOfProperty does not match", () => {
|
|
407
|
+
const node = compileSchema(
|
|
408
|
+
{
|
|
409
|
+
type: "array",
|
|
410
|
+
items: {
|
|
411
|
+
oneOfProperty: "id",
|
|
412
|
+
oneOf: [
|
|
413
|
+
{
|
|
414
|
+
type: "object",
|
|
415
|
+
required: ["id"],
|
|
416
|
+
properties: { id: { const: "one" } }
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
type: "object",
|
|
420
|
+
required: ["id"],
|
|
421
|
+
properties: { id: { const: "two" } }
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
{ drafts: [draftEditor] }
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
const { errors } = node.validate([{ id: "unknown" }]);
|
|
430
|
+
|
|
431
|
+
assert.equal(errors.length, 1);
|
|
432
|
+
assert.deepEqual(errors[0].code, "one-of-error");
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it("should return validation errors of object identified by oneOfProperty", () => {
|
|
436
|
+
const node = compileSchema(
|
|
437
|
+
{
|
|
438
|
+
type: "array",
|
|
439
|
+
items: {
|
|
440
|
+
oneOfProperty: "id",
|
|
441
|
+
oneOf: [
|
|
442
|
+
{
|
|
443
|
+
type: "object",
|
|
444
|
+
required: ["id"],
|
|
445
|
+
properties: {
|
|
446
|
+
id: { const: "one" },
|
|
447
|
+
title: { type: "string" }
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
{ drafts: [draftEditor] }
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
const { errors } = node.validate([{ id: "one", title: 123 }]);
|
|
457
|
+
|
|
458
|
+
assert.equal(errors.length, 1);
|
|
459
|
+
assert.deepEqual(errors[0].code, "type-error");
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// issue json-editor
|
|
463
|
+
it("should return unique-items error for failed oneOf item", () => {
|
|
464
|
+
const node = compileSchema(
|
|
465
|
+
{
|
|
466
|
+
type: "object",
|
|
467
|
+
required: ["main"],
|
|
468
|
+
properties: {
|
|
469
|
+
main: {
|
|
470
|
+
type: "array",
|
|
471
|
+
items: {
|
|
472
|
+
oneOfProperty: "type",
|
|
473
|
+
oneOf: [{ $ref: "#/$defs/parent" }]
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
},
|
|
477
|
+
$defs: {
|
|
478
|
+
parent: {
|
|
479
|
+
type: "object",
|
|
480
|
+
title: "Parent",
|
|
481
|
+
description:
|
|
482
|
+
"Adding a duplicate item to this list fails as uniqueItems=true in children. @todo correct error message",
|
|
483
|
+
required: ["type", "children"],
|
|
484
|
+
properties: {
|
|
485
|
+
type: {
|
|
486
|
+
options: { hidden: true },
|
|
487
|
+
type: "string",
|
|
488
|
+
const: "parent"
|
|
489
|
+
},
|
|
490
|
+
children: {
|
|
491
|
+
type: "array",
|
|
492
|
+
title: "Children",
|
|
493
|
+
uniqueItems: true,
|
|
494
|
+
items: {
|
|
495
|
+
oneOfProperty: "type",
|
|
496
|
+
oneOf: [
|
|
497
|
+
{
|
|
498
|
+
type: "object",
|
|
499
|
+
title: "Child: First",
|
|
500
|
+
required: ["type"],
|
|
501
|
+
properties: {
|
|
502
|
+
type: {
|
|
503
|
+
options: { hidden: true },
|
|
504
|
+
type: "string",
|
|
505
|
+
const: "one"
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
type: "object",
|
|
511
|
+
title: "Child: Second",
|
|
512
|
+
required: ["type"],
|
|
513
|
+
properties: {
|
|
514
|
+
type: {
|
|
515
|
+
options: { hidden: true },
|
|
516
|
+
type: "string",
|
|
517
|
+
const: "two"
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
]
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
{ drafts: [draftEditor] }
|
|
529
|
+
);
|
|
530
|
+
const { errors } = node.validate({
|
|
531
|
+
main: [{ type: "parent", children: [{ type: "one" }, { type: "one" }] }]
|
|
532
|
+
});
|
|
533
|
+
assert.equal(errors.length, 1);
|
|
534
|
+
assert.deepEqual(errors[0].data.pointer, "#/main/0/children/1");
|
|
535
|
+
assert.deepEqual(errors[0].code, "unique-items-error");
|
|
536
|
+
});
|
|
379
537
|
});
|