-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathdependentSchemas.ts
97 lines (88 loc) · 3.33 KB
/
dependentSchemas.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
95
96
97
import { mergeSchema } from "../utils/mergeSchema";
import { isObject } from "../utils/isObject";
import { isSchemaNode, SchemaNode, JsonSchema } from "../types";
import { Keyword, JsonSchemaReducerParams, JsonSchemaValidatorParams, ValidationResult } from "../Keyword";
import { validateNode } from "../validateNode";
export const dependentSchemasKeyword: Keyword = {
id: "dependentSchemas",
keyword: "dependentSchemas",
parse: parseDependentSchemas,
addReduce: (node) => node.dependentSchemas != null,
reduce: reduceDependentSchemas,
addValidate: (node) => node.dependentSchemas != null,
validate: validateDependentSchemas
};
export function parseDependentSchemas(node: SchemaNode) {
const { dependentSchemas } = node.schema;
if (!isObject(dependentSchemas)) {
return;
}
const schemas = Object.keys(dependentSchemas);
if (schemas.length === 0) {
return;
}
node.dependentSchemas = {};
schemas.forEach((property) => {
const schema = dependentSchemas[property];
if (isObject(schema)) {
node.dependentSchemas[property] = node.compileSchema(
schema,
`${node.evaluationPath}/dependentSchemas/${property}`,
`${node.schemaLocation}/dependentSchemas/${property}`
);
} else if (typeof schema === "boolean") {
node.dependentSchemas[property] = schema;
}
});
}
export function reduceDependentSchemas({ node, data }: JsonSchemaReducerParams) {
if (!isObject(data)) {
// @todo remove dependentSchemas
return node;
}
let mergedSchema: JsonSchema;
const { dependentSchemas } = node;
let added = 0;
let dynamicId = `${node.schemaLocation}(`;
Object.keys(data).forEach((propertyName) => {
if (dependentSchemas[propertyName] == null) {
return;
}
mergedSchema = mergedSchema ?? { properties: {} };
if (isSchemaNode(dependentSchemas[propertyName])) {
mergedSchema = mergeSchema(mergedSchema, dependentSchemas[propertyName].schema);
} else {
mergedSchema.properties[propertyName] = dependentSchemas[propertyName];
}
dynamicId += `${added ? "," : ""}dependentSchemas/${propertyName}`;
added++;
});
if (mergedSchema == null) {
return node;
}
mergedSchema = mergeSchema(node.schema, mergedSchema, "dependentSchemas");
return node.compileSchema(mergedSchema, node.evaluationPath, node.schemaLocation, `${dynamicId})`);
}
export function validateDependentSchemas({ node, data, pointer, path }: JsonSchemaValidatorParams) {
const { schema, dependentSchemas } = node;
if (!isObject(data) || dependentSchemas == null) {
return undefined;
}
const errors: ValidationResult[] = [];
Object.keys(data).forEach((property) => {
const dependencies = dependentSchemas[property];
// @draft >= 6 boolean schema
if (dependencies === true) {
return;
}
if (dependencies === false) {
errors.push(node.createError("missing-dependency-error", { pointer, schema, value: data }));
return;
}
if (isSchemaNode(dependencies)) {
errors.push(...validateNode(dependencies, data, pointer, path));
return;
}
});
return errors;
}