json-schema-library 11.5.0 → 11.6.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 +7 -0
- package/README.md +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.mts +7 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/jlib.js +2 -2
- package/package.json +1 -1
- package/src/SchemaNode.ts +18 -2
- package/src/compileSchema.test.ts +37 -16
- package/src/compileSchema.ts +12 -1
- package/src/keywords/allOf.ts +1 -7
- package/src/keywords/oneOf.test.ts +11 -0
- package/src/keywords/oneOf.ts +32 -0
- package/src/keywords/propertyDependencies.test.ts +21 -0
- package/src/keywords/propertyDependencies.ts +7 -6
- package/src/keywords/unevaluatedProperties.test.ts +57 -0
- package/src/keywords/unevaluatedProperties.ts +7 -0
- package/src/methods/getChildSelection.test.ts +24 -1
- package/src/methods/getChildSelection.ts +8 -3
- package/src/settings.ts +2 -2
- package/src/validateSchema.test.ts +12 -0
package/package.json
CHANGED
package/src/SchemaNode.ts
CHANGED
|
@@ -551,7 +551,7 @@ export const SchemaNodeMethods = {
|
|
|
551
551
|
schema.$id = resolveUri(schema.$id || url);
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
const node = this as SchemaNode;
|
|
554
|
+
const node = this as SchemaNode & { schemaErrors?: JsonError[]; schemaAnnotations: JsonAnnotation[] };
|
|
555
555
|
const { context } = node;
|
|
556
556
|
const schemaId = isJsonSchema(schema) ? (node.context.draft ?? schema.$schema) : undefined;
|
|
557
557
|
const draft = getDraft(context.drafts, schemaId ?? context.rootNode.schema?.$schema);
|
|
@@ -576,7 +576,22 @@ export const SchemaNodeMethods = {
|
|
|
576
576
|
|
|
577
577
|
remoteNode.context.rootNode = remoteNode;
|
|
578
578
|
remoteNode.context.remotes[resolveUri(url)] = remoteNode;
|
|
579
|
-
|
|
579
|
+
|
|
580
|
+
// parse and validate schema
|
|
581
|
+
// @todo this is a duplicated to compileSchema
|
|
582
|
+
let schemaValidation = addKeywords(remoteNode).filter((err) => err != null);
|
|
583
|
+
schemaValidation = sanitizeErrors(schemaValidation);
|
|
584
|
+
const schemaErrors: JsonError[] = [];
|
|
585
|
+
const schemaAnnotations: JsonAnnotation[] = [];
|
|
586
|
+
schemaValidation.forEach((error) => {
|
|
587
|
+
if (isJsonError(error)) {
|
|
588
|
+
schemaErrors.push(error);
|
|
589
|
+
} else if (isJsonAnnotation(error)) {
|
|
590
|
+
schemaAnnotations.push(error);
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
node.schemaErrors = schemaErrors;
|
|
594
|
+
node.schemaAnnotations = schemaAnnotations;
|
|
580
595
|
|
|
581
596
|
return node;
|
|
582
597
|
},
|
|
@@ -631,6 +646,7 @@ export function addKeywords(node: SchemaNode) {
|
|
|
631
646
|
).forEach((keyword) => {
|
|
632
647
|
errors.push(
|
|
633
648
|
node.createAnnotation("unknown-keyword-warning", {
|
|
649
|
+
$id: node.$id,
|
|
634
650
|
pointer: `${node.schemaLocation}/${keyword}`,
|
|
635
651
|
schema: node.schema,
|
|
636
652
|
value: keyword,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { compileSchema } from "./compileSchema";
|
|
2
2
|
import { strict as assert } from "assert";
|
|
3
|
-
import {
|
|
4
|
-
import { SchemaNode } from "./SchemaNode";
|
|
3
|
+
import { isSchemaNode, SchemaNode } from "./SchemaNode";
|
|
5
4
|
import { draft04 } from "./draft04";
|
|
6
5
|
import { draft07 } from "./draft07";
|
|
7
6
|
import { draft2020 } from "./draft2020";
|
|
@@ -106,6 +105,42 @@ describe("compileSchema remotes", () => {
|
|
|
106
105
|
const data = node.getData();
|
|
107
106
|
assert.deepEqual(data, { string: "a", number: 9 });
|
|
108
107
|
});
|
|
108
|
+
|
|
109
|
+
it("should resolve definition of remote schema", () => {
|
|
110
|
+
const node = compileSchema(
|
|
111
|
+
{
|
|
112
|
+
type: "object",
|
|
113
|
+
required: ["value"],
|
|
114
|
+
properties: {
|
|
115
|
+
value: { $ref: "https://remote.com/definitions.json#/$defs/property" }
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
drafts: [draft2020],
|
|
120
|
+
remotes: [
|
|
121
|
+
{
|
|
122
|
+
$id: "https://remote.com/definitions.json",
|
|
123
|
+
$defs: {
|
|
124
|
+
property: {
|
|
125
|
+
title: "remote boolean definition",
|
|
126
|
+
type: "boolean"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const data = node.getData();
|
|
135
|
+
assert.deepEqual(data, { value: false });
|
|
136
|
+
|
|
137
|
+
const { node: valueNode } = node.getNode("#/value");
|
|
138
|
+
assert(isSchemaNode(valueNode), "expected returned node to be a valid SchemaNode");
|
|
139
|
+
assert.deepEqual(valueNode.schema, {
|
|
140
|
+
title: "remote boolean definition",
|
|
141
|
+
type: "boolean"
|
|
142
|
+
});
|
|
143
|
+
});
|
|
109
144
|
});
|
|
110
145
|
|
|
111
146
|
describe("compileSchema vocabulary", () => {
|
|
@@ -250,17 +285,3 @@ describe("compileSchema `schemaLocation`", () => {
|
|
|
250
285
|
assert.deepEqual(node?.schemaLocation, "#");
|
|
251
286
|
});
|
|
252
287
|
});
|
|
253
|
-
|
|
254
|
-
describe("compileSchema `errors`", () => {
|
|
255
|
-
it("draftEditor come with custom minLengthOneError", () => {
|
|
256
|
-
const { errors } = compileSchema(
|
|
257
|
-
{
|
|
258
|
-
type: "string",
|
|
259
|
-
minLength: 1
|
|
260
|
-
},
|
|
261
|
-
{ drafts: [draftEditor] }
|
|
262
|
-
).validate("");
|
|
263
|
-
assert.equal(errors.length, 1);
|
|
264
|
-
assert.deepEqual(errors[0].code, "min-length-one-error");
|
|
265
|
-
});
|
|
266
|
-
});
|
package/src/compileSchema.ts
CHANGED
|
@@ -66,7 +66,10 @@ export type CompileOptions = {
|
|
|
66
66
|
/**
|
|
67
67
|
* Set node and its remote schemata as remote schemata for this node and schema to resolve $ref
|
|
68
68
|
*/
|
|
69
|
-
remote?: SchemaNode;
|
|
69
|
+
remote?: SchemaNode & { schemaErrors?: JsonError[]; schemaAnnotations: JsonAnnotation[] };
|
|
70
|
+
/**
|
|
71
|
+
* a list of remotes to add, requires a unique $id for each schema. Will be ignored if `remote` is set
|
|
72
|
+
*/
|
|
70
73
|
remotes?: JsonSchema[];
|
|
71
74
|
/**
|
|
72
75
|
* Enables `format`-keyword assertions when this is set tor `true` or sets assertion as defined by
|
|
@@ -177,11 +180,19 @@ export function compileSchema(schema: JsonSchema | BooleanSchema, options: Compi
|
|
|
177
180
|
const schemaAnnotations: JsonAnnotation[] = [];
|
|
178
181
|
schemaValidation.forEach((error) => {
|
|
179
182
|
if (isJsonError(error)) {
|
|
183
|
+
error.data.schemaId = node.context.rootNode.$id ?? "#";
|
|
180
184
|
schemaErrors.push(error);
|
|
181
185
|
} else if (isJsonAnnotation(error)) {
|
|
186
|
+
error.data.schemaId = node.context.rootNode.$id ?? "#";
|
|
182
187
|
schemaAnnotations.push(error);
|
|
183
188
|
}
|
|
184
189
|
});
|
|
190
|
+
if (Array.isArray(remote?.schemaErrors)) {
|
|
191
|
+
schemaErrors.push(...remote.schemaErrors);
|
|
192
|
+
}
|
|
193
|
+
if (Array.isArray(remote?.schemaAnnotations)) {
|
|
194
|
+
schemaAnnotations.push(...remote.schemaAnnotations);
|
|
195
|
+
}
|
|
185
196
|
|
|
186
197
|
if (options.throwOnInvalidSchema && schemaErrors.length > 0) {
|
|
187
198
|
const error = new Error("Invalid schema passed to compileSchema");
|
package/src/keywords/allOf.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { mergeSchema } from "../utils/mergeSchema";
|
|
2
|
-
import {
|
|
3
|
-
Keyword,
|
|
4
|
-
JsonSchemaReducerParams,
|
|
5
|
-
JsonSchemaValidatorParams,
|
|
6
|
-
ValidationReturnType,
|
|
7
|
-
ValidationAnnotation
|
|
8
|
-
} from "../Keyword";
|
|
2
|
+
import { Keyword, JsonSchemaReducerParams, JsonSchemaValidatorParams, ValidationReturnType } from "../Keyword";
|
|
9
3
|
import { SchemaNode } from "../types";
|
|
10
4
|
import { validateNode } from "../validateNode";
|
|
11
5
|
import { collectValidationErrors } from "src/utils/collectValidationErrors";
|
|
@@ -160,6 +160,17 @@ describe("keyword : oneof-fuzzy : reduce", () => {
|
|
|
160
160
|
assert.equal(res.oneOfIndex, 1, "should have exposed correct resolved oneOfIndex");
|
|
161
161
|
});
|
|
162
162
|
|
|
163
|
+
it("should resolve to best matching oneOf", () => {
|
|
164
|
+
const node = compileSchema({
|
|
165
|
+
oneOf: [
|
|
166
|
+
{ type: "array", items: { oneOf: [{ type: "string" }] } },
|
|
167
|
+
{ type: "array", items: { oneOf: [{ type: "number" }] } }
|
|
168
|
+
]
|
|
169
|
+
});
|
|
170
|
+
const res = reduceOneOfFuzzy({ node, data: [1, 2, "3"], pointer: "#", path: [] });
|
|
171
|
+
assert.deepEqual(res?.schema, { type: "array", items: { oneOf: [{ type: "number" }] } });
|
|
172
|
+
});
|
|
173
|
+
|
|
163
174
|
describe("object", () => {
|
|
164
175
|
it("should return schema with matching properties", () => {
|
|
165
176
|
const node = compileSchema({
|
package/src/keywords/oneOf.ts
CHANGED
|
@@ -257,6 +257,38 @@ export function reduceOneOfFuzzy({ node, data, pointer, path }: Omit<JsonSchemaR
|
|
|
257
257
|
});
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
const { node: reducedNode, error } = nodeOfItem.reduceNode(data, { pointer, path });
|
|
261
|
+
if (reducedNode) {
|
|
262
|
+
reducedNode.oneOfIndex = schemaOfIndex; // @evaluation-info
|
|
263
|
+
return reducedNode;
|
|
264
|
+
}
|
|
265
|
+
return error;
|
|
266
|
+
} else if (Array.isArray(data)) {
|
|
267
|
+
let nodeOfItem: SchemaNode | undefined;
|
|
268
|
+
let schemaOfIndex = -1;
|
|
269
|
+
let errorCount = Infinity;
|
|
270
|
+
|
|
271
|
+
for (let i = 0; i < node.oneOf.length; i += 1) {
|
|
272
|
+
const oneNode = node.oneOf[i];
|
|
273
|
+
const { errors } = oneNode.validate(data);
|
|
274
|
+
const nextErrorCount = errors.length;
|
|
275
|
+
|
|
276
|
+
if (nextErrorCount < errorCount) {
|
|
277
|
+
errorCount = nextErrorCount;
|
|
278
|
+
nodeOfItem = oneNode;
|
|
279
|
+
schemaOfIndex = i;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (nodeOfItem === undefined) {
|
|
284
|
+
return node.createError("one-of-error", {
|
|
285
|
+
value: JSON.stringify(data),
|
|
286
|
+
pointer,
|
|
287
|
+
schema: node.schema,
|
|
288
|
+
oneOf: node.schema.oneOf
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
260
292
|
const { node: reducedNode, error } = nodeOfItem.reduceNode(data, { pointer, path });
|
|
261
293
|
if (reducedNode) {
|
|
262
294
|
reducedNode.oneOfIndex = schemaOfIndex; // @evaluation-info
|
|
@@ -139,6 +139,27 @@ describe("keyword : propertyDependencies : validate", () => {
|
|
|
139
139
|
const { errors } = node.validate([{ propertyName: "propertyValue", type: "headline", test: 123 }]);
|
|
140
140
|
assert.equal(errors.length, 0);
|
|
141
141
|
});
|
|
142
|
+
|
|
143
|
+
it("should safely support __proto__ as property dependency key", () => {
|
|
144
|
+
const schema = JSON.parse(`{
|
|
145
|
+
"type": "array",
|
|
146
|
+
"items": {
|
|
147
|
+
"propertyDependencies": {
|
|
148
|
+
"__proto__": {
|
|
149
|
+
"polluted": {
|
|
150
|
+
"type": "object",
|
|
151
|
+
"required": ["safe"]
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}`);
|
|
157
|
+
const node = compileSchema(schema, { drafts });
|
|
158
|
+
const data = JSON.parse(`[{ "__proto__": "polluted" }]`);
|
|
159
|
+
|
|
160
|
+
const { errors } = node.validate(data);
|
|
161
|
+
assert.equal(errors.length, 1);
|
|
162
|
+
});
|
|
142
163
|
});
|
|
143
164
|
|
|
144
165
|
describe("keyword : propertyDependencies : validate", () => {
|
|
@@ -24,12 +24,13 @@ function findMatchingSchemata(node: SchemaNode, data: Record<string, unknown>) {
|
|
|
24
24
|
const matchingSchemata: { property: string; value: string; node: SchemaNode }[] = [];
|
|
25
25
|
for (const propertyName of dependentPropertyNames) {
|
|
26
26
|
if (hasProperty(data, propertyName)) {
|
|
27
|
-
const
|
|
28
|
-
|
|
27
|
+
const dependentValues = dependentProperties[propertyName];
|
|
28
|
+
const value = `${data[propertyName]}`;
|
|
29
|
+
if (hasProperty(dependentValues, value)) {
|
|
29
30
|
matchingSchemata.push({
|
|
30
31
|
property: propertyName,
|
|
31
|
-
value
|
|
32
|
-
node:
|
|
32
|
+
value,
|
|
33
|
+
node: dependentValues[value]
|
|
33
34
|
});
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -82,7 +83,7 @@ function parsePropertyDependencies(node: SchemaNode) {
|
|
|
82
83
|
message: `Keyword '${KEYWORD}' must be an object - received '${typeof propertyDependencies}'`
|
|
83
84
|
});
|
|
84
85
|
}
|
|
85
|
-
const parsed: Record<string, Record<string, SchemaNode>> =
|
|
86
|
+
const parsed: Record<string, Record<string, SchemaNode>> = Object.create(null);
|
|
86
87
|
const errors: ValidationAnnotation[] = [];
|
|
87
88
|
Object.keys(propertyDependencies).map((propertyName) => {
|
|
88
89
|
const values = propertyDependencies[propertyName];
|
|
@@ -110,7 +111,7 @@ function parsePropertyDependencies(node: SchemaNode) {
|
|
|
110
111
|
);
|
|
111
112
|
return;
|
|
112
113
|
}
|
|
113
|
-
parsed[propertyName] = parsed[propertyName] ??
|
|
114
|
+
parsed[propertyName] = parsed[propertyName] ?? Object.create(null);
|
|
114
115
|
parsed[propertyName][value] = node.compileSchema(
|
|
115
116
|
schema,
|
|
116
117
|
`${node.evaluationPath}/${KEYWORD}/${propertyName}/${value}`,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compileSchema } from "../compileSchema";
|
|
2
|
+
import { draft2020 } from "../draft2020";
|
|
2
3
|
import { strict as assert } from "assert";
|
|
3
4
|
|
|
4
5
|
describe("keyword : unevaluatedProperties : validation", () => {
|
|
@@ -13,4 +14,60 @@ describe("keyword : unevaluatedProperties : validation", () => {
|
|
|
13
14
|
});
|
|
14
15
|
assert.equal(errors.length, 0);
|
|
15
16
|
});
|
|
17
|
+
|
|
18
|
+
it("should not return unevaluated-property-error for a property that fails format validation", () => {
|
|
19
|
+
const node = compileSchema(
|
|
20
|
+
{
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
name: { type: "string" },
|
|
24
|
+
email: { type: "string", format: "email" }
|
|
25
|
+
},
|
|
26
|
+
unevaluatedProperties: false
|
|
27
|
+
},
|
|
28
|
+
{ drafts: [draft2020] }
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const { errors } = node.validate({ name: "Alice", email: "not-an-email" });
|
|
32
|
+
|
|
33
|
+
const unevaluatedErrors = errors.filter((e) => e.code === "unevaluated-property-error");
|
|
34
|
+
assert.equal(unevaluatedErrors.length, 0, "should not flag email as unevaluated");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should not return unevaluated-property-error for a property that fails type validation", () => {
|
|
38
|
+
const node = compileSchema(
|
|
39
|
+
{
|
|
40
|
+
type: "object",
|
|
41
|
+
properties: {
|
|
42
|
+
name: { type: "string" },
|
|
43
|
+
age: { type: "number" }
|
|
44
|
+
},
|
|
45
|
+
unevaluatedProperties: false
|
|
46
|
+
},
|
|
47
|
+
{ drafts: [draft2020] }
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const { errors } = node.validate({ name: "Alice", age: "not-a-number" });
|
|
51
|
+
|
|
52
|
+
const unevaluatedErrors = errors.filter((e) => e.code === "unevaluated-property-error");
|
|
53
|
+
assert.equal(unevaluatedErrors.length, 0, "should not flag age as unevaluated");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should still return unevaluated-property-error for truly unknown properties", () => {
|
|
57
|
+
const node = compileSchema(
|
|
58
|
+
{
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
name: { type: "string" }
|
|
62
|
+
},
|
|
63
|
+
unevaluatedProperties: false
|
|
64
|
+
},
|
|
65
|
+
{ drafts: [draft2020] }
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const { errors } = node.validate({ name: "Alice", unknown: "value" });
|
|
69
|
+
|
|
70
|
+
const unevaluatedErrors = errors.filter((e) => e.code === "unevaluated-property-error");
|
|
71
|
+
assert.equal(unevaluatedErrors.length, 1, "should flag unknown as unevaluated");
|
|
72
|
+
});
|
|
16
73
|
});
|
|
@@ -56,6 +56,13 @@ function validateUnevaluatedProperties({ node, data, pointer, path }: JsonSchema
|
|
|
56
56
|
|
|
57
57
|
const errors: ValidationReturnType = [];
|
|
58
58
|
for (const propertyName of unevaluated) {
|
|
59
|
+
// Properties defined directly on this schema object are always
|
|
60
|
+
// evaluated by the "properties" keyword, regardless of whether the
|
|
61
|
+
// value passes validation (per JSON Schema spec, annotations from
|
|
62
|
+
// adjacent keywords are always collected)
|
|
63
|
+
if (node.properties?.[propertyName]) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
59
66
|
if (isPropertyEvaluated({ node, data, key: propertyName, pointer, path })) {
|
|
60
67
|
continue;
|
|
61
68
|
}
|
|
@@ -88,7 +88,30 @@ describe("getChildSelection", () => {
|
|
|
88
88
|
number: { type: "number" },
|
|
89
89
|
string: { type: "string" }
|
|
90
90
|
}
|
|
91
|
-
}).getChildSelection(
|
|
91
|
+
}).getChildSelection(1);
|
|
92
|
+
|
|
93
|
+
assert(!isJsonError(result));
|
|
94
|
+
assert.deepEqual(result.length, 2);
|
|
95
|
+
assert.deepEqual(
|
|
96
|
+
result.map((n) => n.schema),
|
|
97
|
+
[{ type: "string" }, { type: "number" }]
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should resolve items $ref", () => {
|
|
102
|
+
const result = compileSchema({
|
|
103
|
+
type: "array",
|
|
104
|
+
items: {
|
|
105
|
+
$ref: "#/$defs/oneOfRef"
|
|
106
|
+
},
|
|
107
|
+
$defs: {
|
|
108
|
+
oneOfRef: {
|
|
109
|
+
oneOf: [{ $ref: "#/$defs/string" }, { $ref: "#/$defs/number" }]
|
|
110
|
+
},
|
|
111
|
+
number: { type: "number" },
|
|
112
|
+
string: { type: "string" }
|
|
113
|
+
}
|
|
114
|
+
}).getChildSelection(1);
|
|
92
115
|
|
|
93
116
|
assert(!isJsonError(result));
|
|
94
117
|
assert.deepEqual(result.length, 2);
|
|
@@ -6,12 +6,17 @@ import { isSchemaNode, JsonError, SchemaNode } from "../types";
|
|
|
6
6
|
* a list with a single item will be returned
|
|
7
7
|
*/
|
|
8
8
|
export function getChildSelection(node: SchemaNode, property: string | number) {
|
|
9
|
+
if (node.items) {
|
|
10
|
+
const items = node.items.resolveRef();
|
|
11
|
+
if (items?.oneOf) {
|
|
12
|
+
return items.oneOf.map((childNode: SchemaNode) => childNode.resolveRef());
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
if (node.oneOf) {
|
|
10
17
|
return node.oneOf.map((childNode: SchemaNode) => childNode.resolveRef());
|
|
11
18
|
}
|
|
12
|
-
|
|
13
|
-
return node.items.oneOf.map((childNode: SchemaNode) => childNode.resolveRef());
|
|
14
|
-
}
|
|
19
|
+
|
|
15
20
|
// array.items[] found
|
|
16
21
|
if (node.prefixItems && node.prefixItems.length > +property) {
|
|
17
22
|
const { node: childNode, error } = node.getNodeChild(property);
|
package/src/settings.ts
CHANGED
|
@@ -19,7 +19,7 @@ export default {
|
|
|
19
19
|
],
|
|
20
20
|
REGEX_FLAGS: "u",
|
|
21
21
|
/** additional keywords that should not produce an unknown-keyword-warning */
|
|
22
|
-
VALID_ANNOTATION_KEYWORDS: ["title", "description", "default"],
|
|
22
|
+
VALID_ANNOTATION_KEYWORDS: ["$id", "$schema", "title", "description", "default", "oneOfProperty"],
|
|
23
23
|
/**
|
|
24
24
|
* properties to keep from a $ref-schema when resolving a $ref (recursively)
|
|
25
25
|
* this allows to overwrite specified properties locally on a $ref-definition
|
|
@@ -45,5 +45,5 @@ export default {
|
|
|
45
45
|
* type: "object"
|
|
46
46
|
* }
|
|
47
47
|
*/
|
|
48
|
-
PROPERTIES_TO_MERGE: ["title", "description", "options", "x-options", "readOnly", "writeOnly"]
|
|
48
|
+
PROPERTIES_TO_MERGE: ["title", "description", "default", "options", "x-options", "readOnly", "writeOnly"]
|
|
49
49
|
};
|
|
@@ -250,6 +250,18 @@ describe("validateSchema", () => {
|
|
|
250
250
|
assert.equal(schemaErrors[0].data.pointer, "#/uniqueItems");
|
|
251
251
|
});
|
|
252
252
|
|
|
253
|
+
describe("remotes", () => {
|
|
254
|
+
it("should return errors of remotes", () => {
|
|
255
|
+
const { schemaErrors } = compileSchema(
|
|
256
|
+
{},
|
|
257
|
+
{ remotes: [{ $id: "https://remote.com/error.json", anyOf: [999] }] }
|
|
258
|
+
);
|
|
259
|
+
assert.equal(schemaErrors?.length, 1);
|
|
260
|
+
assert.equal(schemaErrors[0].data.pointer, "#/anyOf/0");
|
|
261
|
+
assert.equal(schemaErrors[0].data.schemaId, "https://remote.com/error.json");
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
253
265
|
describe("annotations", () => {
|
|
254
266
|
it("should return unknown keywords as annotation", () => {
|
|
255
267
|
const { schemaAnnotations } = compileSchema({
|