schema-shield 0.0.2 → 0.0.3
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/LICENSE +201 -0
- package/README.md +738 -6
- package/dist/formats.d.ts +2 -2
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +25 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +891 -964
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +904 -964
- package/dist/keywords/array-keywords.d.ts +2 -2
- package/dist/keywords/array-keywords.d.ts.map +1 -1
- package/dist/keywords/number-keywords.d.ts +2 -2
- package/dist/keywords/number-keywords.d.ts.map +1 -1
- package/dist/keywords/object-keywords.d.ts +2 -2
- package/dist/keywords/object-keywords.d.ts.map +1 -1
- package/dist/keywords/other-keywords.d.ts +2 -2
- package/dist/keywords/other-keywords.d.ts.map +1 -1
- package/dist/keywords/string-keywords.d.ts +2 -2
- package/dist/keywords/string-keywords.d.ts.map +1 -1
- package/dist/keywords.d.ts +2 -2
- package/dist/keywords.d.ts.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +23 -7
- package/dist/utils.d.ts.map +1 -1
- package/lib/formats.ts +80 -36
- package/lib/index.ts +175 -221
- package/lib/keywords/array-keywords.ts +137 -145
- package/lib/keywords/number-keywords.ts +78 -62
- package/lib/keywords/object-keywords.ts +199 -144
- package/lib/keywords/other-keywords.ts +137 -195
- package/lib/keywords/string-keywords.ts +25 -132
- package/lib/keywords.ts +2 -2
- package/lib/types.ts +37 -164
- package/lib/utils.ts +106 -28
- package/package.json +3 -2
package/lib/types.ts
CHANGED
|
@@ -1,176 +1,49 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { TypeFunction } from "./index";
|
|
2
|
+
import { isObject } from "./utils";
|
|
3
3
|
|
|
4
|
-
export const Types: Record<string,
|
|
5
|
-
object(
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
valid: true,
|
|
9
|
-
errors: [],
|
|
10
|
-
data
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
valid: false,
|
|
16
|
-
errors: [
|
|
17
|
-
new ValidationError("Data is not an object", {
|
|
18
|
-
pointer,
|
|
19
|
-
value: data,
|
|
20
|
-
code: "NOT_AN_OBJECT"
|
|
21
|
-
})
|
|
22
|
-
],
|
|
23
|
-
data
|
|
24
|
-
};
|
|
4
|
+
export const Types: Record<string, TypeFunction | false> = {
|
|
5
|
+
object(data) {
|
|
6
|
+
return isObject(data);
|
|
25
7
|
},
|
|
26
|
-
array(
|
|
8
|
+
array(data) {
|
|
27
9
|
if (Array.isArray(data)) {
|
|
28
|
-
return
|
|
29
|
-
valid: true,
|
|
30
|
-
errors: [],
|
|
31
|
-
data
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (typeof data === "object" && data !== null && "length" in data) {
|
|
36
|
-
// Check if the first key is a number and the length is the same as the number of keys - 1 (length)
|
|
37
|
-
const keys = Object.keys(data);
|
|
38
|
-
if (keys.length > 0 && (keys[0] !== "0" || keys.length !== data.length)) {
|
|
39
|
-
return {
|
|
40
|
-
valid: false,
|
|
41
|
-
errors: [
|
|
42
|
-
new ValidationError("Data is not an array", {
|
|
43
|
-
pointer,
|
|
44
|
-
value: data,
|
|
45
|
-
code: "NOT_AN_ARRAY"
|
|
46
|
-
})
|
|
47
|
-
],
|
|
48
|
-
data
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
valid: true,
|
|
54
|
-
errors: [],
|
|
55
|
-
data
|
|
56
|
-
};
|
|
10
|
+
return true;
|
|
57
11
|
}
|
|
58
12
|
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
67
|
-
],
|
|
68
|
-
data
|
|
69
|
-
};
|
|
13
|
+
return (
|
|
14
|
+
typeof data === "object" &&
|
|
15
|
+
data !== null &&
|
|
16
|
+
"length" in data &&
|
|
17
|
+
"0" in data &&
|
|
18
|
+
Object.keys(data).length - 1 === data.length
|
|
19
|
+
);
|
|
70
20
|
},
|
|
71
|
-
string(
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
valid: true,
|
|
75
|
-
errors: [],
|
|
76
|
-
data
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
valid: false,
|
|
82
|
-
errors: [
|
|
83
|
-
new ValidationError("Data is not a string", {
|
|
84
|
-
pointer,
|
|
85
|
-
value: data,
|
|
86
|
-
code: "NOT_A_STRING"
|
|
87
|
-
})
|
|
88
|
-
],
|
|
89
|
-
data
|
|
90
|
-
};
|
|
21
|
+
string(data) {
|
|
22
|
+
return typeof data === "string";
|
|
91
23
|
},
|
|
92
|
-
number(
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
valid: true,
|
|
96
|
-
errors: [],
|
|
97
|
-
data
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
valid: false,
|
|
103
|
-
errors: [
|
|
104
|
-
new ValidationError("Data is not a number", {
|
|
105
|
-
pointer,
|
|
106
|
-
value: data,
|
|
107
|
-
code: "NOT_A_NUMBER"
|
|
108
|
-
})
|
|
109
|
-
],
|
|
110
|
-
data
|
|
111
|
-
};
|
|
24
|
+
number(data) {
|
|
25
|
+
return typeof data === "number";
|
|
112
26
|
},
|
|
113
|
-
integer(
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
valid: true,
|
|
117
|
-
errors: [],
|
|
118
|
-
data
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
valid: false,
|
|
124
|
-
errors: [
|
|
125
|
-
new ValidationError("Data is not an integer", {
|
|
126
|
-
pointer,
|
|
127
|
-
value: data,
|
|
128
|
-
code: "NOT_AN_INTEGER"
|
|
129
|
-
})
|
|
130
|
-
],
|
|
131
|
-
data
|
|
132
|
-
};
|
|
27
|
+
integer(data) {
|
|
28
|
+
return typeof data === "number" && data % 1 === 0;
|
|
133
29
|
},
|
|
134
|
-
boolean(
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
valid: true,
|
|
138
|
-
errors: [],
|
|
139
|
-
data
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
valid: false,
|
|
145
|
-
errors: [
|
|
146
|
-
new ValidationError("Data is not a boolean", {
|
|
147
|
-
pointer,
|
|
148
|
-
value: data,
|
|
149
|
-
code: "NOT_A_BOOLEAN"
|
|
150
|
-
})
|
|
151
|
-
],
|
|
152
|
-
data
|
|
153
|
-
};
|
|
30
|
+
boolean(data) {
|
|
31
|
+
return typeof data === "boolean";
|
|
154
32
|
},
|
|
155
|
-
null(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
33
|
+
null(data) {
|
|
34
|
+
return data === null;
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Not implemented yet
|
|
38
|
+
timestamp: false,
|
|
39
|
+
int8: false,
|
|
40
|
+
unit8: false,
|
|
41
|
+
int16: false,
|
|
42
|
+
unit16: false,
|
|
43
|
+
int32: false,
|
|
44
|
+
unit32: false,
|
|
45
|
+
float32: false,
|
|
46
|
+
float64: false
|
|
47
|
+
|
|
163
48
|
|
|
164
|
-
return {
|
|
165
|
-
valid: false,
|
|
166
|
-
errors: [
|
|
167
|
-
new ValidationError("Data is not null", {
|
|
168
|
-
pointer,
|
|
169
|
-
value: data,
|
|
170
|
-
code: "NOT_NULL"
|
|
171
|
-
})
|
|
172
|
-
],
|
|
173
|
-
data
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
49
|
};
|
package/lib/utils.ts
CHANGED
|
@@ -1,38 +1,65 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CompiledSchema } from "./index";
|
|
2
2
|
|
|
3
3
|
export class ValidationError extends Error {
|
|
4
|
-
name: string;
|
|
5
|
-
pointer: string;
|
|
6
4
|
message: string;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
item: string | number;
|
|
6
|
+
keyword: string;
|
|
7
|
+
cause: ValidationError;
|
|
8
|
+
path: string = "";
|
|
9
|
+
data?: any;
|
|
10
|
+
schema?: CompiledSchema;
|
|
11
|
+
|
|
12
|
+
private _getCause(pointer = "#") {
|
|
13
|
+
const path =
|
|
14
|
+
pointer +
|
|
15
|
+
"/" +
|
|
16
|
+
this.keyword +
|
|
17
|
+
(typeof this.item !== "undefined" ? "/" + this.item : "");
|
|
18
|
+
|
|
19
|
+
if (!this.cause) {
|
|
20
|
+
this.path = path;
|
|
21
|
+
return this;
|
|
16
22
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
this.code = options.code;
|
|
23
|
+
|
|
24
|
+
return this.cause._getCause(path);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getCause() {
|
|
28
|
+
return this._getCause();
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
32
|
+
export interface DefineErrorOptions {
|
|
33
|
+
item?: any; // Final item in the path
|
|
34
|
+
cause?: ValidationError; // Cause of the error
|
|
35
|
+
data?: any; // Data that caused the error
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface DefineErrorFunction {
|
|
39
|
+
(message: string, options?: DefineErrorOptions): ValidationError;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getDefinedErrorFunctionForKey(
|
|
43
|
+
key: string,
|
|
44
|
+
schema: CompiledSchema
|
|
45
|
+
) {
|
|
46
|
+
const KeywordError = new ValidationError(`Invalid ${key}`);
|
|
47
|
+
KeywordError.keyword = key;
|
|
48
|
+
KeywordError.schema = schema;
|
|
49
|
+
|
|
50
|
+
const defineError: DefineErrorFunction = (message, options = {}) => {
|
|
51
|
+
KeywordError.message = message;
|
|
52
|
+
KeywordError.item = options.item;
|
|
53
|
+
KeywordError.cause = options.cause;
|
|
54
|
+
KeywordError.data = options.data;
|
|
55
|
+
return KeywordError;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return getNamedFunction<DefineErrorFunction>(
|
|
59
|
+
`defineError_${key}`,
|
|
60
|
+
defineError
|
|
61
|
+
);
|
|
62
|
+
}
|
|
36
63
|
|
|
37
64
|
export function deepEqual(
|
|
38
65
|
obj: Array<any> | Record<string, any>,
|
|
@@ -77,3 +104,54 @@ export function deepEqual(
|
|
|
77
104
|
export function isObject(data) {
|
|
78
105
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
79
106
|
}
|
|
107
|
+
|
|
108
|
+
export function areCloseEnough(a, b, epsilon = 1e-15) {
|
|
109
|
+
return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function getUTF16Length(str) {
|
|
113
|
+
let length = 0;
|
|
114
|
+
for (let i = 0; i < str.length; i++) {
|
|
115
|
+
const codePoint = str.codePointAt(i);
|
|
116
|
+
if (codePoint > 0xffff) {
|
|
117
|
+
i++;
|
|
118
|
+
}
|
|
119
|
+
length++;
|
|
120
|
+
}
|
|
121
|
+
return length;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function deepClone(obj: any): any {
|
|
125
|
+
if (Array.isArray(obj)) {
|
|
126
|
+
const result = [];
|
|
127
|
+
for (let i = 0; i < obj.length; i++) {
|
|
128
|
+
result[i] = deepClone(obj[i]);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Is class instance of any kind
|
|
134
|
+
if (obj && obj.constructor && obj.constructor.name !== "Object") {
|
|
135
|
+
return obj;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (isObject(obj)) {
|
|
139
|
+
const result = {
|
|
140
|
+
...obj
|
|
141
|
+
};
|
|
142
|
+
for (const key in obj) {
|
|
143
|
+
result[key] = deepClone(obj[key]);
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return obj;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function isCompiledSchema(subSchema: any): subSchema is CompiledSchema {
|
|
152
|
+
return isObject(subSchema) && "$validate" in subSchema;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function getNamedFunction<T>(name: string, fn: T): T {
|
|
156
|
+
return Object.defineProperty(fn, "name", { value: name });
|
|
157
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "schema-shield",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "A fast library that protects your JSON schema from invalid data.",
|
|
5
5
|
"repository": "git@github.com:Masquerade-Circus/schema-shield.git",
|
|
6
6
|
"author": "Masquerade <christian@masquerade-circus.net>",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"node": ">=12.0.0"
|
|
70
70
|
},
|
|
71
71
|
"scripts": {
|
|
72
|
-
"test": "mocha --bail --recursive --no-timeouts --exit --require ts-node/register --enable-source-maps tests/**/*.test.ts",
|
|
72
|
+
"test": "mocha --bail --recursive --no-timeouts --forbid-only --exit --require ts-node/register --enable-source-maps tests/**/*.test.ts",
|
|
73
73
|
"dev:test": "nodemon -e ts,js -w ./tests -w ./lib --exec npm run test",
|
|
74
74
|
"dev:source": "NODE_ENV=development nodemon --enable-source-maps -e tsx,ts,json,css -w ./lib -w ./www source.js",
|
|
75
75
|
"build": "node source.js",
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"release-test": "release-it --dry-run --verbose"
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|
|
82
|
+
"is-my-ip-valid": "^1.0.1",
|
|
82
83
|
"ts-node": "^10.9.1",
|
|
83
84
|
"tsc-prog": "^2.2.1",
|
|
84
85
|
"tslib": "^2.5.0",
|