schema-shield 1.0.0 → 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 +38 -12
- package/dist/formats.d.ts.map +1 -1
- package/dist/index.d.ts +14 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1445 -447
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.mjs +1445 -447
- 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} +3 -6
- 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 +402 -84
- package/lib/index.ts +494 -46
- package/lib/keywords/array-keywords.ts +215 -21
- package/lib/keywords/number-keywords.ts +1 -1
- package/lib/keywords/object-keywords.ts +218 -113
- package/lib/keywords/other-keywords.ts +229 -76
- package/lib/keywords/string-keywords.ts +97 -7
- package/lib/types.ts +4 -5
- 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/main-utils.ts +190 -0
- package/lib/utils/pattern-matcher.ts +66 -0
- package/package.json +1 -1
- package/dist/utils.d.ts.map +0 -1
- package/lib/utils.ts +0 -362
package/lib/utils.ts
DELETED
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
import { CompiledSchema } from "./index";
|
|
2
|
-
|
|
3
|
-
interface ErrorTree {
|
|
4
|
-
message: string;
|
|
5
|
-
keyword: string;
|
|
6
|
-
item?: string | number;
|
|
7
|
-
schemaPath: string;
|
|
8
|
-
instancePath: string;
|
|
9
|
-
data?: any;
|
|
10
|
-
cause?: ErrorTree;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class ValidationError extends Error {
|
|
14
|
-
message: string;
|
|
15
|
-
item?: string | number;
|
|
16
|
-
keyword: string;
|
|
17
|
-
cause?: ValidationError;
|
|
18
|
-
schemaPath: string = "";
|
|
19
|
-
instancePath: string = "";
|
|
20
|
-
data?: any;
|
|
21
|
-
schema?: CompiledSchema;
|
|
22
|
-
|
|
23
|
-
private _getCause(pointer = "#", instancePointer = "#"): ValidationError {
|
|
24
|
-
let schemaPath = `${pointer}/${this.keyword}`;
|
|
25
|
-
let instancePath = `${instancePointer}`;
|
|
26
|
-
if (typeof this.item !== "undefined") {
|
|
27
|
-
if (typeof this.item === "string" && this.item in this.schema) {
|
|
28
|
-
schemaPath += `/${this.item}`;
|
|
29
|
-
}
|
|
30
|
-
instancePath += `/${this.item}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
this.instancePath = instancePath;
|
|
34
|
-
this.schemaPath = schemaPath;
|
|
35
|
-
|
|
36
|
-
// If there is no cause or the cause is not a ValidationError, return this
|
|
37
|
-
if (!this.cause || !(this.cause instanceof ValidationError)) {
|
|
38
|
-
return this;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return this.cause._getCause(schemaPath, instancePath);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
getCause(): ValidationError {
|
|
45
|
-
return this._getCause();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
private _getTree(): ErrorTree {
|
|
49
|
-
const tree: ErrorTree = {
|
|
50
|
-
message: this.message,
|
|
51
|
-
keyword: this.keyword,
|
|
52
|
-
item: this.item,
|
|
53
|
-
schemaPath: this.schemaPath,
|
|
54
|
-
instancePath: this.instancePath,
|
|
55
|
-
data: this.data
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
if (this.cause) {
|
|
59
|
-
tree.cause = this.cause._getTree();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return tree;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
getTree(): ErrorTree {
|
|
66
|
-
this.getCause();
|
|
67
|
-
return this._getTree();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
getPath() {
|
|
71
|
-
const cause = this.getCause();
|
|
72
|
-
return {
|
|
73
|
-
schemaPath: cause.schemaPath,
|
|
74
|
-
instancePath: cause.instancePath
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface DefineErrorOptions {
|
|
80
|
-
item?: any; // Final item in the schemaPath
|
|
81
|
-
cause?: ValidationError | true; // Cause of the error
|
|
82
|
-
data?: any; // Data that caused the error
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface DefineErrorFunction {
|
|
86
|
-
(message: string, options?: DefineErrorOptions):
|
|
87
|
-
| ValidationError
|
|
88
|
-
| void
|
|
89
|
-
| true;
|
|
90
|
-
}
|
|
91
|
-
const FAIL_FAST_DEFINE_ERROR: DefineErrorFunction = () => true;
|
|
92
|
-
|
|
93
|
-
export function getDefinedErrorFunctionForKey(
|
|
94
|
-
key: string,
|
|
95
|
-
schema: CompiledSchema,
|
|
96
|
-
failFast: boolean
|
|
97
|
-
) {
|
|
98
|
-
if (failFast) {
|
|
99
|
-
return FAIL_FAST_DEFINE_ERROR;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const KeywordError = new ValidationError(`Invalid ${key}`);
|
|
103
|
-
KeywordError.keyword = key;
|
|
104
|
-
KeywordError.schema = schema;
|
|
105
|
-
|
|
106
|
-
const defineError: DefineErrorFunction = (message, options = {}) => {
|
|
107
|
-
KeywordError.message = message;
|
|
108
|
-
KeywordError.item = options.item;
|
|
109
|
-
KeywordError.cause =
|
|
110
|
-
options.cause && options.cause !== true ? options.cause : undefined;
|
|
111
|
-
KeywordError.data = options.data;
|
|
112
|
-
return KeywordError;
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
return getNamedFunction<DefineErrorFunction>(
|
|
116
|
-
`defineError_${key}`,
|
|
117
|
-
defineError
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function hasChanged(prev: any, current: any) {
|
|
122
|
-
if (Array.isArray(prev)) {
|
|
123
|
-
if (Array.isArray(current) === false) {
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (prev.length !== current.length) {
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
for (let i = 0; i < current.length; i++) {
|
|
132
|
-
if (hasChanged(prev[i], current[i])) {
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (typeof prev === "object" && prev !== null) {
|
|
141
|
-
if (typeof current !== "object" || current === null) {
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
for (const key in current) {
|
|
146
|
-
if (hasChanged(prev[key], current[key])) {
|
|
147
|
-
return true;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
for (const key in prev) {
|
|
152
|
-
if (hasChanged(prev[key], current[key])) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return Object.is(prev, current) === false;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export function isObject(data) {
|
|
164
|
-
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export function areCloseEnough(a, b, epsilon = 1e-15) {
|
|
168
|
-
return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function getUTF16Length(str) {
|
|
172
|
-
let length = 0;
|
|
173
|
-
for (let i = 0; i < str.length; i++) {
|
|
174
|
-
const codePoint = str.codePointAt(i);
|
|
175
|
-
if (codePoint > 0xffff) {
|
|
176
|
-
i++;
|
|
177
|
-
}
|
|
178
|
-
length++;
|
|
179
|
-
}
|
|
180
|
-
return length;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function deepClone<T>(
|
|
184
|
-
obj: T,
|
|
185
|
-
cloneClassInstances = false,
|
|
186
|
-
seen = new WeakMap()
|
|
187
|
-
): T {
|
|
188
|
-
if (typeof obj === "undefined" || obj === null || typeof obj !== "object") {
|
|
189
|
-
return obj;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (seen.has(obj)) {
|
|
193
|
-
return seen.get(obj);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
let clone: any;
|
|
197
|
-
|
|
198
|
-
if (typeof structuredClone === "function") {
|
|
199
|
-
clone = structuredClone(obj);
|
|
200
|
-
seen.set(obj, clone);
|
|
201
|
-
return clone;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
switch (true) {
|
|
205
|
-
case Array.isArray(obj): {
|
|
206
|
-
clone = [];
|
|
207
|
-
seen.set(obj, clone);
|
|
208
|
-
for (let i = 0, l = obj.length; i < l; i++) {
|
|
209
|
-
clone[i] = deepClone(obj[i], cloneClassInstances, seen);
|
|
210
|
-
}
|
|
211
|
-
return clone;
|
|
212
|
-
}
|
|
213
|
-
case obj instanceof Date: {
|
|
214
|
-
clone = new Date(obj.getTime());
|
|
215
|
-
seen.set(obj, clone);
|
|
216
|
-
return clone;
|
|
217
|
-
}
|
|
218
|
-
case obj instanceof RegExp: {
|
|
219
|
-
clone = new RegExp(obj.source, obj.flags);
|
|
220
|
-
seen.set(obj, clone);
|
|
221
|
-
return clone;
|
|
222
|
-
}
|
|
223
|
-
case obj instanceof Map: {
|
|
224
|
-
clone = new Map();
|
|
225
|
-
seen.set(obj, clone);
|
|
226
|
-
for (const [key, value] of obj.entries()) {
|
|
227
|
-
clone.set(
|
|
228
|
-
deepClone(key, cloneClassInstances, seen),
|
|
229
|
-
deepClone(value, cloneClassInstances, seen)
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
return clone;
|
|
233
|
-
}
|
|
234
|
-
case obj instanceof Set: {
|
|
235
|
-
clone = new Set();
|
|
236
|
-
seen.set(obj, clone);
|
|
237
|
-
for (const value of obj.values()) {
|
|
238
|
-
clone.add(deepClone(value, cloneClassInstances, seen));
|
|
239
|
-
}
|
|
240
|
-
return clone;
|
|
241
|
-
}
|
|
242
|
-
case obj instanceof ArrayBuffer: {
|
|
243
|
-
clone = obj.slice(0);
|
|
244
|
-
seen.set(obj, clone);
|
|
245
|
-
return clone;
|
|
246
|
-
}
|
|
247
|
-
// TypedArrays and DataView
|
|
248
|
-
case ArrayBuffer.isView(obj): {
|
|
249
|
-
clone = new (obj as any).constructor(obj.buffer.slice(0));
|
|
250
|
-
seen.set(obj, clone);
|
|
251
|
-
return clone;
|
|
252
|
-
}
|
|
253
|
-
// Node.js Buffer
|
|
254
|
-
case typeof Buffer !== "undefined" && obj instanceof Buffer: {
|
|
255
|
-
clone = Buffer.from(obj as any);
|
|
256
|
-
seen.set(obj, clone);
|
|
257
|
-
return clone;
|
|
258
|
-
}
|
|
259
|
-
case obj instanceof Error: {
|
|
260
|
-
clone = new (obj as any).constructor(obj.message);
|
|
261
|
-
seen.set(obj, clone);
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
// Non clonable objects
|
|
265
|
-
case obj instanceof Promise ||
|
|
266
|
-
obj instanceof WeakMap ||
|
|
267
|
-
obj instanceof WeakSet: {
|
|
268
|
-
clone = obj;
|
|
269
|
-
seen.set(obj, clone);
|
|
270
|
-
return clone;
|
|
271
|
-
}
|
|
272
|
-
// Instance of a class
|
|
273
|
-
case obj.constructor && obj.constructor !== Object: {
|
|
274
|
-
if (!cloneClassInstances) {
|
|
275
|
-
clone = obj;
|
|
276
|
-
seen.set(obj, clone);
|
|
277
|
-
return clone;
|
|
278
|
-
}
|
|
279
|
-
clone = Object.create(Object.getPrototypeOf(obj));
|
|
280
|
-
seen.set(obj, clone);
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Plain objects
|
|
285
|
-
default: {
|
|
286
|
-
clone = {};
|
|
287
|
-
seen.set(obj, clone);
|
|
288
|
-
|
|
289
|
-
const keys = Reflect.ownKeys(obj);
|
|
290
|
-
for (let i = 0, l = keys.length; i < l; i++) {
|
|
291
|
-
const key = keys[i];
|
|
292
|
-
clone[key as string] = deepClone(
|
|
293
|
-
(obj as any)[key as string],
|
|
294
|
-
cloneClassInstances,
|
|
295
|
-
seen
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
return clone;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
|
303
|
-
for (const key of Reflect.ownKeys(descriptors)) {
|
|
304
|
-
const descriptor = descriptors[key as string];
|
|
305
|
-
if ("value" in descriptor) {
|
|
306
|
-
descriptor.value = deepClone(descriptor.value, cloneClassInstances, seen);
|
|
307
|
-
}
|
|
308
|
-
Object.defineProperty(clone, key, descriptor);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return clone;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export function isCompiledSchema(subSchema: any): subSchema is CompiledSchema {
|
|
315
|
-
return isObject(subSchema) && "$validate" in subSchema;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export function getNamedFunction<T>(name: string, fn: T): T {
|
|
319
|
-
return Object.defineProperty(fn, "name", { value: name });
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export function resolvePath(root: any, path: string): any {
|
|
323
|
-
if (!path || path === "#") {
|
|
324
|
-
return root;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// JSON Pointer
|
|
328
|
-
if (path.startsWith("#/")) {
|
|
329
|
-
const parts = path.split("/").slice(1);
|
|
330
|
-
let current = root;
|
|
331
|
-
|
|
332
|
-
for (const part of parts) {
|
|
333
|
-
const decodedUriPart = decodeURIComponent(part);
|
|
334
|
-
const key = decodedUriPart.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
335
|
-
|
|
336
|
-
if (current && typeof current === "object" && key in current) {
|
|
337
|
-
current = current[key];
|
|
338
|
-
} else {
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
return current;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Simple lookup by definition name (non-standard, but useful)
|
|
346
|
-
if (!path.includes("#")) {
|
|
347
|
-
if (root.definitions && root.definitions[path]) {
|
|
348
|
-
return root.definitions[path];
|
|
349
|
-
}
|
|
350
|
-
if (root.defs && root.defs[path]) {
|
|
351
|
-
return root.defs[path];
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (root.$id && typeof root.$id === "string") {
|
|
355
|
-
if (root.$id === path || root.$id.endsWith("/" + path)) {
|
|
356
|
-
return root;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return;
|
|
362
|
-
}
|