json-schema-library 5.2.1 → 6.1.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/.prettierignore +1 -0
- package/.prettierrc +7 -0
- package/README.md +9 -8
- package/dist/index.d.ts +13 -44
- package/dist/jsonSchemaLibrary.js +1 -1
- package/dist/lib/addValidator.d.ts +2 -1
- package/dist/lib/compile/index.d.ts +11 -0
- package/dist/lib/config/strings.d.ts +1 -39
- package/dist/lib/cores/CoreInterface.d.ts +28 -9
- package/dist/lib/cores/Draft04.d.ts +2 -2
- package/dist/lib/cores/Draft06.d.ts +15 -0
- package/dist/lib/cores/Draft07.d.ts +15 -0
- package/dist/lib/cores/JsonEditor.d.ts +2 -2
- package/dist/lib/draft06/addSchema.d.ts +7 -0
- package/dist/lib/draft06/compile/index.d.ts +15 -0
- package/dist/lib/draft06/validation/keyword.d.ts +3 -0
- package/dist/lib/draft06/validation/type.d.ts +17 -0
- package/dist/lib/draft06/validation/typeKeywordMapping.d.ts +13 -0
- package/dist/lib/getChildSchemaSelection.d.ts +7 -5
- package/dist/lib/getSchema.d.ts +1 -1
- package/dist/lib/getTemplate.d.ts +5 -1
- package/dist/lib/getTypeOf.d.ts +2 -1
- package/dist/lib/schema/getTypeId.d.ts +1 -1
- package/dist/lib/step.d.ts +4 -4
- package/dist/lib/types.d.ts +10 -2
- package/dist/lib/utils/filter.d.ts +0 -1
- package/dist/lib/utils/merge.d.ts +3 -0
- package/dist/lib/validate.d.ts +1 -1
- package/dist/lib/validation/format.d.ts +6 -0
- package/dist/lib/validation/keyword.d.ts +2 -27
- package/dist/lib/validation/type.d.ts +3 -10
- package/dist/lib/validation/typeKeywordMapping.d.ts +4 -4
- package/dist/module/index.js +13 -6
- package/dist/module/lib/addValidator.js +3 -4
- package/dist/module/lib/compile/getRef.js +1 -1
- package/dist/module/lib/compile/index.js +11 -0
- package/dist/module/lib/config/strings.js +15 -2
- package/dist/module/lib/cores/CoreInterface.js +22 -0
- package/dist/module/lib/cores/Draft06.js +61 -0
- package/dist/module/lib/cores/Draft07.js +61 -0
- package/dist/module/lib/createSchemaOf.js +1 -1
- package/dist/module/lib/draft06/addSchema.js +11 -0
- package/dist/module/lib/draft06/compile/index.js +65 -0
- package/dist/module/lib/draft06/validation/keyword.js +156 -0
- package/dist/module/lib/draft06/validation/type.js +30 -0
- package/dist/module/lib/draft06/validation/typeKeywordMapping.js +15 -0
- package/dist/module/lib/each.js +1 -1
- package/dist/module/lib/eachSchema.js +3 -3
- package/dist/module/lib/getChildSchemaSelection.js +7 -6
- package/dist/module/lib/getSchema.js +2 -1
- package/dist/module/lib/getTemplate.js +57 -23
- package/dist/module/lib/resolveAllOf.js +3 -4
- package/dist/module/lib/resolveOneOf.fuzzy.js +13 -3
- package/dist/module/lib/resolveOneOf.strict.js +11 -2
- package/dist/module/lib/resolveRef.strict.js +8 -0
- package/dist/module/lib/schema/getTypeDefs.js +12 -1
- package/dist/module/lib/schema/getTypeId.js +1 -1
- package/dist/module/lib/step.js +62 -11
- package/dist/module/lib/types.js +7 -1
- package/dist/module/lib/utils/filter.js +3 -5
- package/dist/module/lib/utils/merge.js +3 -0
- package/dist/module/lib/validate.js +33 -8
- package/dist/module/lib/validateAsync.js +7 -7
- package/dist/module/lib/validation/errors.js +15 -2
- package/dist/module/lib/validation/format.js +105 -4
- package/dist/module/lib/validation/keyword.js +77 -30
- package/dist/module/lib/validation/type.js +2 -1
- package/dist/module/remotes/draft06.json +155 -0
- package/dist/module/remotes/draft07.json +172 -0
- package/dist/module/remotes/index.js +0 -1
- package/dist/remotes/index.d.ts +0 -1
- package/index.ts +14 -5
- package/lib/addValidator.ts +5 -5
- package/lib/compile/getRef.ts +1 -1
- package/lib/compile/index.ts +11 -1
- package/lib/config/strings.ts +17 -3
- package/lib/cores/CoreInterface.ts +37 -10
- package/lib/cores/Draft04.ts +2 -4
- package/lib/cores/Draft06.ts +76 -0
- package/lib/cores/Draft07.ts +75 -0
- package/lib/cores/JsonEditor.ts +2 -4
- package/lib/createSchemaOf.ts +1 -3
- package/lib/draft06/addSchema.ts +14 -0
- package/lib/draft06/compile/index.ts +68 -0
- package/lib/draft06/validation/keyword.ts +177 -0
- package/lib/draft06/validation/type.ts +43 -0
- package/lib/draft06/validation/typeKeywordMapping.ts +15 -0
- package/lib/each.ts +8 -3
- package/lib/eachSchema.ts +3 -3
- package/lib/getChildSchemaSelection.ts +14 -7
- package/lib/getSchema.ts +15 -7
- package/lib/getTemplate.ts +148 -38
- package/lib/getTypeOf.ts +2 -1
- package/lib/resolveAllOf.ts +9 -5
- package/lib/resolveOneOf.fuzzy.ts +25 -8
- package/lib/resolveOneOf.strict.ts +17 -4
- package/lib/resolveRef.strict.ts +9 -0
- package/lib/schema/getTypeDefs.ts +14 -1
- package/lib/schema/getTypeId.ts +2 -2
- package/lib/step.ts +103 -22
- package/lib/types.ts +21 -4
- package/lib/utils/filter.ts +4 -6
- package/lib/utils/merge.ts +4 -0
- package/lib/validate.ts +45 -15
- package/lib/validateAsync.ts +13 -12
- package/lib/validation/errors.ts +15 -2
- package/lib/validation/format.ts +113 -4
- package/lib/validation/keyword.ts +147 -78
- package/lib/validation/type.ts +5 -1
- package/package.json +73 -63
- package/remotes/draft06.json +155 -0
- package/remotes/draft07.json +172 -0
- package/remotes/draft2019-09.json +86 -0
- package/remotes/index.ts +0 -2
- package/tsconfig.json +2 -9
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import CoreInterface from "./CoreInterface";
|
|
2
|
+
import step from "../step";
|
|
3
|
+
import validate from "../validate";
|
|
4
|
+
import resolveOneOf from "../resolveOneOf.strict";
|
|
5
|
+
import resolveRef from "../resolveRef.strict";
|
|
6
|
+
import getTemplate from "../getTemplate";
|
|
7
|
+
import getSchema from "../getSchema";
|
|
8
|
+
import each from "../each";
|
|
9
|
+
import compileSchema from "../draft06/compile";
|
|
10
|
+
import remotes from "../../remotes";
|
|
11
|
+
import draft06 from "../../remotes/draft06.json";
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
remotes["http://json-schema.org/draft-06/schema"] = compileSchema(draft06);
|
|
14
|
+
import TYPE_KEYWORD_MAPPING from "../draft06/validation/typeKeywordMapping";
|
|
15
|
+
import KEYWORDS from "../draft06/validation/keyword";
|
|
16
|
+
import TYPES from "../draft06/validation/type";
|
|
17
|
+
import FORMATS from "../validation/format";
|
|
18
|
+
import ERRORS from "../validation/errors";
|
|
19
|
+
export default class Draft06Core extends CoreInterface {
|
|
20
|
+
constructor(schema) {
|
|
21
|
+
super(schema);
|
|
22
|
+
this.typeKeywords = JSON.parse(JSON.stringify(TYPE_KEYWORD_MAPPING));
|
|
23
|
+
this.validateKeyword = Object.assign({}, KEYWORDS);
|
|
24
|
+
this.validateType = Object.assign({}, TYPES);
|
|
25
|
+
this.validateFormat = Object.assign({}, FORMATS);
|
|
26
|
+
this.errors = Object.assign({}, ERRORS);
|
|
27
|
+
}
|
|
28
|
+
get rootSchema() {
|
|
29
|
+
return this.__rootSchema;
|
|
30
|
+
}
|
|
31
|
+
set rootSchema(rootSchema) {
|
|
32
|
+
if (rootSchema == null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.__rootSchema = compileSchema(rootSchema);
|
|
36
|
+
}
|
|
37
|
+
each(data, callback, schema = this.rootSchema, pointer = "#") {
|
|
38
|
+
each(this, data, callback, schema, pointer);
|
|
39
|
+
}
|
|
40
|
+
validate(data, schema = this.rootSchema, pointer = "#") {
|
|
41
|
+
return validate(this, data, schema, pointer);
|
|
42
|
+
}
|
|
43
|
+
isValid(data, schema = this.rootSchema, pointer = "#") {
|
|
44
|
+
return this.validate(data, schema, pointer).length === 0;
|
|
45
|
+
}
|
|
46
|
+
resolveOneOf(data, schema, pointer) {
|
|
47
|
+
return resolveOneOf(this, data, schema, pointer);
|
|
48
|
+
}
|
|
49
|
+
resolveRef(schema) {
|
|
50
|
+
return resolveRef(schema, this.rootSchema);
|
|
51
|
+
}
|
|
52
|
+
getSchema(pointer, data, schema = this.rootSchema) {
|
|
53
|
+
return getSchema(this, pointer, data, schema);
|
|
54
|
+
}
|
|
55
|
+
getTemplate(data, schema = this.rootSchema) {
|
|
56
|
+
return getTemplate(this, data, schema);
|
|
57
|
+
}
|
|
58
|
+
step(key, schema, data, pointer = "#") {
|
|
59
|
+
return step(this, key, schema, data, pointer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import CoreInterface from "./CoreInterface";
|
|
2
|
+
import step from "../step";
|
|
3
|
+
import validate from "../validate";
|
|
4
|
+
import resolveOneOf from "../resolveOneOf.strict";
|
|
5
|
+
import resolveRef from "../resolveRef.strict";
|
|
6
|
+
import getTemplate from "../getTemplate";
|
|
7
|
+
import getSchema from "../getSchema";
|
|
8
|
+
import addSchema from "../addSchema";
|
|
9
|
+
import each from "../each";
|
|
10
|
+
import compileSchema from "../draft06/compile";
|
|
11
|
+
import draft07 from "../../remotes/draft07.json";
|
|
12
|
+
import TYPE_KEYWORD_MAPPING from "../draft06/validation/typeKeywordMapping";
|
|
13
|
+
import KEYWORDS from "../draft06/validation/keyword";
|
|
14
|
+
import TYPES from "../draft06/validation/type";
|
|
15
|
+
import FORMATS from "../validation/format";
|
|
16
|
+
import ERRORS from "../validation/errors";
|
|
17
|
+
import addValidator from "../addValidator";
|
|
18
|
+
addSchema("http://json-schema.org/draft-07/schema", draft07);
|
|
19
|
+
export default class Draft07Core extends CoreInterface {
|
|
20
|
+
constructor(schema) {
|
|
21
|
+
super(schema);
|
|
22
|
+
this.typeKeywords = JSON.parse(JSON.stringify(TYPE_KEYWORD_MAPPING));
|
|
23
|
+
Object.assign(this.validateKeyword, KEYWORDS);
|
|
24
|
+
Object.assign(this.validateType, TYPES);
|
|
25
|
+
Object.keys(FORMATS).forEach((id) => addValidator.format(this, id, FORMATS[id]));
|
|
26
|
+
Object.keys(ERRORS).forEach((id) => addValidator.error(this, id, ERRORS[id]));
|
|
27
|
+
}
|
|
28
|
+
get rootSchema() {
|
|
29
|
+
return this.__rootSchema;
|
|
30
|
+
}
|
|
31
|
+
set rootSchema(rootSchema) {
|
|
32
|
+
if (rootSchema == null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.__rootSchema = compileSchema(rootSchema);
|
|
36
|
+
}
|
|
37
|
+
each(data, callback, schema = this.rootSchema, pointer = "#") {
|
|
38
|
+
each(this, data, callback, schema, pointer);
|
|
39
|
+
}
|
|
40
|
+
validate(data, schema = this.rootSchema, pointer = "#") {
|
|
41
|
+
return validate(this, data, schema, pointer);
|
|
42
|
+
}
|
|
43
|
+
isValid(data, schema = this.rootSchema, pointer = "#") {
|
|
44
|
+
return this.validate(data, schema, pointer).length === 0;
|
|
45
|
+
}
|
|
46
|
+
resolveOneOf(data, schema, pointer) {
|
|
47
|
+
return resolveOneOf(this, data, schema, pointer);
|
|
48
|
+
}
|
|
49
|
+
resolveRef(schema) {
|
|
50
|
+
return resolveRef(schema, this.rootSchema);
|
|
51
|
+
}
|
|
52
|
+
getSchema(pointer, data, schema = this.rootSchema) {
|
|
53
|
+
return getSchema(this, pointer, data, schema);
|
|
54
|
+
}
|
|
55
|
+
getTemplate(data, schema = this.rootSchema) {
|
|
56
|
+
return getTemplate(this, data, schema);
|
|
57
|
+
}
|
|
58
|
+
step(key, schema, data, pointer = "#") {
|
|
59
|
+
return step(this, key, schema, data, pointer);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -10,7 +10,7 @@ export default function createSchemaOf(data) {
|
|
|
10
10
|
};
|
|
11
11
|
if (schema.type === "object") {
|
|
12
12
|
schema.properties = {};
|
|
13
|
-
Object.keys(data).forEach(key => (schema.properties[key] = createSchemaOf(data[key])));
|
|
13
|
+
Object.keys(data).forEach((key) => (schema.properties[key] = createSchemaOf(data[key])));
|
|
14
14
|
}
|
|
15
15
|
if (schema.type === "array" && data.length === 1) {
|
|
16
16
|
schema.items = createSchemaOf(data[0]);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import remotes from "../../remotes";
|
|
2
|
+
import compileSchema from "./compile";
|
|
3
|
+
/**
|
|
4
|
+
* register a json-schema to be referenced from another json-schema
|
|
5
|
+
* @param url base-url of json-schema (aka id)
|
|
6
|
+
* @param schema
|
|
7
|
+
*/
|
|
8
|
+
export default function addSchema(url, schema) {
|
|
9
|
+
schema.id = schema.id || url;
|
|
10
|
+
remotes[url] = compileSchema(schema);
|
|
11
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint max-statements-per-line: ["error", { "max": 2 }] */
|
|
2
|
+
import eachSchema from "../../eachSchema";
|
|
3
|
+
import remotes from "../../../remotes";
|
|
4
|
+
import joinScope from "../../compile/joinScope";
|
|
5
|
+
import getRef from "../../compile/getRef";
|
|
6
|
+
const COMPILED = "__compiled";
|
|
7
|
+
const COMPILED_REF = "__ref";
|
|
8
|
+
const GET_REF = "getRef";
|
|
9
|
+
const GET_ROOT = "getRoot";
|
|
10
|
+
const suffixes = /(#|\/)+$/g;
|
|
11
|
+
/**
|
|
12
|
+
* @draft starting with _draft 06_ keyword `id` has been renamed to `$id`
|
|
13
|
+
*
|
|
14
|
+
* compiles the input root schema for $ref resolution and returns it again
|
|
15
|
+
* @attention this modifies input schema but maintains object-structure
|
|
16
|
+
*
|
|
17
|
+
* for a compiled json-schema you can call getRef on any contained schema (location of type).
|
|
18
|
+
* this resolves a $ref target to a valid schema (for a valid $ref)
|
|
19
|
+
*
|
|
20
|
+
* @param rootSchema root json-schema ($id, defs, ... ) to compile
|
|
21
|
+
* @param [force] = false force compile json-schema
|
|
22
|
+
* @return compiled json-schema
|
|
23
|
+
*/
|
|
24
|
+
export default function compile(rootSchema, force = false) {
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
if (rootSchema === true || rootSchema === false) {
|
|
27
|
+
return rootSchema;
|
|
28
|
+
}
|
|
29
|
+
if (rootSchema[COMPILED] !== undefined) {
|
|
30
|
+
return rootSchema;
|
|
31
|
+
} // eslint-disable-line
|
|
32
|
+
const context = { ids: {}, remotes: Object.assign({}, remotes) };
|
|
33
|
+
const rootSchemaAsString = JSON.stringify(rootSchema);
|
|
34
|
+
rootSchema = JSON.parse(rootSchemaAsString);
|
|
35
|
+
Object.defineProperty(rootSchema, COMPILED, { enumerable: false, value: true });
|
|
36
|
+
Object.defineProperty(rootSchema, GET_REF, { enumerable: false, value: getRef.bind(null, context, rootSchema) });
|
|
37
|
+
if (force === false && rootSchemaAsString.includes("$ref") === false) {
|
|
38
|
+
// bail early, when no $refs are defined
|
|
39
|
+
return rootSchema;
|
|
40
|
+
}
|
|
41
|
+
const scopes = {};
|
|
42
|
+
const getRoot = () => rootSchema;
|
|
43
|
+
eachSchema(rootSchema, (schema, pointer) => {
|
|
44
|
+
if (schema.$id) {
|
|
45
|
+
context.ids[schema.$id.replace(suffixes, "")] = pointer;
|
|
46
|
+
}
|
|
47
|
+
// build up scopes and add them to $ref-resolution map
|
|
48
|
+
pointer = `#${pointer}`.replace(/##+/, "#");
|
|
49
|
+
const previousPointer = pointer.replace(/\/[^/]+$/, "");
|
|
50
|
+
const parentPointer = pointer.replace(/\/[^/]+\/[^/]+$/, "");
|
|
51
|
+
const previousScope = scopes[previousPointer] || scopes[parentPointer];
|
|
52
|
+
const scope = joinScope(previousScope, schema.$id);
|
|
53
|
+
scopes[pointer] = scope;
|
|
54
|
+
if (context.ids[scope] == null) {
|
|
55
|
+
context.ids[scope] = pointer;
|
|
56
|
+
}
|
|
57
|
+
if (schema.$ref) {
|
|
58
|
+
Object.defineProperty(schema, COMPILED_REF, { enumerable: false, value: joinScope(scope, schema.$ref) });
|
|
59
|
+
// @todo currently not used:
|
|
60
|
+
Object.defineProperty(schema, GET_ROOT, { enumerable: false, value: getRoot });
|
|
61
|
+
// console.log("compiled ref", scope, schema.$ref, "=>", joinScope(scope, schema.$ref));
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return rootSchema;
|
|
65
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import Keywords from "../../validation/keyword";
|
|
2
|
+
import getTypeOf from "../../getTypeOf";
|
|
3
|
+
const KeywordValidation = {
|
|
4
|
+
...Keywords,
|
|
5
|
+
// @draft >= 6
|
|
6
|
+
contains: (core, schema, value, pointer) => {
|
|
7
|
+
if (schema.contains === false) {
|
|
8
|
+
return core.errors.containsArrayError({ pointer, value });
|
|
9
|
+
}
|
|
10
|
+
if (schema.contains === true) {
|
|
11
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
12
|
+
return core.errors.containsAnyError({ pointer });
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
if (getTypeOf(schema.contains) !== "object") {
|
|
17
|
+
// ignore invalid schema
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
21
|
+
if (core.isValid(value[i], schema.contains)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return core.errors.containsError({ pointer, schema: JSON.stringify(schema.contains) });
|
|
26
|
+
},
|
|
27
|
+
exclusiveMaximum: (core, schema, value, pointer) => {
|
|
28
|
+
if (isNaN(schema.exclusiveMaximum)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
if (schema.exclusiveMaximum <= value) {
|
|
32
|
+
return core.errors.maximumError({ maximum: schema.exclusiveMaximum, length: value, pointer });
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
},
|
|
36
|
+
exclusiveMinimum: (core, schema, value, pointer) => {
|
|
37
|
+
if (isNaN(schema.exclusiveMinimum)) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (schema.exclusiveMinimum >= value) {
|
|
41
|
+
return core.errors.minimumError({ minimum: schema.exclusiveMinimum, length: value, pointer });
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
},
|
|
45
|
+
if: (core, schema, value, pointer) => {
|
|
46
|
+
if (schema.if == null) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const ifErrors = core.validate(value, schema.if, pointer);
|
|
50
|
+
// console.log("if Errors", value, ifErrors);
|
|
51
|
+
if (ifErrors.length === 0 && schema.then) {
|
|
52
|
+
return core.validate(value, schema.then, pointer);
|
|
53
|
+
}
|
|
54
|
+
if (ifErrors.length !== 0 && schema.else) {
|
|
55
|
+
return core.validate(value, schema.else, pointer);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
maximum: (core, schema, value, pointer) => {
|
|
59
|
+
if (isNaN(schema.maximum)) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
if (schema.maximum && schema.maximum < value) {
|
|
63
|
+
return core.errors.maximumError({ maximum: schema.maximum, length: value, pointer });
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
},
|
|
67
|
+
minimum: (core, schema, value, pointer) => {
|
|
68
|
+
if (isNaN(schema.minimum)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (schema.minimum > value) {
|
|
72
|
+
return core.errors.minimumError({ minimum: schema.minimum, length: value, pointer });
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
},
|
|
76
|
+
patternProperties: (core, schema, value, pointer) => {
|
|
77
|
+
const properties = schema.properties || {};
|
|
78
|
+
const pp = schema.patternProperties;
|
|
79
|
+
if (getTypeOf(pp) !== "object") {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const errors = [];
|
|
83
|
+
const keys = Object.keys(value);
|
|
84
|
+
const patterns = Object.keys(pp).map(expr => ({
|
|
85
|
+
regex: new RegExp(expr),
|
|
86
|
+
patternSchema: pp[expr]
|
|
87
|
+
}));
|
|
88
|
+
keys.forEach(key => {
|
|
89
|
+
let patternFound = false;
|
|
90
|
+
for (let i = 0, l = patterns.length; i < l; i += 1) {
|
|
91
|
+
if (patterns[i].regex.test(key)) {
|
|
92
|
+
patternFound = true;
|
|
93
|
+
// for a boolean schema `false`, always invalidate
|
|
94
|
+
if (patterns[i].patternSchema === false) {
|
|
95
|
+
errors.push(core.errors.patternPropertiesError({
|
|
96
|
+
key, pointer, patterns: Object.keys(pp).join(",")
|
|
97
|
+
}));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const valErrors = core.validate(value[key], patterns[i].patternSchema, `${pointer}/${key}`);
|
|
101
|
+
if (valErrors && valErrors.length > 0) {
|
|
102
|
+
errors.push(...valErrors);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (properties[key]) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (patternFound === false && schema.additionalProperties === false) {
|
|
110
|
+
// this is an arrangement with additionalProperties
|
|
111
|
+
errors.push(core.errors.patternPropertiesError({
|
|
112
|
+
key, pointer, patterns: Object.keys(pp).join(",")
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return errors;
|
|
117
|
+
},
|
|
118
|
+
// @draft >= 6
|
|
119
|
+
propertyNames: (core, schema, value, pointer) => {
|
|
120
|
+
// bool schema
|
|
121
|
+
if (schema.propertyNames === false) {
|
|
122
|
+
// empty objects are valid
|
|
123
|
+
if (Object.keys(value).length === 0) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
return core.errors.invalidPropertyNameError({
|
|
127
|
+
property: Object.keys(value),
|
|
128
|
+
pointer,
|
|
129
|
+
value
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
if (schema.propertyNames === true) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
if (getTypeOf(schema.propertyNames) !== "object") {
|
|
136
|
+
// ignore invalid schema
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
const errors = [];
|
|
140
|
+
const properties = Object.keys(value);
|
|
141
|
+
const propertySchema = { ...schema.propertyNames, type: "string" };
|
|
142
|
+
properties.forEach(prop => {
|
|
143
|
+
const validationResult = core.validate(prop, propertySchema, `${pointer}/${prop}`);
|
|
144
|
+
if (validationResult.length > 0) {
|
|
145
|
+
errors.push(core.errors.invalidPropertyNameError({
|
|
146
|
+
property: prop,
|
|
147
|
+
pointer,
|
|
148
|
+
validationError: validationResult[0],
|
|
149
|
+
value: value[prop]
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return errors;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
export default KeywordValidation;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @todo: type is also a keyword, as is properties, items, etc
|
|
3
|
+
*
|
|
4
|
+
* An instance has one of six primitive types (http://json-schema.org/latest/json-schema-core.html#rfc.section.4.2)
|
|
5
|
+
* or seven in case of ajv https://github.com/epoberezkin/ajv/blob/master/KEYWORDS.md#type
|
|
6
|
+
* 1 null, 2 boolean, 3 object, 4 array, 5 number, 6 string (7 integer)
|
|
7
|
+
*/
|
|
8
|
+
export default {
|
|
9
|
+
array: (core, schema, value, pointer) => core.typeKeywords.array
|
|
10
|
+
.filter(key => schema && schema[key] != null)
|
|
11
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer)),
|
|
12
|
+
object: (core, schema, value, pointer) => core.typeKeywords.object
|
|
13
|
+
.filter(key => schema && schema[key] != null)
|
|
14
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer)),
|
|
15
|
+
string: (core, schema, value, pointer) => core.typeKeywords.string
|
|
16
|
+
.filter(key => schema && schema[key] != null)
|
|
17
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer)),
|
|
18
|
+
integer: (core, schema, value, pointer) => core.typeKeywords.number
|
|
19
|
+
.filter(key => schema && schema[key] != null)
|
|
20
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer)),
|
|
21
|
+
number: (core, schema, value, pointer) => core.typeKeywords.number
|
|
22
|
+
.filter(key => schema && schema[key] != null)
|
|
23
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer)),
|
|
24
|
+
"boolean": (core, schema, value, pointer) => core.typeKeywords.boolean
|
|
25
|
+
.filter(key => schema && schema[key] != null)
|
|
26
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer)),
|
|
27
|
+
"null": (core, schema, value, pointer) => core.typeKeywords.null
|
|
28
|
+
.filter(key => schema && schema[key] != null)
|
|
29
|
+
.map(key => core.validateKeyword[key](core, schema, value, pointer))
|
|
30
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mapping, used in type validation to iterate over type-specific keywords to validate
|
|
3
|
+
* - overview https://epoberezkin.github.io/ajv/keywords.html
|
|
4
|
+
*/
|
|
5
|
+
export default {
|
|
6
|
+
array: ["enum", "contains", "items", "minItems", "maxItems", "uniqueItems", "not", "if"],
|
|
7
|
+
boolean: ["enum", "not"],
|
|
8
|
+
object: [
|
|
9
|
+
"additionalProperties", "dependencies", "enum", "format", "minProperties", "maxProperties",
|
|
10
|
+
"patternProperties", "properties", "propertyNames", "required", "not", "oneOf", "allOf", "anyOf", "if"
|
|
11
|
+
],
|
|
12
|
+
string: ["enum", "format", "maxLength", "minLength", "pattern", "not", "oneOf", "allOf", "anyOf", "if"],
|
|
13
|
+
number: ["enum", "exclusiveMaximum", "exclusiveMinimum", "format", "maximum", "minimum", "multipleOf", "not", "oneOf", "allOf", "anyOf", "if"],
|
|
14
|
+
null: ["enum", "format", "not", "oneOf", "allOf", "anyOf"]
|
|
15
|
+
};
|
package/dist/module/lib/each.js
CHANGED
|
@@ -12,7 +12,7 @@ export default function each(core, data, callback, schema = core.rootSchema, poi
|
|
|
12
12
|
callback(schema, data, pointer);
|
|
13
13
|
const dataType = getTypeOf(data);
|
|
14
14
|
if (dataType === "object") {
|
|
15
|
-
Object.keys(data).forEach(key => {
|
|
15
|
+
Object.keys(data).forEach((key) => {
|
|
16
16
|
const nextSchema = core.step(key, schema, data, pointer); // not save
|
|
17
17
|
const next = data[key]; // save
|
|
18
18
|
core.each(next, callback, nextSchema, `${pointer}/${key}`);
|
|
@@ -12,11 +12,11 @@ function nextTypeDefs(schema, pointer) {
|
|
|
12
12
|
function eachDefinition(walk, schema, pointer) {
|
|
13
13
|
Object.keys(schema.definitions)
|
|
14
14
|
.forEach(defId => {
|
|
15
|
-
if (
|
|
16
|
-
|
|
15
|
+
if (schema.definitions[defId] === false || isObject(schema.definitions[defId])) {
|
|
16
|
+
walk.nextTypeDefs(schema.definitions[defId], gp.join(pointer, "definitions", defId, false));
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
console.log(`Invalid schema in ${pointer}/definitions/${defId}`);
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
export default function eachSchema(schema, callback, pointer = "#") {
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
+
import { isJSONError } from "./types";
|
|
1
2
|
/**
|
|
2
3
|
* Returns a list of possible child-schemas for the given property key. In case of a oneOf selection, multiple schemas
|
|
3
4
|
* could be added at the given property (e.g. item-index), thus an array of options is returned. In all other cases
|
|
4
5
|
* a list with a single item will be returned
|
|
5
6
|
*
|
|
6
|
-
* @param
|
|
7
|
-
* @param
|
|
8
|
-
* @param
|
|
9
|
-
* @return
|
|
7
|
+
* @param core - core to use
|
|
8
|
+
* @param property - parent schema of following property
|
|
9
|
+
* @param [schema] - parent schema of following property
|
|
10
|
+
* @return
|
|
10
11
|
*/
|
|
11
12
|
export default function getChildSchemaSelection(core, property, schema = core.rootSchema) {
|
|
12
13
|
const result = core.step(property, schema, {}, "#");
|
|
13
|
-
if (result
|
|
14
|
+
if (isJSONError(result)) {
|
|
14
15
|
if (result.code === "one-of-error") {
|
|
15
|
-
return result.data.oneOf.map(item => core.resolveRef(item));
|
|
16
|
+
return result.data.oneOf.map((item) => core.resolveRef(item));
|
|
16
17
|
}
|
|
17
18
|
return result;
|
|
18
19
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import gp from "gson-pointer";
|
|
2
|
+
import { isJSONError } from "./types";
|
|
2
3
|
const emptyObject = {};
|
|
3
4
|
/**
|
|
4
5
|
* Returns the json-schema of a data-json-pointer.
|
|
@@ -23,7 +24,7 @@ function _get(core, schema, frags, pointer, data = emptyObject) {
|
|
|
23
24
|
}
|
|
24
25
|
const key = frags.shift(); // step key
|
|
25
26
|
schema = core.step(key, schema, data, pointer); // step schema
|
|
26
|
-
if (schema
|
|
27
|
+
if (isJSONError(schema)) {
|
|
27
28
|
return schema;
|
|
28
29
|
}
|
|
29
30
|
data = data[key]; // step data
|
|
@@ -4,6 +4,10 @@ import getTypeOf from "./getTypeOf";
|
|
|
4
4
|
import merge from "./utils/merge";
|
|
5
5
|
import copy from "./utils/copy";
|
|
6
6
|
import settings from "./config/settings";
|
|
7
|
+
import { isJSONError } from "./types";
|
|
8
|
+
const defaultOptions = {
|
|
9
|
+
addOptionalProps: true
|
|
10
|
+
};
|
|
7
11
|
let cache;
|
|
8
12
|
function shouldResolveRef(schema, pointer) {
|
|
9
13
|
// ensure we refactored consistently
|
|
@@ -14,7 +18,7 @@ function shouldResolveRef(schema, pointer) {
|
|
|
14
18
|
if ($ref == null) {
|
|
15
19
|
return true;
|
|
16
20
|
}
|
|
17
|
-
const value =
|
|
21
|
+
const value = cache[pointer] == null || cache[pointer][$ref] == null ? 0 : cache[pointer][$ref];
|
|
18
22
|
return value < settings.GET_TEMPLATE_RECURSION_LIMIT;
|
|
19
23
|
}
|
|
20
24
|
function resolveRef(core, schema, pointer) {
|
|
@@ -102,7 +106,7 @@ const isJSONSchema = (template) => template && typeof template === "object";
|
|
|
102
106
|
* @param [schema] - json schema, defaults to rootSchema
|
|
103
107
|
* @return created template data
|
|
104
108
|
*/
|
|
105
|
-
function getTemplate(core, data, _schema, pointer) {
|
|
109
|
+
function getTemplate(core, data, _schema, pointer, opts) {
|
|
106
110
|
if (_schema == null) {
|
|
107
111
|
throw new Error(`getTemplate: missing schema for data: ${JSON.stringify(data)}`);
|
|
108
112
|
}
|
|
@@ -115,13 +119,16 @@ function getTemplate(core, data, _schema, pointer) {
|
|
|
115
119
|
return undefined;
|
|
116
120
|
}
|
|
117
121
|
pointer = schema.pointer;
|
|
122
|
+
if (schema === null || schema === void 0 ? void 0 : schema.const) {
|
|
123
|
+
return schema.const;
|
|
124
|
+
}
|
|
118
125
|
if (schema.oneOf) {
|
|
119
126
|
// find correct schema for data
|
|
120
127
|
const resolvedSchema = resolveOneOfFuzzy(core, data, schema);
|
|
121
|
-
if (data == null && resolvedSchema
|
|
128
|
+
if (data == null && isJSONError(resolvedSchema)) {
|
|
122
129
|
schema = schema.oneOf[0];
|
|
123
130
|
}
|
|
124
|
-
else if (resolvedSchema.type
|
|
131
|
+
else if (isJSONError(resolvedSchema.type)) {
|
|
125
132
|
// @todo - check: do not return schema, but either input-data or undefined (clearing wrong data)
|
|
126
133
|
return data;
|
|
127
134
|
}
|
|
@@ -129,6 +136,9 @@ function getTemplate(core, data, _schema, pointer) {
|
|
|
129
136
|
schema = resolvedSchema;
|
|
130
137
|
}
|
|
131
138
|
}
|
|
139
|
+
// @todo Array.isArray(schema.type)
|
|
140
|
+
// -> hasDefault? return
|
|
141
|
+
// if not -> pick first type
|
|
132
142
|
if (!isJSONSchema(schema) || schema.type == null) {
|
|
133
143
|
return undefined;
|
|
134
144
|
}
|
|
@@ -136,35 +146,56 @@ function getTemplate(core, data, _schema, pointer) {
|
|
|
136
146
|
if (data != null && getTypeOf(data) !== schema.type) {
|
|
137
147
|
data = convertValue(schema.type, data);
|
|
138
148
|
}
|
|
139
|
-
if (TYPE[schema.type] == null) {
|
|
149
|
+
if (TYPE[schema.type] == null) {
|
|
150
|
+
// eslint-disable-line no-use-before-define
|
|
140
151
|
throw new Error(`Unsupported type '${schema.type} in ${JSON.stringify(schema)}'`);
|
|
141
152
|
}
|
|
142
|
-
const templateData = TYPE[schema.type](core, schema, data, pointer); // eslint-disable-line no-use-before-define
|
|
153
|
+
const templateData = TYPE[schema.type](core, schema, data, pointer, opts); // eslint-disable-line no-use-before-define
|
|
143
154
|
return templateData;
|
|
144
155
|
}
|
|
145
156
|
const TYPE = {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
null: (core, schema, data) => getDefault(schema, data, null),
|
|
158
|
+
string: (core, schema, data) => getDefault(schema, data, ""),
|
|
159
|
+
number: (core, schema, data) => getDefault(schema, data, 0),
|
|
160
|
+
integer: (core, schema, data) => getDefault(schema, data, 0),
|
|
161
|
+
boolean: (core, schema, data) => getDefault(schema, data, false),
|
|
162
|
+
object: (core, schema, data, pointer, opts) => {
|
|
151
163
|
const template = schema.default === undefined ? {} : schema.default;
|
|
152
164
|
const d = {}; // do not assign data here, to keep ordering from json-schema
|
|
153
165
|
if (schema.properties) {
|
|
154
|
-
Object.keys(schema.properties).forEach(key => {
|
|
155
|
-
const value =
|
|
156
|
-
|
|
166
|
+
Object.keys(schema.properties).forEach((key) => {
|
|
167
|
+
const value = data == null || data[key] == null ? template[key] : data[key];
|
|
168
|
+
const isRequired = Array.isArray(schema.required) && schema.required.includes(key);
|
|
169
|
+
// Omit adding a property if it is not required or optional props should be added
|
|
170
|
+
if (value != null || isRequired || opts.addOptionalProps) {
|
|
171
|
+
d[key] = getTemplate(core, value, schema.properties[key], `${pointer}/properties/${key}`, opts);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (schema.dependencies) {
|
|
176
|
+
Object.keys(schema.dependencies).forEach((key) => {
|
|
177
|
+
const dependency = schema.dependencies[key];
|
|
178
|
+
if (getTypeOf(dependency) !== "object") {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (d[key] === undefined) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const result = getTemplate(core, data, { ...dependency, type: "object" }, `${pointer}/dependencies/${key}`, opts);
|
|
185
|
+
if (result && !isJSONError(result)) {
|
|
186
|
+
Object.assign(d, result);
|
|
187
|
+
}
|
|
157
188
|
});
|
|
158
189
|
}
|
|
159
190
|
if (data) {
|
|
160
191
|
// merge any missing data (additionals) to resulting object
|
|
161
|
-
Object.keys(data).forEach(key =>
|
|
192
|
+
Object.keys(data).forEach((key) => d[key] == null && (d[key] = data[key]));
|
|
162
193
|
}
|
|
163
194
|
// returns object, which is ordered by json-schema
|
|
164
195
|
return d;
|
|
165
196
|
},
|
|
166
197
|
// build array type of items, ignores additionalItems
|
|
167
|
-
|
|
198
|
+
array: (core, schema, data, pointer, opts) => {
|
|
168
199
|
const template = schema.default === undefined ? [] : schema.default;
|
|
169
200
|
const d = data || [];
|
|
170
201
|
schema.minItems = schema.minItems || 0;
|
|
@@ -175,7 +206,7 @@ const TYPE = {
|
|
|
175
206
|
// build defined set of items
|
|
176
207
|
if (Array.isArray(schema.items)) {
|
|
177
208
|
for (let i = 0, l = Math.min(schema.minItems, schema.items.length); i < l; i += 1) {
|
|
178
|
-
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], schema.items[i], `${pointer}/items/${i}
|
|
209
|
+
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], schema.items[i], `${pointer}/items/${i}`, opts);
|
|
179
210
|
}
|
|
180
211
|
return d;
|
|
181
212
|
}
|
|
@@ -193,7 +224,7 @@ const TYPE = {
|
|
|
193
224
|
if (templateSchema.oneOf && d.length === 0) {
|
|
194
225
|
const oneOfSchema = templateSchema.oneOf[0];
|
|
195
226
|
for (let i = 0; i < schema.minItems; i += 1) {
|
|
196
|
-
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], oneOfSchema, `${pointer}/oneOf/0
|
|
227
|
+
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], oneOfSchema, `${pointer}/oneOf/0`, opts);
|
|
197
228
|
}
|
|
198
229
|
return d;
|
|
199
230
|
}
|
|
@@ -203,7 +234,7 @@ const TYPE = {
|
|
|
203
234
|
const value = d[i] == null ? template[i] : d[i];
|
|
204
235
|
const one = resolveOneOfFuzzy(core, value, templateSchema);
|
|
205
236
|
if (one) {
|
|
206
|
-
d[i] = getTemplate(core, value, one, `${pointer}/oneOf/${i}
|
|
237
|
+
d[i] = getTemplate(core, value, one, `${pointer}/oneOf/${i}`, opts);
|
|
207
238
|
}
|
|
208
239
|
else {
|
|
209
240
|
d[i] = value;
|
|
@@ -214,7 +245,7 @@ const TYPE = {
|
|
|
214
245
|
// build items-definition
|
|
215
246
|
if (templateSchema.type) {
|
|
216
247
|
for (let i = 0, l = Math.max(schema.minItems, d.length); i < l; i += 1) {
|
|
217
|
-
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], templateSchema, `${pointer}/items
|
|
248
|
+
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], templateSchema, `${pointer}/items`, opts);
|
|
218
249
|
}
|
|
219
250
|
return d;
|
|
220
251
|
}
|
|
@@ -225,6 +256,9 @@ function getDefault(schema, templateValue, initValue) {
|
|
|
225
256
|
if (templateValue != null) {
|
|
226
257
|
return templateValue;
|
|
227
258
|
}
|
|
259
|
+
else if (schema.const) {
|
|
260
|
+
return schema.const;
|
|
261
|
+
}
|
|
228
262
|
else if (schema.default === undefined && Array.isArray(schema.enum)) {
|
|
229
263
|
return schema.enum[0];
|
|
230
264
|
}
|
|
@@ -233,7 +267,7 @@ function getDefault(schema, templateValue, initValue) {
|
|
|
233
267
|
}
|
|
234
268
|
return schema.default;
|
|
235
269
|
}
|
|
236
|
-
export default (core, data, schema = core.rootSchema) => {
|
|
237
|
-
cache = {
|
|
238
|
-
return getTemplate(core, data, schema, "#");
|
|
270
|
+
export default (core, data, schema = core.rootSchema, opts = defaultOptions) => {
|
|
271
|
+
cache = { mi: ".." };
|
|
272
|
+
return getTemplate(core, data, schema, "#", opts);
|
|
239
273
|
};
|