schema-shield 0.0.6 → 1.0.1
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/README.md +219 -65
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +25 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1837 -484
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +1837 -484
- package/dist/keywords/array-keywords.d.ts.map +1 -1
- package/dist/keywords/object-keywords.d.ts.map +1 -1
- package/dist/keywords/other-keywords.d.ts.map +1 -1
- package/dist/keywords/string-keywords.d.ts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/deep-freeze.d.ts +5 -0
- package/dist/utils/deep-freeze.d.ts.map +1 -0
- package/dist/utils/has-changed.d.ts +2 -0
- package/dist/utils/has-changed.d.ts.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/{utils.d.ts → utils/main-utils.d.ts} +7 -9
- package/dist/utils/main-utils.d.ts.map +1 -0
- package/dist/utils/pattern-matcher.d.ts +3 -0
- package/dist/utils/pattern-matcher.d.ts.map +1 -0
- package/lib/formats.ts +468 -155
- package/lib/index.ts +702 -107
- package/lib/keywords/array-keywords.ts +260 -52
- package/lib/keywords/number-keywords.ts +1 -1
- package/lib/keywords/object-keywords.ts +295 -88
- package/lib/keywords/other-keywords.ts +263 -70
- package/lib/keywords/string-keywords.ts +123 -7
- package/lib/types.ts +5 -18
- package/lib/utils/deep-freeze.ts +208 -0
- package/lib/utils/has-changed.ts +51 -0
- package/lib/utils/index.ts +4 -0
- package/lib/{utils.ts → utils/main-utils.ts} +63 -77
- package/lib/utils/pattern-matcher.ts +66 -0
- package/package.json +2 -2
- package/tsconfig.json +4 -4
- package/dist/utils.d.ts.map +0 -1
|
@@ -1,27 +1,96 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isCompiledSchema } from "../utils/main-utils";
|
|
2
2
|
|
|
3
3
|
import { KeywordFunction } from "../index";
|
|
4
|
+
import { hasChanged } from "../utils/has-changed";
|
|
5
|
+
|
|
6
|
+
type BranchEntry =
|
|
7
|
+
| { kind: "validate"; validate: (data: any) => any }
|
|
8
|
+
| { kind: "alwaysValid" }
|
|
9
|
+
| { kind: "alwaysInvalid" }
|
|
10
|
+
| { kind: "literal"; value: any };
|
|
11
|
+
|
|
12
|
+
function toBranchEntry(item: any): BranchEntry {
|
|
13
|
+
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
14
|
+
if ("$validate" in item && typeof item.$validate === "function") {
|
|
15
|
+
return { kind: "validate", validate: item.$validate };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return { kind: "alwaysValid" };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (typeof item === "boolean") {
|
|
22
|
+
return { kind: item ? "alwaysValid" : "alwaysInvalid" };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { kind: "literal", value: item };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getBranchEntries(schema: any, key: "allOf" | "anyOf" | "oneOf") {
|
|
29
|
+
const cacheKey = `_${key}BranchEntries`;
|
|
30
|
+
let entries = schema[cacheKey] as BranchEntry[] | undefined;
|
|
31
|
+
|
|
32
|
+
if (entries) {
|
|
33
|
+
return entries;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const source = schema[key] || [];
|
|
37
|
+
entries = [];
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < source.length; i++) {
|
|
40
|
+
entries.push(toBranchEntry(source[i]));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Object.defineProperty(schema, cacheKey, {
|
|
44
|
+
value: entries,
|
|
45
|
+
enumerable: false,
|
|
46
|
+
configurable: false,
|
|
47
|
+
writable: false
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return entries;
|
|
51
|
+
}
|
|
4
52
|
|
|
5
53
|
export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
6
54
|
enum(schema, data, defineError) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
55
|
+
let enumCache = (schema as any)._enumCache as
|
|
56
|
+
| { primitiveSet: Set<any>; objectValues: any[] }
|
|
57
|
+
| undefined;
|
|
10
58
|
|
|
11
|
-
|
|
12
|
-
const
|
|
59
|
+
if (!enumCache) {
|
|
60
|
+
const primitiveSet = new Set<any>();
|
|
61
|
+
const objectValues: any[] = [];
|
|
62
|
+
const list = schema.enum;
|
|
13
63
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
64
|
+
for (let i = 0; i < list.length; i++) {
|
|
65
|
+
const enumItem = list[i];
|
|
66
|
+
if (enumItem !== null && typeof enumItem === "object") {
|
|
67
|
+
objectValues.push(enumItem);
|
|
68
|
+
} else {
|
|
69
|
+
primitiveSet.add(enumItem);
|
|
70
|
+
}
|
|
17
71
|
}
|
|
18
72
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
73
|
+
enumCache = { primitiveSet, objectValues };
|
|
74
|
+
Object.defineProperty(schema, "_enumCache", {
|
|
75
|
+
value: enumCache,
|
|
76
|
+
enumerable: false,
|
|
77
|
+
configurable: false,
|
|
78
|
+
writable: false
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
!(typeof data === "number" && Number.isNaN(data)) &&
|
|
84
|
+
enumCache.primitiveSet.has(data)
|
|
85
|
+
) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (data !== null && typeof data === "object") {
|
|
90
|
+
// Conservative exact-semantics path.
|
|
91
|
+
// Future opt-in optimization: structural hashing buckets for large enums.
|
|
92
|
+
for (let i = 0; i < enumCache.objectValues.length; i++) {
|
|
93
|
+
if (!hasChanged(enumCache.objectValues[i], data)) {
|
|
25
94
|
return;
|
|
26
95
|
}
|
|
27
96
|
}
|
|
@@ -31,25 +100,54 @@ export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
|
31
100
|
},
|
|
32
101
|
|
|
33
102
|
allOf(schema, data, defineError) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
103
|
+
const branches = getBranchEntries(schema, "allOf");
|
|
104
|
+
|
|
105
|
+
if (branches.length === 1) {
|
|
106
|
+
const onlyBranch = branches[0];
|
|
107
|
+
|
|
108
|
+
if (onlyBranch.kind === "validate") {
|
|
109
|
+
const error = onlyBranch.validate(data);
|
|
110
|
+
if (error) {
|
|
111
|
+
return defineError("Value is not valid", { cause: error, data });
|
|
41
112
|
}
|
|
42
|
-
|
|
113
|
+
return;
|
|
43
114
|
}
|
|
44
115
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
116
|
+
if (onlyBranch.kind === "alwaysValid") {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (onlyBranch.kind === "alwaysInvalid") {
|
|
121
|
+
return defineError("Value is not valid", { data });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (data !== onlyBranch.value) {
|
|
125
|
+
return defineError("Value is not valid", { data });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (let i = 0; i < branches.length; i++) {
|
|
132
|
+
const branch = branches[i];
|
|
133
|
+
|
|
134
|
+
if (branch.kind === "validate") {
|
|
135
|
+
const error = branch.validate(data);
|
|
136
|
+
if (error) {
|
|
137
|
+
return defineError("Value is not valid", { cause: error, data });
|
|
48
138
|
}
|
|
49
139
|
continue;
|
|
50
140
|
}
|
|
51
141
|
|
|
52
|
-
if (
|
|
142
|
+
if (branch.kind === "alwaysValid") {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (branch.kind === "alwaysInvalid") {
|
|
147
|
+
return defineError("Value is not valid", { data });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (data !== branch.value) {
|
|
53
151
|
return defineError("Value is not valid", { data });
|
|
54
152
|
}
|
|
55
153
|
}
|
|
@@ -58,26 +156,55 @@ export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
|
58
156
|
},
|
|
59
157
|
|
|
60
158
|
anyOf(schema, data, defineError) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
159
|
+
const branches = getBranchEntries(schema, "anyOf");
|
|
160
|
+
|
|
161
|
+
if (branches.length === 1) {
|
|
162
|
+
const onlyBranch = branches[0];
|
|
163
|
+
|
|
164
|
+
if (onlyBranch.kind === "validate") {
|
|
165
|
+
const error = onlyBranch.validate(data);
|
|
166
|
+
if (!error) {
|
|
167
|
+
return;
|
|
69
168
|
}
|
|
169
|
+
return defineError("Value is not valid", { data });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (onlyBranch.kind === "alwaysValid") {
|
|
70
173
|
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (onlyBranch.kind === "alwaysInvalid") {
|
|
177
|
+
return defineError("Value is not valid", { data });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (data === onlyBranch.value) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return defineError("Value is not valid", { data });
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
for (let i = 0; i < branches.length; i++) {
|
|
188
|
+
const branch = branches[i];
|
|
77
189
|
|
|
78
|
-
|
|
190
|
+
if (branch.kind === "validate") {
|
|
191
|
+
const error = branch.validate(data);
|
|
192
|
+
if (!error) {
|
|
79
193
|
return;
|
|
80
194
|
}
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (branch.kind === "alwaysValid") {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (branch.kind === "alwaysInvalid") {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (data === branch.value) {
|
|
207
|
+
return;
|
|
81
208
|
}
|
|
82
209
|
}
|
|
83
210
|
|
|
@@ -85,28 +212,54 @@ export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
|
85
212
|
},
|
|
86
213
|
|
|
87
214
|
oneOf(schema, data, defineError) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
215
|
+
const branches = getBranchEntries(schema, "oneOf");
|
|
216
|
+
|
|
217
|
+
if (branches.length === 1) {
|
|
218
|
+
const onlyBranch = branches[0];
|
|
219
|
+
|
|
220
|
+
if (onlyBranch.kind === "validate") {
|
|
221
|
+
const error = onlyBranch.validate(data);
|
|
222
|
+
if (!error) {
|
|
223
|
+
return;
|
|
97
224
|
}
|
|
98
|
-
|
|
99
|
-
|
|
225
|
+
return defineError("Value is not valid", { data });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (onlyBranch.kind === "alwaysValid") {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (onlyBranch.kind === "alwaysInvalid") {
|
|
233
|
+
return defineError("Value is not valid", { data });
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (data === onlyBranch.value) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return defineError("Value is not valid", { data });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let validCount = 0;
|
|
244
|
+
|
|
245
|
+
for (let i = 0; i < branches.length; i++) {
|
|
246
|
+
const branch = branches[i];
|
|
247
|
+
let isValid = false;
|
|
248
|
+
|
|
249
|
+
if (branch.kind === "validate") {
|
|
250
|
+
isValid = !branch.validate(data);
|
|
251
|
+
} else if (branch.kind === "alwaysValid") {
|
|
252
|
+
isValid = true;
|
|
253
|
+
} else if (branch.kind === "alwaysInvalid") {
|
|
254
|
+
isValid = false;
|
|
100
255
|
} else {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
validCount++;
|
|
104
|
-
}
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
256
|
+
isValid = data === branch.value;
|
|
257
|
+
}
|
|
107
258
|
|
|
108
|
-
|
|
109
|
-
|
|
259
|
+
if (isValid) {
|
|
260
|
+
validCount++;
|
|
261
|
+
if (validCount > 1) {
|
|
262
|
+
return defineError("Value is not valid", { data });
|
|
110
263
|
}
|
|
111
264
|
}
|
|
112
265
|
}
|
|
@@ -119,21 +272,28 @@ export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
|
119
272
|
},
|
|
120
273
|
|
|
121
274
|
const(schema, data, defineError) {
|
|
275
|
+
if (data === schema.const) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
122
279
|
if (
|
|
123
|
-
data
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
280
|
+
(data &&
|
|
281
|
+
typeof data === "object" &&
|
|
282
|
+
!Array.isArray(data) &&
|
|
283
|
+
schema.const &&
|
|
284
|
+
typeof schema.const === "object" &&
|
|
285
|
+
!Array.isArray(schema.const) &&
|
|
286
|
+
!hasChanged(data, schema.const)) ||
|
|
127
287
|
(Array.isArray(data) &&
|
|
128
288
|
Array.isArray(schema.const) &&
|
|
129
|
-
|
|
289
|
+
!hasChanged(data, schema.const))
|
|
130
290
|
) {
|
|
131
291
|
return;
|
|
132
292
|
}
|
|
133
293
|
return defineError("Value is not valid", { data });
|
|
134
294
|
},
|
|
135
295
|
|
|
136
|
-
if(schema, data
|
|
296
|
+
if(schema, data) {
|
|
137
297
|
if ("then" in schema === false && "else" in schema === false) {
|
|
138
298
|
return;
|
|
139
299
|
}
|
|
@@ -174,11 +334,15 @@ export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
|
174
334
|
return;
|
|
175
335
|
}
|
|
176
336
|
|
|
177
|
-
if (
|
|
337
|
+
if (
|
|
338
|
+
schema.not &&
|
|
339
|
+
typeof schema.not === "object" &&
|
|
340
|
+
!Array.isArray(schema.not)
|
|
341
|
+
) {
|
|
178
342
|
if ("$validate" in schema.not) {
|
|
179
|
-
const error = schema.not.$validate(data);
|
|
343
|
+
const error = (schema.not as any).$validate(data);
|
|
180
344
|
if (!error) {
|
|
181
|
-
return defineError("Value is not valid", {
|
|
345
|
+
return defineError("Value is not valid", { data });
|
|
182
346
|
}
|
|
183
347
|
return;
|
|
184
348
|
}
|
|
@@ -186,5 +350,34 @@ export const OtherKeywords: Record<string, KeywordFunction> = {
|
|
|
186
350
|
}
|
|
187
351
|
|
|
188
352
|
return defineError("Value is not valid", { data });
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
$ref(schema, data, defineError, instance) {
|
|
356
|
+
if (schema._resolvedRef) {
|
|
357
|
+
if (schema.$validate !== schema._resolvedRef) {
|
|
358
|
+
schema.$validate = schema._resolvedRef;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return schema._resolvedRef(data);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const refPath = schema.$ref;
|
|
365
|
+
let targetSchema = instance.getSchemaRef(refPath);
|
|
366
|
+
|
|
367
|
+
if (!targetSchema) {
|
|
368
|
+
targetSchema = instance.getSchemaById(refPath);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (!targetSchema) {
|
|
372
|
+
return defineError(`Missing reference: ${refPath}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (!targetSchema.$validate) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
schema._resolvedRef = targetSchema.$validate;
|
|
380
|
+
schema.$validate = schema._resolvedRef;
|
|
381
|
+
return schema._resolvedRef(data);
|
|
189
382
|
}
|
|
190
383
|
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import { KeywordFunction } from "../index";
|
|
1
|
+
import { FormatFunction, KeywordFunction } from "../index";
|
|
2
|
+
import { compilePatternMatcher } from "../utils/pattern-matcher";
|
|
3
|
+
|
|
4
|
+
const PATTERN_MATCH_CACHE_LIMIT = 512;
|
|
5
|
+
const FORMAT_RESULT_CACHE_LIMIT = 512;
|
|
2
6
|
|
|
3
7
|
export const StringKeywords: Record<string, KeywordFunction> = {
|
|
4
8
|
minLength(schema, data, defineError) {
|
|
@@ -22,13 +26,58 @@ export const StringKeywords: Record<string, KeywordFunction> = {
|
|
|
22
26
|
return;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
let patternMatch = (schema as any)._patternMatch as
|
|
30
|
+
| ((value: string) => boolean)
|
|
31
|
+
| undefined;
|
|
32
|
+
|
|
33
|
+
let patternMatchCache = (schema as any)._patternMatchCache as
|
|
34
|
+
| Map<string, boolean>
|
|
35
|
+
| undefined;
|
|
26
36
|
|
|
27
|
-
if (
|
|
28
|
-
|
|
37
|
+
if (!patternMatch) {
|
|
38
|
+
try {
|
|
39
|
+
const compiled = compilePatternMatcher(schema.pattern);
|
|
40
|
+
patternMatch =
|
|
41
|
+
compiled instanceof RegExp
|
|
42
|
+
? (value: string) => compiled.test(value)
|
|
43
|
+
: compiled;
|
|
44
|
+
|
|
45
|
+
Object.defineProperty(schema, "_patternMatch", {
|
|
46
|
+
value: patternMatch,
|
|
47
|
+
enumerable: false,
|
|
48
|
+
configurable: false,
|
|
49
|
+
writable: false
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return defineError("Invalid regular expression", {
|
|
53
|
+
data,
|
|
54
|
+
cause: error
|
|
55
|
+
});
|
|
56
|
+
}
|
|
29
57
|
}
|
|
30
58
|
|
|
31
|
-
if (
|
|
59
|
+
if (!patternMatchCache) {
|
|
60
|
+
patternMatchCache = new Map<string, boolean>();
|
|
61
|
+
Object.defineProperty(schema, "_patternMatchCache", {
|
|
62
|
+
value: patternMatchCache,
|
|
63
|
+
enumerable: false,
|
|
64
|
+
configurable: false,
|
|
65
|
+
writable: false
|
|
66
|
+
});
|
|
67
|
+
} else if (patternMatchCache.has(data)) {
|
|
68
|
+
if (patternMatchCache.get(data)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return defineError("Value does not match the pattern", { data });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const isMatch = patternMatch(data);
|
|
76
|
+
if (patternMatchCache.size < PATTERN_MATCH_CACHE_LIMIT) {
|
|
77
|
+
patternMatchCache.set(data, isMatch);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (isMatch) {
|
|
32
81
|
return;
|
|
33
82
|
}
|
|
34
83
|
|
|
@@ -42,8 +91,75 @@ export const StringKeywords: Record<string, KeywordFunction> = {
|
|
|
42
91
|
return;
|
|
43
92
|
}
|
|
44
93
|
|
|
45
|
-
|
|
46
|
-
|
|
94
|
+
let formatValidate = (schema as any)._formatValidate as
|
|
95
|
+
| FormatFunction
|
|
96
|
+
| false
|
|
97
|
+
| undefined;
|
|
98
|
+
let formatResultCacheEnabled = (schema as any)._formatResultCacheEnabled as
|
|
99
|
+
| boolean
|
|
100
|
+
| undefined;
|
|
101
|
+
let formatResultCache = (schema as any)._formatResultCache as
|
|
102
|
+
| Map<string, boolean>
|
|
103
|
+
| undefined;
|
|
104
|
+
|
|
105
|
+
if (formatValidate === undefined) {
|
|
106
|
+
formatValidate = instance.getFormat(schema.format);
|
|
107
|
+
Object.defineProperty(schema, "_formatValidate", {
|
|
108
|
+
value: formatValidate,
|
|
109
|
+
enumerable: false,
|
|
110
|
+
configurable: false,
|
|
111
|
+
writable: false
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!formatValidate) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (formatResultCacheEnabled === undefined) {
|
|
120
|
+
formatResultCacheEnabled = instance.isDefaultFormatValidator(
|
|
121
|
+
schema.format,
|
|
122
|
+
formatValidate
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
Object.defineProperty(schema, "_formatResultCacheEnabled", {
|
|
126
|
+
value: formatResultCacheEnabled,
|
|
127
|
+
enumerable: false,
|
|
128
|
+
configurable: false,
|
|
129
|
+
writable: false
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (!formatResultCacheEnabled) {
|
|
134
|
+
if (formatValidate(data)) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return defineError("Value does not match the format", { data });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!formatResultCache) {
|
|
142
|
+
formatResultCache = new Map<string, boolean>();
|
|
143
|
+
Object.defineProperty(schema, "_formatResultCache", {
|
|
144
|
+
value: formatResultCache,
|
|
145
|
+
enumerable: false,
|
|
146
|
+
configurable: false,
|
|
147
|
+
writable: false
|
|
148
|
+
});
|
|
149
|
+
} else if (formatResultCache.has(data)) {
|
|
150
|
+
if (formatResultCache.get(data)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return defineError("Value does not match the format", { data });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const isValid = formatValidate(data);
|
|
158
|
+
if (formatResultCache.size < FORMAT_RESULT_CACHE_LIMIT) {
|
|
159
|
+
formatResultCache.set(data, isValid);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (isValid) {
|
|
47
163
|
return;
|
|
48
164
|
}
|
|
49
165
|
|
package/lib/types.ts
CHANGED
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
import { TypeFunction } from "./index";
|
|
2
|
-
import { isObject } from "./utils";
|
|
3
2
|
|
|
4
3
|
export const Types: Record<string, TypeFunction | false> = {
|
|
5
4
|
object(data) {
|
|
6
|
-
return
|
|
5
|
+
return data !== null && typeof data === "object" && !Array.isArray(data);
|
|
7
6
|
},
|
|
8
7
|
array(data) {
|
|
9
|
-
|
|
10
|
-
return true;
|
|
11
|
-
}
|
|
12
|
-
|
|
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
|
-
);
|
|
8
|
+
return Array.isArray(data);
|
|
20
9
|
},
|
|
21
10
|
string(data) {
|
|
22
11
|
return typeof data === "string";
|
|
@@ -37,13 +26,11 @@ export const Types: Record<string, TypeFunction | false> = {
|
|
|
37
26
|
// Not implemented yet
|
|
38
27
|
timestamp: false,
|
|
39
28
|
int8: false,
|
|
40
|
-
|
|
29
|
+
uint8: false,
|
|
41
30
|
int16: false,
|
|
42
|
-
|
|
31
|
+
uint16: false,
|
|
43
32
|
int32: false,
|
|
44
|
-
|
|
33
|
+
uint32: false,
|
|
45
34
|
float32: false,
|
|
46
35
|
float64: false
|
|
47
|
-
|
|
48
|
-
|
|
49
36
|
};
|