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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-schema-library",
3
- "version": "10.4.2",
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 as string]?.(currentNode, defaultData, opts);
175
+ const templateData = TYPE[type]?.(currentNode, defaultData, opts);
176
176
  return templateData === undefined ? defaultData : templateData;
177
177
  }
178
178
 
179
- const TYPE: Record<string, (node: SchemaNode, data: unknown, opts: TemplateOptions) => unknown> = {
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
+ });
@@ -24,6 +24,7 @@ function validateEnum({ node, data, pointer = "#" }: JsonSchemaValidatorParams)
24
24
  return node.createError("enum-error", {
25
25
  pointer,
26
26
  schema,
27
- value: data
27
+ value: data,
28
+ values: schema.enum
28
29
  });
29
30
  }
@@ -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): keyof typeof SCHEMA_TYPES | undefined {
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
- return SCHEMA_TYPES.includes(dataType) ? (dataType as keyof typeof SCHEMA_TYPES) : undefined;
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 keyof typeof SCHEMA_TYPES;
65
+ return dataType as SchemaType;
62
66
  }
63
67
  const defaultType = getTypeOf(schema.default);
64
68
  if (schemaType.includes(defaultType)) {
65
- return defaultType as keyof typeof SCHEMA_TYPES;
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 keyof typeof SCHEMA_TYPES;
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 keyof typeof SCHEMA_TYPES;
84
+ return dataType as SchemaType;
81
85
  }
82
86
  const defaultType = getTypeOf(schema.default);
83
87
  if (enumSchemaType.includes(defaultType)) {
84
- return defaultType as keyof typeof SCHEMA_TYPES;
88
+ return defaultType as SchemaType;
85
89
  }
86
- return enumSchemaType[0] as keyof typeof SCHEMA_TYPES;
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" as keyof typeof SCHEMA_TYPES;
100
+ return "object";
97
101
  }
98
102
 
99
103
  if (arrayProperties.length > 0 && arrayProperties.length > objectProperties.length) {
100
- return "array" as keyof typeof SCHEMA_TYPES;
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
  }