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
package/lib/validate.ts
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import getTypeOf from "./getTypeOf";
|
|
1
|
+
import getTypeOf, { JSType } from "./getTypeOf";
|
|
2
2
|
import { errorOrPromise } from "./utils/filter";
|
|
3
3
|
import flattenArray from "./utils/flattenArray";
|
|
4
|
-
import { JSONSchema, JSONPointer, JSONError } from "./types";
|
|
5
|
-
import Core from "./
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function getJsonSchemaType(value, expectedType) {
|
|
9
|
-
let jsType = getTypeOf(value);
|
|
4
|
+
import { JSONSchema, JSONPointer, JSONError, isJSONError } from "./types";
|
|
5
|
+
import { Draft as Core } from "./draft";
|
|
6
|
+
import equal from "fast-deep-equal";
|
|
10
7
|
|
|
8
|
+
function getJsonSchemaType(value: unknown, expectedType: string | string[]): JSType | "integer" {
|
|
9
|
+
const jsType = getTypeOf(value);
|
|
11
10
|
if (
|
|
12
|
-
jsType === "number" &&
|
|
13
|
-
(
|
|
11
|
+
jsType === "number" &&
|
|
12
|
+
(expectedType === "integer" ||
|
|
13
|
+
(Array.isArray(expectedType) && expectedType.includes("integer")))
|
|
14
14
|
) {
|
|
15
|
-
|
|
15
|
+
return Number.isInteger(value) ? "integer" : "number";
|
|
16
16
|
}
|
|
17
17
|
return jsType;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
20
|
/**
|
|
22
21
|
* Validate data by a json schema
|
|
23
22
|
*
|
|
@@ -27,18 +26,49 @@ function getJsonSchemaType(value, expectedType) {
|
|
|
27
26
|
* @param [pointer] - json pointer pointing to value (used for error-messages only)
|
|
28
27
|
* @return list of errors or empty
|
|
29
28
|
*/
|
|
30
|
-
export default function validate(
|
|
31
|
-
|
|
29
|
+
export default function validate(
|
|
30
|
+
core: Core,
|
|
31
|
+
value: unknown,
|
|
32
|
+
schema: JSONSchema = core.rootSchema,
|
|
33
|
+
pointer: JSONPointer = "#"
|
|
34
|
+
): Array<JSONError> {
|
|
35
|
+
schema = core.resolveRef(schema);
|
|
36
|
+
|
|
37
|
+
// this is a high level v7 schema validation
|
|
38
|
+
if (getTypeOf(schema) === "boolean") {
|
|
39
|
+
if (schema) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
return [core.errors.invalidDataError({ value, pointer })];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (isJSONError(schema)) {
|
|
32
46
|
return [schema as JSONError];
|
|
33
47
|
}
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
// @draft >= 6 const
|
|
50
|
+
if (schema.const !== undefined) {
|
|
51
|
+
if (equal(schema.const, value)) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
return [core.errors.constError({ value, expected: schema.const, pointer })];
|
|
55
|
+
}
|
|
36
56
|
|
|
37
57
|
const receivedType = getJsonSchemaType(value, schema.type);
|
|
38
58
|
const expectedType = schema.type || receivedType;
|
|
39
59
|
|
|
40
|
-
if (
|
|
41
|
-
|
|
60
|
+
if (
|
|
61
|
+
receivedType !== expectedType &&
|
|
62
|
+
(!Array.isArray(expectedType) || !expectedType.includes(receivedType))
|
|
63
|
+
) {
|
|
64
|
+
return [
|
|
65
|
+
core.errors.typeError({
|
|
66
|
+
received: receivedType,
|
|
67
|
+
expected: expectedType,
|
|
68
|
+
value,
|
|
69
|
+
pointer
|
|
70
|
+
})
|
|
71
|
+
];
|
|
42
72
|
}
|
|
43
73
|
|
|
44
74
|
if (core.validateType[receivedType] == null) {
|
|
@@ -47,5 +77,6 @@ export default function validate(core: Core, value: any, schema: JSONSchema = co
|
|
|
47
77
|
|
|
48
78
|
const errors = flattenArray(core.validateType[receivedType](core, schema, value, pointer));
|
|
49
79
|
// also promises may be passed along (validateAsync)
|
|
80
|
+
// @ts-ignore
|
|
50
81
|
return errors.filter(errorOrPromise);
|
|
51
82
|
}
|
package/lib/validateAsync.ts
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { errorsOnly } from "./utils/filter";
|
|
2
2
|
import flattenArray from "./utils/flattenArray";
|
|
3
|
-
import { JSONSchema, JSONPointer, JSONError } from "./types";
|
|
4
|
-
import Core from "./
|
|
5
|
-
|
|
3
|
+
import { JSONSchema, JSONPointer, JSONError, isJSONError } from "./types";
|
|
4
|
+
import { Draft as Core } from "./draft";
|
|
6
5
|
|
|
7
6
|
function createErrorNotification(onError: OnError) {
|
|
8
|
-
return function notifyError(error) {
|
|
7
|
+
return function notifyError(error: JSONError | JSONError[]) {
|
|
9
8
|
if (Array.isArray(error)) {
|
|
10
9
|
error = flattenArray(error);
|
|
11
10
|
error.forEach(notifyError);
|
|
12
11
|
return error;
|
|
13
12
|
}
|
|
14
|
-
if (
|
|
13
|
+
if (isJSONError(error)) {
|
|
15
14
|
onError(error);
|
|
16
15
|
}
|
|
17
16
|
return error;
|
|
18
17
|
};
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
|
|
22
20
|
export interface OnError {
|
|
23
21
|
(error: JSONError): void;
|
|
24
22
|
}
|
|
@@ -27,7 +25,7 @@ export type Options = {
|
|
|
27
25
|
schema?: JSONSchema;
|
|
28
26
|
pointer?: JSONPointer;
|
|
29
27
|
onError?: OnError;
|
|
30
|
-
}
|
|
28
|
+
};
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
31
|
* @async
|
|
@@ -41,7 +39,11 @@ export type Options = {
|
|
|
41
39
|
* @param options.onError - will be called for each error as soon as it is resolved
|
|
42
40
|
* @return list of errors or empty
|
|
43
41
|
*/
|
|
44
|
-
export default function validateAsync(
|
|
42
|
+
export default function validateAsync(
|
|
43
|
+
core: Core,
|
|
44
|
+
value: any,
|
|
45
|
+
options?: Options
|
|
46
|
+
): Promise<Array<JSONError>> {
|
|
45
47
|
const { schema, pointer, onError } = { schema: core.rootSchema, pointer: "#", ...options };
|
|
46
48
|
|
|
47
49
|
let errors: Array<JSONError> = core.validate(value, schema, pointer);
|
|
@@ -51,17 +53,16 @@ export default function validateAsync(core: Core, value: any, options?: Options)
|
|
|
51
53
|
for (let i = 0; i < errors.length; i += 1) {
|
|
52
54
|
if (errors[i] instanceof Promise) {
|
|
53
55
|
errors[i].then(notifyError);
|
|
54
|
-
} else if (
|
|
56
|
+
} else if (isJSONError(errors[i])) {
|
|
55
57
|
onError(errors[i]);
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
return Promise
|
|
61
|
-
.all(errors)
|
|
62
|
+
return Promise.all(errors)
|
|
62
63
|
.then(flattenArray)
|
|
63
|
-
.then(resolvedErrors => resolvedErrors.filter(errorsOnly))
|
|
64
|
-
.catch(e => {
|
|
64
|
+
.then((resolvedErrors) => resolvedErrors.filter(errorsOnly))
|
|
65
|
+
.catch((e) => {
|
|
65
66
|
console.log("Failed resolving promises", e.message);
|
|
66
67
|
console.log(e.stack);
|
|
67
68
|
throw e;
|
package/lib/validation/errors.ts
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
/* eslint no-invalid-this: 0 */
|
|
2
|
-
import createCustomError,
|
|
2
|
+
import { createCustomError, CreateError } from "../utils/createCustomError";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
const errors: { [p: string]: CreateError } = {
|
|
4
|
+
const errors: Record<string, CreateError> = {
|
|
6
5
|
additionalItemsError: createCustomError("AdditionalItemsError"),
|
|
7
6
|
additionalPropertiesError: createCustomError("AdditionalPropertiesError"),
|
|
8
7
|
anyOfError: createCustomError("AnyOfError"),
|
|
9
8
|
allOfError: createCustomError("AllOfError"),
|
|
9
|
+
constError: createCustomError("ConstError"),
|
|
10
|
+
containsError: createCustomError("ContainsError"),
|
|
11
|
+
containsArrayError: createCustomError("ContainsArrayError"),
|
|
12
|
+
containsAnyError: createCustomError("ContainsAnyError"),
|
|
10
13
|
enumError: createCustomError("EnumError"),
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
formatURLError: createCustomError("FormatURLError"),
|
|
15
|
+
formatURIError: createCustomError("FormatURIError"),
|
|
16
|
+
formatURIReferenceError: createCustomError("FormatURIReferenceError"),
|
|
17
|
+
formatURITemplateError: createCustomError("FormatURITemplateError"),
|
|
18
|
+
formatDateError: createCustomError("FormatDateaError"),
|
|
13
19
|
formatDateTimeError: createCustomError("FormatDateTimeError"),
|
|
14
20
|
formatEmailError: createCustomError("FormatEmailError"),
|
|
15
21
|
formatHostnameError: createCustomError("FormatHostnameError"),
|
|
16
22
|
formatIPV4Error: createCustomError("FormatIPV4Error"),
|
|
23
|
+
formatIPV4LeadingZeroError: createCustomError("FormatIPV4LeadingZeroError"),
|
|
17
24
|
formatIPV6Error: createCustomError("FormatIPV6Error"),
|
|
25
|
+
formatIPV6LeadingZeroError: createCustomError("FormatIPV6LeadingZeroError"),
|
|
26
|
+
formatJSONPointerError: createCustomError("FormatJSONPointerError"),
|
|
18
27
|
formatRegExError: createCustomError("FormatRegExError"),
|
|
28
|
+
formatTimeError: createCustomError("FormatTimeError"),
|
|
19
29
|
invalidSchemaError: createCustomError("InvalidSchemaError"),
|
|
30
|
+
invalidDataError: createCustomError("InvalidDataError"),
|
|
20
31
|
invalidTypeError: createCustomError("InvalidTypeError"),
|
|
32
|
+
invalidPropertyNameError: createCustomError("InvalidPropertyNameError"),
|
|
21
33
|
maximumError: createCustomError("MaximumError"),
|
|
22
34
|
maxItemsError: createCustomError("MaxItemsError"),
|
|
23
35
|
maxLengthError: createCustomError("MaxLengthError"),
|
|
@@ -44,5 +56,4 @@ const errors: { [p: string]: CreateError } = {
|
|
|
44
56
|
valueNotEmptyError: createCustomError("ValueNotEmptyError")
|
|
45
57
|
};
|
|
46
58
|
|
|
47
|
-
|
|
48
59
|
export default errors;
|
package/lib/validation/format.ts
CHANGED
|
@@ -1,16 +1,68 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
1
|
+
/* eslint-disable max-len, no-control-regex */
|
|
2
2
|
import errors from "./errors";
|
|
3
|
+
import { JSONError, JSONSchema } from "../types";
|
|
4
|
+
import { Draft } from "../draft";
|
|
3
5
|
import validUrl from "valid-url";
|
|
4
6
|
|
|
7
|
+
// referenced
|
|
8
|
+
// https://github.com/cfworker/cfworker/blob/main/packages/json-schema/src/format.ts
|
|
9
|
+
|
|
5
10
|
// https://gist.github.com/marcelotmelo/b67f58a08bee6c2468f8
|
|
6
|
-
const isValidDateTime = new RegExp(
|
|
11
|
+
const isValidDateTime = new RegExp(
|
|
12
|
+
"^([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]))$"
|
|
13
|
+
);
|
|
7
14
|
const isValidIPV4 = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
|
8
|
-
const isValidIPV6 =
|
|
9
|
-
|
|
15
|
+
const isValidIPV6 =
|
|
16
|
+
/^((([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;
|
|
17
|
+
const isValidHostname =
|
|
18
|
+
/^(?=.{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])?)*\.?$/;
|
|
19
|
+
const matchDate = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
20
|
+
const matchTime = /^(\d\d):(\d\d):(\d\d)(\.\d+)?(z|[+-]\d\d(?::?\d\d)?)?$/i;
|
|
21
|
+
const DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
10
22
|
|
|
23
|
+
const isValidJSONPointer = /^(?:\/(?:[^~/]|~0|~1)*)*$/;
|
|
24
|
+
const isValidRelativeJSONPointer = /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;
|
|
25
|
+
const isValidURIRef =
|
|
26
|
+
/^(?:[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;
|
|
27
|
+
// uri-template: https://tools.ietf.org/html/rfc6570
|
|
28
|
+
const isValidURITemplate =
|
|
29
|
+
/^(?:(?:[^\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;
|
|
11
30
|
|
|
12
31
|
// Default JSON-Schema formats: date-time, email, hostname, ipv4, ipv6, uri, uriref
|
|
13
|
-
|
|
32
|
+
const formatValidators: Record<
|
|
33
|
+
string,
|
|
34
|
+
(
|
|
35
|
+
draft: Draft,
|
|
36
|
+
schema: JSONSchema,
|
|
37
|
+
value: unknown,
|
|
38
|
+
pointer: string
|
|
39
|
+
) => undefined | JSONError | JSONError[]
|
|
40
|
+
> = {
|
|
41
|
+
date: (core, schema, value, pointer) => {
|
|
42
|
+
if (typeof value !== "string") {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
// https://github.com/cfworker/cfworker/blob/main/packages/json-schema/src/format.ts
|
|
46
|
+
// full-date from http://tools.ietf.org/html/rfc3339#section-5.6
|
|
47
|
+
const matches = value.match(matchDate);
|
|
48
|
+
if (!matches) {
|
|
49
|
+
return errors.formatDateTimeError({ value, pointer });
|
|
50
|
+
}
|
|
51
|
+
const year = +matches[1];
|
|
52
|
+
const month = +matches[2];
|
|
53
|
+
const day = +matches[3];
|
|
54
|
+
// https://tools.ietf.org/html/rfc3339#appendix-C
|
|
55
|
+
const isLeapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
56
|
+
if (
|
|
57
|
+
month >= 1 &&
|
|
58
|
+
month <= 12 &&
|
|
59
|
+
day >= 1 &&
|
|
60
|
+
day <= (month == 2 && isLeapYear ? 29 : DAYS[month])
|
|
61
|
+
) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return errors.formatDateError({ value, pointer });
|
|
65
|
+
},
|
|
14
66
|
|
|
15
67
|
"date-time": (core, schema, value, pointer) => {
|
|
16
68
|
if (typeof value !== "string") {
|
|
@@ -33,17 +85,17 @@ export default {
|
|
|
33
85
|
if (value[0] === '"') {
|
|
34
86
|
return errors.formatEmailError({ value, pointer });
|
|
35
87
|
}
|
|
36
|
-
const [name, host, ...rest] = value.split(
|
|
37
|
-
if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253
|
|
88
|
+
const [name, host, ...rest] = value.split("@");
|
|
89
|
+
if (!name || !host || rest.length !== 0 || name.length > 64 || host.length > 253) {
|
|
38
90
|
return errors.formatEmailError({ value, pointer });
|
|
39
91
|
}
|
|
40
|
-
if (name[0] ===
|
|
92
|
+
if (name[0] === "." || name.endsWith(".") || name.includes("..")) {
|
|
41
93
|
return errors.formatEmailError({ value, pointer });
|
|
42
94
|
}
|
|
43
95
|
if (!/^[a-z0-9.-]+$/i.test(host) || !/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+$/i.test(name)) {
|
|
44
96
|
return errors.formatEmailError({ value, pointer });
|
|
45
97
|
}
|
|
46
|
-
if (!host.split(
|
|
98
|
+
if (!host.split(".").every((part) => /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(part))) {
|
|
47
99
|
return errors.formatEmailError({ value, pointer });
|
|
48
100
|
}
|
|
49
101
|
return undefined;
|
|
@@ -63,6 +115,10 @@ export default {
|
|
|
63
115
|
if (typeof value !== "string" || value === "") {
|
|
64
116
|
return undefined;
|
|
65
117
|
}
|
|
118
|
+
if (value && value[0] === "0") {
|
|
119
|
+
// leading zeroes should be rejected, as they are treated as octals
|
|
120
|
+
return errors.formatIPV4LeadingZeroError({ value, pointer });
|
|
121
|
+
}
|
|
66
122
|
if (value.length <= 15 && isValidIPV4.test(value)) {
|
|
67
123
|
return undefined;
|
|
68
124
|
}
|
|
@@ -73,33 +129,111 @@ export default {
|
|
|
73
129
|
if (typeof value !== "string" || value === "") {
|
|
74
130
|
return undefined;
|
|
75
131
|
}
|
|
132
|
+
if (value && value[0] === "0") {
|
|
133
|
+
// leading zeroes should be rejected, as they are treated as octals
|
|
134
|
+
return errors.formatIPV6LeadingZeroError({ value, pointer });
|
|
135
|
+
}
|
|
76
136
|
if (value.length <= 45 && isValidIPV6.test(value)) {
|
|
77
137
|
return undefined;
|
|
78
138
|
}
|
|
79
139
|
return errors.formatIPV6Error({ value, pointer });
|
|
80
140
|
},
|
|
81
141
|
|
|
142
|
+
"json-pointer": (core, schema, value, pointer) => {
|
|
143
|
+
if (typeof value !== "string" || value === "") {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
if (isValidJSONPointer.test(value)) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
return errors.formatJSONPointerError({ value, pointer });
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
"relative-json-pointer": (core, schema, value, pointer) => {
|
|
153
|
+
if (typeof value !== "string" || value === "") {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
if (isValidRelativeJSONPointer.test(value)) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
return errors.formatJSONPointerError({ value, pointer });
|
|
160
|
+
},
|
|
161
|
+
|
|
82
162
|
regex: (core, schema, value, pointer) => {
|
|
83
163
|
if (typeof value === "string" && /\\Z$/.test(value) === false) {
|
|
164
|
+
try {
|
|
165
|
+
new RegExp(value);
|
|
166
|
+
return undefined;
|
|
167
|
+
} catch (e) {} // eslint-disable-line no-empty
|
|
168
|
+
|
|
169
|
+
return errors.formatRegExError({ value, pointer });
|
|
170
|
+
}
|
|
171
|
+
// v7 tests, ignore non-regex values
|
|
172
|
+
if (typeof value === "object" || typeof value === "number" || Array.isArray(value)) {
|
|
84
173
|
return undefined;
|
|
85
174
|
}
|
|
86
175
|
return errors.formatRegExError({ value, pointer });
|
|
87
176
|
},
|
|
88
177
|
|
|
89
|
-
|
|
178
|
+
time: (core, schema, value, pointer) => {
|
|
90
179
|
if (typeof value !== "string") {
|
|
91
180
|
return undefined;
|
|
92
181
|
}
|
|
93
|
-
|
|
182
|
+
// https://github.com/cfworker/cfworker/blob/main/packages/json-schema/src/format.ts
|
|
183
|
+
const matches = value.match(matchTime);
|
|
184
|
+
if (!matches) {
|
|
185
|
+
return errors.formatDateTimeError({ value, pointer });
|
|
186
|
+
}
|
|
187
|
+
const hour = +matches[1];
|
|
188
|
+
const minute = +matches[2];
|
|
189
|
+
const second = +matches[3];
|
|
190
|
+
const timeZone = !!matches[5];
|
|
191
|
+
if (
|
|
192
|
+
((hour <= 23 && minute <= 59 && second <= 59) ||
|
|
193
|
+
(hour == 23 && minute == 59 && second == 60)) &&
|
|
194
|
+
timeZone
|
|
195
|
+
) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
return errors.formatTimeError({ value, pointer });
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
uri: (core, schema, value, pointer) => {
|
|
202
|
+
if (typeof value !== "string" || value === "") {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
if (validUrl.isUri(value)) {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
return errors.formatURIError({ value, pointer });
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
"uri-reference": (core, schema, value, pointer) => {
|
|
212
|
+
if (typeof value !== "string" || value === "") {
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
if (isValidURIRef.test(value)) {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
return errors.formatURIReferenceError({ value, pointer });
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
"uri-template": (core, schema, value, pointer) => {
|
|
222
|
+
if (typeof value !== "string" || value === "") {
|
|
94
223
|
return undefined;
|
|
95
224
|
}
|
|
96
|
-
|
|
225
|
+
if (isValidURITemplate.test(value)) {
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
return errors.formatURITemplateError({ value, pointer });
|
|
97
229
|
},
|
|
98
230
|
|
|
99
|
-
url: (core, schema, value, pointer) => {
|
|
231
|
+
url: (core, schema, value: string, pointer) => {
|
|
100
232
|
if (value === "" || validUrl.isWebUri(value)) {
|
|
101
233
|
return undefined;
|
|
102
234
|
}
|
|
103
235
|
return errors.formatUrlError({ value, pointer });
|
|
104
236
|
}
|
|
105
237
|
};
|
|
238
|
+
|
|
239
|
+
export default formatValidators;
|