koatty_validation 1.3.6 → 1.6.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/.rollup.config.js +62 -59
- package/CHANGELOG.md +97 -75
- package/LICENSE +29 -29
- package/README.md +363 -116
- package/coverage.lcov +1607 -0
- package/dist/LICENSE +29 -29
- package/dist/README.md +363 -116
- package/dist/index.d.ts +463 -230
- package/dist/index.js +962 -2158
- package/dist/index.mjs +931 -2144
- package/dist/package.json +91 -94
- package/examples/README.md +90 -0
- package/examples/basic-usage.ts +239 -0
- package/examples/custom-decorators-example.ts +230 -0
- package/examples/usage-example.ts +284 -0
- package/package.json +91 -94
package/dist/index.js
CHANGED
|
@@ -1,1444 +1,473 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* @Author: richen
|
|
3
|
-
* @Date:
|
|
3
|
+
* @Date: 2025-10-23 01:25:03
|
|
4
4
|
* @License: BSD (3-Clause)
|
|
5
5
|
* @Copyright (c) - <richenlin(at)gmail.com>
|
|
6
6
|
* @HomePage: https://koatty.org/
|
|
7
7
|
*/
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
var classValidator = require('class-validator');
|
|
11
10
|
var helper = require('koatty_lib');
|
|
11
|
+
require('reflect-metadata');
|
|
12
12
|
var koatty_container = require('koatty_container');
|
|
13
|
+
var lruCache = require('lru-cache');
|
|
14
|
+
var classValidator = require('class-validator');
|
|
13
15
|
|
|
14
16
|
function _interopNamespaceDefault(e) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
var n = Object.create(null);
|
|
18
|
+
if (e) {
|
|
19
|
+
Object.keys(e).forEach(function (k) {
|
|
20
|
+
if (k !== 'default') {
|
|
21
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
22
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return e[k]; }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
n.default = e;
|
|
30
|
+
return Object.freeze(n);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
var helper__namespace = /*#__PURE__*/_interopNamespaceDefault(helper);
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
44
|
-
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
|
45
|
-
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
|
46
|
-
MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
47
|
-
|
|
48
|
-
See the Apache Version 2.0 License for specific language governing permissions
|
|
49
|
-
and limitations under the License.
|
|
50
|
-
***************************************************************************** */
|
|
51
|
-
|
|
52
|
-
var hasRequired_Reflect;
|
|
35
|
+
/**
|
|
36
|
+
* koatty_validation 类型定义
|
|
37
|
+
* @author richen
|
|
38
|
+
* @copyright Copyright (c) - <richenlin(at)gmail.com>
|
|
39
|
+
* @license MIT
|
|
40
|
+
*/
|
|
41
|
+
/**
|
|
42
|
+
* 参数类型键常量
|
|
43
|
+
*/
|
|
44
|
+
const PARAM_TYPE_KEY = 'PARAM_TYPE_KEY';
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
* result = Reflect.getMetadataKeys(Example, "staticProperty");
|
|
479
|
-
*
|
|
480
|
-
* // property (on prototype)
|
|
481
|
-
* result = Reflect.getMetadataKeys(Example.prototype, "property");
|
|
482
|
-
*
|
|
483
|
-
* // method (on constructor)
|
|
484
|
-
* result = Reflect.getMetadataKeys(Example, "staticMethod");
|
|
485
|
-
*
|
|
486
|
-
* // method (on prototype)
|
|
487
|
-
* result = Reflect.getMetadataKeys(Example.prototype, "method");
|
|
488
|
-
*
|
|
489
|
-
*/
|
|
490
|
-
function getMetadataKeys(target, propertyKey) {
|
|
491
|
-
if (!IsObject(target))
|
|
492
|
-
throw new TypeError();
|
|
493
|
-
if (!IsUndefined(propertyKey))
|
|
494
|
-
propertyKey = ToPropertyKey(propertyKey);
|
|
495
|
-
return OrdinaryMetadataKeys(target, propertyKey);
|
|
496
|
-
}
|
|
497
|
-
exporter("getMetadataKeys", getMetadataKeys);
|
|
498
|
-
/**
|
|
499
|
-
* Gets the unique metadata keys defined on the target object.
|
|
500
|
-
* @param target The target object on which the metadata is defined.
|
|
501
|
-
* @param propertyKey (Optional) The property key for the target.
|
|
502
|
-
* @returns An array of unique metadata keys.
|
|
503
|
-
* @example
|
|
504
|
-
*
|
|
505
|
-
* class Example {
|
|
506
|
-
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
507
|
-
* // static staticProperty;
|
|
508
|
-
* // property;
|
|
509
|
-
*
|
|
510
|
-
* constructor(p) { }
|
|
511
|
-
* static staticMethod(p) { }
|
|
512
|
-
* method(p) { }
|
|
513
|
-
* }
|
|
514
|
-
*
|
|
515
|
-
* // constructor
|
|
516
|
-
* result = Reflect.getOwnMetadataKeys(Example);
|
|
517
|
-
*
|
|
518
|
-
* // property (on constructor)
|
|
519
|
-
* result = Reflect.getOwnMetadataKeys(Example, "staticProperty");
|
|
520
|
-
*
|
|
521
|
-
* // property (on prototype)
|
|
522
|
-
* result = Reflect.getOwnMetadataKeys(Example.prototype, "property");
|
|
523
|
-
*
|
|
524
|
-
* // method (on constructor)
|
|
525
|
-
* result = Reflect.getOwnMetadataKeys(Example, "staticMethod");
|
|
526
|
-
*
|
|
527
|
-
* // method (on prototype)
|
|
528
|
-
* result = Reflect.getOwnMetadataKeys(Example.prototype, "method");
|
|
529
|
-
*
|
|
530
|
-
*/
|
|
531
|
-
function getOwnMetadataKeys(target, propertyKey) {
|
|
532
|
-
if (!IsObject(target))
|
|
533
|
-
throw new TypeError();
|
|
534
|
-
if (!IsUndefined(propertyKey))
|
|
535
|
-
propertyKey = ToPropertyKey(propertyKey);
|
|
536
|
-
return OrdinaryOwnMetadataKeys(target, propertyKey);
|
|
537
|
-
}
|
|
538
|
-
exporter("getOwnMetadataKeys", getOwnMetadataKeys);
|
|
539
|
-
/**
|
|
540
|
-
* Deletes the metadata entry from the target object with the provided key.
|
|
541
|
-
* @param metadataKey A key used to store and retrieve metadata.
|
|
542
|
-
* @param target The target object on which the metadata is defined.
|
|
543
|
-
* @param propertyKey (Optional) The property key for the target.
|
|
544
|
-
* @returns `true` if the metadata entry was found and deleted; otherwise, false.
|
|
545
|
-
* @example
|
|
546
|
-
*
|
|
547
|
-
* class Example {
|
|
548
|
-
* // property declarations are not part of ES6, though they are valid in TypeScript:
|
|
549
|
-
* // static staticProperty;
|
|
550
|
-
* // property;
|
|
551
|
-
*
|
|
552
|
-
* constructor(p) { }
|
|
553
|
-
* static staticMethod(p) { }
|
|
554
|
-
* method(p) { }
|
|
555
|
-
* }
|
|
556
|
-
*
|
|
557
|
-
* // constructor
|
|
558
|
-
* result = Reflect.deleteMetadata("custom:annotation", Example);
|
|
559
|
-
*
|
|
560
|
-
* // property (on constructor)
|
|
561
|
-
* result = Reflect.deleteMetadata("custom:annotation", Example, "staticProperty");
|
|
562
|
-
*
|
|
563
|
-
* // property (on prototype)
|
|
564
|
-
* result = Reflect.deleteMetadata("custom:annotation", Example.prototype, "property");
|
|
565
|
-
*
|
|
566
|
-
* // method (on constructor)
|
|
567
|
-
* result = Reflect.deleteMetadata("custom:annotation", Example, "staticMethod");
|
|
568
|
-
*
|
|
569
|
-
* // method (on prototype)
|
|
570
|
-
* result = Reflect.deleteMetadata("custom:annotation", Example.prototype, "method");
|
|
571
|
-
*
|
|
572
|
-
*/
|
|
573
|
-
function deleteMetadata(metadataKey, target, propertyKey) {
|
|
574
|
-
if (!IsObject(target))
|
|
575
|
-
throw new TypeError();
|
|
576
|
-
if (!IsUndefined(propertyKey))
|
|
577
|
-
propertyKey = ToPropertyKey(propertyKey);
|
|
578
|
-
if (!IsObject(target))
|
|
579
|
-
throw new TypeError();
|
|
580
|
-
if (!IsUndefined(propertyKey))
|
|
581
|
-
propertyKey = ToPropertyKey(propertyKey);
|
|
582
|
-
var provider = GetMetadataProvider(target, propertyKey, /*Create*/ false);
|
|
583
|
-
if (IsUndefined(provider))
|
|
584
|
-
return false;
|
|
585
|
-
return provider.OrdinaryDeleteMetadata(metadataKey, target, propertyKey);
|
|
586
|
-
}
|
|
587
|
-
exporter("deleteMetadata", deleteMetadata);
|
|
588
|
-
function DecorateConstructor(decorators, target) {
|
|
589
|
-
for (var i = decorators.length - 1; i >= 0; --i) {
|
|
590
|
-
var decorator = decorators[i];
|
|
591
|
-
var decorated = decorator(target);
|
|
592
|
-
if (!IsUndefined(decorated) && !IsNull(decorated)) {
|
|
593
|
-
if (!IsConstructor(decorated))
|
|
594
|
-
throw new TypeError();
|
|
595
|
-
target = decorated;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
return target;
|
|
599
|
-
}
|
|
600
|
-
function DecorateProperty(decorators, target, propertyKey, descriptor) {
|
|
601
|
-
for (var i = decorators.length - 1; i >= 0; --i) {
|
|
602
|
-
var decorator = decorators[i];
|
|
603
|
-
var decorated = decorator(target, propertyKey, descriptor);
|
|
604
|
-
if (!IsUndefined(decorated) && !IsNull(decorated)) {
|
|
605
|
-
if (!IsObject(decorated))
|
|
606
|
-
throw new TypeError();
|
|
607
|
-
descriptor = decorated;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
return descriptor;
|
|
611
|
-
}
|
|
612
|
-
// 3.1.1.1 OrdinaryHasMetadata(MetadataKey, O, P)
|
|
613
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinaryhasmetadata
|
|
614
|
-
function OrdinaryHasMetadata(MetadataKey, O, P) {
|
|
615
|
-
var hasOwn = OrdinaryHasOwnMetadata(MetadataKey, O, P);
|
|
616
|
-
if (hasOwn)
|
|
617
|
-
return true;
|
|
618
|
-
var parent = OrdinaryGetPrototypeOf(O);
|
|
619
|
-
if (!IsNull(parent))
|
|
620
|
-
return OrdinaryHasMetadata(MetadataKey, parent, P);
|
|
621
|
-
return false;
|
|
622
|
-
}
|
|
623
|
-
// 3.1.2.1 OrdinaryHasOwnMetadata(MetadataKey, O, P)
|
|
624
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinaryhasownmetadata
|
|
625
|
-
function OrdinaryHasOwnMetadata(MetadataKey, O, P) {
|
|
626
|
-
var provider = GetMetadataProvider(O, P, /*Create*/ false);
|
|
627
|
-
if (IsUndefined(provider))
|
|
628
|
-
return false;
|
|
629
|
-
return ToBoolean(provider.OrdinaryHasOwnMetadata(MetadataKey, O, P));
|
|
630
|
-
}
|
|
631
|
-
// 3.1.3.1 OrdinaryGetMetadata(MetadataKey, O, P)
|
|
632
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinarygetmetadata
|
|
633
|
-
function OrdinaryGetMetadata(MetadataKey, O, P) {
|
|
634
|
-
var hasOwn = OrdinaryHasOwnMetadata(MetadataKey, O, P);
|
|
635
|
-
if (hasOwn)
|
|
636
|
-
return OrdinaryGetOwnMetadata(MetadataKey, O, P);
|
|
637
|
-
var parent = OrdinaryGetPrototypeOf(O);
|
|
638
|
-
if (!IsNull(parent))
|
|
639
|
-
return OrdinaryGetMetadata(MetadataKey, parent, P);
|
|
640
|
-
return undefined;
|
|
641
|
-
}
|
|
642
|
-
// 3.1.4.1 OrdinaryGetOwnMetadata(MetadataKey, O, P)
|
|
643
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinarygetownmetadata
|
|
644
|
-
function OrdinaryGetOwnMetadata(MetadataKey, O, P) {
|
|
645
|
-
var provider = GetMetadataProvider(O, P, /*Create*/ false);
|
|
646
|
-
if (IsUndefined(provider))
|
|
647
|
-
return;
|
|
648
|
-
return provider.OrdinaryGetOwnMetadata(MetadataKey, O, P);
|
|
649
|
-
}
|
|
650
|
-
// 3.1.5.1 OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P)
|
|
651
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinarydefineownmetadata
|
|
652
|
-
function OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P) {
|
|
653
|
-
var provider = GetMetadataProvider(O, P, /*Create*/ true);
|
|
654
|
-
provider.OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P);
|
|
655
|
-
}
|
|
656
|
-
// 3.1.6.1 OrdinaryMetadataKeys(O, P)
|
|
657
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinarymetadatakeys
|
|
658
|
-
function OrdinaryMetadataKeys(O, P) {
|
|
659
|
-
var ownKeys = OrdinaryOwnMetadataKeys(O, P);
|
|
660
|
-
var parent = OrdinaryGetPrototypeOf(O);
|
|
661
|
-
if (parent === null)
|
|
662
|
-
return ownKeys;
|
|
663
|
-
var parentKeys = OrdinaryMetadataKeys(parent, P);
|
|
664
|
-
if (parentKeys.length <= 0)
|
|
665
|
-
return ownKeys;
|
|
666
|
-
if (ownKeys.length <= 0)
|
|
667
|
-
return parentKeys;
|
|
668
|
-
var set = new _Set();
|
|
669
|
-
var keys = [];
|
|
670
|
-
for (var _i = 0, ownKeys_1 = ownKeys; _i < ownKeys_1.length; _i++) {
|
|
671
|
-
var key = ownKeys_1[_i];
|
|
672
|
-
var hasKey = set.has(key);
|
|
673
|
-
if (!hasKey) {
|
|
674
|
-
set.add(key);
|
|
675
|
-
keys.push(key);
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
for (var _a = 0, parentKeys_1 = parentKeys; _a < parentKeys_1.length; _a++) {
|
|
679
|
-
var key = parentKeys_1[_a];
|
|
680
|
-
var hasKey = set.has(key);
|
|
681
|
-
if (!hasKey) {
|
|
682
|
-
set.add(key);
|
|
683
|
-
keys.push(key);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return keys;
|
|
687
|
-
}
|
|
688
|
-
// 3.1.7.1 OrdinaryOwnMetadataKeys(O, P)
|
|
689
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinaryownmetadatakeys
|
|
690
|
-
function OrdinaryOwnMetadataKeys(O, P) {
|
|
691
|
-
var provider = GetMetadataProvider(O, P, /*create*/ false);
|
|
692
|
-
if (!provider) {
|
|
693
|
-
return [];
|
|
694
|
-
}
|
|
695
|
-
return provider.OrdinaryOwnMetadataKeys(O, P);
|
|
696
|
-
}
|
|
697
|
-
// 6 ECMAScript Data Typ0es and Values
|
|
698
|
-
// https://tc39.github.io/ecma262/#sec-ecmascript-data-types-and-values
|
|
699
|
-
function Type(x) {
|
|
700
|
-
if (x === null)
|
|
701
|
-
return 1 /* Null */;
|
|
702
|
-
switch (typeof x) {
|
|
703
|
-
case "undefined": return 0 /* Undefined */;
|
|
704
|
-
case "boolean": return 2 /* Boolean */;
|
|
705
|
-
case "string": return 3 /* String */;
|
|
706
|
-
case "symbol": return 4 /* Symbol */;
|
|
707
|
-
case "number": return 5 /* Number */;
|
|
708
|
-
case "object": return x === null ? 1 /* Null */ : 6 /* Object */;
|
|
709
|
-
default: return 6 /* Object */;
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
// 6.1.1 The Undefined Type
|
|
713
|
-
// https://tc39.github.io/ecma262/#sec-ecmascript-language-types-undefined-type
|
|
714
|
-
function IsUndefined(x) {
|
|
715
|
-
return x === undefined;
|
|
716
|
-
}
|
|
717
|
-
// 6.1.2 The Null Type
|
|
718
|
-
// https://tc39.github.io/ecma262/#sec-ecmascript-language-types-null-type
|
|
719
|
-
function IsNull(x) {
|
|
720
|
-
return x === null;
|
|
721
|
-
}
|
|
722
|
-
// 6.1.5 The Symbol Type
|
|
723
|
-
// https://tc39.github.io/ecma262/#sec-ecmascript-language-types-symbol-type
|
|
724
|
-
function IsSymbol(x) {
|
|
725
|
-
return typeof x === "symbol";
|
|
726
|
-
}
|
|
727
|
-
// 6.1.7 The Object Type
|
|
728
|
-
// https://tc39.github.io/ecma262/#sec-object-type
|
|
729
|
-
function IsObject(x) {
|
|
730
|
-
return typeof x === "object" ? x !== null : typeof x === "function";
|
|
731
|
-
}
|
|
732
|
-
// 7.1 Type Conversion
|
|
733
|
-
// https://tc39.github.io/ecma262/#sec-type-conversion
|
|
734
|
-
// 7.1.1 ToPrimitive(input [, PreferredType])
|
|
735
|
-
// https://tc39.github.io/ecma262/#sec-toprimitive
|
|
736
|
-
function ToPrimitive(input, PreferredType) {
|
|
737
|
-
switch (Type(input)) {
|
|
738
|
-
case 0 /* Undefined */: return input;
|
|
739
|
-
case 1 /* Null */: return input;
|
|
740
|
-
case 2 /* Boolean */: return input;
|
|
741
|
-
case 3 /* String */: return input;
|
|
742
|
-
case 4 /* Symbol */: return input;
|
|
743
|
-
case 5 /* Number */: return input;
|
|
744
|
-
}
|
|
745
|
-
var hint = "string" ;
|
|
746
|
-
var exoticToPrim = GetMethod(input, toPrimitiveSymbol);
|
|
747
|
-
if (exoticToPrim !== undefined) {
|
|
748
|
-
var result = exoticToPrim.call(input, hint);
|
|
749
|
-
if (IsObject(result))
|
|
750
|
-
throw new TypeError();
|
|
751
|
-
return result;
|
|
752
|
-
}
|
|
753
|
-
return OrdinaryToPrimitive(input);
|
|
754
|
-
}
|
|
755
|
-
// 7.1.1.1 OrdinaryToPrimitive(O, hint)
|
|
756
|
-
// https://tc39.github.io/ecma262/#sec-ordinarytoprimitive
|
|
757
|
-
function OrdinaryToPrimitive(O, hint) {
|
|
758
|
-
var valueOf, result; {
|
|
759
|
-
var toString_1 = O.toString;
|
|
760
|
-
if (IsCallable(toString_1)) {
|
|
761
|
-
var result = toString_1.call(O);
|
|
762
|
-
if (!IsObject(result))
|
|
763
|
-
return result;
|
|
764
|
-
}
|
|
765
|
-
var valueOf = O.valueOf;
|
|
766
|
-
if (IsCallable(valueOf)) {
|
|
767
|
-
var result = valueOf.call(O);
|
|
768
|
-
if (!IsObject(result))
|
|
769
|
-
return result;
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
throw new TypeError();
|
|
773
|
-
}
|
|
774
|
-
// 7.1.2 ToBoolean(argument)
|
|
775
|
-
// https://tc39.github.io/ecma262/2016/#sec-toboolean
|
|
776
|
-
function ToBoolean(argument) {
|
|
777
|
-
return !!argument;
|
|
778
|
-
}
|
|
779
|
-
// 7.1.12 ToString(argument)
|
|
780
|
-
// https://tc39.github.io/ecma262/#sec-tostring
|
|
781
|
-
function ToString(argument) {
|
|
782
|
-
return "" + argument;
|
|
783
|
-
}
|
|
784
|
-
// 7.1.14 ToPropertyKey(argument)
|
|
785
|
-
// https://tc39.github.io/ecma262/#sec-topropertykey
|
|
786
|
-
function ToPropertyKey(argument) {
|
|
787
|
-
var key = ToPrimitive(argument);
|
|
788
|
-
if (IsSymbol(key))
|
|
789
|
-
return key;
|
|
790
|
-
return ToString(key);
|
|
791
|
-
}
|
|
792
|
-
// 7.2 Testing and Comparison Operations
|
|
793
|
-
// https://tc39.github.io/ecma262/#sec-testing-and-comparison-operations
|
|
794
|
-
// 7.2.2 IsArray(argument)
|
|
795
|
-
// https://tc39.github.io/ecma262/#sec-isarray
|
|
796
|
-
function IsArray(argument) {
|
|
797
|
-
return Array.isArray
|
|
798
|
-
? Array.isArray(argument)
|
|
799
|
-
: argument instanceof Object
|
|
800
|
-
? argument instanceof Array
|
|
801
|
-
: Object.prototype.toString.call(argument) === "[object Array]";
|
|
802
|
-
}
|
|
803
|
-
// 7.2.3 IsCallable(argument)
|
|
804
|
-
// https://tc39.github.io/ecma262/#sec-iscallable
|
|
805
|
-
function IsCallable(argument) {
|
|
806
|
-
// NOTE: This is an approximation as we cannot check for [[Call]] internal method.
|
|
807
|
-
return typeof argument === "function";
|
|
808
|
-
}
|
|
809
|
-
// 7.2.4 IsConstructor(argument)
|
|
810
|
-
// https://tc39.github.io/ecma262/#sec-isconstructor
|
|
811
|
-
function IsConstructor(argument) {
|
|
812
|
-
// NOTE: This is an approximation as we cannot check for [[Construct]] internal method.
|
|
813
|
-
return typeof argument === "function";
|
|
814
|
-
}
|
|
815
|
-
// 7.2.7 IsPropertyKey(argument)
|
|
816
|
-
// https://tc39.github.io/ecma262/#sec-ispropertykey
|
|
817
|
-
function IsPropertyKey(argument) {
|
|
818
|
-
switch (Type(argument)) {
|
|
819
|
-
case 3 /* String */: return true;
|
|
820
|
-
case 4 /* Symbol */: return true;
|
|
821
|
-
default: return false;
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
function SameValueZero(x, y) {
|
|
825
|
-
return x === y || x !== x && y !== y;
|
|
826
|
-
}
|
|
827
|
-
// 7.3 Operations on Objects
|
|
828
|
-
// https://tc39.github.io/ecma262/#sec-operations-on-objects
|
|
829
|
-
// 7.3.9 GetMethod(V, P)
|
|
830
|
-
// https://tc39.github.io/ecma262/#sec-getmethod
|
|
831
|
-
function GetMethod(V, P) {
|
|
832
|
-
var func = V[P];
|
|
833
|
-
if (func === undefined || func === null)
|
|
834
|
-
return undefined;
|
|
835
|
-
if (!IsCallable(func))
|
|
836
|
-
throw new TypeError();
|
|
837
|
-
return func;
|
|
838
|
-
}
|
|
839
|
-
// 7.4 Operations on Iterator Objects
|
|
840
|
-
// https://tc39.github.io/ecma262/#sec-operations-on-iterator-objects
|
|
841
|
-
function GetIterator(obj) {
|
|
842
|
-
var method = GetMethod(obj, iteratorSymbol);
|
|
843
|
-
if (!IsCallable(method))
|
|
844
|
-
throw new TypeError(); // from Call
|
|
845
|
-
var iterator = method.call(obj);
|
|
846
|
-
if (!IsObject(iterator))
|
|
847
|
-
throw new TypeError();
|
|
848
|
-
return iterator;
|
|
849
|
-
}
|
|
850
|
-
// 7.4.4 IteratorValue(iterResult)
|
|
851
|
-
// https://tc39.github.io/ecma262/2016/#sec-iteratorvalue
|
|
852
|
-
function IteratorValue(iterResult) {
|
|
853
|
-
return iterResult.value;
|
|
854
|
-
}
|
|
855
|
-
// 7.4.5 IteratorStep(iterator)
|
|
856
|
-
// https://tc39.github.io/ecma262/#sec-iteratorstep
|
|
857
|
-
function IteratorStep(iterator) {
|
|
858
|
-
var result = iterator.next();
|
|
859
|
-
return result.done ? false : result;
|
|
860
|
-
}
|
|
861
|
-
// 7.4.6 IteratorClose(iterator, completion)
|
|
862
|
-
// https://tc39.github.io/ecma262/#sec-iteratorclose
|
|
863
|
-
function IteratorClose(iterator) {
|
|
864
|
-
var f = iterator["return"];
|
|
865
|
-
if (f)
|
|
866
|
-
f.call(iterator);
|
|
867
|
-
}
|
|
868
|
-
// 9.1 Ordinary Object Internal Methods and Internal Slots
|
|
869
|
-
// https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots
|
|
870
|
-
// 9.1.1.1 OrdinaryGetPrototypeOf(O)
|
|
871
|
-
// https://tc39.github.io/ecma262/#sec-ordinarygetprototypeof
|
|
872
|
-
function OrdinaryGetPrototypeOf(O) {
|
|
873
|
-
var proto = Object.getPrototypeOf(O);
|
|
874
|
-
if (typeof O !== "function" || O === functionPrototype)
|
|
875
|
-
return proto;
|
|
876
|
-
// TypeScript doesn't set __proto__ in ES5, as it's non-standard.
|
|
877
|
-
// Try to determine the superclass constructor. Compatible implementations
|
|
878
|
-
// must either set __proto__ on a subclass constructor to the superclass constructor,
|
|
879
|
-
// or ensure each class has a valid `constructor` property on its prototype that
|
|
880
|
-
// points back to the constructor.
|
|
881
|
-
// If this is not the same as Function.[[Prototype]], then this is definately inherited.
|
|
882
|
-
// This is the case when in ES6 or when using __proto__ in a compatible browser.
|
|
883
|
-
if (proto !== functionPrototype)
|
|
884
|
-
return proto;
|
|
885
|
-
// If the super prototype is Object.prototype, null, or undefined, then we cannot determine the heritage.
|
|
886
|
-
var prototype = O.prototype;
|
|
887
|
-
var prototypeProto = prototype && Object.getPrototypeOf(prototype);
|
|
888
|
-
if (prototypeProto == null || prototypeProto === Object.prototype)
|
|
889
|
-
return proto;
|
|
890
|
-
// If the constructor was not a function, then we cannot determine the heritage.
|
|
891
|
-
var constructor = prototypeProto.constructor;
|
|
892
|
-
if (typeof constructor !== "function")
|
|
893
|
-
return proto;
|
|
894
|
-
// If we have some kind of self-reference, then we cannot determine the heritage.
|
|
895
|
-
if (constructor === O)
|
|
896
|
-
return proto;
|
|
897
|
-
// we have a pretty good guess at the heritage.
|
|
898
|
-
return constructor;
|
|
899
|
-
}
|
|
900
|
-
// Global metadata registry
|
|
901
|
-
// - Allows `import "reflect-metadata"` and `import "reflect-metadata/no-conflict"` to interoperate.
|
|
902
|
-
// - Uses isolated metadata if `Reflect` is frozen before the registry can be installed.
|
|
903
|
-
/**
|
|
904
|
-
* Creates a registry used to allow multiple `reflect-metadata` providers.
|
|
905
|
-
*/
|
|
906
|
-
function CreateMetadataRegistry() {
|
|
907
|
-
var fallback;
|
|
908
|
-
if (!IsUndefined(registrySymbol) &&
|
|
909
|
-
typeof root.Reflect !== "undefined" &&
|
|
910
|
-
!(registrySymbol in root.Reflect) &&
|
|
911
|
-
typeof root.Reflect.defineMetadata === "function") {
|
|
912
|
-
// interoperate with older version of `reflect-metadata` that did not support a registry.
|
|
913
|
-
fallback = CreateFallbackProvider(root.Reflect);
|
|
914
|
-
}
|
|
915
|
-
var first;
|
|
916
|
-
var second;
|
|
917
|
-
var rest;
|
|
918
|
-
var targetProviderMap = new _WeakMap();
|
|
919
|
-
var registry = {
|
|
920
|
-
registerProvider: registerProvider,
|
|
921
|
-
getProvider: getProvider,
|
|
922
|
-
setProvider: setProvider,
|
|
923
|
-
};
|
|
924
|
-
return registry;
|
|
925
|
-
function registerProvider(provider) {
|
|
926
|
-
if (!Object.isExtensible(registry)) {
|
|
927
|
-
throw new Error("Cannot add provider to a frozen registry.");
|
|
928
|
-
}
|
|
929
|
-
switch (true) {
|
|
930
|
-
case fallback === provider: break;
|
|
931
|
-
case IsUndefined(first):
|
|
932
|
-
first = provider;
|
|
933
|
-
break;
|
|
934
|
-
case first === provider: break;
|
|
935
|
-
case IsUndefined(second):
|
|
936
|
-
second = provider;
|
|
937
|
-
break;
|
|
938
|
-
case second === provider: break;
|
|
939
|
-
default:
|
|
940
|
-
if (rest === undefined)
|
|
941
|
-
rest = new _Set();
|
|
942
|
-
rest.add(provider);
|
|
943
|
-
break;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
function getProviderNoCache(O, P) {
|
|
947
|
-
if (!IsUndefined(first)) {
|
|
948
|
-
if (first.isProviderFor(O, P))
|
|
949
|
-
return first;
|
|
950
|
-
if (!IsUndefined(second)) {
|
|
951
|
-
if (second.isProviderFor(O, P))
|
|
952
|
-
return first;
|
|
953
|
-
if (!IsUndefined(rest)) {
|
|
954
|
-
var iterator = GetIterator(rest);
|
|
955
|
-
while (true) {
|
|
956
|
-
var next = IteratorStep(iterator);
|
|
957
|
-
if (!next) {
|
|
958
|
-
return undefined;
|
|
959
|
-
}
|
|
960
|
-
var provider = IteratorValue(next);
|
|
961
|
-
if (provider.isProviderFor(O, P)) {
|
|
962
|
-
IteratorClose(iterator);
|
|
963
|
-
return provider;
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
if (!IsUndefined(fallback) && fallback.isProviderFor(O, P)) {
|
|
970
|
-
return fallback;
|
|
971
|
-
}
|
|
972
|
-
return undefined;
|
|
973
|
-
}
|
|
974
|
-
function getProvider(O, P) {
|
|
975
|
-
var providerMap = targetProviderMap.get(O);
|
|
976
|
-
var provider;
|
|
977
|
-
if (!IsUndefined(providerMap)) {
|
|
978
|
-
provider = providerMap.get(P);
|
|
979
|
-
}
|
|
980
|
-
if (!IsUndefined(provider)) {
|
|
981
|
-
return provider;
|
|
982
|
-
}
|
|
983
|
-
provider = getProviderNoCache(O, P);
|
|
984
|
-
if (!IsUndefined(provider)) {
|
|
985
|
-
if (IsUndefined(providerMap)) {
|
|
986
|
-
providerMap = new _Map();
|
|
987
|
-
targetProviderMap.set(O, providerMap);
|
|
988
|
-
}
|
|
989
|
-
providerMap.set(P, provider);
|
|
990
|
-
}
|
|
991
|
-
return provider;
|
|
992
|
-
}
|
|
993
|
-
function hasProvider(provider) {
|
|
994
|
-
if (IsUndefined(provider))
|
|
995
|
-
throw new TypeError();
|
|
996
|
-
return first === provider || second === provider || !IsUndefined(rest) && rest.has(provider);
|
|
997
|
-
}
|
|
998
|
-
function setProvider(O, P, provider) {
|
|
999
|
-
if (!hasProvider(provider)) {
|
|
1000
|
-
throw new Error("Metadata provider not registered.");
|
|
1001
|
-
}
|
|
1002
|
-
var existingProvider = getProvider(O, P);
|
|
1003
|
-
if (existingProvider !== provider) {
|
|
1004
|
-
if (!IsUndefined(existingProvider)) {
|
|
1005
|
-
return false;
|
|
1006
|
-
}
|
|
1007
|
-
var providerMap = targetProviderMap.get(O);
|
|
1008
|
-
if (IsUndefined(providerMap)) {
|
|
1009
|
-
providerMap = new _Map();
|
|
1010
|
-
targetProviderMap.set(O, providerMap);
|
|
1011
|
-
}
|
|
1012
|
-
providerMap.set(P, provider);
|
|
1013
|
-
}
|
|
1014
|
-
return true;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
/**
|
|
1018
|
-
* Gets or creates the shared registry of metadata providers.
|
|
1019
|
-
*/
|
|
1020
|
-
function GetOrCreateMetadataRegistry() {
|
|
1021
|
-
var metadataRegistry;
|
|
1022
|
-
if (!IsUndefined(registrySymbol) && IsObject(root.Reflect) && Object.isExtensible(root.Reflect)) {
|
|
1023
|
-
metadataRegistry = root.Reflect[registrySymbol];
|
|
1024
|
-
}
|
|
1025
|
-
if (IsUndefined(metadataRegistry)) {
|
|
1026
|
-
metadataRegistry = CreateMetadataRegistry();
|
|
1027
|
-
}
|
|
1028
|
-
if (!IsUndefined(registrySymbol) && IsObject(root.Reflect) && Object.isExtensible(root.Reflect)) {
|
|
1029
|
-
Object.defineProperty(root.Reflect, registrySymbol, {
|
|
1030
|
-
enumerable: false,
|
|
1031
|
-
configurable: false,
|
|
1032
|
-
writable: false,
|
|
1033
|
-
value: metadataRegistry
|
|
1034
|
-
});
|
|
1035
|
-
}
|
|
1036
|
-
return metadataRegistry;
|
|
1037
|
-
}
|
|
1038
|
-
function CreateMetadataProvider(registry) {
|
|
1039
|
-
// [[Metadata]] internal slot
|
|
1040
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinary-object-internal-methods-and-internal-slots
|
|
1041
|
-
var metadata = new _WeakMap();
|
|
1042
|
-
var provider = {
|
|
1043
|
-
isProviderFor: function (O, P) {
|
|
1044
|
-
var targetMetadata = metadata.get(O);
|
|
1045
|
-
if (IsUndefined(targetMetadata))
|
|
1046
|
-
return false;
|
|
1047
|
-
return targetMetadata.has(P);
|
|
1048
|
-
},
|
|
1049
|
-
OrdinaryDefineOwnMetadata: OrdinaryDefineOwnMetadata,
|
|
1050
|
-
OrdinaryHasOwnMetadata: OrdinaryHasOwnMetadata,
|
|
1051
|
-
OrdinaryGetOwnMetadata: OrdinaryGetOwnMetadata,
|
|
1052
|
-
OrdinaryOwnMetadataKeys: OrdinaryOwnMetadataKeys,
|
|
1053
|
-
OrdinaryDeleteMetadata: OrdinaryDeleteMetadata,
|
|
1054
|
-
};
|
|
1055
|
-
metadataRegistry.registerProvider(provider);
|
|
1056
|
-
return provider;
|
|
1057
|
-
function GetOrCreateMetadataMap(O, P, Create) {
|
|
1058
|
-
var targetMetadata = metadata.get(O);
|
|
1059
|
-
var createdTargetMetadata = false;
|
|
1060
|
-
if (IsUndefined(targetMetadata)) {
|
|
1061
|
-
if (!Create)
|
|
1062
|
-
return undefined;
|
|
1063
|
-
targetMetadata = new _Map();
|
|
1064
|
-
metadata.set(O, targetMetadata);
|
|
1065
|
-
createdTargetMetadata = true;
|
|
1066
|
-
}
|
|
1067
|
-
var metadataMap = targetMetadata.get(P);
|
|
1068
|
-
if (IsUndefined(metadataMap)) {
|
|
1069
|
-
if (!Create)
|
|
1070
|
-
return undefined;
|
|
1071
|
-
metadataMap = new _Map();
|
|
1072
|
-
targetMetadata.set(P, metadataMap);
|
|
1073
|
-
if (!registry.setProvider(O, P, provider)) {
|
|
1074
|
-
targetMetadata.delete(P);
|
|
1075
|
-
if (createdTargetMetadata) {
|
|
1076
|
-
metadata.delete(O);
|
|
1077
|
-
}
|
|
1078
|
-
throw new Error("Wrong provider for target.");
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
return metadataMap;
|
|
1082
|
-
}
|
|
1083
|
-
// 3.1.2.1 OrdinaryHasOwnMetadata(MetadataKey, O, P)
|
|
1084
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinaryhasownmetadata
|
|
1085
|
-
function OrdinaryHasOwnMetadata(MetadataKey, O, P) {
|
|
1086
|
-
var metadataMap = GetOrCreateMetadataMap(O, P, /*Create*/ false);
|
|
1087
|
-
if (IsUndefined(metadataMap))
|
|
1088
|
-
return false;
|
|
1089
|
-
return ToBoolean(metadataMap.has(MetadataKey));
|
|
1090
|
-
}
|
|
1091
|
-
// 3.1.4.1 OrdinaryGetOwnMetadata(MetadataKey, O, P)
|
|
1092
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinarygetownmetadata
|
|
1093
|
-
function OrdinaryGetOwnMetadata(MetadataKey, O, P) {
|
|
1094
|
-
var metadataMap = GetOrCreateMetadataMap(O, P, /*Create*/ false);
|
|
1095
|
-
if (IsUndefined(metadataMap))
|
|
1096
|
-
return undefined;
|
|
1097
|
-
return metadataMap.get(MetadataKey);
|
|
1098
|
-
}
|
|
1099
|
-
// 3.1.5.1 OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P)
|
|
1100
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinarydefineownmetadata
|
|
1101
|
-
function OrdinaryDefineOwnMetadata(MetadataKey, MetadataValue, O, P) {
|
|
1102
|
-
var metadataMap = GetOrCreateMetadataMap(O, P, /*Create*/ true);
|
|
1103
|
-
metadataMap.set(MetadataKey, MetadataValue);
|
|
1104
|
-
}
|
|
1105
|
-
// 3.1.7.1 OrdinaryOwnMetadataKeys(O, P)
|
|
1106
|
-
// https://rbuckton.github.io/reflect-metadata/#ordinaryownmetadatakeys
|
|
1107
|
-
function OrdinaryOwnMetadataKeys(O, P) {
|
|
1108
|
-
var keys = [];
|
|
1109
|
-
var metadataMap = GetOrCreateMetadataMap(O, P, /*Create*/ false);
|
|
1110
|
-
if (IsUndefined(metadataMap))
|
|
1111
|
-
return keys;
|
|
1112
|
-
var keysObj = metadataMap.keys();
|
|
1113
|
-
var iterator = GetIterator(keysObj);
|
|
1114
|
-
var k = 0;
|
|
1115
|
-
while (true) {
|
|
1116
|
-
var next = IteratorStep(iterator);
|
|
1117
|
-
if (!next) {
|
|
1118
|
-
keys.length = k;
|
|
1119
|
-
return keys;
|
|
1120
|
-
}
|
|
1121
|
-
var nextValue = IteratorValue(next);
|
|
1122
|
-
try {
|
|
1123
|
-
keys[k] = nextValue;
|
|
1124
|
-
}
|
|
1125
|
-
catch (e) {
|
|
1126
|
-
try {
|
|
1127
|
-
IteratorClose(iterator);
|
|
1128
|
-
}
|
|
1129
|
-
finally {
|
|
1130
|
-
throw e;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
k++;
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
function OrdinaryDeleteMetadata(MetadataKey, O, P) {
|
|
1137
|
-
var metadataMap = GetOrCreateMetadataMap(O, P, /*Create*/ false);
|
|
1138
|
-
if (IsUndefined(metadataMap))
|
|
1139
|
-
return false;
|
|
1140
|
-
if (!metadataMap.delete(MetadataKey))
|
|
1141
|
-
return false;
|
|
1142
|
-
if (metadataMap.size === 0) {
|
|
1143
|
-
var targetMetadata = metadata.get(O);
|
|
1144
|
-
if (!IsUndefined(targetMetadata)) {
|
|
1145
|
-
targetMetadata.delete(P);
|
|
1146
|
-
if (targetMetadata.size === 0) {
|
|
1147
|
-
metadata.delete(targetMetadata);
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
return true;
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
function CreateFallbackProvider(reflect) {
|
|
1155
|
-
var defineMetadata = reflect.defineMetadata, hasOwnMetadata = reflect.hasOwnMetadata, getOwnMetadata = reflect.getOwnMetadata, getOwnMetadataKeys = reflect.getOwnMetadataKeys, deleteMetadata = reflect.deleteMetadata;
|
|
1156
|
-
var metadataOwner = new _WeakMap();
|
|
1157
|
-
var provider = {
|
|
1158
|
-
isProviderFor: function (O, P) {
|
|
1159
|
-
var metadataPropertySet = metadataOwner.get(O);
|
|
1160
|
-
if (!IsUndefined(metadataPropertySet)) {
|
|
1161
|
-
return metadataPropertySet.has(P);
|
|
1162
|
-
}
|
|
1163
|
-
if (getOwnMetadataKeys(O, P).length) {
|
|
1164
|
-
if (IsUndefined(metadataPropertySet)) {
|
|
1165
|
-
metadataPropertySet = new _Set();
|
|
1166
|
-
metadataOwner.set(O, metadataPropertySet);
|
|
1167
|
-
}
|
|
1168
|
-
metadataPropertySet.add(P);
|
|
1169
|
-
return true;
|
|
1170
|
-
}
|
|
1171
|
-
return false;
|
|
1172
|
-
},
|
|
1173
|
-
OrdinaryDefineOwnMetadata: defineMetadata,
|
|
1174
|
-
OrdinaryHasOwnMetadata: hasOwnMetadata,
|
|
1175
|
-
OrdinaryGetOwnMetadata: getOwnMetadata,
|
|
1176
|
-
OrdinaryOwnMetadataKeys: getOwnMetadataKeys,
|
|
1177
|
-
OrdinaryDeleteMetadata: deleteMetadata,
|
|
1178
|
-
};
|
|
1179
|
-
return provider;
|
|
1180
|
-
}
|
|
1181
|
-
/**
|
|
1182
|
-
* Gets the metadata provider for an object. If the object has no metadata provider and this is for a create operation,
|
|
1183
|
-
* then this module's metadata provider is assigned to the object.
|
|
1184
|
-
*/
|
|
1185
|
-
function GetMetadataProvider(O, P, Create) {
|
|
1186
|
-
var registeredProvider = metadataRegistry.getProvider(O, P);
|
|
1187
|
-
if (!IsUndefined(registeredProvider)) {
|
|
1188
|
-
return registeredProvider;
|
|
1189
|
-
}
|
|
1190
|
-
if (Create) {
|
|
1191
|
-
if (metadataRegistry.setProvider(O, P, metadataProvider)) {
|
|
1192
|
-
return metadataProvider;
|
|
1193
|
-
}
|
|
1194
|
-
throw new Error("Illegal state.");
|
|
1195
|
-
}
|
|
1196
|
-
return undefined;
|
|
1197
|
-
}
|
|
1198
|
-
// naive Map shim
|
|
1199
|
-
function CreateMapPolyfill() {
|
|
1200
|
-
var cacheSentinel = {};
|
|
1201
|
-
var arraySentinel = [];
|
|
1202
|
-
var MapIterator = /** @class */ (function () {
|
|
1203
|
-
function MapIterator(keys, values, selector) {
|
|
1204
|
-
this._index = 0;
|
|
1205
|
-
this._keys = keys;
|
|
1206
|
-
this._values = values;
|
|
1207
|
-
this._selector = selector;
|
|
1208
|
-
}
|
|
1209
|
-
MapIterator.prototype["@@iterator"] = function () { return this; };
|
|
1210
|
-
MapIterator.prototype[iteratorSymbol] = function () { return this; };
|
|
1211
|
-
MapIterator.prototype.next = function () {
|
|
1212
|
-
var index = this._index;
|
|
1213
|
-
if (index >= 0 && index < this._keys.length) {
|
|
1214
|
-
var result = this._selector(this._keys[index], this._values[index]);
|
|
1215
|
-
if (index + 1 >= this._keys.length) {
|
|
1216
|
-
this._index = -1;
|
|
1217
|
-
this._keys = arraySentinel;
|
|
1218
|
-
this._values = arraySentinel;
|
|
1219
|
-
}
|
|
1220
|
-
else {
|
|
1221
|
-
this._index++;
|
|
1222
|
-
}
|
|
1223
|
-
return { value: result, done: false };
|
|
1224
|
-
}
|
|
1225
|
-
return { value: undefined, done: true };
|
|
1226
|
-
};
|
|
1227
|
-
MapIterator.prototype.throw = function (error) {
|
|
1228
|
-
if (this._index >= 0) {
|
|
1229
|
-
this._index = -1;
|
|
1230
|
-
this._keys = arraySentinel;
|
|
1231
|
-
this._values = arraySentinel;
|
|
1232
|
-
}
|
|
1233
|
-
throw error;
|
|
1234
|
-
};
|
|
1235
|
-
MapIterator.prototype.return = function (value) {
|
|
1236
|
-
if (this._index >= 0) {
|
|
1237
|
-
this._index = -1;
|
|
1238
|
-
this._keys = arraySentinel;
|
|
1239
|
-
this._values = arraySentinel;
|
|
1240
|
-
}
|
|
1241
|
-
return { value: value, done: true };
|
|
1242
|
-
};
|
|
1243
|
-
return MapIterator;
|
|
1244
|
-
}());
|
|
1245
|
-
var Map = /** @class */ (function () {
|
|
1246
|
-
function Map() {
|
|
1247
|
-
this._keys = [];
|
|
1248
|
-
this._values = [];
|
|
1249
|
-
this._cacheKey = cacheSentinel;
|
|
1250
|
-
this._cacheIndex = -2;
|
|
1251
|
-
}
|
|
1252
|
-
Object.defineProperty(Map.prototype, "size", {
|
|
1253
|
-
get: function () { return this._keys.length; },
|
|
1254
|
-
enumerable: true,
|
|
1255
|
-
configurable: true
|
|
1256
|
-
});
|
|
1257
|
-
Map.prototype.has = function (key) { return this._find(key, /*insert*/ false) >= 0; };
|
|
1258
|
-
Map.prototype.get = function (key) {
|
|
1259
|
-
var index = this._find(key, /*insert*/ false);
|
|
1260
|
-
return index >= 0 ? this._values[index] : undefined;
|
|
1261
|
-
};
|
|
1262
|
-
Map.prototype.set = function (key, value) {
|
|
1263
|
-
var index = this._find(key, /*insert*/ true);
|
|
1264
|
-
this._values[index] = value;
|
|
1265
|
-
return this;
|
|
1266
|
-
};
|
|
1267
|
-
Map.prototype.delete = function (key) {
|
|
1268
|
-
var index = this._find(key, /*insert*/ false);
|
|
1269
|
-
if (index >= 0) {
|
|
1270
|
-
var size = this._keys.length;
|
|
1271
|
-
for (var i = index + 1; i < size; i++) {
|
|
1272
|
-
this._keys[i - 1] = this._keys[i];
|
|
1273
|
-
this._values[i - 1] = this._values[i];
|
|
1274
|
-
}
|
|
1275
|
-
this._keys.length--;
|
|
1276
|
-
this._values.length--;
|
|
1277
|
-
if (SameValueZero(key, this._cacheKey)) {
|
|
1278
|
-
this._cacheKey = cacheSentinel;
|
|
1279
|
-
this._cacheIndex = -2;
|
|
1280
|
-
}
|
|
1281
|
-
return true;
|
|
1282
|
-
}
|
|
1283
|
-
return false;
|
|
1284
|
-
};
|
|
1285
|
-
Map.prototype.clear = function () {
|
|
1286
|
-
this._keys.length = 0;
|
|
1287
|
-
this._values.length = 0;
|
|
1288
|
-
this._cacheKey = cacheSentinel;
|
|
1289
|
-
this._cacheIndex = -2;
|
|
1290
|
-
};
|
|
1291
|
-
Map.prototype.keys = function () { return new MapIterator(this._keys, this._values, getKey); };
|
|
1292
|
-
Map.prototype.values = function () { return new MapIterator(this._keys, this._values, getValue); };
|
|
1293
|
-
Map.prototype.entries = function () { return new MapIterator(this._keys, this._values, getEntry); };
|
|
1294
|
-
Map.prototype["@@iterator"] = function () { return this.entries(); };
|
|
1295
|
-
Map.prototype[iteratorSymbol] = function () { return this.entries(); };
|
|
1296
|
-
Map.prototype._find = function (key, insert) {
|
|
1297
|
-
if (!SameValueZero(this._cacheKey, key)) {
|
|
1298
|
-
this._cacheIndex = -1;
|
|
1299
|
-
for (var i = 0; i < this._keys.length; i++) {
|
|
1300
|
-
if (SameValueZero(this._keys[i], key)) {
|
|
1301
|
-
this._cacheIndex = i;
|
|
1302
|
-
break;
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
if (this._cacheIndex < 0 && insert) {
|
|
1307
|
-
this._cacheIndex = this._keys.length;
|
|
1308
|
-
this._keys.push(key);
|
|
1309
|
-
this._values.push(undefined);
|
|
1310
|
-
}
|
|
1311
|
-
return this._cacheIndex;
|
|
1312
|
-
};
|
|
1313
|
-
return Map;
|
|
1314
|
-
}());
|
|
1315
|
-
return Map;
|
|
1316
|
-
function getKey(key, _) {
|
|
1317
|
-
return key;
|
|
1318
|
-
}
|
|
1319
|
-
function getValue(_, value) {
|
|
1320
|
-
return value;
|
|
1321
|
-
}
|
|
1322
|
-
function getEntry(key, value) {
|
|
1323
|
-
return [key, value];
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
// naive Set shim
|
|
1327
|
-
function CreateSetPolyfill() {
|
|
1328
|
-
var Set = /** @class */ (function () {
|
|
1329
|
-
function Set() {
|
|
1330
|
-
this._map = new _Map();
|
|
1331
|
-
}
|
|
1332
|
-
Object.defineProperty(Set.prototype, "size", {
|
|
1333
|
-
get: function () { return this._map.size; },
|
|
1334
|
-
enumerable: true,
|
|
1335
|
-
configurable: true
|
|
1336
|
-
});
|
|
1337
|
-
Set.prototype.has = function (value) { return this._map.has(value); };
|
|
1338
|
-
Set.prototype.add = function (value) { return this._map.set(value, value), this; };
|
|
1339
|
-
Set.prototype.delete = function (value) { return this._map.delete(value); };
|
|
1340
|
-
Set.prototype.clear = function () { this._map.clear(); };
|
|
1341
|
-
Set.prototype.keys = function () { return this._map.keys(); };
|
|
1342
|
-
Set.prototype.values = function () { return this._map.keys(); };
|
|
1343
|
-
Set.prototype.entries = function () { return this._map.entries(); };
|
|
1344
|
-
Set.prototype["@@iterator"] = function () { return this.keys(); };
|
|
1345
|
-
Set.prototype[iteratorSymbol] = function () { return this.keys(); };
|
|
1346
|
-
return Set;
|
|
1347
|
-
}());
|
|
1348
|
-
return Set;
|
|
1349
|
-
}
|
|
1350
|
-
// naive WeakMap shim
|
|
1351
|
-
function CreateWeakMapPolyfill() {
|
|
1352
|
-
var UUID_SIZE = 16;
|
|
1353
|
-
var keys = HashMap.create();
|
|
1354
|
-
var rootKey = CreateUniqueKey();
|
|
1355
|
-
return /** @class */ (function () {
|
|
1356
|
-
function WeakMap() {
|
|
1357
|
-
this._key = CreateUniqueKey();
|
|
1358
|
-
}
|
|
1359
|
-
WeakMap.prototype.has = function (target) {
|
|
1360
|
-
var table = GetOrCreateWeakMapTable(target, /*create*/ false);
|
|
1361
|
-
return table !== undefined ? HashMap.has(table, this._key) : false;
|
|
1362
|
-
};
|
|
1363
|
-
WeakMap.prototype.get = function (target) {
|
|
1364
|
-
var table = GetOrCreateWeakMapTable(target, /*create*/ false);
|
|
1365
|
-
return table !== undefined ? HashMap.get(table, this._key) : undefined;
|
|
1366
|
-
};
|
|
1367
|
-
WeakMap.prototype.set = function (target, value) {
|
|
1368
|
-
var table = GetOrCreateWeakMapTable(target, /*create*/ true);
|
|
1369
|
-
table[this._key] = value;
|
|
1370
|
-
return this;
|
|
1371
|
-
};
|
|
1372
|
-
WeakMap.prototype.delete = function (target) {
|
|
1373
|
-
var table = GetOrCreateWeakMapTable(target, /*create*/ false);
|
|
1374
|
-
return table !== undefined ? delete table[this._key] : false;
|
|
1375
|
-
};
|
|
1376
|
-
WeakMap.prototype.clear = function () {
|
|
1377
|
-
// NOTE: not a real clear, just makes the previous data unreachable
|
|
1378
|
-
this._key = CreateUniqueKey();
|
|
1379
|
-
};
|
|
1380
|
-
return WeakMap;
|
|
1381
|
-
}());
|
|
1382
|
-
function CreateUniqueKey() {
|
|
1383
|
-
var key;
|
|
1384
|
-
do
|
|
1385
|
-
key = "@@WeakMap@@" + CreateUUID();
|
|
1386
|
-
while (HashMap.has(keys, key));
|
|
1387
|
-
keys[key] = true;
|
|
1388
|
-
return key;
|
|
1389
|
-
}
|
|
1390
|
-
function GetOrCreateWeakMapTable(target, create) {
|
|
1391
|
-
if (!hasOwn.call(target, rootKey)) {
|
|
1392
|
-
if (!create)
|
|
1393
|
-
return undefined;
|
|
1394
|
-
Object.defineProperty(target, rootKey, { value: HashMap.create() });
|
|
1395
|
-
}
|
|
1396
|
-
return target[rootKey];
|
|
1397
|
-
}
|
|
1398
|
-
function FillRandomBytes(buffer, size) {
|
|
1399
|
-
for (var i = 0; i < size; ++i)
|
|
1400
|
-
buffer[i] = Math.random() * 0xff | 0;
|
|
1401
|
-
return buffer;
|
|
1402
|
-
}
|
|
1403
|
-
function GenRandomBytes(size) {
|
|
1404
|
-
if (typeof Uint8Array === "function") {
|
|
1405
|
-
if (typeof crypto !== "undefined")
|
|
1406
|
-
return crypto.getRandomValues(new Uint8Array(size));
|
|
1407
|
-
if (typeof msCrypto !== "undefined")
|
|
1408
|
-
return msCrypto.getRandomValues(new Uint8Array(size));
|
|
1409
|
-
return FillRandomBytes(new Uint8Array(size), size);
|
|
1410
|
-
}
|
|
1411
|
-
return FillRandomBytes(new Array(size), size);
|
|
1412
|
-
}
|
|
1413
|
-
function CreateUUID() {
|
|
1414
|
-
var data = GenRandomBytes(UUID_SIZE);
|
|
1415
|
-
// mark as random - RFC 4122 § 4.4
|
|
1416
|
-
data[6] = data[6] & 0x4f | 0x40;
|
|
1417
|
-
data[8] = data[8] & 0xbf | 0x80;
|
|
1418
|
-
var result = "";
|
|
1419
|
-
for (var offset = 0; offset < UUID_SIZE; ++offset) {
|
|
1420
|
-
var byte = data[offset];
|
|
1421
|
-
if (offset === 4 || offset === 6 || offset === 8)
|
|
1422
|
-
result += "-";
|
|
1423
|
-
if (byte < 16)
|
|
1424
|
-
result += "0";
|
|
1425
|
-
result += byte.toString(16).toLowerCase();
|
|
1426
|
-
}
|
|
1427
|
-
return result;
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
// uses a heuristic used by v8 and chakra to force an object into dictionary mode.
|
|
1431
|
-
function MakeDictionary(obj) {
|
|
1432
|
-
obj.__ = undefined;
|
|
1433
|
-
delete obj.__;
|
|
1434
|
-
return obj;
|
|
1435
|
-
}
|
|
1436
|
-
});
|
|
1437
|
-
})(Reflect || (Reflect = {}));
|
|
1438
|
-
return _Reflect;
|
|
46
|
+
/**
|
|
47
|
+
* 性能缓存模块 - 提供多层次缓存和性能监控
|
|
48
|
+
* @author richen
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* 元数据缓存
|
|
52
|
+
*/
|
|
53
|
+
class MetadataCache {
|
|
54
|
+
constructor() {
|
|
55
|
+
this.cache = new WeakMap();
|
|
56
|
+
}
|
|
57
|
+
static getInstance() {
|
|
58
|
+
if (!MetadataCache.instance) {
|
|
59
|
+
MetadataCache.instance = new MetadataCache();
|
|
60
|
+
}
|
|
61
|
+
return MetadataCache.instance;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 获取类的元数据缓存
|
|
65
|
+
*/
|
|
66
|
+
getClassCache(target) {
|
|
67
|
+
if (!this.cache.has(target)) {
|
|
68
|
+
this.cache.set(target, new Map());
|
|
69
|
+
}
|
|
70
|
+
return this.cache.get(target);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 缓存元数据
|
|
74
|
+
*/
|
|
75
|
+
setMetadata(target, key, value) {
|
|
76
|
+
const classCache = this.getClassCache(target);
|
|
77
|
+
classCache.set(key, value);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* 获取缓存的元数据
|
|
81
|
+
*/
|
|
82
|
+
getMetadata(target, key) {
|
|
83
|
+
const classCache = this.getClassCache(target);
|
|
84
|
+
return classCache.get(key);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 检查是否已缓存
|
|
88
|
+
*/
|
|
89
|
+
hasMetadata(target, key) {
|
|
90
|
+
const classCache = this.getClassCache(target);
|
|
91
|
+
return classCache.has(key);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 清空指定类的缓存
|
|
95
|
+
*/
|
|
96
|
+
clearClassCache(target) {
|
|
97
|
+
if (this.cache.has(target)) {
|
|
98
|
+
this.cache.delete(target);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 验证结果缓存
|
|
104
|
+
*/
|
|
105
|
+
class ValidationCache {
|
|
106
|
+
constructor(options) {
|
|
107
|
+
this.hits = 0;
|
|
108
|
+
this.misses = 0;
|
|
109
|
+
this.cache = new lruCache.LRUCache({
|
|
110
|
+
max: (options === null || options === void 0 ? void 0 : options.max) || 5000,
|
|
111
|
+
ttl: (options === null || options === void 0 ? void 0 : options.ttl) || 1000 * 60 * 10, // 10分钟
|
|
112
|
+
allowStale: (options === null || options === void 0 ? void 0 : options.allowStale) || false,
|
|
113
|
+
updateAgeOnGet: (options === null || options === void 0 ? void 0 : options.updateAgeOnGet) || true,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
static getInstance(options) {
|
|
117
|
+
if (!ValidationCache.instance) {
|
|
118
|
+
ValidationCache.instance = new ValidationCache(options);
|
|
119
|
+
}
|
|
120
|
+
return ValidationCache.instance;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* 生成缓存键
|
|
124
|
+
*/
|
|
125
|
+
generateKey(validator, value, ...args) {
|
|
126
|
+
const valueStr = this.serializeValue(value);
|
|
127
|
+
const argsStr = args.length > 0 ? JSON.stringify(args) : '';
|
|
128
|
+
return `${validator}:${valueStr}:${argsStr}`;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* 序列化值用于缓存键
|
|
132
|
+
*/
|
|
133
|
+
serializeValue(value) {
|
|
134
|
+
if (value === null)
|
|
135
|
+
return 'null';
|
|
136
|
+
if (value === undefined)
|
|
137
|
+
return 'undefined';
|
|
138
|
+
if (typeof value === 'string')
|
|
139
|
+
return `s:${value}`;
|
|
140
|
+
if (typeof value === 'number')
|
|
141
|
+
return `n:${value}`;
|
|
142
|
+
if (typeof value === 'boolean')
|
|
143
|
+
return `b:${value}`;
|
|
144
|
+
if (Array.isArray(value))
|
|
145
|
+
return `a:${JSON.stringify(value)}`;
|
|
146
|
+
if (typeof value === 'object')
|
|
147
|
+
return `o:${JSON.stringify(value)}`;
|
|
148
|
+
return String(value);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 获取缓存的验证结果
|
|
152
|
+
*/
|
|
153
|
+
get(validator, value, ...args) {
|
|
154
|
+
const key = this.generateKey(validator, value, ...args);
|
|
155
|
+
const result = this.cache.get(key);
|
|
156
|
+
// Track cache hits and misses
|
|
157
|
+
if (result !== undefined) {
|
|
158
|
+
this.hits++;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.misses++;
|
|
162
|
+
}
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 缓存验证结果
|
|
167
|
+
*/
|
|
168
|
+
set(validator, value, result, ...args) {
|
|
169
|
+
const key = this.generateKey(validator, value, ...args);
|
|
170
|
+
this.cache.set(key, result);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 检查是否存在缓存
|
|
174
|
+
*/
|
|
175
|
+
has(validator, value, ...args) {
|
|
176
|
+
const key = this.generateKey(validator, value, ...args);
|
|
177
|
+
return this.cache.has(key);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* 删除特定缓存
|
|
181
|
+
*/
|
|
182
|
+
delete(validator, value, ...args) {
|
|
183
|
+
const key = this.generateKey(validator, value, ...args);
|
|
184
|
+
return this.cache.delete(key);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 清空缓存
|
|
188
|
+
*/
|
|
189
|
+
clear() {
|
|
190
|
+
this.cache.clear();
|
|
191
|
+
this.hits = 0;
|
|
192
|
+
this.misses = 0;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 获取缓存统计
|
|
196
|
+
*/
|
|
197
|
+
getStats() {
|
|
198
|
+
const totalRequests = this.hits + this.misses;
|
|
199
|
+
const hitRate = totalRequests > 0 ? this.hits / totalRequests : 0;
|
|
200
|
+
return {
|
|
201
|
+
size: this.cache.size,
|
|
202
|
+
max: this.cache.max,
|
|
203
|
+
calculatedSize: this.cache.calculatedSize,
|
|
204
|
+
keyCount: this.cache.size,
|
|
205
|
+
hits: this.hits,
|
|
206
|
+
misses: this.misses,
|
|
207
|
+
hitRate: Math.round(hitRate * 10000) / 100, // Percentage with 2 decimal places
|
|
208
|
+
totalRequests,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* 设置缓存TTL
|
|
213
|
+
*/
|
|
214
|
+
setTTL(validator, value, ttl, ...args) {
|
|
215
|
+
const key = this.generateKey(validator, value, ...args);
|
|
216
|
+
const existingValue = this.cache.get(key);
|
|
217
|
+
if (existingValue !== undefined) {
|
|
218
|
+
this.cache.set(key, existingValue, { ttl });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* 正则表达式缓存
|
|
224
|
+
*/
|
|
225
|
+
class RegexCache {
|
|
226
|
+
constructor(options) {
|
|
227
|
+
this.cache = new lruCache.LRUCache({
|
|
228
|
+
max: (options === null || options === void 0 ? void 0 : options.max) || 200,
|
|
229
|
+
ttl: (options === null || options === void 0 ? void 0 : options.ttl) || 1000 * 60 * 30, // 30分钟
|
|
230
|
+
allowStale: (options === null || options === void 0 ? void 0 : options.allowStale) || false,
|
|
231
|
+
updateAgeOnGet: (options === null || options === void 0 ? void 0 : options.updateAgeOnGet) || true,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
static getInstance(options) {
|
|
235
|
+
if (!RegexCache.instance) {
|
|
236
|
+
RegexCache.instance = new RegexCache(options);
|
|
237
|
+
}
|
|
238
|
+
return RegexCache.instance;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 获取缓存的正则表达式
|
|
242
|
+
*/
|
|
243
|
+
get(pattern, flags) {
|
|
244
|
+
const key = flags ? `${pattern}:::${flags}` : pattern;
|
|
245
|
+
let regex = this.cache.get(key);
|
|
246
|
+
if (!regex) {
|
|
247
|
+
try {
|
|
248
|
+
regex = new RegExp(pattern, flags);
|
|
249
|
+
this.cache.set(key, regex);
|
|
250
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
251
|
+
}
|
|
252
|
+
catch (_error) {
|
|
253
|
+
// 如果正则表达式无效,抛出错误
|
|
254
|
+
throw new Error(`Invalid regex pattern: ${pattern}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return regex;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* 预编译常用正则表达式
|
|
261
|
+
*/
|
|
262
|
+
precompile(patterns) {
|
|
263
|
+
patterns.forEach(({ pattern, flags }) => {
|
|
264
|
+
try {
|
|
265
|
+
this.get(pattern, flags);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
console.warn(`Failed to precompile regex: ${pattern}`, error);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* 获取缓存统计
|
|
274
|
+
*/
|
|
275
|
+
getStats() {
|
|
276
|
+
return {
|
|
277
|
+
size: this.cache.size,
|
|
278
|
+
max: this.cache.max,
|
|
279
|
+
calculatedSize: this.cache.calculatedSize,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* 清空缓存
|
|
284
|
+
*/
|
|
285
|
+
clear() {
|
|
286
|
+
this.cache.clear();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* 性能监控
|
|
291
|
+
*/
|
|
292
|
+
class PerformanceMonitor {
|
|
293
|
+
constructor() {
|
|
294
|
+
this.metrics = new Map();
|
|
295
|
+
}
|
|
296
|
+
static getInstance() {
|
|
297
|
+
if (!PerformanceMonitor.instance) {
|
|
298
|
+
PerformanceMonitor.instance = new PerformanceMonitor();
|
|
299
|
+
}
|
|
300
|
+
return PerformanceMonitor.instance;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* 开始计时
|
|
304
|
+
*/
|
|
305
|
+
startTimer(name) {
|
|
306
|
+
const start = performance.now();
|
|
307
|
+
return () => {
|
|
308
|
+
const duration = performance.now() - start;
|
|
309
|
+
this.recordMetric(name, duration);
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* 记录性能指标
|
|
314
|
+
*/
|
|
315
|
+
recordMetric(name, duration) {
|
|
316
|
+
if (!this.metrics.has(name)) {
|
|
317
|
+
this.metrics.set(name, {
|
|
318
|
+
count: 0,
|
|
319
|
+
totalTime: 0,
|
|
320
|
+
avgTime: 0,
|
|
321
|
+
maxTime: 0,
|
|
322
|
+
minTime: Infinity,
|
|
323
|
+
lastExecutionTime: new Date(),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const metric = this.metrics.get(name);
|
|
327
|
+
metric.count++;
|
|
328
|
+
metric.totalTime += duration;
|
|
329
|
+
metric.avgTime = metric.totalTime / metric.count;
|
|
330
|
+
metric.maxTime = Math.max(metric.maxTime, duration);
|
|
331
|
+
metric.minTime = Math.min(metric.minTime, duration);
|
|
332
|
+
metric.lastExecutionTime = new Date();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* 获取性能报告
|
|
336
|
+
*/
|
|
337
|
+
getReport() {
|
|
338
|
+
const report = {};
|
|
339
|
+
for (const [name, metric] of this.metrics) {
|
|
340
|
+
report[name] = {
|
|
341
|
+
...metric,
|
|
342
|
+
minTime: metric.minTime === Infinity ? 0 : metric.minTime,
|
|
343
|
+
avgTimeFormatted: `${metric.avgTime.toFixed(2)}ms`,
|
|
344
|
+
totalTimeFormatted: `${metric.totalTime.toFixed(2)}ms`,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return report;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* 获取热点分析(执行时间最长的操作)
|
|
351
|
+
*/
|
|
352
|
+
getHotspots(limit = 10) {
|
|
353
|
+
return Array.from(this.metrics.entries())
|
|
354
|
+
.map(([name, metric]) => ({
|
|
355
|
+
name,
|
|
356
|
+
avgTime: metric.avgTime,
|
|
357
|
+
count: metric.count,
|
|
358
|
+
}))
|
|
359
|
+
.sort((a, b) => b.avgTime - a.avgTime)
|
|
360
|
+
.slice(0, limit);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* 清空指标
|
|
364
|
+
*/
|
|
365
|
+
clear() {
|
|
366
|
+
this.metrics.clear();
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* 导出性能数据为CSV格式
|
|
370
|
+
*/
|
|
371
|
+
exportToCSV() {
|
|
372
|
+
const headers = ['Name', 'Count', 'Total Time (ms)', 'Avg Time (ms)', 'Max Time (ms)', 'Min Time (ms)', 'Last Execution'];
|
|
373
|
+
const rows = [headers.join(',')];
|
|
374
|
+
for (const [name, metric] of this.metrics) {
|
|
375
|
+
const row = [
|
|
376
|
+
name,
|
|
377
|
+
metric.count.toString(),
|
|
378
|
+
metric.totalTime.toFixed(2),
|
|
379
|
+
metric.avgTime.toFixed(2),
|
|
380
|
+
metric.maxTime.toFixed(2),
|
|
381
|
+
(metric.minTime === Infinity ? 0 : metric.minTime).toFixed(2),
|
|
382
|
+
metric.lastExecutionTime.toISOString(),
|
|
383
|
+
];
|
|
384
|
+
rows.push(row.join(','));
|
|
385
|
+
}
|
|
386
|
+
return rows.join('\n');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// 导出单例实例
|
|
390
|
+
const metadataCache = MetadataCache.getInstance();
|
|
391
|
+
const validationCache = ValidationCache.getInstance();
|
|
392
|
+
const regexCache = RegexCache.getInstance();
|
|
393
|
+
const performanceMonitor = PerformanceMonitor.getInstance();
|
|
394
|
+
/**
|
|
395
|
+
* 缓存装饰器 - 用于缓存验证函数结果
|
|
396
|
+
*/
|
|
397
|
+
function cached(validator, ttl) {
|
|
398
|
+
return function (target, propertyName, descriptor) {
|
|
399
|
+
const originalMethod = descriptor.value;
|
|
400
|
+
descriptor.value = function (...args) {
|
|
401
|
+
const value = args[0];
|
|
402
|
+
const additionalArgs = args.slice(1);
|
|
403
|
+
// 尝试从缓存获取结果
|
|
404
|
+
const cachedResult = validationCache.get(validator, value, ...additionalArgs);
|
|
405
|
+
if (cachedResult !== undefined) {
|
|
406
|
+
return cachedResult;
|
|
407
|
+
}
|
|
408
|
+
// 执行验证并缓存结果
|
|
409
|
+
const endTimer = performanceMonitor.startTimer(validator);
|
|
410
|
+
try {
|
|
411
|
+
const result = originalMethod.apply(this, args);
|
|
412
|
+
validationCache.set(validator, value, result, ...additionalArgs);
|
|
413
|
+
// 如果指定了TTL,设置过期时间
|
|
414
|
+
if (ttl && ttl > 0) {
|
|
415
|
+
validationCache.setTTL(validator, value, ttl, ...additionalArgs);
|
|
416
|
+
}
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
endTimer();
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
return descriptor;
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* 获取所有缓存统计信息
|
|
428
|
+
*/
|
|
429
|
+
function getAllCacheStats() {
|
|
430
|
+
return {
|
|
431
|
+
validation: validationCache.getStats(),
|
|
432
|
+
regex: regexCache.getStats(),
|
|
433
|
+
performance: performanceMonitor.getReport(),
|
|
434
|
+
hotspots: performanceMonitor.getHotspots(),
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* 预热缓存 - 预编译常用正则表达式
|
|
439
|
+
*/
|
|
440
|
+
function warmupCaches() {
|
|
441
|
+
// 预编译中文验证相关的正则表达式
|
|
442
|
+
const commonPatterns = [
|
|
443
|
+
{ pattern: '^[\u4e00-\u9fa5]{2,8}$' }, // 中文姓名
|
|
444
|
+
{ pattern: '^1[3-9]\\d{9}$' }, // 手机号
|
|
445
|
+
{ pattern: '^\\d{6}$' }, // 邮政编码
|
|
446
|
+
{ pattern: '^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]' }, // 车牌号开头
|
|
447
|
+
];
|
|
448
|
+
regexCache.precompile(commonPatterns);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* 清空所有缓存
|
|
452
|
+
*/
|
|
453
|
+
function clearAllCaches() {
|
|
454
|
+
validationCache.clear();
|
|
455
|
+
regexCache.clear();
|
|
456
|
+
performanceMonitor.clear();
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* 配置缓存设置
|
|
460
|
+
*/
|
|
461
|
+
function configureCaches(options) {
|
|
462
|
+
if (options.validation) {
|
|
463
|
+
// 重新创建验证缓存实例
|
|
464
|
+
ValidationCache.instance = new ValidationCache(options.validation);
|
|
465
|
+
}
|
|
466
|
+
if (options.regex) {
|
|
467
|
+
// 重新创建正则缓存实例
|
|
468
|
+
RegexCache.instance = new RegexCache(options.regex);
|
|
469
|
+
}
|
|
1439
470
|
}
|
|
1440
|
-
|
|
1441
|
-
require_Reflect();
|
|
1442
471
|
|
|
1443
472
|
/**
|
|
1444
473
|
* @ author: richen
|
|
@@ -1573,10 +602,18 @@ function convertParamsType(param, type) {
|
|
|
1573
602
|
return NaN;
|
|
1574
603
|
}
|
|
1575
604
|
if (helper__namespace.isNumber(param)) {
|
|
605
|
+
// Check for safe integer range
|
|
606
|
+
if (Number.isInteger(param) && !Number.isSafeInteger(param)) {
|
|
607
|
+
console.warn(`[koatty_validation] Number ${param} exceeds safe integer range`);
|
|
608
|
+
}
|
|
1576
609
|
return param;
|
|
1577
610
|
}
|
|
1578
611
|
if (helper__namespace.isNumberString(param)) {
|
|
1579
|
-
|
|
612
|
+
const num = helper__namespace.toNumber(param);
|
|
613
|
+
if (Number.isInteger(num) && !Number.isSafeInteger(num)) {
|
|
614
|
+
console.warn(`[koatty_validation] Number ${param} exceeds safe integer range`);
|
|
615
|
+
}
|
|
616
|
+
return num;
|
|
1580
617
|
}
|
|
1581
618
|
return NaN;
|
|
1582
619
|
case "Boolean":
|
|
@@ -1613,9 +650,10 @@ function convertParamsType(param, type) {
|
|
|
1613
650
|
default: //any
|
|
1614
651
|
return param;
|
|
1615
652
|
}
|
|
1616
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1617
653
|
}
|
|
1618
|
-
catch (
|
|
654
|
+
catch (error) {
|
|
655
|
+
// Log conversion errors for debugging
|
|
656
|
+
console.warn(`[koatty_validation] Type conversion error for type "${type}":`, error instanceof Error ? error.message : String(error));
|
|
1619
657
|
return param;
|
|
1620
658
|
}
|
|
1621
659
|
}
|
|
@@ -1691,7 +729,12 @@ function checkParamsType(value, type) {
|
|
|
1691
729
|
* @returns {boolean}
|
|
1692
730
|
*/
|
|
1693
731
|
function cnName(value) {
|
|
1694
|
-
|
|
732
|
+
// Add length limit for security
|
|
733
|
+
if (value.length > 50) {
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
// Use regex cache for better performance
|
|
737
|
+
const reg = regexCache.get('^([a-zA-Z0-9\\u4e00-\\u9fa5\\·]{1,10})$');
|
|
1695
738
|
return reg.test(value);
|
|
1696
739
|
}
|
|
1697
740
|
/**
|
|
@@ -1701,10 +744,18 @@ function cnName(value) {
|
|
|
1701
744
|
* @returns
|
|
1702
745
|
*/
|
|
1703
746
|
function idNumber(value) {
|
|
1704
|
-
|
|
747
|
+
// Add length limit for security
|
|
748
|
+
if (!value || value.length > 20) {
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
// Check 15-digit ID
|
|
752
|
+
const reg15 = regexCache.get('^\\d{15}$');
|
|
753
|
+
if (reg15.test(value)) {
|
|
1705
754
|
return true;
|
|
1706
755
|
}
|
|
1707
|
-
|
|
756
|
+
// Check 18-digit ID with validation
|
|
757
|
+
const reg18 = regexCache.get('^\\d{17}[0-9X]$');
|
|
758
|
+
if (reg18.test(value)) {
|
|
1708
759
|
const vs = '1,0,x,9,8,7,6,5,4,3,2'.split(',');
|
|
1709
760
|
const ps = '7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2'.split(',');
|
|
1710
761
|
const ss = value.toLowerCase().split('');
|
|
@@ -1724,7 +775,11 @@ function idNumber(value) {
|
|
|
1724
775
|
* @returns {boolean}
|
|
1725
776
|
*/
|
|
1726
777
|
function mobile(value) {
|
|
1727
|
-
|
|
778
|
+
// Add length limit for security (prevent ReDoS)
|
|
779
|
+
if (!value || value.length > 20) {
|
|
780
|
+
return false;
|
|
781
|
+
}
|
|
782
|
+
const reg = regexCache.get('^(13|14|15|16|17|18|19)\\d{9}$');
|
|
1728
783
|
return reg.test(value);
|
|
1729
784
|
}
|
|
1730
785
|
/**
|
|
@@ -1734,7 +789,11 @@ function mobile(value) {
|
|
|
1734
789
|
* @returns {boolean}
|
|
1735
790
|
*/
|
|
1736
791
|
function zipCode(value) {
|
|
1737
|
-
|
|
792
|
+
// Add length limit for security
|
|
793
|
+
if (!value || value.length > 10) {
|
|
794
|
+
return false;
|
|
795
|
+
}
|
|
796
|
+
const reg = regexCache.get('^\\d{6}$');
|
|
1738
797
|
return reg.test(value);
|
|
1739
798
|
}
|
|
1740
799
|
/**
|
|
@@ -1744,16 +803,19 @@ function zipCode(value) {
|
|
|
1744
803
|
* @returns {boolean}
|
|
1745
804
|
*/
|
|
1746
805
|
function plateNumber(value) {
|
|
1747
|
-
//
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
806
|
+
// Add length limit for security
|
|
807
|
+
if (!value || value.length > 15) {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
// New energy vehicle plate number (8 characters)
|
|
811
|
+
const xReg = regexCache.get('^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))');
|
|
812
|
+
// Traditional vehicle plate number (7 characters)
|
|
813
|
+
const cReg = regexCache.get('^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$');
|
|
1752
814
|
if (value.length === 7) {
|
|
1753
815
|
return cReg.test(value);
|
|
1754
816
|
}
|
|
1755
817
|
else {
|
|
1756
|
-
|
|
818
|
+
// New energy vehicle plate
|
|
1757
819
|
return xReg.test(value);
|
|
1758
820
|
}
|
|
1759
821
|
}
|
|
@@ -1763,10 +825,9 @@ function plateNumber(value) {
|
|
|
1763
825
|
* @Usage:
|
|
1764
826
|
* @Author: richen
|
|
1765
827
|
* @Date: 2021-11-25 10:47:04
|
|
1766
|
-
* @LastEditTime: 2024-
|
|
828
|
+
* @LastEditTime: 2024-01-03 14:32:49
|
|
1767
829
|
*/
|
|
1768
830
|
// constant
|
|
1769
|
-
const PARAM_TYPE_KEY = 'PARAM_TYPE_KEY';
|
|
1770
831
|
const PARAM_RULE_KEY = 'PARAM_RULE_KEY';
|
|
1771
832
|
const PARAM_CHECK_KEY = 'PARAM_CHECK_KEY';
|
|
1772
833
|
const ENABLE_VALIDATED = "ENABLE_VALIDATED";
|
|
@@ -1800,7 +861,6 @@ exports.paramterTypes = void 0;
|
|
|
1800
861
|
paramterTypes[paramterTypes["undefined"] = 19] = "undefined";
|
|
1801
862
|
})(exports.paramterTypes || (exports.paramterTypes = {}));
|
|
1802
863
|
class ValidateClass {
|
|
1803
|
-
static instance;
|
|
1804
864
|
constructor() {
|
|
1805
865
|
}
|
|
1806
866
|
/**
|
|
@@ -1823,10 +883,20 @@ class ValidateClass {
|
|
|
1823
883
|
* @memberof ValidateClass
|
|
1824
884
|
*/
|
|
1825
885
|
async valid(Clazz, data, convert = false) {
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
886
|
+
let obj = {};
|
|
887
|
+
if (data instanceof Clazz) {
|
|
888
|
+
obj = data;
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
obj = plainToClass(Clazz, data, convert);
|
|
892
|
+
}
|
|
893
|
+
let errors = [];
|
|
894
|
+
if (convert) {
|
|
895
|
+
errors = await classValidator.validate(obj);
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
errors = await classValidator.validate(obj, { skipMissingProperties: true });
|
|
899
|
+
}
|
|
1830
900
|
if (errors.length > 0) {
|
|
1831
901
|
throw new Error(Object.values(errors[0].constraints)[0]);
|
|
1832
902
|
}
|
|
@@ -1837,6 +907,23 @@ class ValidateClass {
|
|
|
1837
907
|
* ClassValidator for manual
|
|
1838
908
|
*/
|
|
1839
909
|
const ClassValidator = ValidateClass.getInstance();
|
|
910
|
+
/**
|
|
911
|
+
* Helper function to wrap validation with cache
|
|
912
|
+
*/
|
|
913
|
+
function withCache(validatorName, validatorFunc) {
|
|
914
|
+
return (value, ...args) => {
|
|
915
|
+
// Check cache first
|
|
916
|
+
const cached = validationCache.get(validatorName, value, ...args);
|
|
917
|
+
if (cached !== undefined) {
|
|
918
|
+
return cached;
|
|
919
|
+
}
|
|
920
|
+
// Execute validation
|
|
921
|
+
const result = validatorFunc(value, ...args);
|
|
922
|
+
// Cache the result
|
|
923
|
+
validationCache.set(validatorName, value, result, ...args);
|
|
924
|
+
return result;
|
|
925
|
+
};
|
|
926
|
+
}
|
|
1840
927
|
/**
|
|
1841
928
|
* Validator Functions
|
|
1842
929
|
*/
|
|
@@ -1845,27 +932,27 @@ const ValidFuncs = {
|
|
|
1845
932
|
* Checks value is not empty, undefined, null, '', NaN, [], {} and any empty string(including spaces,
|
|
1846
933
|
* tabs, formfeeds, etc.), returns false
|
|
1847
934
|
*/
|
|
1848
|
-
IsNotEmpty: (value) => {
|
|
935
|
+
IsNotEmpty: withCache('IsNotEmpty', (value) => {
|
|
1849
936
|
return !helper__namespace.isEmpty(value);
|
|
1850
|
-
},
|
|
937
|
+
}),
|
|
1851
938
|
/**
|
|
1852
939
|
* Checks if a given value is a real date.
|
|
1853
940
|
*/
|
|
1854
|
-
IsDate: (value) => {
|
|
941
|
+
IsDate: withCache('IsDate', (value) => {
|
|
1855
942
|
return helper__namespace.isDate(value);
|
|
1856
|
-
},
|
|
943
|
+
}),
|
|
1857
944
|
/**
|
|
1858
945
|
* Checks if the string is an email. If given value is not a string, then it returns false.
|
|
1859
946
|
*/
|
|
1860
|
-
IsEmail: (value, options) => {
|
|
947
|
+
IsEmail: withCache('IsEmail', (value, options) => {
|
|
1861
948
|
return classValidator.isEmail(value, options);
|
|
1862
|
-
},
|
|
949
|
+
}),
|
|
1863
950
|
/**
|
|
1864
951
|
* Checks if the string is an IP (version 4 or 6). If given value is not a string, then it returns false.
|
|
1865
952
|
*/
|
|
1866
|
-
IsIP: (value, version) => {
|
|
953
|
+
IsIP: withCache('IsIP', (value, version) => {
|
|
1867
954
|
return classValidator.isIP(value, version);
|
|
1868
|
-
},
|
|
955
|
+
}),
|
|
1869
956
|
/**
|
|
1870
957
|
* Checks if the string is a valid phone number.
|
|
1871
958
|
* @param value — the potential phone number string to test
|
|
@@ -1874,875 +961,576 @@ const ValidFuncs = {
|
|
|
1874
961
|
* See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]
|
|
1875
962
|
* {@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33}
|
|
1876
963
|
*/
|
|
1877
|
-
IsPhoneNumber: (value, region) => {
|
|
964
|
+
IsPhoneNumber: withCache('IsPhoneNumber', (value, region) => {
|
|
1878
965
|
return classValidator.isPhoneNumber(value, region);
|
|
1879
|
-
},
|
|
966
|
+
}),
|
|
1880
967
|
/**
|
|
1881
968
|
* Checks if the string is an url. If given value is not a string, then it returns false.
|
|
1882
969
|
*/
|
|
1883
|
-
IsUrl: (value, options) => {
|
|
970
|
+
IsUrl: withCache('IsUrl', (value, options) => {
|
|
1884
971
|
return classValidator.isURL(value, options);
|
|
1885
|
-
},
|
|
972
|
+
}),
|
|
1886
973
|
/**
|
|
1887
974
|
* check if the string is a hash of type algorithm. Algorithm is one of
|
|
1888
975
|
* ['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']
|
|
1889
976
|
*/
|
|
1890
|
-
IsHash: (value, algorithm) => {
|
|
977
|
+
IsHash: withCache('IsHash', (value, algorithm) => {
|
|
1891
978
|
return classValidator.isHash(value, algorithm);
|
|
1892
|
-
},
|
|
979
|
+
}),
|
|
1893
980
|
/**
|
|
1894
981
|
* Checks if value is a chinese name.
|
|
1895
982
|
*/
|
|
1896
|
-
IsCnName: (value) => {
|
|
983
|
+
IsCnName: withCache('IsCnName', (value) => {
|
|
1897
984
|
if (!helper__namespace.isString(value)) {
|
|
1898
985
|
return false;
|
|
1899
986
|
}
|
|
1900
987
|
return cnName(value);
|
|
1901
|
-
},
|
|
988
|
+
}),
|
|
1902
989
|
/**
|
|
1903
990
|
* Checks if value is a idcard number.
|
|
1904
991
|
*/
|
|
1905
|
-
IsIdNumber: (value) => {
|
|
992
|
+
IsIdNumber: withCache('IsIdNumber', (value) => {
|
|
1906
993
|
if (!helper__namespace.isString(value)) {
|
|
1907
994
|
return false;
|
|
1908
995
|
}
|
|
1909
996
|
return idNumber(value);
|
|
1910
|
-
},
|
|
997
|
+
}),
|
|
1911
998
|
/**
|
|
1912
999
|
* Checks if value is a zipCode.
|
|
1913
1000
|
*/
|
|
1914
|
-
IsZipCode: (value) => {
|
|
1001
|
+
IsZipCode: withCache('IsZipCode', (value) => {
|
|
1915
1002
|
if (!helper__namespace.isString(value)) {
|
|
1916
1003
|
return false;
|
|
1917
1004
|
}
|
|
1918
1005
|
return zipCode(value);
|
|
1919
|
-
},
|
|
1006
|
+
}),
|
|
1920
1007
|
/**
|
|
1921
1008
|
* Checks if value is a mobile phone number.
|
|
1922
1009
|
*/
|
|
1923
|
-
IsMobile: (value) => {
|
|
1010
|
+
IsMobile: withCache('IsMobile', (value) => {
|
|
1924
1011
|
if (!helper__namespace.isString(value)) {
|
|
1925
1012
|
return false;
|
|
1926
1013
|
}
|
|
1927
1014
|
return mobile(value);
|
|
1928
|
-
},
|
|
1015
|
+
}),
|
|
1929
1016
|
/**
|
|
1930
1017
|
* Checks if value is a plateNumber.
|
|
1931
1018
|
*/
|
|
1932
|
-
IsPlateNumber: (value) => {
|
|
1019
|
+
IsPlateNumber: withCache('IsPlateNumber', (value) => {
|
|
1933
1020
|
if (!helper__namespace.isString(value)) {
|
|
1934
1021
|
return false;
|
|
1935
1022
|
}
|
|
1936
1023
|
return plateNumber(value);
|
|
1937
|
-
},
|
|
1024
|
+
}),
|
|
1938
1025
|
/**
|
|
1939
1026
|
* Checks if value matches ("===") the comparison.
|
|
1940
1027
|
*/
|
|
1941
|
-
Equals: (value, comparison) => {
|
|
1028
|
+
Equals: withCache('Equals', (value, comparison) => {
|
|
1942
1029
|
return classValidator.equals(value, comparison);
|
|
1943
|
-
},
|
|
1030
|
+
}),
|
|
1944
1031
|
/**
|
|
1945
1032
|
* Checks if value does not match ("!==") the comparison.
|
|
1946
1033
|
*/
|
|
1947
|
-
NotEquals: (value, comparison) => {
|
|
1034
|
+
NotEquals: withCache('NotEquals', (value, comparison) => {
|
|
1948
1035
|
return classValidator.notEquals(value, comparison);
|
|
1949
|
-
},
|
|
1036
|
+
}),
|
|
1950
1037
|
/**
|
|
1951
1038
|
* Checks if the string contains the seed. If given value is not a string, then it returns false.
|
|
1952
1039
|
*/
|
|
1953
|
-
Contains: (value, seed) => {
|
|
1040
|
+
Contains: withCache('Contains', (value, seed) => {
|
|
1954
1041
|
return classValidator.contains(value, seed);
|
|
1955
|
-
},
|
|
1042
|
+
}),
|
|
1956
1043
|
/**
|
|
1957
1044
|
* Checks if given value is in a array of allowed values.
|
|
1958
1045
|
*/
|
|
1959
|
-
IsIn: (value, possibleValues) => {
|
|
1046
|
+
IsIn: withCache('IsIn', (value, possibleValues) => {
|
|
1960
1047
|
return classValidator.isIn(value, possibleValues);
|
|
1961
|
-
},
|
|
1048
|
+
}),
|
|
1962
1049
|
/**
|
|
1963
1050
|
* Checks if given value not in a array of allowed values.
|
|
1964
1051
|
*/
|
|
1965
|
-
IsNotIn: (value, possibleValues) => {
|
|
1052
|
+
IsNotIn: withCache('IsNotIn', (value, possibleValues) => {
|
|
1966
1053
|
return classValidator.isNotIn(value, possibleValues);
|
|
1967
|
-
},
|
|
1054
|
+
}),
|
|
1968
1055
|
/**
|
|
1969
1056
|
* Checks if the first number is greater than or equal to the second.
|
|
1970
1057
|
*/
|
|
1971
|
-
Gt: (num, min) => {
|
|
1058
|
+
Gt: withCache('Gt', (num, min) => {
|
|
1972
1059
|
return helper__namespace.toNumber(num) > min;
|
|
1973
|
-
},
|
|
1060
|
+
}),
|
|
1974
1061
|
/**
|
|
1975
1062
|
* Checks if the first number is less than or equal to the second.
|
|
1976
1063
|
*/
|
|
1977
|
-
Lt: (num, max) => {
|
|
1064
|
+
Lt: withCache('Lt', (num, max) => {
|
|
1978
1065
|
return helper__namespace.toNumber(num) < max;
|
|
1979
|
-
},
|
|
1066
|
+
}),
|
|
1980
1067
|
/**
|
|
1981
1068
|
* Checks if the first number is greater than or equal to the second.
|
|
1982
1069
|
*/
|
|
1983
|
-
Gte: (num, min) => {
|
|
1070
|
+
Gte: withCache('Gte', (num, min) => {
|
|
1984
1071
|
return helper__namespace.toNumber(num) >= min;
|
|
1985
|
-
},
|
|
1072
|
+
}),
|
|
1986
1073
|
/**
|
|
1987
1074
|
* Checks if the first number is less than or equal to the second.
|
|
1988
1075
|
*/
|
|
1989
|
-
Lte: (num, max) => {
|
|
1076
|
+
Lte: withCache('Lte', (num, max) => {
|
|
1990
1077
|
return helper__namespace.toNumber(num) <= max;
|
|
1991
|
-
},
|
|
1078
|
+
}),
|
|
1992
1079
|
};
|
|
1993
1080
|
/**
|
|
1994
|
-
*
|
|
1995
|
-
*
|
|
1996
|
-
* @export
|
|
1997
|
-
* @param {ValidRules} rule
|
|
1998
|
-
* @param {unknown} value
|
|
1999
|
-
* @param {(string | ValidOtpions)} [options]
|
|
2000
|
-
* @returns {*}
|
|
1081
|
+
* Helper function to create validator function
|
|
2001
1082
|
*/
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
if (
|
|
2006
|
-
|
|
2007
|
-
}
|
|
2008
|
-
if (!ValidFuncs[key](value, options.value)) {
|
|
2009
|
-
throw new Error(options.message || `ValidatorError: invalid arguments.`);
|
|
1083
|
+
function createValidatorFunction(validatorFunc, defaultMessage) {
|
|
1084
|
+
return (value, options) => {
|
|
1085
|
+
let validOptions;
|
|
1086
|
+
if (typeof options === 'string') {
|
|
1087
|
+
validOptions = { message: options, value: null };
|
|
2010
1088
|
}
|
|
2011
|
-
|
|
2012
|
-
}
|
|
2013
|
-
|
|
2014
|
-
/*
|
|
2015
|
-
* @Description:
|
|
2016
|
-
* @Usage:
|
|
2017
|
-
* @Author: richen
|
|
2018
|
-
* @Date: 2021-11-25 10:46:57
|
|
2019
|
-
* @LastEditTime: 2024-10-31 16:49:26
|
|
2020
|
-
*/
|
|
2021
|
-
/**
|
|
2022
|
-
* Validation parameter's type and values.
|
|
2023
|
-
*
|
|
2024
|
-
* @export
|
|
2025
|
-
* @param {(ValidRules | ValidRules[] | Function)} rule
|
|
2026
|
-
* @param {*} [options] If the options type is a string, the value is the error message of the validation rule.
|
|
2027
|
-
* Some validation rules require additional parameters, ext: @Valid("Gte", {message:"Requires value greater than or equal to 100", value: 100})
|
|
2028
|
-
* @returns {*} {ParameterDecorator}
|
|
2029
|
-
*/
|
|
2030
|
-
function Valid(rule, options) {
|
|
2031
|
-
let rules = [];
|
|
2032
|
-
if (helper__namespace.isString(rule)) {
|
|
2033
|
-
rules = rule.split(",");
|
|
2034
|
-
}
|
|
2035
|
-
else {
|
|
2036
|
-
rules = rule;
|
|
2037
|
-
}
|
|
2038
|
-
return (target, propertyKey, descriptor) => {
|
|
2039
|
-
// 获取成员参数类型
|
|
2040
|
-
const paramTypes = Reflect.getMetadata("design:paramtypes", target, propertyKey);
|
|
2041
|
-
const type = (paramTypes[descriptor]?.name) ? paramTypes[descriptor].name : 'object';
|
|
2042
|
-
if (helper__namespace.isString(options)) {
|
|
2043
|
-
options = { message: options, value: null };
|
|
1089
|
+
else {
|
|
1090
|
+
validOptions = options || { message: defaultMessage, value: null };
|
|
2044
1091
|
}
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
}, target, propertyKey);
|
|
2052
|
-
};
|
|
2053
|
-
}
|
|
2054
|
-
/**
|
|
2055
|
-
* Validation parameter's type and values from DTO class.
|
|
2056
|
-
*
|
|
2057
|
-
* @export
|
|
2058
|
-
* @returns {MethodDecorator}
|
|
2059
|
-
*/
|
|
2060
|
-
function Validated() {
|
|
2061
|
-
return (target, propertyKey, _descriptor) => {
|
|
2062
|
-
//
|
|
2063
|
-
koatty_container.IOCContainer.savePropertyData(PARAM_CHECK_KEY, {
|
|
2064
|
-
dtoCheck: 1
|
|
2065
|
-
}, target, propertyKey);
|
|
2066
|
-
// 获取成员参数类型
|
|
2067
|
-
// const paramTypes = Reflect.getMetadata("design:paramtypes", target, propertyKey) || [];
|
|
2068
|
-
// const { value, configurable, enumerable } = descriptor;
|
|
2069
|
-
// descriptor = {
|
|
2070
|
-
// configurable,
|
|
2071
|
-
// enumerable,
|
|
2072
|
-
// writable: true,
|
|
2073
|
-
// value: async function valid(...props: any[]) {
|
|
2074
|
-
// const ps: any[] = [];
|
|
2075
|
-
// // tslint:disable-next-line: no-unused-expression
|
|
2076
|
-
// (props || []).map((value: any, index: number) => {
|
|
2077
|
-
// const type = (paramTypes[index] && paramTypes[index].name) ? paramTypes[index].name : "any";
|
|
2078
|
-
// if (!paramterTypes[type]) {
|
|
2079
|
-
// ps.push(ClassValidator.valid(paramTypes[index], value, true));
|
|
2080
|
-
// } else {
|
|
2081
|
-
// ps.push(Promise.resolve(value));
|
|
2082
|
-
// }
|
|
2083
|
-
// });
|
|
2084
|
-
// if (ps.length > 0) {
|
|
2085
|
-
// props = await Promise.all(ps);
|
|
2086
|
-
// }
|
|
2087
|
-
// // tslint:disable-next-line: no-invalid-this
|
|
2088
|
-
// return value.apply(this, props);
|
|
2089
|
-
// }
|
|
2090
|
-
// };
|
|
2091
|
-
// return descriptor;
|
|
2092
|
-
};
|
|
2093
|
-
}
|
|
2094
|
-
/**
|
|
2095
|
-
* Marks property as included in the process of transformation.
|
|
2096
|
-
*
|
|
2097
|
-
* @export
|
|
2098
|
-
* @returns {PropertyDecorator}
|
|
2099
|
-
*/
|
|
2100
|
-
function Expose() {
|
|
2101
|
-
return function (object, propertyName) {
|
|
2102
|
-
setExpose(object, propertyName);
|
|
2103
|
-
};
|
|
2104
|
-
}
|
|
2105
|
-
/**
|
|
2106
|
-
* Alias of Expose
|
|
2107
|
-
*
|
|
2108
|
-
* @export
|
|
2109
|
-
* @returns {PropertyDecorator}
|
|
2110
|
-
*/
|
|
2111
|
-
function IsDefined() {
|
|
2112
|
-
return function (object, propertyName) {
|
|
2113
|
-
setExpose(object, propertyName);
|
|
2114
|
-
};
|
|
2115
|
-
}
|
|
2116
|
-
/**
|
|
2117
|
-
* Checks if value is a chinese name.
|
|
2118
|
-
*
|
|
2119
|
-
* @export
|
|
2120
|
-
* @param {string} property
|
|
2121
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2122
|
-
* @returns {PropertyDecorator}
|
|
2123
|
-
*/
|
|
2124
|
-
function IsCnName(validationOptions) {
|
|
2125
|
-
return function (object, propertyName) {
|
|
2126
|
-
setExpose(object, propertyName);
|
|
2127
|
-
classValidator.registerDecorator({
|
|
2128
|
-
name: "IsCnName",
|
|
2129
|
-
target: object.constructor,
|
|
2130
|
-
propertyName,
|
|
2131
|
-
options: validationOptions,
|
|
2132
|
-
validator: {
|
|
2133
|
-
validate(value, _args) {
|
|
2134
|
-
return cnName(value);
|
|
2135
|
-
},
|
|
2136
|
-
defaultMessage(_args) {
|
|
2137
|
-
return "invalid parameter ($property).";
|
|
2138
|
-
}
|
|
1092
|
+
if (!validatorFunc(value, validOptions.value)) {
|
|
1093
|
+
// Priority: validOptions.message -> defaultMessage -> fallback error
|
|
1094
|
+
let errorMessage = validOptions.message;
|
|
1095
|
+
// If message is empty or whitespace, use defaultMessage
|
|
1096
|
+
if (!errorMessage || !errorMessage.trim()) {
|
|
1097
|
+
errorMessage = defaultMessage;
|
|
2139
1098
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
/**
|
|
2144
|
-
* Checks if value is a idCard number(chinese).
|
|
2145
|
-
*
|
|
2146
|
-
* @export
|
|
2147
|
-
* @param {string} property
|
|
2148
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2149
|
-
* @returns {PropertyDecorator}
|
|
2150
|
-
*/
|
|
2151
|
-
function IsIdNumber(validationOptions) {
|
|
2152
|
-
return function (object, propertyName) {
|
|
2153
|
-
setExpose(object, propertyName);
|
|
2154
|
-
classValidator.registerDecorator({
|
|
2155
|
-
name: "IsIdNumber",
|
|
2156
|
-
target: object.constructor,
|
|
2157
|
-
propertyName,
|
|
2158
|
-
options: validationOptions,
|
|
2159
|
-
validator: {
|
|
2160
|
-
validate(value, _args) {
|
|
2161
|
-
return idNumber(value);
|
|
2162
|
-
},
|
|
2163
|
-
defaultMessage(_args) {
|
|
2164
|
-
return "invalid parameter ($property).";
|
|
2165
|
-
}
|
|
1099
|
+
// If defaultMessage is also empty, use fallback
|
|
1100
|
+
if (!errorMessage || !errorMessage.trim()) {
|
|
1101
|
+
errorMessage = 'ValidatorError: invalid arguments.';
|
|
2166
1102
|
}
|
|
2167
|
-
|
|
1103
|
+
throw new Error(errorMessage);
|
|
1104
|
+
}
|
|
2168
1105
|
};
|
|
2169
1106
|
}
|
|
2170
1107
|
/**
|
|
2171
|
-
*
|
|
1108
|
+
* Use functions or built-in rules for validation.
|
|
1109
|
+
* Throws error if validation fails.
|
|
2172
1110
|
*
|
|
2173
1111
|
* @export
|
|
2174
|
-
* @param {string} property
|
|
2175
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2176
|
-
* @returns {PropertyDecorator}
|
|
2177
1112
|
*/
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
1113
|
+
const FunctionValidator = {
|
|
1114
|
+
IsNotEmpty: createValidatorFunction(ValidFuncs.IsNotEmpty, 'Value should not be empty'),
|
|
1115
|
+
IsDate: createValidatorFunction(ValidFuncs.IsDate, 'Must be a valid date'),
|
|
1116
|
+
IsEmail: createValidatorFunction(ValidFuncs.IsEmail, 'Must be a valid email'),
|
|
1117
|
+
IsIP: createValidatorFunction(ValidFuncs.IsIP, 'Must be a valid IP address'),
|
|
1118
|
+
IsPhoneNumber: createValidatorFunction(ValidFuncs.IsPhoneNumber, 'Must be a valid phone number'),
|
|
1119
|
+
IsUrl: createValidatorFunction(ValidFuncs.IsUrl, 'Must be a valid URL'),
|
|
1120
|
+
IsHash: createValidatorFunction(ValidFuncs.IsHash, 'Must be a valid hash'),
|
|
1121
|
+
IsCnName: createValidatorFunction(ValidFuncs.IsCnName, 'Must be a valid Chinese name'),
|
|
1122
|
+
IsIdNumber: createValidatorFunction(ValidFuncs.IsIdNumber, 'Must be a valid ID number'),
|
|
1123
|
+
IsZipCode: createValidatorFunction(ValidFuncs.IsZipCode, 'Must be a valid zip code'),
|
|
1124
|
+
IsMobile: createValidatorFunction(ValidFuncs.IsMobile, 'Must be a valid mobile number'),
|
|
1125
|
+
IsPlateNumber: createValidatorFunction(ValidFuncs.IsPlateNumber, 'Must be a valid plate number'),
|
|
1126
|
+
Equals: createValidatorFunction(ValidFuncs.Equals, 'Values must be equal'),
|
|
1127
|
+
NotEquals: createValidatorFunction(ValidFuncs.NotEquals, 'Values must not be equal'),
|
|
1128
|
+
Contains: createValidatorFunction(ValidFuncs.Contains, 'Value must contain specified substring'),
|
|
1129
|
+
IsIn: createValidatorFunction(ValidFuncs.IsIn, 'Value must be in the allowed list'),
|
|
1130
|
+
IsNotIn: createValidatorFunction(ValidFuncs.IsNotIn, 'Value must not be in the forbidden list'),
|
|
1131
|
+
Gt: createValidatorFunction(ValidFuncs.Gt, 'Value must be greater than threshold'),
|
|
1132
|
+
Lt: createValidatorFunction(ValidFuncs.Lt, 'Value must be less than threshold'),
|
|
1133
|
+
Gte: createValidatorFunction(ValidFuncs.Gte, 'Value must be greater than or equal to threshold'),
|
|
1134
|
+
Lte: createValidatorFunction(ValidFuncs.Lte, 'Value must be less than or equal to threshold'),
|
|
1135
|
+
};
|
|
1136
|
+
|
|
2197
1137
|
/**
|
|
2198
|
-
*
|
|
2199
|
-
*
|
|
2200
|
-
* @export
|
|
2201
|
-
* @param {string} property
|
|
2202
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2203
|
-
* @returns {PropertyDecorator}
|
|
1138
|
+
* 装饰器工厂 - 消除装饰器代码重复
|
|
1139
|
+
* @author richen
|
|
2204
1140
|
*/
|
|
2205
|
-
function IsMobile(validationOptions) {
|
|
2206
|
-
return function (object, propertyName) {
|
|
2207
|
-
setExpose(object, propertyName);
|
|
2208
|
-
classValidator.registerDecorator({
|
|
2209
|
-
name: "IsMobile",
|
|
2210
|
-
target: object.constructor,
|
|
2211
|
-
propertyName,
|
|
2212
|
-
options: validationOptions,
|
|
2213
|
-
validator: {
|
|
2214
|
-
validate(value, _args) {
|
|
2215
|
-
return mobile(value);
|
|
2216
|
-
},
|
|
2217
|
-
defaultMessage(_args) {
|
|
2218
|
-
return "invalid parameter ($property).";
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
});
|
|
2222
|
-
};
|
|
2223
|
-
}
|
|
2224
1141
|
/**
|
|
2225
|
-
*
|
|
2226
|
-
*
|
|
2227
|
-
* @
|
|
2228
|
-
* @param {string} property
|
|
2229
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2230
|
-
* @returns {PropertyDecorator}
|
|
1142
|
+
* 创建验证装饰器的工厂函数
|
|
1143
|
+
* @param options 装饰器配置选项
|
|
1144
|
+
* @returns 装饰器工厂函数
|
|
2231
1145
|
*/
|
|
2232
|
-
function
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
1146
|
+
function createValidationDecorator(options) {
|
|
1147
|
+
const { name, validator, defaultMessage, requiresValue = false } = options;
|
|
1148
|
+
return function decoratorFactory(...args) {
|
|
1149
|
+
// 处理参数:最后一个参数是ValidationOptions,前面是验证函数的参数
|
|
1150
|
+
const validationOptions = args[args.length - 1];
|
|
1151
|
+
const validatorArgs = requiresValue ? args.slice(0, -1) : [];
|
|
1152
|
+
return function propertyDecorator(object, propertyName) {
|
|
1153
|
+
// 设置属性为可导出
|
|
1154
|
+
setExpose(object, propertyName);
|
|
1155
|
+
// 注册验证装饰器
|
|
1156
|
+
classValidator.registerDecorator({
|
|
1157
|
+
name,
|
|
1158
|
+
target: object.constructor,
|
|
1159
|
+
propertyName,
|
|
1160
|
+
options: validationOptions,
|
|
1161
|
+
constraints: validatorArgs,
|
|
1162
|
+
validator: {
|
|
1163
|
+
validate(value) {
|
|
1164
|
+
try {
|
|
1165
|
+
return validator(value, ...validatorArgs);
|
|
1166
|
+
}
|
|
1167
|
+
catch {
|
|
1168
|
+
return false;
|
|
1169
|
+
}
|
|
1170
|
+
},
|
|
1171
|
+
defaultMessage(validationArguments) {
|
|
1172
|
+
const property = validationArguments.property;
|
|
1173
|
+
return defaultMessage
|
|
1174
|
+
? defaultMessage.replace('$property', property)
|
|
1175
|
+
: `Invalid value for ${property}`;
|
|
1176
|
+
}
|
|
2246
1177
|
}
|
|
2247
|
-
}
|
|
2248
|
-
}
|
|
1178
|
+
});
|
|
1179
|
+
};
|
|
2249
1180
|
};
|
|
2250
1181
|
}
|
|
2251
1182
|
/**
|
|
2252
|
-
*
|
|
2253
|
-
*
|
|
2254
|
-
* @
|
|
2255
|
-
* @param
|
|
2256
|
-
* @returns
|
|
1183
|
+
* 创建简单验证装饰器(不需要额外参数)
|
|
1184
|
+
* @param name 装饰器名称
|
|
1185
|
+
* @param validator 验证函数
|
|
1186
|
+
* @param defaultMessage 默认错误信息
|
|
1187
|
+
* @returns 装饰器函数
|
|
2257
1188
|
*/
|
|
2258
|
-
function
|
|
2259
|
-
return
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
options: validationOptions,
|
|
2266
|
-
validator: {
|
|
2267
|
-
validate(value, _args) {
|
|
2268
|
-
return !helper__namespace.isEmpty(value);
|
|
2269
|
-
},
|
|
2270
|
-
defaultMessage(_args) {
|
|
2271
|
-
return "invalid parameter ($property).";
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
});
|
|
2275
|
-
};
|
|
2276
|
-
}
|
|
2277
|
-
/**
|
|
2278
|
-
* Checks if value matches ("===") the comparison.
|
|
2279
|
-
*
|
|
2280
|
-
* @export
|
|
2281
|
-
* @param {*} comparison
|
|
2282
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2283
|
-
* @returns {PropertyDecorator}
|
|
2284
|
-
*/
|
|
2285
|
-
function Equals(comparison, validationOptions) {
|
|
2286
|
-
return function (object, propertyName) {
|
|
2287
|
-
setExpose(object, propertyName);
|
|
2288
|
-
classValidator.registerDecorator({
|
|
2289
|
-
name: "vEquals",
|
|
2290
|
-
target: object.constructor,
|
|
2291
|
-
propertyName,
|
|
2292
|
-
options: validationOptions,
|
|
2293
|
-
validator: {
|
|
2294
|
-
validate(value, _args) {
|
|
2295
|
-
return classValidator.equals(value, comparison);
|
|
2296
|
-
},
|
|
2297
|
-
defaultMessage(_args) {
|
|
2298
|
-
return `invalid parameter, ($property) must be equals ${comparison}.`;
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
});
|
|
2302
|
-
};
|
|
1189
|
+
function createSimpleDecorator(name, validator, defaultMessage) {
|
|
1190
|
+
return createValidationDecorator({
|
|
1191
|
+
name,
|
|
1192
|
+
validator,
|
|
1193
|
+
defaultMessage,
|
|
1194
|
+
requiresValue: false
|
|
1195
|
+
});
|
|
2303
1196
|
}
|
|
2304
1197
|
/**
|
|
2305
|
-
*
|
|
2306
|
-
*
|
|
2307
|
-
* @
|
|
2308
|
-
* @param
|
|
2309
|
-
* @
|
|
2310
|
-
* @returns {PropertyDecorator}
|
|
1198
|
+
* 创建带参数的验证装饰器
|
|
1199
|
+
* @param name 装饰器名称
|
|
1200
|
+
* @param validator 验证函数
|
|
1201
|
+
* @param defaultMessage 默认错误信息
|
|
1202
|
+
* @returns 装饰器工厂函数
|
|
2311
1203
|
*/
|
|
2312
|
-
function
|
|
2313
|
-
return
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
options: validationOptions,
|
|
2320
|
-
validator: {
|
|
2321
|
-
validate(value, _args) {
|
|
2322
|
-
return classValidator.notEquals(value, comparison);
|
|
2323
|
-
},
|
|
2324
|
-
defaultMessage(_args) {
|
|
2325
|
-
return `invalid parameter, ($property) must be not equals ${comparison}.`;
|
|
2326
|
-
}
|
|
2327
|
-
}
|
|
2328
|
-
});
|
|
2329
|
-
};
|
|
1204
|
+
function createParameterizedDecorator(name, validator, defaultMessage) {
|
|
1205
|
+
return createValidationDecorator({
|
|
1206
|
+
name,
|
|
1207
|
+
validator,
|
|
1208
|
+
defaultMessage,
|
|
1209
|
+
requiresValue: true
|
|
1210
|
+
});
|
|
2330
1211
|
}
|
|
1212
|
+
|
|
2331
1213
|
/**
|
|
2332
|
-
*
|
|
2333
|
-
*
|
|
2334
|
-
* @export
|
|
2335
|
-
* @param {string} seed
|
|
2336
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2337
|
-
* @returns {PropertyDecorator}
|
|
1214
|
+
* 改进的错误处理机制
|
|
1215
|
+
* @author richen
|
|
2338
1216
|
*/
|
|
2339
|
-
function Contains(seed, validationOptions) {
|
|
2340
|
-
return function (object, propertyName) {
|
|
2341
|
-
setExpose(object, propertyName);
|
|
2342
|
-
classValidator.registerDecorator({
|
|
2343
|
-
name: "vContains",
|
|
2344
|
-
target: object.constructor,
|
|
2345
|
-
propertyName,
|
|
2346
|
-
options: validationOptions,
|
|
2347
|
-
validator: {
|
|
2348
|
-
validate(value, _args) {
|
|
2349
|
-
return classValidator.contains(value, seed);
|
|
2350
|
-
// return typeof value === "string" && (value.indexOf(seed) > -1);
|
|
2351
|
-
},
|
|
2352
|
-
defaultMessage(_args) {
|
|
2353
|
-
return `invalid parameter, ($property) must be contains ${seed}.`;
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
});
|
|
2357
|
-
};
|
|
2358
|
-
}
|
|
2359
1217
|
/**
|
|
2360
|
-
*
|
|
2361
|
-
*
|
|
2362
|
-
* @export
|
|
2363
|
-
* @param {any[]} possibleValues
|
|
2364
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2365
|
-
* @returns {PropertyDecorator}
|
|
1218
|
+
* 错误信息国际化
|
|
2366
1219
|
*/
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
}
|
|
1220
|
+
const ERROR_MESSAGES = {
|
|
1221
|
+
zh: {
|
|
1222
|
+
// 中国本土化验证
|
|
1223
|
+
IsCnName: '必须是有效的中文姓名',
|
|
1224
|
+
IsIdNumber: '必须是有效的身份证号码',
|
|
1225
|
+
IsZipCode: '必须是有效的邮政编码',
|
|
1226
|
+
IsMobile: '必须是有效的手机号码',
|
|
1227
|
+
IsPlateNumber: '必须是有效的车牌号码',
|
|
1228
|
+
// 基础验证
|
|
1229
|
+
IsNotEmpty: '不能为空',
|
|
1230
|
+
IsDate: '必须是有效的日期',
|
|
1231
|
+
IsEmail: '必须是有效的邮箱地址',
|
|
1232
|
+
IsIP: '必须是有效的IP地址',
|
|
1233
|
+
IsPhoneNumber: '必须是有效的电话号码',
|
|
1234
|
+
IsUrl: '必须是有效的URL地址',
|
|
1235
|
+
IsHash: '必须是有效的哈希值',
|
|
1236
|
+
// 比较验证
|
|
1237
|
+
Equals: '必须等于 {comparison}',
|
|
1238
|
+
NotEquals: '不能等于 {comparison}',
|
|
1239
|
+
Contains: '必须包含 {seed}',
|
|
1240
|
+
IsIn: '必须是以下值之一: {possibleValues}',
|
|
1241
|
+
IsNotIn: '不能是以下值之一: {possibleValues}',
|
|
1242
|
+
Gt: '必须大于 {min}',
|
|
1243
|
+
Gte: '必须大于或等于 {min}',
|
|
1244
|
+
Lt: '必须小于 {max}',
|
|
1245
|
+
Lte: '必须小于或等于 {max}',
|
|
1246
|
+
// 通用错误
|
|
1247
|
+
invalidParameter: '参数 {field} 无效',
|
|
1248
|
+
validationFailed: '验证失败',
|
|
1249
|
+
},
|
|
1250
|
+
en: {
|
|
1251
|
+
// Chinese localization validators
|
|
1252
|
+
IsCnName: 'must be a valid Chinese name',
|
|
1253
|
+
IsIdNumber: 'must be a valid ID number',
|
|
1254
|
+
IsZipCode: 'must be a valid zip code',
|
|
1255
|
+
IsMobile: 'must be a valid mobile number',
|
|
1256
|
+
IsPlateNumber: 'must be a valid plate number',
|
|
1257
|
+
// Basic validators
|
|
1258
|
+
IsNotEmpty: 'should not be empty',
|
|
1259
|
+
IsDate: 'must be a valid date',
|
|
1260
|
+
IsEmail: 'must be a valid email',
|
|
1261
|
+
IsIP: 'must be a valid IP address',
|
|
1262
|
+
IsPhoneNumber: 'must be a valid phone number',
|
|
1263
|
+
IsUrl: 'must be a valid URL',
|
|
1264
|
+
IsHash: 'must be a valid hash',
|
|
1265
|
+
// Comparison validators
|
|
1266
|
+
Equals: 'must equal to {comparison}',
|
|
1267
|
+
NotEquals: 'should not equal to {comparison}',
|
|
1268
|
+
Contains: 'must contain {seed}',
|
|
1269
|
+
IsIn: 'must be one of the following values: {possibleValues}',
|
|
1270
|
+
IsNotIn: 'should not be one of the following values: {possibleValues}',
|
|
1271
|
+
Gt: 'must be greater than {min}',
|
|
1272
|
+
Gte: 'must be greater than or equal to {min}',
|
|
1273
|
+
Lt: 'must be less than {max}',
|
|
1274
|
+
Lte: 'must be less than or equal to {max}',
|
|
1275
|
+
// Common errors
|
|
1276
|
+
invalidParameter: 'invalid parameter {field}',
|
|
1277
|
+
validationFailed: 'validation failed',
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
2386
1280
|
/**
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2389
|
-
* @export
|
|
2390
|
-
* @param {any[]} possibleValues
|
|
2391
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2392
|
-
* @returns {PropertyDecorator}
|
|
1281
|
+
* 增强的验证错误类
|
|
2393
1282
|
*/
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
1283
|
+
class KoattyValidationError extends Error {
|
|
1284
|
+
constructor(errors, message) {
|
|
1285
|
+
const errorMessage = message || 'Validation failed';
|
|
1286
|
+
super(errorMessage);
|
|
1287
|
+
this.name = 'KoattyValidationError';
|
|
1288
|
+
this.errors = errors;
|
|
1289
|
+
this.statusCode = 400;
|
|
1290
|
+
this.timestamp = new Date();
|
|
1291
|
+
// 确保正确的原型链
|
|
1292
|
+
Object.setPrototypeOf(this, KoattyValidationError.prototype);
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* 获取第一个错误信息
|
|
1296
|
+
*/
|
|
1297
|
+
getFirstError() {
|
|
1298
|
+
return this.errors[0];
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* 获取指定字段的错误
|
|
1302
|
+
*/
|
|
1303
|
+
getFieldErrors(field) {
|
|
1304
|
+
return this.errors.filter(error => error.field === field);
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* 转换为JSON格式
|
|
1308
|
+
*/
|
|
1309
|
+
toJSON() {
|
|
1310
|
+
return {
|
|
1311
|
+
name: this.name,
|
|
1312
|
+
message: this.message,
|
|
1313
|
+
statusCode: this.statusCode,
|
|
1314
|
+
timestamp: this.timestamp,
|
|
1315
|
+
errors: this.errors
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
2412
1318
|
}
|
|
2413
1319
|
/**
|
|
2414
|
-
*
|
|
2415
|
-
*
|
|
2416
|
-
* @export
|
|
2417
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2418
|
-
* @returns {PropertyDecorator}
|
|
1320
|
+
* 错误信息格式化器
|
|
2419
1321
|
*/
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
1322
|
+
class ErrorMessageFormatter {
|
|
1323
|
+
constructor(language = 'zh') {
|
|
1324
|
+
this.language = 'zh';
|
|
1325
|
+
this.language = language;
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* 设置语言
|
|
1329
|
+
*/
|
|
1330
|
+
setLanguage(language) {
|
|
1331
|
+
this.language = language;
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* 格式化错误消息
|
|
1335
|
+
*/
|
|
1336
|
+
formatMessage(constraint, field, value, context) {
|
|
1337
|
+
const messages = ERROR_MESSAGES[this.language];
|
|
1338
|
+
let template = messages[constraint] || messages.invalidParameter;
|
|
1339
|
+
// 替换占位符
|
|
1340
|
+
template = template.replace('{field}', field);
|
|
1341
|
+
// 优先使用上下文中的值,然后是传入的value
|
|
1342
|
+
if (context) {
|
|
1343
|
+
Object.entries(context).forEach(([key, val]) => {
|
|
1344
|
+
template = template.replace(`{${key}}`, this.formatValue(val));
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
// 如果还有{value}占位符且传入了value,则替换
|
|
1348
|
+
if (value !== undefined && template.includes('{value}')) {
|
|
1349
|
+
template = template.replace('{value}', this.formatValue(value));
|
|
1350
|
+
}
|
|
1351
|
+
return template;
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* 格式化值用于消息显示
|
|
1355
|
+
* @private
|
|
1356
|
+
*/
|
|
1357
|
+
formatValue(value) {
|
|
1358
|
+
if (value === null)
|
|
1359
|
+
return 'null';
|
|
1360
|
+
if (value === undefined)
|
|
1361
|
+
return 'undefined';
|
|
1362
|
+
if (typeof value === 'number')
|
|
1363
|
+
return String(value);
|
|
1364
|
+
if (typeof value === 'string')
|
|
1365
|
+
return `"${value}"`;
|
|
1366
|
+
if (Array.isArray(value))
|
|
1367
|
+
return `[${value.map(v => this.formatValue(v)).join(', ')}]`;
|
|
1368
|
+
if (typeof value === 'object') {
|
|
1369
|
+
try {
|
|
1370
|
+
return JSON.stringify(value);
|
|
2435
1371
|
}
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
/**
|
|
2440
|
-
* Checks if the first number is greater than or equal to the min value.
|
|
2441
|
-
*
|
|
2442
|
-
* @export
|
|
2443
|
-
* @param {number} min
|
|
2444
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2445
|
-
* @returns {PropertyDecorator}
|
|
2446
|
-
*/
|
|
2447
|
-
function Gt(min, validationOptions) {
|
|
2448
|
-
return function (object, propertyName) {
|
|
2449
|
-
setExpose(object, propertyName);
|
|
2450
|
-
classValidator.registerDecorator({
|
|
2451
|
-
name: "vMin",
|
|
2452
|
-
target: object.constructor,
|
|
2453
|
-
propertyName,
|
|
2454
|
-
options: validationOptions,
|
|
2455
|
-
validator: {
|
|
2456
|
-
validate(value, _args) {
|
|
2457
|
-
return helper__namespace.toNumber(value) > min;
|
|
2458
|
-
},
|
|
2459
|
-
defaultMessage(_args) {
|
|
2460
|
-
return `invalid parameter ($property).`;
|
|
2461
|
-
}
|
|
1372
|
+
catch {
|
|
1373
|
+
// 处理循环引用
|
|
1374
|
+
return '[Circular Reference]';
|
|
2462
1375
|
}
|
|
2463
|
-
}
|
|
2464
|
-
|
|
1376
|
+
}
|
|
1377
|
+
return String(value);
|
|
1378
|
+
}
|
|
2465
1379
|
}
|
|
2466
1380
|
/**
|
|
2467
|
-
*
|
|
2468
|
-
*
|
|
2469
|
-
* @export
|
|
2470
|
-
* @param {number} max
|
|
2471
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2472
|
-
* @returns {PropertyDecorator}
|
|
1381
|
+
* 全局错误信息格式化器实例
|
|
2473
1382
|
*/
|
|
2474
|
-
|
|
2475
|
-
return function (object, propertyName) {
|
|
2476
|
-
setExpose(object, propertyName);
|
|
2477
|
-
classValidator.registerDecorator({
|
|
2478
|
-
name: "vMax",
|
|
2479
|
-
target: object.constructor,
|
|
2480
|
-
propertyName,
|
|
2481
|
-
options: validationOptions,
|
|
2482
|
-
validator: {
|
|
2483
|
-
validate(value, _args) {
|
|
2484
|
-
return helper__namespace.toNumber(value) < max;
|
|
2485
|
-
},
|
|
2486
|
-
defaultMessage(_args) {
|
|
2487
|
-
return `invalid parameter ($property).`;
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
});
|
|
2491
|
-
};
|
|
2492
|
-
}
|
|
1383
|
+
const errorFormatter = new ErrorMessageFormatter();
|
|
2493
1384
|
/**
|
|
2494
|
-
*
|
|
2495
|
-
*
|
|
2496
|
-
* @export
|
|
2497
|
-
* @param {number} min
|
|
2498
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2499
|
-
* @returns {PropertyDecorator}
|
|
1385
|
+
* 设置全局语言
|
|
2500
1386
|
*/
|
|
2501
|
-
function
|
|
2502
|
-
|
|
2503
|
-
setExpose(object, propertyName);
|
|
2504
|
-
classValidator.registerDecorator({
|
|
2505
|
-
name: "vMin",
|
|
2506
|
-
target: object.constructor,
|
|
2507
|
-
propertyName,
|
|
2508
|
-
options: validationOptions,
|
|
2509
|
-
validator: {
|
|
2510
|
-
validate(value, _args) {
|
|
2511
|
-
return helper__namespace.toNumber(value) >= min;
|
|
2512
|
-
},
|
|
2513
|
-
defaultMessage(_args) {
|
|
2514
|
-
return `invalid parameter ($property).`;
|
|
2515
|
-
}
|
|
2516
|
-
}
|
|
2517
|
-
});
|
|
2518
|
-
};
|
|
1387
|
+
function setValidationLanguage(language) {
|
|
1388
|
+
errorFormatter.setLanguage(language);
|
|
2519
1389
|
}
|
|
2520
1390
|
/**
|
|
2521
|
-
*
|
|
2522
|
-
*
|
|
2523
|
-
* @export
|
|
2524
|
-
* @param {number} max
|
|
2525
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2526
|
-
* @returns {PropertyDecorator}
|
|
1391
|
+
* 创建验证错误
|
|
2527
1392
|
*/
|
|
2528
|
-
function
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
validator: {
|
|
2537
|
-
validate(value, _args) {
|
|
2538
|
-
return helper__namespace.toNumber(value) <= max;
|
|
2539
|
-
},
|
|
2540
|
-
defaultMessage(_args) {
|
|
2541
|
-
return `invalid parameter ($property).`;
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
});
|
|
1393
|
+
function createValidationError(field, value, constraint, customMessage, context) {
|
|
1394
|
+
const message = customMessage || errorFormatter.formatMessage(constraint, field, value, context);
|
|
1395
|
+
return {
|
|
1396
|
+
field,
|
|
1397
|
+
value,
|
|
1398
|
+
constraint,
|
|
1399
|
+
message,
|
|
1400
|
+
context
|
|
2545
1401
|
};
|
|
2546
1402
|
}
|
|
2547
1403
|
/**
|
|
2548
|
-
*
|
|
2549
|
-
* If given value is not a string, then it returns false.
|
|
2550
|
-
*
|
|
2551
|
-
* @export
|
|
2552
|
-
* @param {number} min
|
|
2553
|
-
* @param {number} [max]
|
|
2554
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2555
|
-
* @returns {PropertyDecorator}
|
|
1404
|
+
* 批量创建验证错误
|
|
2556
1405
|
*/
|
|
2557
|
-
function
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
classValidator.registerDecorator({
|
|
2561
|
-
name: "vLength",
|
|
2562
|
-
target: object.constructor,
|
|
2563
|
-
propertyName,
|
|
2564
|
-
options: validationOptions,
|
|
2565
|
-
validator: {
|
|
2566
|
-
validate(value, _args) {
|
|
2567
|
-
return classValidator.length(value, min, max);
|
|
2568
|
-
},
|
|
2569
|
-
defaultMessage(_args) {
|
|
2570
|
-
return `invalid parameter ($property).`;
|
|
2571
|
-
}
|
|
2572
|
-
}
|
|
2573
|
-
});
|
|
2574
|
-
};
|
|
1406
|
+
function createValidationErrors(errors) {
|
|
1407
|
+
const validationErrors = errors.map(error => createValidationError(error.field, error.value, error.constraint, error.message, error.context));
|
|
1408
|
+
return new KoattyValidationError(validationErrors);
|
|
2575
1409
|
}
|
|
1410
|
+
|
|
2576
1411
|
/**
|
|
2577
|
-
*
|
|
2578
|
-
*
|
|
2579
|
-
* @export
|
|
2580
|
-
* @param {IsEmailOptions} [options]
|
|
2581
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2582
|
-
* @returns {PropertyDecorator}
|
|
1412
|
+
* 重构后的装饰器定义 - 使用工厂函数消除重复
|
|
1413
|
+
* @author richen
|
|
2583
1414
|
*/
|
|
1415
|
+
// 中国本土化验证装饰器
|
|
1416
|
+
const IsCnName = createSimpleDecorator('IsCnName', (value) => helper__namespace.isString(value) && cnName(value), 'must be a valid Chinese name');
|
|
1417
|
+
const IsIdNumber = createSimpleDecorator('IsIdNumber', (value) => helper__namespace.isString(value) && idNumber(value), 'must be a valid ID number');
|
|
1418
|
+
const IsZipCode = createSimpleDecorator('IsZipCode', (value) => helper__namespace.isString(value) && zipCode(value), 'must be a valid zip code');
|
|
1419
|
+
const IsMobile = createSimpleDecorator('IsMobile', (value) => helper__namespace.isString(value) && mobile(value), 'must be a valid mobile number');
|
|
1420
|
+
const IsPlateNumber = createSimpleDecorator('IsPlateNumber', (value) => helper__namespace.isString(value) && plateNumber(value), 'must be a valid plate number');
|
|
1421
|
+
// 基础验证装饰器
|
|
1422
|
+
const IsNotEmpty = createSimpleDecorator('IsNotEmpty', (value) => !helper__namespace.isEmpty(value), 'should not be empty');
|
|
1423
|
+
const IsDate = createSimpleDecorator('IsDate', (value) => helper__namespace.isDate(value), 'must be a valid date');
|
|
1424
|
+
// 带参数的验证装饰器
|
|
1425
|
+
const Equals = createParameterizedDecorator('Equals', (value, comparison) => value === comparison, 'must equal to $constraint1');
|
|
1426
|
+
const NotEquals = createParameterizedDecorator('NotEquals', (value, comparison) => value !== comparison, 'should not equal to $constraint1');
|
|
1427
|
+
const Contains = createParameterizedDecorator('Contains', (value, seed) => helper__namespace.isString(value) && value.includes(seed), 'must contain $constraint1');
|
|
1428
|
+
const IsIn = createParameterizedDecorator('IsIn', (value, possibleValues) => possibleValues.includes(value), 'must be one of the following values: $constraint1');
|
|
1429
|
+
const IsNotIn = createParameterizedDecorator('IsNotIn', (value, possibleValues) => !possibleValues.includes(value), 'should not be one of the following values: $constraint1');
|
|
1430
|
+
// 数值比较装饰器
|
|
1431
|
+
const Gt = createParameterizedDecorator('Gt', (value, min) => helper__namespace.toNumber(value) > min, 'must be greater than $constraint1');
|
|
1432
|
+
const Gte = createParameterizedDecorator('Gte', (value, min) => helper__namespace.toNumber(value) >= min, 'must be greater than or equal to $constraint1');
|
|
1433
|
+
const Lt = createParameterizedDecorator('Lt', (value, max) => helper__namespace.toNumber(value) < max, 'must be less than $constraint1');
|
|
1434
|
+
const Lte = createParameterizedDecorator('Lte', (value, max) => helper__namespace.toNumber(value) <= max, 'must be less than or equal to $constraint1');
|
|
1435
|
+
// 复杂验证装饰器(需要特殊处理)
|
|
2584
1436
|
function IsEmail(options, validationOptions) {
|
|
2585
|
-
return
|
|
2586
|
-
setExpose(object, propertyName);
|
|
2587
|
-
classValidator.registerDecorator({
|
|
2588
|
-
name: "vIsEmail",
|
|
2589
|
-
target: object.constructor,
|
|
2590
|
-
propertyName,
|
|
2591
|
-
options: validationOptions,
|
|
2592
|
-
validator: {
|
|
2593
|
-
validate(value, _args) {
|
|
2594
|
-
return classValidator.isEmail(value);
|
|
2595
|
-
},
|
|
2596
|
-
defaultMessage(_args) {
|
|
2597
|
-
return `invalid parameter ($property).`;
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
});
|
|
2601
|
-
};
|
|
1437
|
+
return createParameterizedDecorator('IsEmail', (value) => classValidator.isEmail(value, options), 'must be a valid email')(validationOptions);
|
|
2602
1438
|
}
|
|
2603
|
-
/**
|
|
2604
|
-
* Checks if the string is an IP (version 4 or 6). If given value is not a string, then it returns false.
|
|
2605
|
-
*
|
|
2606
|
-
* @export
|
|
2607
|
-
* @param {number} [version]
|
|
2608
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2609
|
-
* @returns {PropertyDecorator}
|
|
2610
|
-
*/
|
|
2611
1439
|
function IsIP(version, validationOptions) {
|
|
2612
|
-
return
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
},
|
|
2623
|
-
defaultMessage(_args) {
|
|
2624
|
-
return `invalid parameter ($property).`;
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
});
|
|
2628
|
-
};
|
|
1440
|
+
return createParameterizedDecorator('IsIP', (value) => classValidator.isIP(value, version), 'must be a valid IP address')(validationOptions);
|
|
1441
|
+
}
|
|
1442
|
+
function IsPhoneNumber(region, validationOptions) {
|
|
1443
|
+
return createParameterizedDecorator('IsPhoneNumber', (value) => classValidator.isPhoneNumber(value, region), 'must be a valid phone number')(validationOptions);
|
|
1444
|
+
}
|
|
1445
|
+
function IsUrl(options, validationOptions) {
|
|
1446
|
+
return createParameterizedDecorator('IsUrl', (value) => classValidator.isURL(value, options), 'must be a valid URL')(validationOptions);
|
|
1447
|
+
}
|
|
1448
|
+
function IsHash(algorithm, validationOptions) {
|
|
1449
|
+
return createParameterizedDecorator('IsHash', (value) => classValidator.isHash(value, algorithm), 'must be a valid hash')(validationOptions);
|
|
2629
1450
|
}
|
|
1451
|
+
// 基础工具装饰器(从原始decorator.ts移植)
|
|
2630
1452
|
/**
|
|
2631
|
-
*
|
|
2632
|
-
*
|
|
2633
|
-
* @export
|
|
2634
|
-
* @param {string} {string} region 2 characters uppercase country code (e.g. DE, US, CH).
|
|
2635
|
-
* If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region.
|
|
2636
|
-
* See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]
|
|
2637
|
-
* {@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33}
|
|
2638
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2639
|
-
* @returns {PropertyDecorator}
|
|
1453
|
+
* 标记属性为可导出
|
|
2640
1454
|
*/
|
|
2641
|
-
function
|
|
1455
|
+
function Expose() {
|
|
2642
1456
|
return function (object, propertyName) {
|
|
2643
1457
|
setExpose(object, propertyName);
|
|
2644
|
-
classValidator.registerDecorator({
|
|
2645
|
-
name: "vIsPhoneNumber",
|
|
2646
|
-
target: object.constructor,
|
|
2647
|
-
propertyName,
|
|
2648
|
-
options: validationOptions,
|
|
2649
|
-
validator: {
|
|
2650
|
-
validate(value, _args) {
|
|
2651
|
-
return classValidator.isPhoneNumber(value, region);
|
|
2652
|
-
},
|
|
2653
|
-
defaultMessage(_args) {
|
|
2654
|
-
return `invalid parameter ($property).`;
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
});
|
|
2658
1458
|
};
|
|
2659
1459
|
}
|
|
2660
1460
|
/**
|
|
2661
|
-
*
|
|
2662
|
-
*
|
|
2663
|
-
* @export
|
|
2664
|
-
* @param {IsURLOptions} [options]
|
|
2665
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2666
|
-
* @returns {PropertyDecorator}
|
|
1461
|
+
* Expose的别名
|
|
2667
1462
|
*/
|
|
2668
|
-
function
|
|
1463
|
+
function IsDefined() {
|
|
2669
1464
|
return function (object, propertyName) {
|
|
2670
1465
|
setExpose(object, propertyName);
|
|
2671
|
-
classValidator.registerDecorator({
|
|
2672
|
-
name: "vIsUrl",
|
|
2673
|
-
target: object.constructor,
|
|
2674
|
-
propertyName,
|
|
2675
|
-
options: validationOptions,
|
|
2676
|
-
validator: {
|
|
2677
|
-
validate(value, _args) {
|
|
2678
|
-
return classValidator.isURL(value, options);
|
|
2679
|
-
},
|
|
2680
|
-
defaultMessage(_args) {
|
|
2681
|
-
return `invalid parameter ($property).`;
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
});
|
|
2685
1466
|
};
|
|
2686
1467
|
}
|
|
2687
1468
|
/**
|
|
2688
|
-
*
|
|
2689
|
-
* 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']
|
|
2690
|
-
*
|
|
2691
|
-
* @export
|
|
2692
|
-
* @param {HashAlgorithm} algorithm
|
|
2693
|
-
* @param {ValidationOptions} [validationOptions]
|
|
2694
|
-
* @returns {PropertyDecorator}
|
|
1469
|
+
* 参数验证装饰器
|
|
2695
1470
|
*/
|
|
2696
|
-
function
|
|
2697
|
-
return function (object, propertyName) {
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
propertyName,
|
|
2703
|
-
options: validationOptions,
|
|
2704
|
-
validator: {
|
|
2705
|
-
validate(value, _args) {
|
|
2706
|
-
return classValidator.isHash(value, algorithm);
|
|
2707
|
-
},
|
|
2708
|
-
defaultMessage(_args) {
|
|
2709
|
-
return `invalid parameter, ($property) must be is an ${algorithm} Hash string.`;
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
});
|
|
1471
|
+
function Valid(rule, options) {
|
|
1472
|
+
return function (object, propertyName, parameterIndex) {
|
|
1473
|
+
// 这里保持与原始实现一致
|
|
1474
|
+
const existingRules = Reflect.getOwnMetadata("validate", object, propertyName) || {};
|
|
1475
|
+
existingRules[parameterIndex] = { rule, options };
|
|
1476
|
+
Reflect.defineMetadata("validate", existingRules, object, propertyName);
|
|
2713
1477
|
};
|
|
2714
1478
|
}
|
|
2715
1479
|
/**
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2718
|
-
* @param validationOptions
|
|
2719
|
-
* @returns
|
|
1480
|
+
* 方法验证装饰器
|
|
1481
|
+
* 自动验证方法参数中的 DTO 对象
|
|
2720
1482
|
*/
|
|
2721
|
-
function
|
|
2722
|
-
return function (object, propertyName) {
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
1483
|
+
function Validated() {
|
|
1484
|
+
return function (object, propertyName, descriptor) {
|
|
1485
|
+
const originalMethod = descriptor.value;
|
|
1486
|
+
descriptor.value = async function (...args) {
|
|
1487
|
+
// 获取参数类型元数据
|
|
1488
|
+
const paramTypes = Reflect.getMetadata('design:paramtypes', object, propertyName) || [];
|
|
1489
|
+
// 验证每个参数
|
|
1490
|
+
for (let i = 0; i < args.length; i++) {
|
|
1491
|
+
const arg = args[i];
|
|
1492
|
+
const paramType = paramTypes[i];
|
|
1493
|
+
// 如果是类类型且不是基础类型,执行验证
|
|
1494
|
+
if (paramType && typeof paramType === 'function' &&
|
|
1495
|
+
paramType !== String && paramType !== Number &&
|
|
1496
|
+
paramType !== Boolean && paramType !== Array &&
|
|
1497
|
+
paramType !== Object && paramType !== Date) {
|
|
1498
|
+
try {
|
|
1499
|
+
// 如果参数不是目标类型的实例,转换为实例
|
|
1500
|
+
let validationTarget = arg;
|
|
1501
|
+
if (!(arg instanceof paramType)) {
|
|
1502
|
+
validationTarget = Object.assign(new paramType(), arg);
|
|
1503
|
+
}
|
|
1504
|
+
const errors = await classValidator.validate(validationTarget);
|
|
1505
|
+
if (errors.length > 0) {
|
|
1506
|
+
throw createValidationErrors(errors.map(e => ({
|
|
1507
|
+
field: e.property,
|
|
1508
|
+
value: e.value,
|
|
1509
|
+
constraint: Object.keys(e.constraints || {})[0] || 'unknown',
|
|
1510
|
+
message: Object.values(e.constraints || {})[0] || 'Validation failed',
|
|
1511
|
+
context: e.constraints
|
|
1512
|
+
})));
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
catch (error) {
|
|
1516
|
+
// 如果验证失败,重新抛出错误
|
|
1517
|
+
throw error;
|
|
1518
|
+
}
|
|
2735
1519
|
}
|
|
2736
1520
|
}
|
|
2737
|
-
|
|
1521
|
+
// 执行原始方法
|
|
1522
|
+
return originalMethod.apply(this, args);
|
|
1523
|
+
};
|
|
1524
|
+
return descriptor;
|
|
2738
1525
|
};
|
|
2739
1526
|
}
|
|
2740
1527
|
|
|
2741
|
-
exports.CheckFunc = CheckFunc;
|
|
2742
1528
|
exports.ClassValidator = ClassValidator;
|
|
2743
1529
|
exports.Contains = Contains;
|
|
2744
1530
|
exports.ENABLE_VALIDATED = ENABLE_VALIDATED;
|
|
1531
|
+
exports.ERROR_MESSAGES = ERROR_MESSAGES;
|
|
2745
1532
|
exports.Equals = Equals;
|
|
1533
|
+
exports.ErrorMessageFormatter = ErrorMessageFormatter;
|
|
2746
1534
|
exports.Expose = Expose;
|
|
2747
1535
|
exports.FunctionValidator = FunctionValidator;
|
|
2748
1536
|
exports.Gt = Gt;
|
|
@@ -2762,7 +1550,7 @@ exports.IsPhoneNumber = IsPhoneNumber;
|
|
|
2762
1550
|
exports.IsPlateNumber = IsPlateNumber;
|
|
2763
1551
|
exports.IsUrl = IsUrl;
|
|
2764
1552
|
exports.IsZipCode = IsZipCode;
|
|
2765
|
-
exports.
|
|
1553
|
+
exports.KoattyValidationError = KoattyValidationError;
|
|
2766
1554
|
exports.Lt = Lt;
|
|
2767
1555
|
exports.Lte = Lte;
|
|
2768
1556
|
exports.NotEquals = NotEquals;
|
|
@@ -2772,7 +1560,23 @@ exports.PARAM_TYPE_KEY = PARAM_TYPE_KEY;
|
|
|
2772
1560
|
exports.Valid = Valid;
|
|
2773
1561
|
exports.ValidFuncs = ValidFuncs;
|
|
2774
1562
|
exports.Validated = Validated;
|
|
1563
|
+
exports.cached = cached;
|
|
2775
1564
|
exports.checkParamsType = checkParamsType;
|
|
1565
|
+
exports.clearAllCaches = clearAllCaches;
|
|
1566
|
+
exports.configureCaches = configureCaches;
|
|
2776
1567
|
exports.convertDtoParamsType = convertDtoParamsType;
|
|
2777
1568
|
exports.convertParamsType = convertParamsType;
|
|
1569
|
+
exports.createParameterizedDecorator = createParameterizedDecorator;
|
|
1570
|
+
exports.createSimpleDecorator = createSimpleDecorator;
|
|
1571
|
+
exports.createValidationDecorator = createValidationDecorator;
|
|
1572
|
+
exports.createValidationError = createValidationError;
|
|
1573
|
+
exports.createValidationErrors = createValidationErrors;
|
|
1574
|
+
exports.errorFormatter = errorFormatter;
|
|
1575
|
+
exports.getAllCacheStats = getAllCacheStats;
|
|
1576
|
+
exports.metadataCache = metadataCache;
|
|
1577
|
+
exports.performanceMonitor = performanceMonitor;
|
|
2778
1578
|
exports.plainToClass = plainToClass;
|
|
1579
|
+
exports.regexCache = regexCache;
|
|
1580
|
+
exports.setValidationLanguage = setValidationLanguage;
|
|
1581
|
+
exports.validationCache = validationCache;
|
|
1582
|
+
exports.warmupCaches = warmupCaches;
|