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