-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathunevaluatedItems.ts
94 lines (85 loc) · 3.13 KB
/
unevaluatedItems.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import { isObject } from "../utils/isObject";
import { SchemaNode } from "../types";
import { Keyword, JsonSchemaValidatorParams, ValidationResult } from "../Keyword";
import { validateNode } from "../validateNode";
import { isItemEvaluated } from "../isItemEvaluated";
/**
* @draft >= 2019-09
* Similar to additionalItems, but can "see" into subschemas and across references
* https://json-schema.org/draft/2019-09/json-schema-core#rfc.section.9.3.1.3
*/
export const unevaluatedItemsKeyword: Keyword = {
id: "unevaluatedItems",
keyword: "unevaluatedItems",
parse: parseUnevaluatedItems,
addValidate: ({ schema }) => schema.unevaluatedItems != null,
validate: validateUnevaluatedItems
};
export function parseUnevaluatedItems(node: SchemaNode) {
if (!isObject(node.schema.unevaluatedItems)) {
return;
}
node.unevaluatedItems = node.compileSchema(
node.schema.unevaluatedItems,
`${node.evaluationPath}/unevaluatedItems`,
`${node.schemaLocation}/unevaluatedItems`
);
}
function validateUnevaluatedItems({ node, data, pointer, path }: JsonSchemaValidatorParams) {
const { schema } = node;
// if not in items, and not matches additionalItems
if (
!Array.isArray(data) ||
data.length === 0 ||
schema.unevaluatedItems == null ||
schema.unevaluatedItems === true
) {
return undefined;
}
const errors: ValidationResult[] = [];
// "unevaluatedItems with nested items"
for (let i = 0; i < data.length; i += 1) {
if (isItemEvaluated({ node, data, pointer, key: i, path })) {
continue;
}
const value = data[i];
const { node: child } = node.getNodeChild(i, data, { path });
if (child === undefined) {
if (node.unevaluatedItems) {
const result = validateNode(node.unevaluatedItems, value, `${pointer}/${i}`, path);
if (result.length > 0) {
errors.push(...result);
}
} else {
errors.push(
node.createError("unevaluated-items-error", {
pointer: `${pointer}/${i}`,
value: JSON.stringify(value),
schema
})
);
}
}
if (child && validateNode(child, value, `${pointer}/${i}`, path).length > 0) {
// when a single node is invalid
if (
node.unevaluatedItems &&
node.unevaluatedItems.validate(value, `${pointer}/${i}`, path).valid === false
) {
return node.createError("unevaluated-items-error", {
pointer: `${pointer}/${i}`,
value: JSON.stringify(value),
schema
});
}
if (node.schema.unevaluatedItems === false) {
return node.createError("unevaluated-items-error", {
pointer: `${pointer}/${i}`,
value: JSON.stringify(value),
schema
});
}
}
}
return errors;
}