json-schema-library 10.4.2 → 10.5.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/dist/index.d.mts +12 -13
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/jlib.js +2 -2
- package/package.json +1 -1
- package/src/SchemaNode.ts +2 -1
- package/src/draft2019-09/keywords/$ref.ts +1 -1
- package/src/draft2019-09/methods/getData.ts +3 -3
- package/src/keywords/enum.test.ts +19 -0
- package/src/keywords/enum.ts +2 -1
- package/src/utils/getSchemaType.test.ts +108 -0
- package/src/utils/getSchemaType.ts +26 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "json-schema-library",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.5.0",
|
|
4
4
|
"description": "Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
package/src/SchemaNode.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { validateNode } from "./validateNode";
|
|
|
18
18
|
import { hasProperty } from "./utils/hasProperty";
|
|
19
19
|
import { getNode } from "./getNode";
|
|
20
20
|
import { getNodeChild } from "./getNodeChild";
|
|
21
|
+
import { DataNode } from "./methods/toDataNodes";
|
|
21
22
|
|
|
22
23
|
const { DYNAMIC_PROPERTIES, REGEX_FLAGS } = settings;
|
|
23
24
|
|
|
@@ -435,7 +436,7 @@ export const SchemaNodeMethods = {
|
|
|
435
436
|
/**
|
|
436
437
|
* @returns a list of values (including objects and arrays) and their corresponding JSON Schema as SchemaNode
|
|
437
438
|
*/
|
|
438
|
-
toDataNodes(data: unknown, pointer?: string) {
|
|
439
|
+
toDataNodes(data: unknown, pointer?: string): DataNode[] {
|
|
439
440
|
const node = this as SchemaNode;
|
|
440
441
|
return node.context.methods.toDataNodes(node, data, pointer);
|
|
441
442
|
},
|
|
@@ -72,7 +72,7 @@ export function parseRef(node: SchemaNode) {
|
|
|
72
72
|
export function resolveRef({ pointer, path }: { pointer?: string; path?: ValidationPath } = {}) {
|
|
73
73
|
const node = this as SchemaNode;
|
|
74
74
|
if (node.schema.$recursiveRef) {
|
|
75
|
-
const nextNode = resolveRecursiveRef(node, path);
|
|
75
|
+
const nextNode = resolveRecursiveRef(node, path ?? []);
|
|
76
76
|
path?.push({ pointer, node: nextNode });
|
|
77
77
|
return nextNode;
|
|
78
78
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import copy from "fast-copy";
|
|
2
2
|
import { getTypeOf } from "../../utils/getTypeOf";
|
|
3
|
-
import { getSchemaType } from "../../utils/getSchemaType";
|
|
3
|
+
import { getSchemaType, SchemaType } from "../../utils/getSchemaType";
|
|
4
4
|
import { getValue } from "../../utils/getValue";
|
|
5
5
|
import { isEmpty } from "../../utils/isEmpty";
|
|
6
6
|
import { isJsonError } from "../../types";
|
|
@@ -172,11 +172,11 @@ export function getData(node: SchemaNode, data?: unknown, opts?: TemplateOptions
|
|
|
172
172
|
// }
|
|
173
173
|
|
|
174
174
|
const type = getSchemaType(currentNode, defaultData);
|
|
175
|
-
const templateData = TYPE[type
|
|
175
|
+
const templateData = TYPE[type]?.(currentNode, defaultData, opts);
|
|
176
176
|
return templateData === undefined ? defaultData : templateData;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
const TYPE: Record<
|
|
179
|
+
const TYPE: Record<SchemaType, (node: SchemaNode, data: unknown, opts: TemplateOptions) => unknown> = {
|
|
180
180
|
null: (node, data, opts) => getDefault(node, data, null, opts.useTypeDefaults),
|
|
181
181
|
string: (node, data, opts) => getDefault(node, data, "", opts.useTypeDefaults),
|
|
182
182
|
number: (node, data, opts) => getDefault(node, data, 0, opts.useTypeDefaults),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { strict as assert } from "assert";
|
|
2
|
+
|
|
3
|
+
import { compileSchema } from "../compileSchema";
|
|
4
|
+
|
|
5
|
+
describe("keyword : enum : validate", () => {
|
|
6
|
+
it("should return error of type enum-error", () => {
|
|
7
|
+
const node = compileSchema({
|
|
8
|
+
type: "string",
|
|
9
|
+
enum: ["a", "b"]
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const { errors } = node.validate("c");
|
|
13
|
+
|
|
14
|
+
assert.deepEqual(errors.length, 1, "should have returned a single error");
|
|
15
|
+
const [err] = errors;
|
|
16
|
+
assert.deepEqual(err.code, "enum-error");
|
|
17
|
+
assert(err.message.includes(JSON.stringify(["a", "b"])), "error message should mentioned valid values");
|
|
18
|
+
});
|
|
19
|
+
});
|
package/src/keywords/enum.ts
CHANGED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { compileSchema } from "../compileSchema";
|
|
2
|
+
import { getSchemaType } from "./getSchemaType";
|
|
3
|
+
import { strict as assert } from "assert";
|
|
4
|
+
|
|
5
|
+
describe("getSchemaType", () => {
|
|
6
|
+
it("should get correct type for simple ref", () => {
|
|
7
|
+
const schema = compileSchema({
|
|
8
|
+
type: "object",
|
|
9
|
+
$defs: {
|
|
10
|
+
customConst: {
|
|
11
|
+
type: "string"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
properties: {
|
|
15
|
+
name: { $ref: "#/$defs/customConst" }
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
const nameProp = schema.getNodeChild("name").node;
|
|
19
|
+
assert(nameProp != null);
|
|
20
|
+
|
|
21
|
+
assert.equal(getSchemaType(nameProp, undefined), "string");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should handle oneOf refs", () => {
|
|
25
|
+
const schema = compileSchema({
|
|
26
|
+
type: "object",
|
|
27
|
+
$defs: {
|
|
28
|
+
a: {
|
|
29
|
+
type: "string",
|
|
30
|
+
const: "a"
|
|
31
|
+
},
|
|
32
|
+
b: {
|
|
33
|
+
type: "string",
|
|
34
|
+
const: "b"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
properties: {
|
|
39
|
+
oneOf: {
|
|
40
|
+
oneOf: [{ $ref: "#/$defs/a" }, { $ref: "#/$defs/b" }]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const oneOfProp = schema.getNodeChild("oneOf").node;
|
|
45
|
+
assert(oneOfProp != null);
|
|
46
|
+
|
|
47
|
+
assert.equal(getSchemaType(oneOfProp, undefined), "string");
|
|
48
|
+
});
|
|
49
|
+
it("should handle anyOf refs", () => {
|
|
50
|
+
const schema = compileSchema({
|
|
51
|
+
type: "object",
|
|
52
|
+
$defs: {
|
|
53
|
+
a: { type: "string", const: "a" },
|
|
54
|
+
b: { type: "string", const: "b" }
|
|
55
|
+
},
|
|
56
|
+
properties: {
|
|
57
|
+
anyOf: {
|
|
58
|
+
anyOf: [{ $ref: "#/$defs/a" }, { $ref: "#/$defs/b" }]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const anyOfProp = schema.getNodeChild("anyOf").node;
|
|
63
|
+
assert(anyOfProp != null);
|
|
64
|
+
|
|
65
|
+
assert.equal(getSchemaType(anyOfProp, undefined), "string");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should handle allOf refs", () => {
|
|
69
|
+
const schema = compileSchema({
|
|
70
|
+
type: "object",
|
|
71
|
+
$defs: {
|
|
72
|
+
a: { type: "object", properties: { a: { type: "string" } } },
|
|
73
|
+
b: { type: "object", properties: { b: { type: "string" } } }
|
|
74
|
+
},
|
|
75
|
+
properties: {
|
|
76
|
+
allOf: {
|
|
77
|
+
allOf: [{ $ref: "#/$defs/a" }, { $ref: "#/$defs/b" }]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const allOfProp = schema.getNodeChild("allOf").node;
|
|
82
|
+
assert(allOfProp != null);
|
|
83
|
+
|
|
84
|
+
assert.equal(getSchemaType(allOfProp, undefined), "object");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should handle if/then/else refs", () => {
|
|
88
|
+
const schema = compileSchema({
|
|
89
|
+
type: "object",
|
|
90
|
+
$defs: {
|
|
91
|
+
stringSchema: {
|
|
92
|
+
type: "string"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
properties: {
|
|
96
|
+
conditional: {
|
|
97
|
+
if: { $ref: "#/$defs/stringSchema" },
|
|
98
|
+
then: { minLength: 5 },
|
|
99
|
+
else: { maxLength: 2 }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const conditionalProp = schema.getNodeChild("conditional").node;
|
|
104
|
+
assert(conditionalProp != null);
|
|
105
|
+
|
|
106
|
+
assert.equal(getSchemaType(conditionalProp, undefined), "string");
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -2,7 +2,8 @@ import { getTypeOf } from "./getTypeOf";
|
|
|
2
2
|
import { isObject } from "../utils/isObject";
|
|
3
3
|
import { BooleanSchema, JsonSchema, SchemaNode } from "../types";
|
|
4
4
|
|
|
5
|
-
export const SCHEMA_TYPES = ["string", "number", "integer", "boolean", "null", "array", "object"];
|
|
5
|
+
export const SCHEMA_TYPES = ["string", "number", "integer", "boolean", "null", "array", "object"] as const;
|
|
6
|
+
export type SchemaType = (typeof SCHEMA_TYPES)[number];
|
|
6
7
|
const OBJECT_PROPERTIES = [
|
|
7
8
|
"additionalProperties",
|
|
8
9
|
// "allOf",
|
|
@@ -43,11 +44,14 @@ const ARRAY_PROPERTIES = [
|
|
|
43
44
|
* returns schema type, which might be an educated guess based on defined schema
|
|
44
45
|
* properties if an exact type cannot be retried from type.
|
|
45
46
|
*/
|
|
46
|
-
export function getSchemaType(node: SchemaNode, data: unknown):
|
|
47
|
+
export function getSchemaType(node: SchemaNode, data: unknown): SchemaType | undefined {
|
|
47
48
|
const dataType = getTypeOf(data);
|
|
48
49
|
const schema = node.schema as JsonSchema | BooleanSchema;
|
|
49
50
|
if (schema === true) {
|
|
50
|
-
|
|
51
|
+
if (dataType === "bigint") {
|
|
52
|
+
return "number";
|
|
53
|
+
}
|
|
54
|
+
return SCHEMA_TYPES.some((schemaType) => schemaType === dataType) ? (dataType as SchemaType) : undefined;
|
|
51
55
|
}
|
|
52
56
|
// boolean schema false or invalid schema
|
|
53
57
|
if (!isObject(schema)) {
|
|
@@ -58,18 +62,18 @@ export function getSchemaType(node: SchemaNode, data: unknown): keyof typeof SCH
|
|
|
58
62
|
// type: []
|
|
59
63
|
if (Array.isArray(schemaType)) {
|
|
60
64
|
if (schemaType.includes(dataType)) {
|
|
61
|
-
return dataType as
|
|
65
|
+
return dataType as SchemaType;
|
|
62
66
|
}
|
|
63
67
|
const defaultType = getTypeOf(schema.default);
|
|
64
68
|
if (schemaType.includes(defaultType)) {
|
|
65
|
-
return defaultType as
|
|
69
|
+
return defaultType as SchemaType;
|
|
66
70
|
}
|
|
67
71
|
return schemaType[0];
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
// type: ""
|
|
71
75
|
if (schemaType) {
|
|
72
|
-
return schemaType as
|
|
76
|
+
return schemaType as SchemaType;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
// type: undefined, enum: []
|
|
@@ -77,13 +81,13 @@ export function getSchemaType(node: SchemaNode, data: unknown): keyof typeof SCH
|
|
|
77
81
|
const schemaEnum: unknown[] = schema.enum;
|
|
78
82
|
const enumSchemaType = schemaEnum.map((value) => getTypeOf(value)).filter((p, i, l) => l.indexOf(p) === i);
|
|
79
83
|
if (enumSchemaType.includes(dataType)) {
|
|
80
|
-
return dataType as
|
|
84
|
+
return dataType as SchemaType;
|
|
81
85
|
}
|
|
82
86
|
const defaultType = getTypeOf(schema.default);
|
|
83
87
|
if (enumSchemaType.includes(defaultType)) {
|
|
84
|
-
return defaultType as
|
|
88
|
+
return defaultType as SchemaType;
|
|
85
89
|
}
|
|
86
|
-
return enumSchemaType[0] as
|
|
90
|
+
return enumSchemaType[0] as SchemaType;
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
// type: undefined, enum: undefined -- define type by schema-properties
|
|
@@ -93,21 +97,21 @@ export function getSchemaType(node: SchemaNode, data: unknown): keyof typeof SCH
|
|
|
93
97
|
const arrayProperties = schemaProperties.filter((p) => ARRAY_PROPERTIES.includes(p));
|
|
94
98
|
|
|
95
99
|
if (objectProperties.length > 0 && objectProperties.length > arrayProperties.length) {
|
|
96
|
-
return "object"
|
|
100
|
+
return "object";
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
if (arrayProperties.length > 0 && arrayProperties.length > objectProperties.length) {
|
|
100
|
-
return "array"
|
|
104
|
+
return "array";
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
// nothing found yet check dynamic properties for a type
|
|
104
108
|
if (node.if) {
|
|
105
|
-
return getSchemaType(node.if, data);
|
|
109
|
+
return getSchemaType(node.if.resolveRef?.() ?? node.if, data);
|
|
106
110
|
}
|
|
107
111
|
|
|
108
112
|
if (node.allOf) {
|
|
109
113
|
for (let i = 0; i < node.allOf.length; i += 1) {
|
|
110
|
-
const type = getSchemaType(node.allOf[i], data);
|
|
114
|
+
const type = getSchemaType(node.allOf[i].resolveRef?.() ?? node.allOf[i], data);
|
|
111
115
|
if (type) {
|
|
112
116
|
return type;
|
|
113
117
|
}
|
|
@@ -116,7 +120,7 @@ export function getSchemaType(node: SchemaNode, data: unknown): keyof typeof SCH
|
|
|
116
120
|
|
|
117
121
|
if (node.oneOf) {
|
|
118
122
|
for (let i = 0; i < node.oneOf.length; i += 1) {
|
|
119
|
-
const type = getSchemaType(node.oneOf[i], data);
|
|
123
|
+
const type = getSchemaType(node.oneOf[i].resolveRef?.() ?? node.oneOf[i], data);
|
|
120
124
|
if (type) {
|
|
121
125
|
return type;
|
|
122
126
|
}
|
|
@@ -125,12 +129,19 @@ export function getSchemaType(node: SchemaNode, data: unknown): keyof typeof SCH
|
|
|
125
129
|
|
|
126
130
|
if (node.anyOf) {
|
|
127
131
|
for (let i = 0; i < node.anyOf.length; i += 1) {
|
|
128
|
-
const type = getSchemaType(node.anyOf[i], data);
|
|
132
|
+
const type = getSchemaType(node.anyOf[i].resolveRef?.() ?? node.anyOf[i], data);
|
|
129
133
|
if (type) {
|
|
130
134
|
return type;
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
}
|
|
134
138
|
|
|
139
|
+
if (schema.$ref) {
|
|
140
|
+
const refNode = node.resolveRef?.();
|
|
141
|
+
if (refNode) {
|
|
142
|
+
return getSchemaType(refNode, data);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
135
146
|
return undefined;
|
|
136
147
|
}
|