json-schema-library 5.3.0 → 7.0.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/.editorconfig +1 -0
- package/.prettierignore +1 -0
- package/.prettierrc +7 -0
- package/CHANGELOG.md +106 -0
- package/README.md +811 -199
- package/TASKS.md +3 -81
- package/dist/index.d.ts +29 -71
- package/dist/jsonSchemaLibrary.js +1 -1
- package/dist/lib/SchemaService.d.ts +6 -8
- package/dist/lib/{addSchema.d.ts → addRemoteSchema.d.ts} +2 -1
- package/dist/lib/addValidator.d.ts +3 -2
- package/dist/lib/compile/getRef.d.ts +2 -1
- package/dist/lib/compile/index.d.ts +15 -1
- package/dist/lib/compile/types.d.ts +5 -0
- package/dist/lib/config/strings.d.ts +1 -39
- package/dist/lib/draft/index.d.ts +132 -0
- package/dist/lib/draft04/index.d.ts +7 -0
- package/dist/lib/draft06/compile/index.d.ts +16 -0
- package/dist/lib/draft06/index.d.ts +7 -0
- package/dist/lib/draft06/validation/keyword.d.ts +3 -0
- package/dist/lib/draft06/validation/type.d.ts +10 -0
- package/dist/lib/draft06/validation/typeKeywordMapping.d.ts +13 -0
- package/dist/lib/draft07/index.d.ts +7 -0
- package/dist/lib/each.d.ts +3 -2
- package/dist/lib/eachSchema.d.ts +2 -4
- package/dist/lib/getChildSchemaSelection.d.ts +7 -5
- package/dist/lib/getSchema.d.ts +2 -2
- package/dist/lib/getTemplate.d.ts +1 -1
- package/dist/lib/getTypeOf.d.ts +2 -1
- package/dist/lib/isValid.d.ts +1 -1
- package/dist/lib/jsoneditor/index.d.ts +7 -0
- package/dist/lib/resolveAllOf.d.ts +1 -1
- package/dist/lib/resolveAnyOf.d.ts +1 -1
- package/dist/lib/resolveOneOf.fuzzy.d.ts +1 -1
- package/dist/lib/resolveOneOf.strict.d.ts +2 -2
- package/dist/lib/{resolveRef.withOverwrite.d.ts → resolveRef.merge.d.ts} +0 -0
- package/dist/lib/schema/getTypeDefs.d.ts +6 -4
- package/dist/lib/schema/getTypeId.d.ts +1 -1
- package/dist/lib/schema/types.d.ts +7 -57
- package/dist/lib/step.d.ts +5 -5
- package/dist/lib/types.d.ts +11 -3
- package/dist/lib/utils/createCustomError.d.ts +8 -11
- package/dist/lib/utils/filter.d.ts +4 -4
- package/dist/lib/utils/flattenArray.d.ts +1 -1
- package/dist/lib/utils/merge.d.ts +3 -0
- package/dist/lib/utils/punycode.ucs2decode.d.ts +1 -1
- package/dist/lib/validate.d.ts +2 -2
- package/dist/lib/validateAsync.d.ts +1 -1
- package/dist/lib/validation/errors.d.ts +1 -3
- package/dist/lib/validation/format.d.ts +4 -11
- 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 +23 -32
- package/dist/module/lib/SchemaService.js +7 -4
- package/dist/module/lib/{addSchema.js → addRemoteSchema.js} +2 -4
- package/dist/module/lib/addValidator.js +3 -4
- package/dist/module/lib/compile/getRef.js +1 -1
- package/dist/module/lib/compile/index.js +43 -18
- package/dist/module/lib/compile/types.js +1 -0
- package/dist/module/lib/config/strings.js +15 -2
- package/dist/module/lib/createSchemaOf.js +1 -1
- package/dist/module/lib/draft/index.js +133 -0
- package/dist/module/lib/draft04/index.js +90 -0
- package/dist/module/lib/draft06/compile/index.js +77 -0
- package/dist/module/lib/draft06/index.js +96 -0
- package/dist/module/lib/draft06/validation/keyword.js +168 -0
- package/dist/module/lib/draft06/validation/type.js +31 -0
- package/dist/module/lib/draft06/validation/typeKeywordMapping.js +15 -0
- package/dist/module/lib/draft07/index.js +96 -0
- package/dist/module/lib/each.js +2 -2
- package/dist/module/lib/eachSchema.js +28 -19
- package/dist/module/lib/getChildSchemaSelection.js +7 -6
- package/dist/module/lib/getSchema.js +4 -2
- package/dist/module/lib/getTemplate.js +42 -15
- package/dist/module/lib/jsoneditor/index.js +16 -0
- package/dist/module/lib/resolveAllOf.js +3 -4
- package/dist/module/lib/resolveOneOf.fuzzy.js +13 -3
- package/dist/module/lib/resolveOneOf.strict.js +49 -2
- package/dist/module/lib/{resolveRef.withOverwrite.js → resolveRef.merge.js} +0 -0
- package/dist/module/lib/resolveRef.strict.js +8 -0
- package/dist/module/lib/schema/getTypeDefs.js +14 -3
- package/dist/module/lib/schema/getTypeId.js +10 -6
- package/dist/module/lib/schema/types.js +33 -9
- package/dist/module/lib/step.js +67 -13
- package/dist/module/lib/types.js +7 -1
- package/dist/module/lib/utils/createCustomError.js +4 -4
- package/dist/module/lib/utils/filter.js +3 -5
- package/dist/module/lib/utils/flattenArray.js +4 -3
- package/dist/module/lib/utils/merge.js +4 -0
- package/dist/module/lib/utils/punycode.ucs2decode.js +4 -3
- package/dist/module/lib/validate.js +34 -8
- package/dist/module/lib/validateAsync.js +7 -7
- package/dist/module/lib/validation/errors.js +16 -3
- package/dist/module/lib/validation/format.js +115 -8
- package/dist/module/lib/validation/keyword.js +79 -32
- package/dist/module/lib/validation/type.js +2 -1
- package/index.ts +46 -32
- package/lib/SchemaService.ts +18 -11
- package/lib/{addSchema.ts → addRemoteSchema.ts} +3 -5
- package/lib/addValidator.ts +15 -12
- package/lib/compile/getRef.ts +3 -4
- package/lib/compile/index.ts +65 -19
- package/lib/compile/types.ts +6 -0
- package/lib/config/strings.ts +17 -3
- package/lib/createSchemaOf.ts +1 -3
- package/lib/draft/index.ts +201 -0
- package/lib/draft04/index.ts +95 -0
- package/lib/draft06/compile/index.ts +104 -0
- package/lib/draft06/index.ts +101 -0
- package/lib/draft06/validation/keyword.ts +199 -0
- package/lib/draft06/validation/type.ts +47 -0
- package/lib/draft06/validation/typeKeywordMapping.ts +15 -0
- package/lib/draft07/index.ts +101 -0
- package/lib/each.ts +11 -4
- package/lib/eachSchema.ts +45 -32
- package/lib/getChildSchemaSelection.ts +14 -7
- package/lib/getSchema.ts +18 -9
- package/lib/getTemplate.ts +155 -42
- package/lib/getTypeOf.ts +2 -1
- package/lib/isValid.ts +7 -3
- package/lib/jsoneditor/index.ts +20 -0
- package/lib/resolveAllOf.ts +10 -6
- package/lib/resolveAnyOf.ts +7 -3
- package/lib/resolveOneOf.fuzzy.ts +26 -9
- package/lib/resolveOneOf.strict.ts +63 -5
- package/lib/{resolveRef.withOverwrite.ts → resolveRef.merge.ts} +0 -0
- package/lib/resolveRef.strict.ts +9 -0
- package/lib/schema/getTypeDefs.ts +19 -7
- package/lib/schema/getTypeId.ts +11 -8
- package/lib/schema/types.ts +41 -9
- package/lib/step.ts +109 -25
- package/lib/types.ts +23 -5
- package/lib/utils/createCustomError.ts +8 -13
- package/lib/utils/filter.ts +7 -9
- package/lib/utils/flattenArray.ts +5 -4
- package/lib/utils/merge.ts +5 -0
- package/lib/utils/punycode.ucs2decode.ts +6 -5
- package/lib/validate.ts +47 -16
- package/lib/validateAsync.ts +15 -14
- package/lib/validation/errors.ts +17 -6
- package/lib/validation/format.ts +147 -13
- package/lib/validation/keyword.ts +172 -103
- package/lib/validation/type.ts +5 -1
- package/package.json +75 -63
- package/{dist/module/remotes/draft04.json → remotes/draft06.json} +47 -42
- package/remotes/draft07.json +172 -0
- package/remotes/draft2019-09.json +86 -0
- package/tsconfig.json +3 -10
- package/dist/lib/cores/CoreInterface.d.ts +0 -23
- package/dist/lib/cores/Draft04.d.ts +0 -13
- package/dist/lib/cores/JsonEditor.d.ts +0 -13
- package/dist/module/lib/cores/CoreInterface.js +0 -51
- package/dist/module/lib/cores/Draft04.js +0 -52
- package/dist/module/lib/cores/JsonEditor.js +0 -51
- package/dist/module/remotes/index.js +0 -10
- package/dist/remotes/index.d.ts +0 -5
- package/lib/cores/CoreInterface.ts +0 -76
- package/lib/cores/Draft04.ts +0 -66
- package/lib/cores/JsonEditor.ts +0 -64
- package/remotes/index.ts +0 -11
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export default function flattenArray(list, result = []) {
|
|
2
2
|
for (let i = 0; i < list.length; i += 1) {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const item = list[i];
|
|
4
|
+
if (Array.isArray(item)) {
|
|
5
|
+
flattenArray(item, result);
|
|
5
6
|
}
|
|
6
7
|
else {
|
|
7
|
-
result.push(
|
|
8
|
+
result.push(item);
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
return result;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import deepmerge from "deepmerge";
|
|
2
|
+
// @ts-ignore
|
|
2
3
|
const overwriteMerge = (destinationArray, sourceArray) => sourceArray;
|
|
4
|
+
/**
|
|
5
|
+
* returns a new json-schema, where properties are combined and arrays are replaced
|
|
6
|
+
*/
|
|
3
7
|
export default (a, b) => deepmerge(a, b, { arrayMerge: overwriteMerge });
|
|
@@ -20,12 +20,13 @@ export default function ucs2decode(string) {
|
|
|
20
20
|
const length = string.length;
|
|
21
21
|
while (counter < length) {
|
|
22
22
|
const value = string.charCodeAt(counter++);
|
|
23
|
-
if (value >=
|
|
23
|
+
if (value >= 0xd800 && value <= 0xdbff && counter < length) {
|
|
24
24
|
// It's a high surrogate, and there is a next character.
|
|
25
25
|
const extra = string.charCodeAt(counter++);
|
|
26
26
|
// eslint-disable-next-line eqeqeq
|
|
27
|
-
if ((extra &
|
|
28
|
-
|
|
27
|
+
if ((extra & 0xfc00) == 0xdc00) {
|
|
28
|
+
// Low surrogate.
|
|
29
|
+
output.push(((value & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000);
|
|
29
30
|
}
|
|
30
31
|
else {
|
|
31
32
|
// It's an unmatched surrogate; only append this code unit, in case the
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import getTypeOf from "./getTypeOf";
|
|
2
2
|
import { errorOrPromise } from "./utils/filter";
|
|
3
3
|
import flattenArray from "./utils/flattenArray";
|
|
4
|
+
import { isJSONError } from "./types";
|
|
5
|
+
import equal from "fast-deep-equal";
|
|
4
6
|
function getJsonSchemaType(value, expectedType) {
|
|
5
|
-
|
|
6
|
-
if (jsType === "number" &&
|
|
7
|
-
(
|
|
8
|
-
|
|
7
|
+
const jsType = getTypeOf(value);
|
|
8
|
+
if (jsType === "number" &&
|
|
9
|
+
(expectedType === "integer" ||
|
|
10
|
+
(Array.isArray(expectedType) && expectedType.includes("integer")))) {
|
|
11
|
+
return Number.isInteger(value) ? "integer" : "number";
|
|
9
12
|
}
|
|
10
13
|
return jsType;
|
|
11
14
|
}
|
|
@@ -19,19 +22,42 @@ function getJsonSchemaType(value, expectedType) {
|
|
|
19
22
|
* @return list of errors or empty
|
|
20
23
|
*/
|
|
21
24
|
export default function validate(core, value, schema = core.rootSchema, pointer = "#") {
|
|
22
|
-
|
|
25
|
+
schema = core.resolveRef(schema);
|
|
26
|
+
// this is a high level v7 schema validation
|
|
27
|
+
if (getTypeOf(schema) === "boolean") {
|
|
28
|
+
if (schema) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
return [core.errors.invalidDataError({ value, pointer })];
|
|
32
|
+
}
|
|
33
|
+
if (isJSONError(schema)) {
|
|
23
34
|
return [schema];
|
|
24
35
|
}
|
|
25
|
-
|
|
36
|
+
// @draft >= 6 const
|
|
37
|
+
if (schema.const !== undefined) {
|
|
38
|
+
if (equal(schema.const, value)) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
return [core.errors.constError({ value, expected: schema.const, pointer })];
|
|
42
|
+
}
|
|
26
43
|
const receivedType = getJsonSchemaType(value, schema.type);
|
|
27
44
|
const expectedType = schema.type || receivedType;
|
|
28
|
-
if (receivedType !== expectedType &&
|
|
29
|
-
|
|
45
|
+
if (receivedType !== expectedType &&
|
|
46
|
+
(!Array.isArray(expectedType) || !expectedType.includes(receivedType))) {
|
|
47
|
+
return [
|
|
48
|
+
core.errors.typeError({
|
|
49
|
+
received: receivedType,
|
|
50
|
+
expected: expectedType,
|
|
51
|
+
value,
|
|
52
|
+
pointer
|
|
53
|
+
})
|
|
54
|
+
];
|
|
30
55
|
}
|
|
31
56
|
if (core.validateType[receivedType] == null) {
|
|
32
57
|
return [core.errors.invalidTypeError({ receivedType, pointer })];
|
|
33
58
|
}
|
|
34
59
|
const errors = flattenArray(core.validateType[receivedType](core, schema, value, pointer));
|
|
35
60
|
// also promises may be passed along (validateAsync)
|
|
61
|
+
// @ts-ignore
|
|
36
62
|
return errors.filter(errorOrPromise);
|
|
37
63
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { errorsOnly } from "./utils/filter";
|
|
2
2
|
import flattenArray from "./utils/flattenArray";
|
|
3
|
+
import { isJSONError } from "./types";
|
|
3
4
|
function createErrorNotification(onError) {
|
|
4
5
|
return function notifyError(error) {
|
|
5
6
|
if (Array.isArray(error)) {
|
|
@@ -7,7 +8,7 @@ function createErrorNotification(onError) {
|
|
|
7
8
|
error.forEach(notifyError);
|
|
8
9
|
return error;
|
|
9
10
|
}
|
|
10
|
-
if (
|
|
11
|
+
if (isJSONError(error)) {
|
|
11
12
|
onError(error);
|
|
12
13
|
}
|
|
13
14
|
return error;
|
|
@@ -35,16 +36,15 @@ export default function validateAsync(core, value, options) {
|
|
|
35
36
|
if (errors[i] instanceof Promise) {
|
|
36
37
|
errors[i].then(notifyError);
|
|
37
38
|
}
|
|
38
|
-
else if (
|
|
39
|
+
else if (isJSONError(errors[i])) {
|
|
39
40
|
onError(errors[i]);
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
|
-
return Promise
|
|
44
|
-
.all(errors)
|
|
44
|
+
return Promise.all(errors)
|
|
45
45
|
.then(flattenArray)
|
|
46
|
-
.then(resolvedErrors => resolvedErrors.filter(errorsOnly))
|
|
47
|
-
.catch(e => {
|
|
46
|
+
.then((resolvedErrors) => resolvedErrors.filter(errorsOnly))
|
|
47
|
+
.catch((e) => {
|
|
48
48
|
console.log("Failed resolving promises", e.message);
|
|
49
49
|
console.log(e.stack);
|
|
50
50
|
throw e;
|
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
/* eslint no-invalid-this: 0 */
|
|
2
|
-
import createCustomError from "../utils/createCustomError";
|
|
2
|
+
import { createCustomError } from "../utils/createCustomError";
|
|
3
3
|
const errors = {
|
|
4
4
|
additionalItemsError: createCustomError("AdditionalItemsError"),
|
|
5
5
|
additionalPropertiesError: createCustomError("AdditionalPropertiesError"),
|
|
6
6
|
anyOfError: createCustomError("AnyOfError"),
|
|
7
7
|
allOfError: createCustomError("AllOfError"),
|
|
8
|
+
constError: createCustomError("ConstError"),
|
|
9
|
+
containsError: createCustomError("ContainsError"),
|
|
10
|
+
containsArrayError: createCustomError("ContainsArrayError"),
|
|
11
|
+
containsAnyError: createCustomError("ContainsAnyError"),
|
|
8
12
|
enumError: createCustomError("EnumError"),
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
formatURLError: createCustomError("FormatURLError"),
|
|
14
|
+
formatURIError: createCustomError("FormatURIError"),
|
|
15
|
+
formatURIReferenceError: createCustomError("FormatURIReferenceError"),
|
|
16
|
+
formatURITemplateError: createCustomError("FormatURITemplateError"),
|
|
17
|
+
formatDateError: createCustomError("FormatDateaError"),
|
|
11
18
|
formatDateTimeError: createCustomError("FormatDateTimeError"),
|
|
12
19
|
formatEmailError: createCustomError("FormatEmailError"),
|
|
13
20
|
formatHostnameError: createCustomError("FormatHostnameError"),
|
|
14
21
|
formatIPV4Error: createCustomError("FormatIPV4Error"),
|
|
22
|
+
formatIPV4LeadingZeroError: createCustomError("FormatIPV4LeadingZeroError"),
|
|
15
23
|
formatIPV6Error: createCustomError("FormatIPV6Error"),
|
|
24
|
+
formatIPV6LeadingZeroError: createCustomError("FormatIPV6LeadingZeroError"),
|
|
25
|
+
formatJSONPointerError: createCustomError("FormatJSONPointerError"),
|
|
16
26
|
formatRegExError: createCustomError("FormatRegExError"),
|
|
27
|
+
formatTimeError: createCustomError("FormatTimeError"),
|
|
17
28
|
invalidSchemaError: createCustomError("InvalidSchemaError"),
|
|
29
|
+
invalidDataError: createCustomError("InvalidDataError"),
|
|
18
30
|
invalidTypeError: createCustomError("InvalidTypeError"),
|
|
31
|
+
invalidPropertyNameError: createCustomError("InvalidPropertyNameError"),
|
|
19
32
|
maximumError: createCustomError("MaximumError"),
|
|
20
33
|
maxItemsError: createCustomError("MaxItemsError"),
|
|
21
34
|
maxLengthError: createCustomError("MaxLengthError"),
|
|
@@ -1,13 +1,46 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
1
|
+
/* eslint-disable max-len, no-control-regex */
|
|
2
2
|
import errors from "./errors";
|
|
3
3
|
import validUrl from "valid-url";
|
|
4
|
+
// referenced
|
|
5
|
+
// https://github.com/cfworker/cfworker/blob/main/packages/json-schema/src/format.ts
|
|
4
6
|
// https://gist.github.com/marcelotmelo/b67f58a08bee6c2468f8
|
|
5
7
|
const isValidDateTime = new RegExp("^([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[Tt]([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\\.[0-9]+)?(([Zz])|([\\+|\\-]([01][0-9]|2[0-3]):[0-5][0-9]))$");
|
|
6
8
|
const isValidIPV4 = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
|
7
9
|
const isValidIPV6 = /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i;
|
|
8
10
|
const isValidHostname = /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/;
|
|
11
|
+
const matchDate = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
12
|
+
const matchTime = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i;
|
|
13
|
+
const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
14
|
+
const isValidJSONPointer = /^(?:\/(?:[^~/]|~0|~1)*)*$/;
|
|
15
|
+
const isValidRelativeJSONPointer = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;
|
|
16
|
+
const isValidURIRef = /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
|
|
17
|
+
// uri-template: https://tools.ietf.org/html/rfc6570
|
|
18
|
+
const isValidURITemplate = /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i;
|
|
9
19
|
// Default JSON-Schema formats: date-time, email, hostname, ipv4, ipv6, uri, uriref
|
|
10
|
-
|
|
20
|
+
const formatValidators = {
|
|
21
|
+
date: (core, schema, value, pointer) => {
|
|
22
|
+
if (typeof value !== "string") {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
// https://github.com/cfworker/cfworker/blob/main/packages/json-schema/src/format.ts
|
|
26
|
+
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
27
|
+
const matches = value.match(matchDate);
|
|
28
|
+
if (!matches) {
|
|
29
|
+
return errors.formatDateTimeError({ value, pointer });
|
|
30
|
+
}
|
|
31
|
+
const year = +matches[1];
|
|
32
|
+
const month = +matches[2];
|
|
33
|
+
const day = +matches[3];
|
|
34
|
+
// https://tools.ietf.org/html/rfc3339#appendix-C
|
|
35
|
+
const isLeapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
36
|
+
if (month >= 1 &&
|
|
37
|
+
month <= 12 &&
|
|
38
|
+
day >= 1 &&
|
|
39
|
+
day <= (month == 2 && isLeapYear ? 29 : DAYS[month])) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return errors.formatDateError({ value, pointer });
|
|
43
|
+
},
|
|
11
44
|
"date-time": (core, schema, value, pointer) => {
|
|
12
45
|
if (typeof value !== "string") {
|
|
13
46
|
return undefined;
|
|
@@ -28,17 +61,17 @@ export default {
|
|
|
28
61
|
if (value[0] === '"') {
|
|
29
62
|
return errors.formatEmailError({ value, pointer });
|
|
30
63
|
}
|
|
31
|
-
const [name, host, ...rest] = value.split(
|
|
64
|
+
const [name, host, ...rest] = value.split("@");
|
|
32
65
|
if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253) {
|
|
33
66
|
return errors.formatEmailError({ value, pointer });
|
|
34
67
|
}
|
|
35
|
-
if (name[0] ===
|
|
68
|
+
if (name[0] === "." || name.endsWith(".") || name.includes("..")) {
|
|
36
69
|
return errors.formatEmailError({ value, pointer });
|
|
37
70
|
}
|
|
38
71
|
if (!/^[a-z0-9.-]+$/i.test(host) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) {
|
|
39
72
|
return errors.formatEmailError({ value, pointer });
|
|
40
73
|
}
|
|
41
|
-
if (!host.split(
|
|
74
|
+
if (!host.split(".").every((part) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part))) {
|
|
42
75
|
return errors.formatEmailError({ value, pointer });
|
|
43
76
|
}
|
|
44
77
|
return undefined;
|
|
@@ -56,6 +89,10 @@ export default {
|
|
|
56
89
|
if (typeof value !== "string" || value === "") {
|
|
57
90
|
return undefined;
|
|
58
91
|
}
|
|
92
|
+
if (value && value[0] === "0") {
|
|
93
|
+
// leading zeroes should be rejected, as they are treated as octals
|
|
94
|
+
return errors.formatIPV4LeadingZeroError({ value, pointer });
|
|
95
|
+
}
|
|
59
96
|
if (value.length <= 15 && isValidIPV4.test(value)) {
|
|
60
97
|
return undefined;
|
|
61
98
|
}
|
|
@@ -65,25 +102,94 @@ export default {
|
|
|
65
102
|
if (typeof value !== "string" || value === "") {
|
|
66
103
|
return undefined;
|
|
67
104
|
}
|
|
105
|
+
if (value && value[0] === "0") {
|
|
106
|
+
// leading zeroes should be rejected, as they are treated as octals
|
|
107
|
+
return errors.formatIPV6LeadingZeroError({ value, pointer });
|
|
108
|
+
}
|
|
68
109
|
if (value.length <= 45 && isValidIPV6.test(value)) {
|
|
69
110
|
return undefined;
|
|
70
111
|
}
|
|
71
112
|
return errors.formatIPV6Error({ value, pointer });
|
|
72
113
|
},
|
|
114
|
+
"json-pointer": (core, schema, value, pointer) => {
|
|
115
|
+
if (typeof value !== "string" || value === "") {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
if (isValidJSONPointer.test(value)) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
return errors.formatJSONPointerError({ value, pointer });
|
|
122
|
+
},
|
|
123
|
+
"relative-json-pointer": (core, schema, value, pointer) => {
|
|
124
|
+
if (typeof value !== "string" || value === "") {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
if (isValidRelativeJSONPointer.test(value)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return errors.formatJSONPointerError({ value, pointer });
|
|
131
|
+
},
|
|
73
132
|
regex: (core, schema, value, pointer) => {
|
|
74
133
|
if (typeof value === "string" && /\\Z$/.test(value) === false) {
|
|
134
|
+
try {
|
|
135
|
+
new RegExp(value);
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
catch (e) { } // eslint-disable-line no-empty
|
|
139
|
+
return errors.formatRegExError({ value, pointer });
|
|
140
|
+
}
|
|
141
|
+
// v7 tests, ignore non-regex values
|
|
142
|
+
if (typeof value === "object" || typeof value === "number" || Array.isArray(value)) {
|
|
75
143
|
return undefined;
|
|
76
144
|
}
|
|
77
145
|
return errors.formatRegExError({ value, pointer });
|
|
78
146
|
},
|
|
79
|
-
|
|
147
|
+
time: (core, schema, value, pointer) => {
|
|
80
148
|
if (typeof value !== "string") {
|
|
81
149
|
return undefined;
|
|
82
150
|
}
|
|
83
|
-
|
|
151
|
+
// https://github.com/cfworker/cfworker/blob/main/packages/json-schema/src/format.ts
|
|
152
|
+
const matches = value.match(matchTime);
|
|
153
|
+
if (!matches) {
|
|
154
|
+
return errors.formatDateTimeError({ value, pointer });
|
|
155
|
+
}
|
|
156
|
+
const hour = +matches[1];
|
|
157
|
+
const minute = +matches[2];
|
|
158
|
+
const second = +matches[3];
|
|
159
|
+
const timeZone = !!matches[5];
|
|
160
|
+
if (((hour <= 23 && minute <= 59 && second <= 59) ||
|
|
161
|
+
(hour == 23 && minute == 59 && second == 60)) &&
|
|
162
|
+
timeZone) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return errors.formatTimeError({ value, pointer });
|
|
166
|
+
},
|
|
167
|
+
uri: (core, schema, value, pointer) => {
|
|
168
|
+
if (typeof value !== "string" || value === "") {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
if (validUrl.isUri(value)) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
return errors.formatURIError({ value, pointer });
|
|
175
|
+
},
|
|
176
|
+
"uri-reference": (core, schema, value, pointer) => {
|
|
177
|
+
if (typeof value !== "string" || value === "") {
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
if (isValidURIRef.test(value)) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
return errors.formatURIReferenceError({ value, pointer });
|
|
184
|
+
},
|
|
185
|
+
"uri-template": (core, schema, value, pointer) => {
|
|
186
|
+
if (typeof value !== "string" || value === "") {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
if (isValidURITemplate.test(value)) {
|
|
84
190
|
return undefined;
|
|
85
191
|
}
|
|
86
|
-
return errors.
|
|
192
|
+
return errors.formatURITemplateError({ value, pointer });
|
|
87
193
|
},
|
|
88
194
|
url: (core, schema, value, pointer) => {
|
|
89
195
|
if (value === "" || validUrl.isWebUri(value)) {
|
|
@@ -92,3 +198,4 @@ export default {
|
|
|
92
198
|
return errors.formatUrlError({ value, pointer });
|
|
93
199
|
}
|
|
94
200
|
};
|
|
201
|
+
export default formatValidators;
|
|
@@ -2,25 +2,29 @@ import getTypeOf from "../getTypeOf";
|
|
|
2
2
|
import isSame from "../utils/deepCompare";
|
|
3
3
|
import settings from "../config/settings";
|
|
4
4
|
import ucs2decode from "../utils/punycode.ucs2decode";
|
|
5
|
+
import { isJSONError } from "../types";
|
|
5
6
|
const FPP = settings.floatingPointPrecision;
|
|
7
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
8
|
+
const hasProperty = (value, property) => !(value[property] === undefined || !hasOwnProperty.call(value, property));
|
|
6
9
|
// list of validation keywords: http://json-schema.org/latest/json-schema-validation.html#rfc.section.5
|
|
7
10
|
const KeywordValidation = {
|
|
8
11
|
additionalProperties: (core, schema, value, pointer) => {
|
|
9
12
|
if (schema.additionalProperties === true || schema.additionalProperties == null) {
|
|
10
13
|
return undefined;
|
|
11
14
|
}
|
|
12
|
-
if (getTypeOf(schema.patternProperties) === "object" &&
|
|
15
|
+
if (getTypeOf(schema.patternProperties) === "object" &&
|
|
16
|
+
schema.additionalProperties === false) {
|
|
13
17
|
// this is an arrangement with patternProperties. patternProperties validate before additionalProperties:
|
|
14
18
|
// https://spacetelescope.github.io/understanding-json-schema/reference/object.html#index-5
|
|
15
19
|
return undefined;
|
|
16
20
|
}
|
|
17
21
|
const errors = [];
|
|
18
|
-
let receivedProperties = Object.keys(value).filter(prop => settings.propertyBlacklist.includes(prop) === false);
|
|
22
|
+
let receivedProperties = Object.keys(value).filter((prop) => settings.propertyBlacklist.includes(prop) === false);
|
|
19
23
|
const expectedProperties = Object.keys(schema.properties || {});
|
|
20
24
|
if (getTypeOf(schema.patternProperties) === "object") {
|
|
21
25
|
// filter received properties by matching patternProperties
|
|
22
|
-
const patterns = Object.keys(schema.patternProperties).map(pattern => new RegExp(pattern));
|
|
23
|
-
receivedProperties = receivedProperties.filter(prop => {
|
|
26
|
+
const patterns = Object.keys(schema.patternProperties).map((pattern) => new RegExp(pattern));
|
|
27
|
+
receivedProperties = receivedProperties.filter((prop) => {
|
|
24
28
|
for (let i = 0; i < patterns.length; i += 1) {
|
|
25
29
|
if (patterns[i].test(prop)) {
|
|
26
30
|
return false; // remove
|
|
@@ -37,7 +41,7 @@ const KeywordValidation = {
|
|
|
37
41
|
// additionalProperties { oneOf: [] }
|
|
38
42
|
if (isObject && Array.isArray(schema.additionalProperties.oneOf)) {
|
|
39
43
|
const result = core.resolveOneOf(value[property], schema.additionalProperties, `${pointer}/${property}`);
|
|
40
|
-
if (result
|
|
44
|
+
if (isJSONError(result)) {
|
|
41
45
|
errors.push(core.errors.additionalPropertiesError({
|
|
42
46
|
schema: schema.additionalProperties,
|
|
43
47
|
property: receivedProperties[i],
|
|
@@ -48,12 +52,13 @@ const KeywordValidation = {
|
|
|
48
52
|
}));
|
|
49
53
|
}
|
|
50
54
|
else {
|
|
51
|
-
errors.push(core.validate(value[property], result, pointer));
|
|
55
|
+
errors.push(...core.validate(value[property], result, pointer));
|
|
52
56
|
}
|
|
53
57
|
// additionalProperties {}
|
|
54
58
|
}
|
|
55
59
|
else if (isObject) {
|
|
56
|
-
if (core.validate(value[property], schema.additionalProperties, pointer)
|
|
60
|
+
if (core.validate(value[property], schema.additionalProperties, pointer)
|
|
61
|
+
.length !== 0) {
|
|
57
62
|
errors.push(core.errors.additionalPropertiesError({
|
|
58
63
|
schema: schema.additionalProperties,
|
|
59
64
|
property: receivedProperties[i],
|
|
@@ -63,7 +68,11 @@ const KeywordValidation = {
|
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
else {
|
|
66
|
-
errors.push(core.errors.noAdditionalPropertiesError({
|
|
71
|
+
errors.push(core.errors.noAdditionalPropertiesError({
|
|
72
|
+
property: receivedProperties[i],
|
|
73
|
+
properties: expectedProperties,
|
|
74
|
+
pointer
|
|
75
|
+
}));
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
}
|
|
@@ -74,8 +83,8 @@ const KeywordValidation = {
|
|
|
74
83
|
return undefined;
|
|
75
84
|
}
|
|
76
85
|
const errors = [];
|
|
77
|
-
schema.allOf.forEach(subSchema => {
|
|
78
|
-
errors.push(core.validate(value, subSchema, pointer));
|
|
86
|
+
schema.allOf.forEach((subSchema) => {
|
|
87
|
+
errors.push(...core.validate(value, subSchema, pointer));
|
|
79
88
|
});
|
|
80
89
|
return errors;
|
|
81
90
|
},
|
|
@@ -95,17 +104,24 @@ const KeywordValidation = {
|
|
|
95
104
|
return undefined;
|
|
96
105
|
}
|
|
97
106
|
const errors = [];
|
|
98
|
-
Object.keys(value)
|
|
99
|
-
.forEach(property => {
|
|
107
|
+
Object.keys(value).forEach((property) => {
|
|
100
108
|
if (schema.dependencies[property] === undefined) {
|
|
101
109
|
return;
|
|
102
110
|
}
|
|
111
|
+
// @draft >= 6 boolean schema
|
|
112
|
+
if (schema.dependencies[property] === true) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (schema.dependencies[property] === false) {
|
|
116
|
+
errors.push(core.errors.missingDependencyError({ pointer }));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
103
119
|
let dependencyErrors;
|
|
104
120
|
const type = getTypeOf(schema.dependencies[property]);
|
|
105
121
|
if (type === "array") {
|
|
106
122
|
dependencyErrors = schema.dependencies[property]
|
|
107
|
-
.filter(dependency => value[dependency] === undefined)
|
|
108
|
-
.map(missingProperty => core.errors.missingDependencyError({ missingProperty, pointer }));
|
|
123
|
+
.filter((dependency) => value[dependency] === undefined)
|
|
124
|
+
.map((missingProperty) => core.errors.missingDependencyError({ missingProperty, pointer }));
|
|
109
125
|
}
|
|
110
126
|
else if (type === "object") {
|
|
111
127
|
dependencyErrors = core.validate(value, schema.dependencies[property]);
|
|
@@ -117,7 +133,7 @@ const KeywordValidation = {
|
|
|
117
133
|
});
|
|
118
134
|
return errors.length > 0 ? errors : undefined;
|
|
119
135
|
},
|
|
120
|
-
|
|
136
|
+
enum: (core, schema, value, pointer) => {
|
|
121
137
|
const type = getTypeOf(value);
|
|
122
138
|
if (type === "object" || type === "array") {
|
|
123
139
|
const valueStr = JSON.stringify(value);
|
|
@@ -141,12 +157,19 @@ const KeywordValidation = {
|
|
|
141
157
|
return undefined;
|
|
142
158
|
},
|
|
143
159
|
items: (core, schema, value, pointer) => {
|
|
160
|
+
// @draft >= 7 bool schema
|
|
161
|
+
if (schema.items === false) {
|
|
162
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return core.errors.invalidDataError({ pointer, value });
|
|
166
|
+
}
|
|
144
167
|
const errors = [];
|
|
145
168
|
for (let i = 0; i < value.length; i += 1) {
|
|
146
169
|
const itemData = value[i];
|
|
147
170
|
// @todo reevaluate: incomplete schema is created here
|
|
148
171
|
const itemSchema = core.step(i, schema, value, pointer);
|
|
149
|
-
if (itemSchema
|
|
172
|
+
if (isJSONError(itemSchema)) {
|
|
150
173
|
return [itemSchema];
|
|
151
174
|
}
|
|
152
175
|
const itemErrors = core.validate(itemData, itemSchema, `${pointer}/${i}`);
|
|
@@ -171,7 +194,11 @@ const KeywordValidation = {
|
|
|
171
194
|
return undefined;
|
|
172
195
|
}
|
|
173
196
|
if (schema.maxItems < value.length) {
|
|
174
|
-
return core.errors.maxItemsError({
|
|
197
|
+
return core.errors.maxItemsError({
|
|
198
|
+
maximum: schema.maxItems,
|
|
199
|
+
length: value.length,
|
|
200
|
+
pointer
|
|
201
|
+
});
|
|
175
202
|
}
|
|
176
203
|
return undefined;
|
|
177
204
|
},
|
|
@@ -181,7 +208,11 @@ const KeywordValidation = {
|
|
|
181
208
|
}
|
|
182
209
|
const lengthOfString = ucs2decode(value).length;
|
|
183
210
|
if (schema.maxLength < lengthOfString) {
|
|
184
|
-
return core.errors.maxLengthError({
|
|
211
|
+
return core.errors.maxLengthError({
|
|
212
|
+
maxLength: schema.maxLength,
|
|
213
|
+
length: lengthOfString,
|
|
214
|
+
pointer
|
|
215
|
+
});
|
|
185
216
|
}
|
|
186
217
|
return undefined;
|
|
187
218
|
},
|
|
@@ -202,7 +233,11 @@ const KeywordValidation = {
|
|
|
202
233
|
}
|
|
203
234
|
const lengthOfString = ucs2decode(value).length;
|
|
204
235
|
if (schema.minLength > lengthOfString) {
|
|
205
|
-
return core.errors.minLengthError({
|
|
236
|
+
return core.errors.minLengthError({
|
|
237
|
+
minLength: schema.minLength,
|
|
238
|
+
length: lengthOfString,
|
|
239
|
+
pointer
|
|
240
|
+
});
|
|
206
241
|
}
|
|
207
242
|
return undefined;
|
|
208
243
|
},
|
|
@@ -223,7 +258,11 @@ const KeywordValidation = {
|
|
|
223
258
|
return undefined;
|
|
224
259
|
}
|
|
225
260
|
if (schema.minItems > value.length) {
|
|
226
|
-
return core.errors.minItemsError({
|
|
261
|
+
return core.errors.minItemsError({
|
|
262
|
+
minItems: schema.minItems,
|
|
263
|
+
length: value.length,
|
|
264
|
+
pointer
|
|
265
|
+
});
|
|
227
266
|
}
|
|
228
267
|
return undefined;
|
|
229
268
|
},
|
|
@@ -235,7 +274,8 @@ const KeywordValidation = {
|
|
|
235
274
|
if (schema.minProperties > propertyCount) {
|
|
236
275
|
return core.errors.minPropertiesError({
|
|
237
276
|
minProperties: schema.minProperties,
|
|
238
|
-
length: propertyCount,
|
|
277
|
+
length: propertyCount,
|
|
278
|
+
pointer
|
|
239
279
|
});
|
|
240
280
|
}
|
|
241
281
|
return undefined;
|
|
@@ -246,9 +286,10 @@ const KeywordValidation = {
|
|
|
246
286
|
}
|
|
247
287
|
// https://github.com/cfworker/cfworker/blob/master/packages/json-schema/src/validate.ts#L1061
|
|
248
288
|
// https://github.com/ExodusMovement/schemasafe/blob/master/src/compile.js#L441
|
|
249
|
-
if ((value * FPP) % (schema.multipleOf * FPP) / FPP !== 0) {
|
|
289
|
+
if (((value * FPP) % (schema.multipleOf * FPP)) / FPP !== 0) {
|
|
250
290
|
return core.errors.multipleOfError({ multipleOf: schema.multipleOf, value, pointer });
|
|
251
291
|
}
|
|
292
|
+
// also check https://stackoverflow.com/questions/1815367/catch-and-compute-overflow-during-multiplication-of-two-large-integers
|
|
252
293
|
return undefined;
|
|
253
294
|
},
|
|
254
295
|
not: (core, schema, value, pointer) => {
|
|
@@ -263,7 +304,7 @@ const KeywordValidation = {
|
|
|
263
304
|
return undefined;
|
|
264
305
|
}
|
|
265
306
|
schema = core.resolveOneOf(value, schema, pointer);
|
|
266
|
-
if (schema
|
|
307
|
+
if (isJSONError(schema)) {
|
|
267
308
|
return schema;
|
|
268
309
|
}
|
|
269
310
|
return undefined;
|
|
@@ -274,7 +315,8 @@ const KeywordValidation = {
|
|
|
274
315
|
return core.errors.patternError({
|
|
275
316
|
pattern: schema.pattern,
|
|
276
317
|
description: schema.patternExample || schema.pattern,
|
|
277
|
-
received: value,
|
|
318
|
+
received: value,
|
|
319
|
+
pointer
|
|
278
320
|
});
|
|
279
321
|
}
|
|
280
322
|
return undefined;
|
|
@@ -287,11 +329,11 @@ const KeywordValidation = {
|
|
|
287
329
|
}
|
|
288
330
|
const errors = [];
|
|
289
331
|
const keys = Object.keys(value);
|
|
290
|
-
const patterns = Object.keys(pp).map(expr => ({
|
|
332
|
+
const patterns = Object.keys(pp).map((expr) => ({
|
|
291
333
|
regex: new RegExp(expr),
|
|
292
334
|
patternSchema: pp[expr]
|
|
293
335
|
}));
|
|
294
|
-
keys.forEach(key => {
|
|
336
|
+
keys.forEach((key) => {
|
|
295
337
|
let patternFound = false;
|
|
296
338
|
for (let i = 0, l = patterns.length; i < l; i += 1) {
|
|
297
339
|
if (patterns[i].regex.test(key)) {
|
|
@@ -308,7 +350,9 @@ const KeywordValidation = {
|
|
|
308
350
|
if (patternFound === false && schema.additionalProperties === false) {
|
|
309
351
|
// this is an arrangement with additionalProperties
|
|
310
352
|
errors.push(core.errors.patternPropertiesError({
|
|
311
|
-
key,
|
|
353
|
+
key,
|
|
354
|
+
pointer,
|
|
355
|
+
patterns: Object.keys(pp).join(",")
|
|
312
356
|
}));
|
|
313
357
|
}
|
|
314
358
|
});
|
|
@@ -319,7 +363,7 @@ const KeywordValidation = {
|
|
|
319
363
|
const keys = Object.keys(schema.properties || {});
|
|
320
364
|
for (let i = 0; i < keys.length; i += 1) {
|
|
321
365
|
const key = keys[i];
|
|
322
|
-
if (value
|
|
366
|
+
if (hasProperty(value, key)) {
|
|
323
367
|
const itemSchema = core.step(key, schema, value, pointer);
|
|
324
368
|
const keyErrors = core.validate(value[key], itemSchema, `${pointer}/${key}`);
|
|
325
369
|
errors.push(...keyErrors);
|
|
@@ -348,8 +392,8 @@ const KeywordValidation = {
|
|
|
348
392
|
if (Array.isArray(schema.required) === false) {
|
|
349
393
|
return undefined;
|
|
350
394
|
}
|
|
351
|
-
return schema.required.map(property => {
|
|
352
|
-
if (value
|
|
395
|
+
return schema.required.map((property) => {
|
|
396
|
+
if (!hasProperty(value, property)) {
|
|
353
397
|
return core.errors.requiredPropertyError({ key: property, pointer });
|
|
354
398
|
}
|
|
355
399
|
return undefined;
|
|
@@ -360,9 +404,12 @@ const KeywordValidation = {
|
|
|
360
404
|
if (Array.isArray(schema.required) === false) {
|
|
361
405
|
return undefined;
|
|
362
406
|
}
|
|
363
|
-
return schema.required.map(property => {
|
|
407
|
+
return schema.required.map((property) => {
|
|
364
408
|
if (value[property] == null || value[property] === "") {
|
|
365
|
-
return core.errors.valueNotEmptyError({
|
|
409
|
+
return core.errors.valueNotEmptyError({
|
|
410
|
+
property,
|
|
411
|
+
pointer: `${pointer}/${property}`
|
|
412
|
+
});
|
|
366
413
|
}
|
|
367
414
|
return undefined;
|
|
368
415
|
});
|