@rtpaulino/entity 0.14.0 → 0.14.2

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.d.ts CHANGED
@@ -7,4 +7,5 @@ export * from './lib/validation-error.js';
7
7
  export * from './lib/problem.js';
8
8
  export * from './lib/validation-utils.js';
9
9
  export * from './lib/primitive-deserializers.js';
10
+ export * from './lib/validators.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -7,5 +7,6 @@ export * from './lib/validation-error.js';
7
7
  export * from './lib/problem.js';
8
8
  export * from './lib/validation-utils.js';
9
9
  export * from './lib/primitive-deserializers.js';
10
+ export * from './lib/validators.js';
10
11
 
11
12
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nexport * from './lib/entity.js';\nexport * from './lib/entity-utils.js';\nexport * from './lib/types.js';\nexport * from './lib/property.js';\nexport * from './lib/validation-error.js';\nexport * from './lib/problem.js';\nexport * from './lib/validation-utils.js';\nexport * from './lib/primitive-deserializers.js';\n"],"names":[],"mappings":"AAAA,OAAO,mBAAmB;AAE1B,cAAc,kBAAkB;AAChC,cAAc,wBAAwB;AACtC,cAAc,iBAAiB;AAC/B,cAAc,oBAAoB;AAClC,cAAc,4BAA4B;AAC1C,cAAc,mBAAmB;AACjC,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import 'reflect-metadata';\n\nexport * from './lib/entity.js';\nexport * from './lib/entity-utils.js';\nexport * from './lib/types.js';\nexport * from './lib/property.js';\nexport * from './lib/validation-error.js';\nexport * from './lib/problem.js';\nexport * from './lib/validation-utils.js';\nexport * from './lib/primitive-deserializers.js';\nexport * from './lib/validators.js';\n"],"names":[],"mappings":"AAAA,OAAO,mBAAmB;AAE1B,cAAc,kBAAkB;AAChC,cAAc,wBAAwB;AACtC,cAAc,iBAAiB;AAC/B,cAAc,oBAAoB;AAClC,cAAc,4BAA4B;AAC1C,cAAc,mBAAmB;AACjC,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC;AACjD,cAAc,sBAAsB"}
@@ -94,7 +94,7 @@ export declare class EntityUtils {
94
94
  * @param entityClass - The entity class constructor. Must accept a data object parameter.
95
95
  * @param plainObject - The plain object to deserialize
96
96
  * @param options - Parse options (strict mode)
97
- * @returns A new instance of the entity with deserialized values
97
+ * @returns Promise resolving to a new instance of the entity with deserialized values
98
98
  *
99
99
  * @remarks
100
100
  * Deserialization rules:
@@ -111,6 +111,7 @@ export declare class EntityUtils {
111
111
  * - If strict: true - both HARD and SOFT problems throw ValidationError
112
112
  * - If strict: false (default) - HARD problems throw ValidationError, SOFT problems stored
113
113
  * - Property validators run first, then entity validators
114
+ * - Validators can be synchronous or asynchronous
114
115
  * - Problems are accessible via EntityUtils.problems()
115
116
  * - Raw input data is accessible via EntityUtils.getRawInput()
116
117
  *
@@ -127,13 +128,13 @@ export declare class EntityUtils {
127
128
  * }
128
129
  *
129
130
  * const json = { name: 'John', age: 30 };
130
- * const user = EntityUtils.parse(User, json);
131
- * const userStrict = EntityUtils.parse(User, json, { strict: true });
131
+ * const user = await EntityUtils.parse(User, json);
132
+ * const userStrict = await EntityUtils.parse(User, json, { strict: true });
132
133
  * ```
133
134
  */
134
- static parse<T extends object>(entityClass: new (data: any) => T, plainObject: Record<string, unknown>, options?: {
135
+ static parse<T extends object>(entityClass: new (data: any) => T, plainObject: unknown, options?: {
135
136
  strict?: boolean;
136
- }): T;
137
+ }): Promise<T>;
137
138
  /**
138
139
  * Deserializes a single value according to the type metadata
139
140
  * @private
@@ -160,21 +161,21 @@ export declare class EntityUtils {
160
161
  * Validates an entity instance by running all property and entity validators
161
162
  *
162
163
  * @param instance - The entity instance to validate
163
- * @returns Array of Problems found during validation (empty if valid)
164
+ * @returns Promise resolving to array of Problems found during validation (empty if valid)
164
165
  *
165
166
  * @remarks
166
167
  * - Property validators run first, then entity validators
167
- * - Each validator returns an array of Problems
168
+ * - Each validator can be synchronous or asynchronous
168
169
  * - Empty array means no problems found
169
170
  *
170
171
  * @example
171
172
  * ```typescript
172
173
  * const user = new User({ name: '', age: -5 });
173
- * const problems = EntityUtils.validate(user);
174
+ * const problems = await EntityUtils.validate(user);
174
175
  * console.log(problems); // [Problem, Problem, ...]
175
176
  * ```
176
177
  */
177
- static validate<T extends object>(instance: T): Problem[];
178
+ static validate<T extends object>(instance: T): Promise<Problem[]>;
178
179
  /**
179
180
  * Gets the validation problems for an entity instance
180
181
  *
@@ -1 +1 @@
1
- {"version":3,"file":"entity-utils.d.ts","sourceRoot":"","sources":["../../src/lib/entity-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,eAAe,EAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAuBvC,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM;IAmB5C,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAQhD,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAoChD,MAAM,CAAC,kBAAkB,CACvB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG,SAAS;IA8B9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IA2B9C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,EAC1B,SAAS,EAAE,CAAC,EACZ,SAAS,EAAE,CAAC,GACX;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,EAAE;IAoC/D,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAaxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiDG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAmBnE;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAsD7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACH,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAC3B,WAAW,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,EACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,CAAC;IAgGJ;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IA+D/B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IA0BrC;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAkCpC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAoDpC;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,EAAE;IAkCzD;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,EAAE;IAIzD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EACjC,QAAQ,EAAE,CAAC,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAItC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;CA6BnC"}
1
+ {"version":3,"file":"entity-utils.d.ts","sourceRoot":"","sources":["../../src/lib/entity-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,eAAe,EAChB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAuBvC,qBAAa,WAAW;IACtB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM;IAmB5C,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO;IAQhD,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAoChD,MAAM,CAAC,kBAAkB,CACvB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,eAAe,GAAG,SAAS;IA8B9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IA2B9C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,EAC1B,SAAS,EAAE,CAAC,EACZ,SAAS,EAAE,CAAC,GACX;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,EAAE;IAoC/D,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAaxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiDG;IACH,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAmBnE;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAsD7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2CG;WACU,KAAK,CAAC,CAAC,SAAS,MAAM,EACjC,WAAW,EAAE,KAAK,IAAI,EAAE,GAAG,KAAK,CAAC,EACjC,WAAW,EAAE,OAAO,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC7B,OAAO,CAAC,CAAC,CAAC;IA8Gb;;;OAGG;mBACkB,gBAAgB;IAiErC;;;;OAIG;mBACkB,sBAAsB;IA0B3C;;;;OAIG;mBACkB,qBAAqB;IAkC1C;;;OAGG;mBACkB,qBAAqB;IAoD1C;;;;;;;;;;;;;;;;;OAiBG;WACU,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAkCxE;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,OAAO,EAAE;IAIzD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,MAAM,EACjC,QAAQ,EAAE,CAAC,GACV,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAItC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;CA6BnC"}
@@ -262,7 +262,7 @@ export class EntityUtils {
262
262
  * @param entityClass - The entity class constructor. Must accept a data object parameter.
263
263
  * @param plainObject - The plain object to deserialize
264
264
  * @param options - Parse options (strict mode)
265
- * @returns A new instance of the entity with deserialized values
265
+ * @returns Promise resolving to a new instance of the entity with deserialized values
266
266
  *
267
267
  * @remarks
268
268
  * Deserialization rules:
@@ -279,6 +279,7 @@ export class EntityUtils {
279
279
  * - If strict: true - both HARD and SOFT problems throw ValidationError
280
280
  * - If strict: false (default) - HARD problems throw ValidationError, SOFT problems stored
281
281
  * - Property validators run first, then entity validators
282
+ * - Validators can be synchronous or asynchronous
282
283
  * - Problems are accessible via EntityUtils.problems()
283
284
  * - Raw input data is accessible via EntityUtils.getRawInput()
284
285
  *
@@ -295,10 +296,19 @@ export class EntityUtils {
295
296
  * }
296
297
  *
297
298
  * const json = { name: 'John', age: 30 };
298
- * const user = EntityUtils.parse(User, json);
299
- * const userStrict = EntityUtils.parse(User, json, { strict: true });
299
+ * const user = await EntityUtils.parse(User, json);
300
+ * const userStrict = await EntityUtils.parse(User, json, { strict: true });
300
301
  * ```
301
- */ static parse(entityClass, plainObject, options) {
302
+ */ static async parse(entityClass, plainObject, options) {
303
+ if (plainObject == null) {
304
+ throw createValidationError(`Expects an object but received ${typeof plainObject}`);
305
+ }
306
+ if (Array.isArray(plainObject)) {
307
+ throw createValidationError(`Expects an object but received array`);
308
+ }
309
+ if (typeof plainObject !== 'object') {
310
+ throw createValidationError(`Expects an object but received ${typeof plainObject}`);
311
+ }
302
312
  const strict = options?.strict ?? false;
303
313
  const keys = this.getPropertyKeys(entityClass.prototype);
304
314
  const data = {};
@@ -312,12 +322,11 @@ export class EntityUtils {
312
322
  }));
313
323
  continue;
314
324
  }
325
+ const value = plainObject[key];
315
326
  if (propertyOptions.passthrough === true) {
316
- const value = plainObject[key];
317
327
  data[key] = value;
318
328
  continue;
319
329
  }
320
- const value = plainObject[key];
321
330
  const isOptional = propertyOptions.optional === true;
322
331
  if (!(key in plainObject)) {
323
332
  if (!isOptional) {
@@ -339,7 +348,7 @@ export class EntityUtils {
339
348
  continue;
340
349
  }
341
350
  try {
342
- data[key] = this.deserializeValue(value, propertyOptions);
351
+ data[key] = await this.deserializeValue(value, propertyOptions);
343
352
  } catch (error) {
344
353
  if (error instanceof ValidationError) {
345
354
  const problems = prependPropertyPath(key, error);
@@ -359,7 +368,7 @@ export class EntityUtils {
359
368
  }
360
369
  const instance = new entityClass(data);
361
370
  rawInputStorage.set(instance, plainObject);
362
- const problems = this.validate(instance);
371
+ const problems = await this.validate(instance);
363
372
  if (problems.length > 0) {
364
373
  if (strict) {
365
374
  throw new ValidationError(problems);
@@ -372,7 +381,7 @@ export class EntityUtils {
372
381
  /**
373
382
  * Deserializes a single value according to the type metadata
374
383
  * @private
375
- */ static deserializeValue(value, options) {
384
+ */ static async deserializeValue(value, options) {
376
385
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
377
386
  const typeConstructor = options.type();
378
387
  const isArray = options.array === true;
@@ -398,7 +407,7 @@ export class EntityUtils {
398
407
  if (options.deserialize) {
399
408
  result.push(options.deserialize(item));
400
409
  } else {
401
- result.push(this.deserializeSingleValue(item, typeConstructor));
410
+ result.push(await this.deserializeSingleValue(item, typeConstructor));
402
411
  }
403
412
  } catch (error) {
404
413
  if (error instanceof ValidationError) {
@@ -418,13 +427,13 @@ export class EntityUtils {
418
427
  if (options.deserialize) {
419
428
  return options.deserialize(value);
420
429
  }
421
- return this.deserializeSingleValue(value, typeConstructor);
430
+ return await this.deserializeSingleValue(value, typeConstructor);
422
431
  }
423
432
  /**
424
433
  * Deserializes a single non-array value
425
434
  * Reports validation errors with empty property (caller will prepend context)
426
435
  * @private
427
- */ static deserializeSingleValue(value, typeConstructor) {
436
+ */ static async deserializeSingleValue(value, typeConstructor) {
428
437
  if (isPrimitiveConstructor(typeConstructor)) {
429
438
  return deserializePrimitive(value, typeConstructor);
430
439
  }
@@ -432,7 +441,7 @@ export class EntityUtils {
432
441
  if (typeof value !== 'object' || value === null || Array.isArray(value)) {
433
442
  throw createValidationError(`Expects an object but received ${typeof value}`);
434
443
  }
435
- return this.parse(typeConstructor, value);
444
+ return await this.parse(typeConstructor, value);
436
445
  }
437
446
  throw createValidationError(`Has unknown type constructor. Supported types are: String, Number, Boolean, Date, BigInt, and @Entity() classes. Use passthrough: true to explicitly allow unknown types.`);
438
447
  }
@@ -440,11 +449,11 @@ export class EntityUtils {
440
449
  * Validates a property value by running validators and nested entity validation.
441
450
  * Prepends the property path to all returned problems.
442
451
  * @private
443
- */ static validatePropertyValue(propertyPath, value, validators) {
452
+ */ static async validatePropertyValue(propertyPath, value, validators) {
444
453
  const problems = [];
445
454
  if (validators) {
446
455
  for (const validator of validators){
447
- const validatorProblems = validator({
456
+ const validatorProblems = await validator({
448
457
  value
449
458
  });
450
459
  // Prepend propertyPath to all problems
@@ -457,7 +466,7 @@ export class EntityUtils {
457
466
  }
458
467
  }
459
468
  if (EntityUtils.isEntity(value)) {
460
- const nestedProblems = EntityUtils.validate(value);
469
+ const nestedProblems = await EntityUtils.validate(value);
461
470
  const prependedProblems = prependPropertyPath(propertyPath, new ValidationError(nestedProblems));
462
471
  problems.push(...prependedProblems);
463
472
  }
@@ -466,18 +475,18 @@ export class EntityUtils {
466
475
  /**
467
476
  * Runs property validators for a given property value
468
477
  * @private
469
- */ static runPropertyValidators(key, value, options) {
478
+ */ static async runPropertyValidators(key, value, options) {
470
479
  const problems = [];
471
480
  const isArray = options?.array === true;
472
481
  const isPassthrough = options?.passthrough === true;
473
482
  if (isPassthrough || !isArray) {
474
- const valueProblems = this.validatePropertyValue(key, value, options.validators);
483
+ const valueProblems = await this.validatePropertyValue(key, value, options.validators);
475
484
  problems.push(...valueProblems);
476
485
  } else {
477
486
  ok(Array.isArray(value), 'Value must be an array for array property');
478
487
  const arrayValidators = options.arrayValidators || [];
479
488
  for (const validator of arrayValidators){
480
- const validatorProblems = validator({
489
+ const validatorProblems = await validator({
481
490
  value
482
491
  });
483
492
  for (const problem of validatorProblems){
@@ -493,7 +502,7 @@ export class EntityUtils {
493
502
  const element = value[i];
494
503
  if (element !== null && element !== undefined) {
495
504
  const elementPath = `${key}[${i}]`;
496
- const elementProblems = this.validatePropertyValue(elementPath, element, validators);
505
+ const elementProblems = await this.validatePropertyValue(elementPath, element, validators);
497
506
  problems.push(...elementProblems);
498
507
  }
499
508
  }
@@ -505,20 +514,20 @@ export class EntityUtils {
505
514
  * Validates an entity instance by running all property and entity validators
506
515
  *
507
516
  * @param instance - The entity instance to validate
508
- * @returns Array of Problems found during validation (empty if valid)
517
+ * @returns Promise resolving to array of Problems found during validation (empty if valid)
509
518
  *
510
519
  * @remarks
511
520
  * - Property validators run first, then entity validators
512
- * - Each validator returns an array of Problems
521
+ * - Each validator can be synchronous or asynchronous
513
522
  * - Empty array means no problems found
514
523
  *
515
524
  * @example
516
525
  * ```typescript
517
526
  * const user = new User({ name: '', age: -5 });
518
- * const problems = EntityUtils.validate(user);
527
+ * const problems = await EntityUtils.validate(user);
519
528
  * console.log(problems); // [Problem, Problem, ...]
520
529
  * ```
521
- */ static validate(instance) {
530
+ */ static async validate(instance) {
522
531
  if (!this.isEntity(instance)) {
523
532
  throw new Error('Cannot validate non-entity instance');
524
533
  }
@@ -529,14 +538,14 @@ export class EntityUtils {
529
538
  if (options) {
530
539
  const value = instance[key];
531
540
  if (value != null) {
532
- const validationProblems = this.runPropertyValidators(key, value, options);
541
+ const validationProblems = await this.runPropertyValidators(key, value, options);
533
542
  problems.push(...validationProblems);
534
543
  }
535
544
  }
536
545
  }
537
546
  const entityValidators = this.getEntityValidators(instance);
538
547
  for (const validatorMethod of entityValidators){
539
- const validatorProblems = instance[validatorMethod]();
548
+ const validatorProblems = await instance[validatorMethod]();
540
549
  if (Array.isArray(validatorProblems)) {
541
550
  problems.push(...validatorProblems);
542
551
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/entity-utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ENTITY_METADATA_KEY,\n ENTITY_VALIDATOR_METADATA_KEY,\n PROPERTY_METADATA_KEY,\n PROPERTY_OPTIONS_METADATA_KEY,\n PropertyOptions,\n} from './types.js';\nimport { isEqualWith } from 'lodash-es';\nimport { ValidationError } from './validation-error.js';\nimport { Problem } from './problem.js';\nimport {\n prependPropertyPath,\n prependArrayIndex,\n createValidationError,\n combinePropertyPaths,\n} from './validation-utils.js';\nimport {\n isPrimitiveConstructor,\n deserializePrimitive,\n} from './primitive-deserializers.js';\nimport { ok } from 'assert';\n\n/**\n * WeakMap to store validation problems for entity instances\n */\nconst problemsStorage = new WeakMap<object, Problem[]>();\n\n/**\n * WeakMap to store raw input data for entity instances\n */\nconst rawInputStorage = new WeakMap<object, Record<string, unknown>>();\n\nexport class EntityUtils {\n /**\n * Checks if a given object is an instance of a class decorated with @Entity()\n * or if the provided value is an entity class itself\n *\n * @param obj - The object or class to check\n * @returns true if the object is an entity instance or entity class, false otherwise\n *\n * @example\n * ```typescript\n * @Entity()\n * class User {\n * name: string;\n * }\n *\n * const user = new User();\n * console.log(EntityUtils.isEntity(user)); // true\n * console.log(EntityUtils.isEntity(User)); // true\n * console.log(EntityUtils.isEntity({})); // false\n * ```\n */\n static isEntity(obj: unknown): obj is object {\n if (obj == null) {\n return false;\n }\n\n // Check if obj is a constructor function (class)\n if (typeof obj === 'function') {\n return Reflect.hasMetadata(ENTITY_METADATA_KEY, obj);\n }\n\n // Check if obj is an object instance\n if (typeof obj !== 'object' || Array.isArray(obj)) {\n return false;\n }\n\n const constructor = Object.getPrototypeOf(obj).constructor;\n return Reflect.hasMetadata(ENTITY_METADATA_KEY, constructor);\n }\n\n static sameEntity(a: object, b: object): boolean {\n if (!this.isEntity(a) || !this.isEntity(b)) {\n return false;\n }\n\n return Object.getPrototypeOf(a) === Object.getPrototypeOf(b);\n }\n\n static getPropertyKeys(target: object): string[] {\n // Determine if we're dealing with a prototype or an instance\n let currentProto: any;\n\n // Check if target is a prototype by checking if it has a constructor property\n // and if target === target.constructor.prototype\n if (target.constructor && target === target.constructor.prototype) {\n // target is already a prototype\n currentProto = target;\n } else {\n // target is an instance, get its prototype\n currentProto = Object.getPrototypeOf(target);\n }\n\n const keys: string[] = [];\n const seen = new Set<string>();\n\n // Walk the prototype chain to collect all inherited properties\n while (currentProto && currentProto !== Object.prototype) {\n // Use getOwnMetadata to only get metadata directly on this prototype\n const protoKeys: string[] =\n Reflect.getOwnMetadata(PROPERTY_METADATA_KEY, currentProto) || [];\n\n for (const key of protoKeys) {\n if (!seen.has(key)) {\n seen.add(key);\n keys.push(key);\n }\n }\n\n currentProto = Object.getPrototypeOf(currentProto);\n }\n\n return keys;\n }\n\n static getPropertyOptions(\n target: object,\n propertyKey: string,\n ): PropertyOptions | undefined {\n // Determine if we're dealing with a prototype or an instance\n let currentProto: any;\n\n // Check if target is a prototype by checking if it has a constructor property\n // and if target === target.constructor.prototype\n if (target.constructor && target === target.constructor.prototype) {\n // target is already a prototype\n currentProto = target;\n } else {\n // target is an instance, get its prototype\n currentProto = Object.getPrototypeOf(target);\n }\n\n // Walk the prototype chain to find the property options\n while (currentProto && currentProto !== Object.prototype) {\n const protoOptions: Record<string, PropertyOptions> =\n Reflect.getOwnMetadata(PROPERTY_OPTIONS_METADATA_KEY, currentProto) ||\n {};\n\n if (protoOptions[propertyKey]) {\n return protoOptions[propertyKey];\n }\n\n currentProto = Object.getPrototypeOf(currentProto);\n }\n\n return undefined;\n }\n\n static equals(a: unknown, b: unknown): boolean {\n return isEqualWith(a, b, (val1, val2) => {\n if (this.isEntity(val1)) {\n if (!this.sameEntity(val1, val2)) {\n return false;\n }\n\n const diff = this.diff(val1, val2);\n\n return diff.length === 0;\n } else if (\n val1 != null &&\n val2 != null &&\n typeof val1 === 'object' &&\n !Array.isArray(val1) &&\n typeof val2 === 'object' &&\n !Array.isArray(val2) &&\n 'equals' in val1 &&\n typeof val1.equals === 'function'\n ) {\n return val1.equals(val2);\n }\n\n return undefined;\n });\n }\n\n static diff<T extends object>(\n oldEntity: T,\n newEntity: T,\n ): { property: string; oldValue: unknown; newValue: unknown }[] {\n if (!this.sameEntity(oldEntity, newEntity)) {\n throw new Error('Entities must be of the same type to compute diff');\n }\n\n const diffs: { property: string; oldValue: unknown; newValue: unknown }[] =\n [];\n\n const keys = this.getPropertyKeys(oldEntity);\n\n for (const key of keys) {\n const oldValue = (oldEntity as any)[key];\n const newValue = (newEntity as any)[key];\n\n // Check if there's a custom equals function for this property\n const propertyOptions = this.getPropertyOptions(oldEntity, key);\n\n let areEqual: boolean;\n if (oldValue == null && newValue == null) {\n areEqual = oldValue === newValue;\n } else if (oldValue == null || newValue == null) {\n areEqual = false;\n } else {\n areEqual = propertyOptions?.equals\n ? propertyOptions.equals(oldValue, newValue)\n : this.equals(oldValue, newValue);\n }\n\n if (!areEqual) {\n diffs.push({ property: key, oldValue, newValue });\n }\n }\n\n return diffs;\n }\n\n static changes<T extends object>(oldEntity: T, newEntity: T): Partial<T> {\n if (!this.sameEntity(oldEntity, newEntity)) {\n throw new Error('Entities must be of the same type to compute changes');\n }\n\n const diff = this.diff(oldEntity, newEntity);\n\n return diff.reduce((acc, { property, newValue }) => {\n (acc as any)[property] = newValue;\n return acc;\n }, {} as Partial<T>);\n }\n\n /**\n * Serializes an entity to a plain object, converting only properties decorated with @Property()\n *\n * @param entity - The entity instance to serialize\n * @returns A plain object containing only the serialized decorated properties\n *\n * @remarks\n * Serialization rules:\n * - Only properties decorated with @Property() are included\n * - If a property has a custom toJSON() method, it will be used\n * - Nested entities are recursively serialized using EntityUtils.toJSON()\n * - Arrays are mapped with toJSON() applied to each element\n * - Date objects are serialized to ISO strings\n * - bigint values are serialized to strings\n * - undefined values are excluded from the output\n * - null values are included in the output\n * - Circular references are not supported (will cause stack overflow)\n *\n * @example\n * ```typescript\n * @Entity()\n * class Address {\n * @Property() street: string;\n * @Property() city: string;\n * }\n *\n * @Entity()\n * class User {\n * @Property() name: string;\n * @Property() address: Address;\n * @Property() createdAt: Date;\n * undecorated: string; // Will not be serialized\n * }\n *\n * const user = new User();\n * user.name = 'John';\n * user.address = new Address();\n * user.address.street = '123 Main St';\n * user.address.city = 'Boston';\n * user.createdAt = new Date('2024-01-01');\n * user.undecorated = 'ignored';\n *\n * const json = EntityUtils.toJSON(user);\n * // {\n * // name: 'John',\n * // address: { street: '123 Main St', city: 'Boston' },\n * // createdAt: '2024-01-01T00:00:00.000Z'\n * // }\n * ```\n */\n static toJSON<T extends object>(entity: T): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const keys = this.getPropertyKeys(entity);\n\n for (const key of keys) {\n const value = (entity as any)[key];\n\n // Skip undefined values\n if (value === undefined) {\n continue;\n }\n\n const options = this.getPropertyOptions(entity, key);\n result[key] = this.serializeValue(value, options);\n }\n\n return result;\n }\n\n /**\n * Serializes a single value according to the toJSON rules\n * @private\n */\n private static serializeValue(\n value: unknown,\n options?: PropertyOptions,\n ): unknown {\n if (value === null) {\n return null;\n }\n\n if (value === undefined) {\n return undefined;\n }\n\n const passthrough = options?.passthrough === true;\n if (passthrough) {\n return value;\n }\n\n if (Array.isArray(value)) {\n if (options?.serialize) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return value.map((item) => options.serialize!(item as any));\n }\n return value.map((item) => this.serializeValue(item));\n }\n\n if (options?.serialize) {\n return options.serialize(value as any);\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'bigint') {\n return value.toString();\n }\n\n if (this.isEntity(value)) {\n return this.toJSON(value);\n }\n\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n\n throw new Error(\n `Cannot serialize value of type '${typeof value}'. Use passthrough: true in @Property() to explicitly allow serialization of unknown types.`,\n );\n }\n\n /**\n * Deserializes a plain object to an entity instance\n *\n * @param entityClass - The entity class constructor. Must accept a data object parameter.\n * @param plainObject - The plain object to deserialize\n * @param options - Parse options (strict mode)\n * @returns A new instance of the entity with deserialized values\n *\n * @remarks\n * Deserialization rules:\n * - All @Property() decorators must include type metadata for parse() to work\n * - Properties without type metadata will throw an error\n * - Required properties (optional !== true) must be present and not null/undefined\n * - Optional properties (optional === true) can be undefined or null\n * - Arrays are supported with the array: true option\n * - Nested entities are recursively deserialized\n * - Type conversion is strict (no coercion)\n * - Entity constructors must accept a required data parameter\n *\n * Validation behavior:\n * - If strict: true - both HARD and SOFT problems throw ValidationError\n * - If strict: false (default) - HARD problems throw ValidationError, SOFT problems stored\n * - Property validators run first, then entity validators\n * - Problems are accessible via EntityUtils.problems()\n * - Raw input data is accessible via EntityUtils.getRawInput()\n *\n * @example\n * ```typescript\n * @Entity()\n * class User {\n * @Property({ type: () => String }) name!: string;\n * @Property({ type: () => Number }) age!: number;\n *\n * constructor(data: Partial<User>) {\n * Object.assign(this, data);\n * }\n * }\n *\n * const json = { name: 'John', age: 30 };\n * const user = EntityUtils.parse(User, json);\n * const userStrict = EntityUtils.parse(User, json, { strict: true });\n * ```\n */\n static parse<T extends object>(\n entityClass: new (data: any) => T,\n plainObject: Record<string, unknown>,\n options?: { strict?: boolean },\n ): T {\n const strict = options?.strict ?? false;\n const keys = this.getPropertyKeys(entityClass.prototype);\n const data: Record<string, unknown> = {};\n const hardProblems: Problem[] = [];\n\n for (const key of keys) {\n const propertyOptions = this.getPropertyOptions(\n entityClass.prototype,\n key,\n );\n\n if (!propertyOptions) {\n hardProblems.push(\n new Problem({\n property: key,\n message: `Property has no metadata. This should not happen if @Property() was used correctly.`,\n }),\n );\n continue;\n }\n\n if (propertyOptions.passthrough === true) {\n const value = plainObject[key];\n data[key] = value;\n continue;\n }\n\n const value = plainObject[key];\n const isOptional = propertyOptions.optional === true;\n\n if (!(key in plainObject)) {\n if (!isOptional) {\n hardProblems.push(\n new Problem({\n property: key,\n message: 'Required property is missing from input',\n }),\n );\n }\n continue;\n }\n\n if (value === null || value === undefined) {\n if (!isOptional) {\n hardProblems.push(\n new Problem({\n property: key,\n message: 'Cannot be null or undefined',\n }),\n );\n }\n data[key] = value;\n continue;\n }\n\n try {\n data[key] = this.deserializeValue(value, propertyOptions);\n } catch (error) {\n if (error instanceof ValidationError) {\n const problems = prependPropertyPath(key, error);\n hardProblems.push(...problems);\n } else if (error instanceof Error) {\n hardProblems.push(\n new Problem({\n property: key,\n message: error.message,\n }),\n );\n } else {\n throw error;\n }\n }\n }\n\n if (hardProblems.length > 0) {\n throw new ValidationError(hardProblems);\n }\n\n const instance = new entityClass(data);\n\n rawInputStorage.set(instance, plainObject);\n\n const problems = this.validate(instance);\n\n if (problems.length > 0) {\n if (strict) {\n throw new ValidationError(problems);\n } else {\n problemsStorage.set(instance, problems);\n }\n }\n\n return instance;\n }\n\n /**\n * Deserializes a single value according to the type metadata\n * @private\n */\n private static deserializeValue(\n value: unknown,\n options: PropertyOptions,\n ): unknown {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const typeConstructor = options.type!();\n const isArray = options.array === true;\n const isSparse = options.sparse === true;\n\n if (isArray) {\n if (!Array.isArray(value)) {\n throw createValidationError(\n `Expects an array but received ${typeof value}`,\n );\n }\n\n const arrayProblems: Problem[] = [];\n const result: unknown[] = [];\n\n for (let index = 0; index < value.length; index++) {\n const item = value[index];\n if (item === null || item === undefined) {\n if (!isSparse) {\n arrayProblems.push(\n new Problem({\n property: `[${index}]`,\n message: 'Cannot be null or undefined.',\n }),\n );\n }\n result.push(item);\n } else {\n try {\n if (options.deserialize) {\n result.push(options.deserialize(item));\n } else {\n result.push(this.deserializeSingleValue(item, typeConstructor));\n }\n } catch (error) {\n if (error instanceof ValidationError) {\n const problems = prependArrayIndex(index, error);\n arrayProblems.push(...problems);\n } else {\n throw error;\n }\n }\n }\n }\n\n if (arrayProblems.length > 0) {\n throw new ValidationError(arrayProblems);\n }\n\n return result;\n }\n\n if (options.deserialize) {\n return options.deserialize(value);\n }\n\n return this.deserializeSingleValue(value, typeConstructor);\n }\n\n /**\n * Deserializes a single non-array value\n * Reports validation errors with empty property (caller will prepend context)\n * @private\n */\n private static deserializeSingleValue(\n value: unknown,\n typeConstructor: any,\n ): unknown {\n if (isPrimitiveConstructor(typeConstructor)) {\n return deserializePrimitive(value, typeConstructor);\n }\n\n if (this.isEntity(typeConstructor)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw createValidationError(\n `Expects an object but received ${typeof value}`,\n );\n }\n\n return this.parse(\n typeConstructor as new (data: any) => object,\n value as Record<string, unknown>,\n );\n }\n\n throw createValidationError(\n `Has unknown type constructor. Supported types are: String, Number, Boolean, Date, BigInt, and @Entity() classes. Use passthrough: true to explicitly allow unknown types.`,\n );\n }\n\n /**\n * Validates a property value by running validators and nested entity validation.\n * Prepends the property path to all returned problems.\n * @private\n */\n private static validatePropertyValue(\n propertyPath: string,\n value: unknown,\n validators: PropertyOptions['validators'],\n ): Problem[] {\n const problems: Problem[] = [];\n\n if (validators) {\n for (const validator of validators) {\n const validatorProblems = validator({ value });\n // Prepend propertyPath to all problems\n for (const problem of validatorProblems) {\n problems.push(\n new Problem({\n property: combinePropertyPaths(propertyPath, problem.property),\n message: problem.message,\n }),\n );\n }\n }\n }\n\n if (EntityUtils.isEntity(value)) {\n const nestedProblems = EntityUtils.validate(value);\n const prependedProblems = prependPropertyPath(\n propertyPath,\n new ValidationError(nestedProblems),\n );\n problems.push(...prependedProblems);\n }\n\n return problems;\n }\n\n /**\n * Runs property validators for a given property value\n * @private\n */\n private static runPropertyValidators(\n key: string,\n value: unknown,\n options: PropertyOptions,\n ): Problem[] {\n const problems: Problem[] = [];\n const isArray = options?.array === true;\n const isPassthrough = options?.passthrough === true;\n\n if (isPassthrough || !isArray) {\n const valueProblems = this.validatePropertyValue(\n key,\n value,\n options.validators,\n );\n problems.push(...valueProblems);\n } else {\n ok(Array.isArray(value), 'Value must be an array for array property');\n\n const arrayValidators = options.arrayValidators || [];\n for (const validator of arrayValidators) {\n const validatorProblems = validator({ value });\n for (const problem of validatorProblems) {\n problems.push(\n new Problem({\n property: combinePropertyPaths(key, problem.property),\n message: problem.message,\n }),\n );\n }\n }\n\n const validators = options.validators || [];\n if (validators.length > 0) {\n for (let i = 0; i < value.length; i++) {\n const element = value[i];\n if (element !== null && element !== undefined) {\n const elementPath = `${key}[${i}]`;\n const elementProblems = this.validatePropertyValue(\n elementPath,\n element,\n validators,\n );\n problems.push(...elementProblems);\n }\n }\n }\n }\n\n return problems;\n }\n\n /**\n * Validates an entity instance by running all property and entity validators\n *\n * @param instance - The entity instance to validate\n * @returns Array of Problems found during validation (empty if valid)\n *\n * @remarks\n * - Property validators run first, then entity validators\n * - Each validator returns an array of Problems\n * - Empty array means no problems found\n *\n * @example\n * ```typescript\n * const user = new User({ name: '', age: -5 });\n * const problems = EntityUtils.validate(user);\n * console.log(problems); // [Problem, Problem, ...]\n * ```\n */\n static validate<T extends object>(instance: T): Problem[] {\n if (!this.isEntity(instance)) {\n throw new Error('Cannot validate non-entity instance');\n }\n\n const problems: Problem[] = [];\n\n const keys = this.getPropertyKeys(instance);\n for (const key of keys) {\n const options = this.getPropertyOptions(instance, key);\n if (options) {\n const value = (instance as any)[key];\n if (value != null) {\n const validationProblems = this.runPropertyValidators(\n key,\n value,\n options,\n );\n problems.push(...validationProblems);\n }\n }\n }\n\n const entityValidators = this.getEntityValidators(instance);\n for (const validatorMethod of entityValidators) {\n const validatorProblems = (instance as any)[validatorMethod]();\n if (Array.isArray(validatorProblems)) {\n problems.push(...validatorProblems);\n }\n }\n\n return problems;\n }\n\n /**\n * Gets the validation problems for an entity instance\n *\n * @param instance - The entity instance\n * @returns Array of Problems (empty if no problems or instance not parsed)\n *\n * @remarks\n * - Only returns problems from the last parse() call\n * - Returns empty array if instance was not created via parse()\n * - Returns empty array if parse() was called with strict: true\n *\n * @example\n * ```typescript\n * const user = EntityUtils.parse(User, data);\n * const problems = EntityUtils.problems(user);\n * console.log(problems); // [Problem, ...]\n * ```\n */\n static problems<T extends object>(instance: T): Problem[] {\n return problemsStorage.get(instance) || [];\n }\n\n /**\n * Gets the raw input data that was used to create an entity instance\n *\n * @param instance - The entity instance\n * @returns The raw input object, or undefined if not available\n *\n * @remarks\n * - Only available for instances created via parse()\n * - Returns a reference to the original input data (not a copy)\n *\n * @example\n * ```typescript\n * const user = EntityUtils.parse(User, { name: 'John', age: 30 });\n * const rawInput = EntityUtils.getRawInput(user);\n * console.log(rawInput); // { name: 'John', age: 30 }\n * ```\n */\n static getRawInput<T extends object>(\n instance: T,\n ): Record<string, unknown> | undefined {\n return rawInputStorage.get(instance);\n }\n\n /**\n * Gets all entity validator method names for an entity\n * @private\n */\n private static getEntityValidators(target: object): string[] {\n let currentProto: any;\n\n if (target.constructor && target === target.constructor.prototype) {\n currentProto = target;\n } else {\n currentProto = Object.getPrototypeOf(target);\n }\n\n const validators: string[] = [];\n const seen = new Set<string>();\n\n while (currentProto && currentProto !== Object.prototype) {\n const protoValidators: string[] =\n Reflect.getOwnMetadata(ENTITY_VALIDATOR_METADATA_KEY, currentProto) ||\n [];\n\n for (const validator of protoValidators) {\n if (!seen.has(validator)) {\n seen.add(validator);\n validators.push(validator);\n }\n }\n\n currentProto = Object.getPrototypeOf(currentProto);\n }\n\n return validators;\n }\n}\n"],"names":["ENTITY_METADATA_KEY","ENTITY_VALIDATOR_METADATA_KEY","PROPERTY_METADATA_KEY","PROPERTY_OPTIONS_METADATA_KEY","isEqualWith","ValidationError","Problem","prependPropertyPath","prependArrayIndex","createValidationError","combinePropertyPaths","isPrimitiveConstructor","deserializePrimitive","ok","problemsStorage","WeakMap","rawInputStorage","EntityUtils","isEntity","obj","Reflect","hasMetadata","Array","isArray","constructor","Object","getPrototypeOf","sameEntity","a","b","getPropertyKeys","target","currentProto","prototype","keys","seen","Set","protoKeys","getOwnMetadata","key","has","add","push","getPropertyOptions","propertyKey","protoOptions","undefined","equals","val1","val2","diff","length","oldEntity","newEntity","Error","diffs","oldValue","newValue","propertyOptions","areEqual","property","changes","reduce","acc","toJSON","entity","result","value","options","serializeValue","passthrough","serialize","map","item","Date","toISOString","toString","parse","entityClass","plainObject","strict","data","hardProblems","message","isOptional","optional","deserializeValue","error","problems","instance","set","validate","typeConstructor","type","array","isSparse","sparse","arrayProblems","index","deserialize","deserializeSingleValue","validatePropertyValue","propertyPath","validators","validator","validatorProblems","problem","nestedProblems","prependedProblems","runPropertyValidators","isPassthrough","valueProblems","arrayValidators","i","element","elementPath","elementProblems","validationProblems","entityValidators","getEntityValidators","validatorMethod","get","getRawInput","protoValidators"],"mappings":"AAAA,qDAAqD,GACrD,SACEA,mBAAmB,EACnBC,6BAA6B,EAC7BC,qBAAqB,EACrBC,6BAA6B,QAExB,aAAa;AACpB,SAASC,WAAW,QAAQ,YAAY;AACxC,SAASC,eAAe,QAAQ,wBAAwB;AACxD,SAASC,OAAO,QAAQ,eAAe;AACvC,SACEC,mBAAmB,EACnBC,iBAAiB,EACjBC,qBAAqB,EACrBC,oBAAoB,QACf,wBAAwB;AAC/B,SACEC,sBAAsB,EACtBC,oBAAoB,QACf,+BAA+B;AACtC,SAASC,EAAE,QAAQ,SAAS;AAE5B;;CAEC,GACD,MAAMC,kBAAkB,IAAIC;AAE5B;;CAEC,GACD,MAAMC,kBAAkB,IAAID;AAE5B,OAAO,MAAME;IACX;;;;;;;;;;;;;;;;;;;GAmBC,GACD,OAAOC,SAASC,GAAY,EAAiB;QAC3C,IAAIA,OAAO,MAAM;YACf,OAAO;QACT;QAEA,iDAAiD;QACjD,IAAI,OAAOA,QAAQ,YAAY;YAC7B,OAAOC,QAAQC,WAAW,CAACrB,qBAAqBmB;QAClD;QAEA,qCAAqC;QACrC,IAAI,OAAOA,QAAQ,YAAYG,MAAMC,OAAO,CAACJ,MAAM;YACjD,OAAO;QACT;QAEA,MAAMK,cAAcC,OAAOC,cAAc,CAACP,KAAK,WAAW;QAC1D,OAAOC,QAAQC,WAAW,CAACrB,qBAAqBwB;IAClD;IAEA,OAAOG,WAAWC,CAAS,EAAEC,CAAS,EAAW;QAC/C,IAAI,CAAC,IAAI,CAACX,QAAQ,CAACU,MAAM,CAAC,IAAI,CAACV,QAAQ,CAACW,IAAI;YAC1C,OAAO;QACT;QAEA,OAAOJ,OAAOC,cAAc,CAACE,OAAOH,OAAOC,cAAc,CAACG;IAC5D;IAEA,OAAOC,gBAAgBC,MAAc,EAAY;QAC/C,6DAA6D;QAC7D,IAAIC;QAEJ,8EAA8E;QAC9E,iDAAiD;QACjD,IAAID,OAAO,WAAW,IAAIA,WAAWA,OAAO,WAAW,CAACE,SAAS,EAAE;YACjE,gCAAgC;YAChCD,eAAeD;QACjB,OAAO;YACL,2CAA2C;YAC3CC,eAAeP,OAAOC,cAAc,CAACK;QACvC;QAEA,MAAMG,OAAiB,EAAE;QACzB,MAAMC,OAAO,IAAIC;QAEjB,+DAA+D;QAC/D,MAAOJ,gBAAgBA,iBAAiBP,OAAOQ,SAAS,CAAE;YACxD,qEAAqE;YACrE,MAAMI,YACJjB,QAAQkB,cAAc,CAACpC,uBAAuB8B,iBAAiB,EAAE;YAEnE,KAAK,MAAMO,OAAOF,UAAW;gBAC3B,IAAI,CAACF,KAAKK,GAAG,CAACD,MAAM;oBAClBJ,KAAKM,GAAG,CAACF;oBACTL,KAAKQ,IAAI,CAACH;gBACZ;YACF;YAEAP,eAAeP,OAAOC,cAAc,CAACM;QACvC;QAEA,OAAOE;IACT;IAEA,OAAOS,mBACLZ,MAAc,EACda,WAAmB,EACU;QAC7B,6DAA6D;QAC7D,IAAIZ;QAEJ,8EAA8E;QAC9E,iDAAiD;QACjD,IAAID,OAAO,WAAW,IAAIA,WAAWA,OAAO,WAAW,CAACE,SAAS,EAAE;YACjE,gCAAgC;YAChCD,eAAeD;QACjB,OAAO;YACL,2CAA2C;YAC3CC,eAAeP,OAAOC,cAAc,CAACK;QACvC;QAEA,wDAAwD;QACxD,MAAOC,gBAAgBA,iBAAiBP,OAAOQ,SAAS,CAAE;YACxD,MAAMY,eACJzB,QAAQkB,cAAc,CAACnC,+BAA+B6B,iBACtD,CAAC;YAEH,IAAIa,YAAY,CAACD,YAAY,EAAE;gBAC7B,OAAOC,YAAY,CAACD,YAAY;YAClC;YAEAZ,eAAeP,OAAOC,cAAc,CAACM;QACvC;QAEA,OAAOc;IACT;IAEA,OAAOC,OAAOnB,CAAU,EAAEC,CAAU,EAAW;QAC7C,OAAOzB,YAAYwB,GAAGC,GAAG,CAACmB,MAAMC;YAC9B,IAAI,IAAI,CAAC/B,QAAQ,CAAC8B,OAAO;gBACvB,IAAI,CAAC,IAAI,CAACrB,UAAU,CAACqB,MAAMC,OAAO;oBAChC,OAAO;gBACT;gBAEA,MAAMC,OAAO,IAAI,CAACA,IAAI,CAACF,MAAMC;gBAE7B,OAAOC,KAAKC,MAAM,KAAK;YACzB,OAAO,IACLH,QAAQ,QACRC,QAAQ,QACR,OAAOD,SAAS,YAChB,CAAC1B,MAAMC,OAAO,CAACyB,SACf,OAAOC,SAAS,YAChB,CAAC3B,MAAMC,OAAO,CAAC0B,SACf,YAAYD,QACZ,OAAOA,KAAKD,MAAM,KAAK,YACvB;gBACA,OAAOC,KAAKD,MAAM,CAACE;YACrB;YAEA,OAAOH;QACT;IACF;IAEA,OAAOI,KACLE,SAAY,EACZC,SAAY,EACkD;QAC9D,IAAI,CAAC,IAAI,CAAC1B,UAAU,CAACyB,WAAWC,YAAY;YAC1C,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAMC,QACJ,EAAE;QAEJ,MAAMrB,OAAO,IAAI,CAACJ,eAAe,CAACsB;QAElC,KAAK,MAAMb,OAAOL,KAAM;YACtB,MAAMsB,WAAW,AAACJ,SAAiB,CAACb,IAAI;YACxC,MAAMkB,WAAW,AAACJ,SAAiB,CAACd,IAAI;YAExC,8DAA8D;YAC9D,MAAMmB,kBAAkB,IAAI,CAACf,kBAAkB,CAACS,WAAWb;YAE3D,IAAIoB;YACJ,IAAIH,YAAY,QAAQC,YAAY,MAAM;gBACxCE,WAAWH,aAAaC;YAC1B,OAAO,IAAID,YAAY,QAAQC,YAAY,MAAM;gBAC/CE,WAAW;YACb,OAAO;gBACLA,WAAWD,iBAAiBX,SACxBW,gBAAgBX,MAAM,CAACS,UAAUC,YACjC,IAAI,CAACV,MAAM,CAACS,UAAUC;YAC5B;YAEA,IAAI,CAACE,UAAU;gBACbJ,MAAMb,IAAI,CAAC;oBAAEkB,UAAUrB;oBAAKiB;oBAAUC;gBAAS;YACjD;QACF;QAEA,OAAOF;IACT;IAEA,OAAOM,QAA0BT,SAAY,EAAEC,SAAY,EAAc;QACvE,IAAI,CAAC,IAAI,CAAC1B,UAAU,CAACyB,WAAWC,YAAY;YAC1C,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAMJ,OAAO,IAAI,CAACA,IAAI,CAACE,WAAWC;QAElC,OAAOH,KAAKY,MAAM,CAAC,CAACC,KAAK,EAAEH,QAAQ,EAAEH,QAAQ,EAAE;YAC5CM,GAAW,CAACH,SAAS,GAAGH;YACzB,OAAOM;QACT,GAAG,CAAC;IACN;IAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDC,GACD,OAAOC,OAAyBC,MAAS,EAA2B;QAClE,MAAMC,SAAkC,CAAC;QACzC,MAAMhC,OAAO,IAAI,CAACJ,eAAe,CAACmC;QAElC,KAAK,MAAM1B,OAAOL,KAAM;YACtB,MAAMiC,QAAQ,AAACF,MAAc,CAAC1B,IAAI;YAElC,wBAAwB;YACxB,IAAI4B,UAAUrB,WAAW;gBACvB;YACF;YAEA,MAAMsB,UAAU,IAAI,CAACzB,kBAAkB,CAACsB,QAAQ1B;YAChD2B,MAAM,CAAC3B,IAAI,GAAG,IAAI,CAAC8B,cAAc,CAACF,OAAOC;QAC3C;QAEA,OAAOF;IACT;IAEA;;;GAGC,GACD,OAAeG,eACbF,KAAc,EACdC,OAAyB,EAChB;QACT,IAAID,UAAU,MAAM;YAClB,OAAO;QACT;QAEA,IAAIA,UAAUrB,WAAW;YACvB,OAAOA;QACT;QAEA,MAAMwB,cAAcF,SAASE,gBAAgB;QAC7C,IAAIA,aAAa;YACf,OAAOH;QACT;QAEA,IAAI7C,MAAMC,OAAO,CAAC4C,QAAQ;YACxB,IAAIC,SAASG,WAAW;gBACtB,oEAAoE;gBACpE,OAAOJ,MAAMK,GAAG,CAAC,CAACC,OAASL,QAAQG,SAAS,CAAEE;YAChD;YACA,OAAON,MAAMK,GAAG,CAAC,CAACC,OAAS,IAAI,CAACJ,cAAc,CAACI;QACjD;QAEA,IAAIL,SAASG,WAAW;YACtB,OAAOH,QAAQG,SAAS,CAACJ;QAC3B;QAEA,IAAIA,iBAAiBO,MAAM;YACzB,OAAOP,MAAMQ,WAAW;QAC1B;QAEA,IAAI,OAAOR,UAAU,UAAU;YAC7B,OAAOA,MAAMS,QAAQ;QACvB;QAEA,IAAI,IAAI,CAAC1D,QAAQ,CAACiD,QAAQ;YACxB,OAAO,IAAI,CAACH,MAAM,CAACG;QACrB;QAEA,IACE,OAAOA,UAAU,YACjB,OAAOA,UAAU,YACjB,OAAOA,UAAU,WACjB;YACA,OAAOA;QACT;QAEA,MAAM,IAAIb,MACR,CAAC,gCAAgC,EAAE,OAAOa,MAAM,2FAA2F,CAAC;IAEhJ;IAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CC,GACD,OAAOU,MACLC,WAAiC,EACjCC,WAAoC,EACpCX,OAA8B,EAC3B;QACH,MAAMY,SAASZ,SAASY,UAAU;QAClC,MAAM9C,OAAO,IAAI,CAACJ,eAAe,CAACgD,YAAY7C,SAAS;QACvD,MAAMgD,OAAgC,CAAC;QACvC,MAAMC,eAA0B,EAAE;QAElC,KAAK,MAAM3C,OAAOL,KAAM;YACtB,MAAMwB,kBAAkB,IAAI,CAACf,kBAAkB,CAC7CmC,YAAY7C,SAAS,EACrBM;YAGF,IAAI,CAACmB,iBAAiB;gBACpBwB,aAAaxC,IAAI,CACf,IAAIpC,QAAQ;oBACVsD,UAAUrB;oBACV4C,SAAS,CAAC,mFAAmF,CAAC;gBAChG;gBAEF;YACF;YAEA,IAAIzB,gBAAgBY,WAAW,KAAK,MAAM;gBACxC,MAAMH,QAAQY,WAAW,CAACxC,IAAI;gBAC9B0C,IAAI,CAAC1C,IAAI,GAAG4B;gBACZ;YACF;YAEA,MAAMA,QAAQY,WAAW,CAACxC,IAAI;YAC9B,MAAM6C,aAAa1B,gBAAgB2B,QAAQ,KAAK;YAEhD,IAAI,CAAE9C,CAAAA,OAAOwC,WAAU,GAAI;gBACzB,IAAI,CAACK,YAAY;oBACfF,aAAaxC,IAAI,CACf,IAAIpC,QAAQ;wBACVsD,UAAUrB;wBACV4C,SAAS;oBACX;gBAEJ;gBACA;YACF;YAEA,IAAIhB,UAAU,QAAQA,UAAUrB,WAAW;gBACzC,IAAI,CAACsC,YAAY;oBACfF,aAAaxC,IAAI,CACf,IAAIpC,QAAQ;wBACVsD,UAAUrB;wBACV4C,SAAS;oBACX;gBAEJ;gBACAF,IAAI,CAAC1C,IAAI,GAAG4B;gBACZ;YACF;YAEA,IAAI;gBACFc,IAAI,CAAC1C,IAAI,GAAG,IAAI,CAAC+C,gBAAgB,CAACnB,OAAOT;YAC3C,EAAE,OAAO6B,OAAO;gBACd,IAAIA,iBAAiBlF,iBAAiB;oBACpC,MAAMmF,WAAWjF,oBAAoBgC,KAAKgD;oBAC1CL,aAAaxC,IAAI,IAAI8C;gBACvB,OAAO,IAAID,iBAAiBjC,OAAO;oBACjC4B,aAAaxC,IAAI,CACf,IAAIpC,QAAQ;wBACVsD,UAAUrB;wBACV4C,SAASI,MAAMJ,OAAO;oBACxB;gBAEJ,OAAO;oBACL,MAAMI;gBACR;YACF;QACF;QAEA,IAAIL,aAAa/B,MAAM,GAAG,GAAG;YAC3B,MAAM,IAAI9C,gBAAgB6E;QAC5B;QAEA,MAAMO,WAAW,IAAIX,YAAYG;QAEjCjE,gBAAgB0E,GAAG,CAACD,UAAUV;QAE9B,MAAMS,WAAW,IAAI,CAACG,QAAQ,CAACF;QAE/B,IAAID,SAASrC,MAAM,GAAG,GAAG;YACvB,IAAI6B,QAAQ;gBACV,MAAM,IAAI3E,gBAAgBmF;YAC5B,OAAO;gBACL1E,gBAAgB4E,GAAG,CAACD,UAAUD;YAChC;QACF;QAEA,OAAOC;IACT;IAEA;;;GAGC,GACD,OAAeH,iBACbnB,KAAc,EACdC,OAAwB,EACf;QACT,oEAAoE;QACpE,MAAMwB,kBAAkBxB,QAAQyB,IAAI;QACpC,MAAMtE,UAAU6C,QAAQ0B,KAAK,KAAK;QAClC,MAAMC,WAAW3B,QAAQ4B,MAAM,KAAK;QAEpC,IAAIzE,SAAS;YACX,IAAI,CAACD,MAAMC,OAAO,CAAC4C,QAAQ;gBACzB,MAAM1D,sBACJ,CAAC,8BAA8B,EAAE,OAAO0D,OAAO;YAEnD;YAEA,MAAM8B,gBAA2B,EAAE;YACnC,MAAM/B,SAAoB,EAAE;YAE5B,IAAK,IAAIgC,QAAQ,GAAGA,QAAQ/B,MAAMhB,MAAM,EAAE+C,QAAS;gBACjD,MAAMzB,OAAON,KAAK,CAAC+B,MAAM;gBACzB,IAAIzB,SAAS,QAAQA,SAAS3B,WAAW;oBACvC,IAAI,CAACiD,UAAU;wBACbE,cAAcvD,IAAI,CAChB,IAAIpC,QAAQ;4BACVsD,UAAU,CAAC,CAAC,EAAEsC,MAAM,CAAC,CAAC;4BACtBf,SAAS;wBACX;oBAEJ;oBACAjB,OAAOxB,IAAI,CAAC+B;gBACd,OAAO;oBACL,IAAI;wBACF,IAAIL,QAAQ+B,WAAW,EAAE;4BACvBjC,OAAOxB,IAAI,CAAC0B,QAAQ+B,WAAW,CAAC1B;wBAClC,OAAO;4BACLP,OAAOxB,IAAI,CAAC,IAAI,CAAC0D,sBAAsB,CAAC3B,MAAMmB;wBAChD;oBACF,EAAE,OAAOL,OAAO;wBACd,IAAIA,iBAAiBlF,iBAAiB;4BACpC,MAAMmF,WAAWhF,kBAAkB0F,OAAOX;4BAC1CU,cAAcvD,IAAI,IAAI8C;wBACxB,OAAO;4BACL,MAAMD;wBACR;oBACF;gBACF;YACF;YAEA,IAAIU,cAAc9C,MAAM,GAAG,GAAG;gBAC5B,MAAM,IAAI9C,gBAAgB4F;YAC5B;YAEA,OAAO/B;QACT;QAEA,IAAIE,QAAQ+B,WAAW,EAAE;YACvB,OAAO/B,QAAQ+B,WAAW,CAAChC;QAC7B;QAEA,OAAO,IAAI,CAACiC,sBAAsB,CAACjC,OAAOyB;IAC5C;IAEA;;;;GAIC,GACD,OAAeQ,uBACbjC,KAAc,EACdyB,eAAoB,EACX;QACT,IAAIjF,uBAAuBiF,kBAAkB;YAC3C,OAAOhF,qBAAqBuD,OAAOyB;QACrC;QAEA,IAAI,IAAI,CAAC1E,QAAQ,CAAC0E,kBAAkB;YAClC,IAAI,OAAOzB,UAAU,YAAYA,UAAU,QAAQ7C,MAAMC,OAAO,CAAC4C,QAAQ;gBACvE,MAAM1D,sBACJ,CAAC,+BAA+B,EAAE,OAAO0D,OAAO;YAEpD;YAEA,OAAO,IAAI,CAACU,KAAK,CACfe,iBACAzB;QAEJ;QAEA,MAAM1D,sBACJ,CAAC,yKAAyK,CAAC;IAE/K;IAEA;;;;GAIC,GACD,OAAe4F,sBACbC,YAAoB,EACpBnC,KAAc,EACdoC,UAAyC,EAC9B;QACX,MAAMf,WAAsB,EAAE;QAE9B,IAAIe,YAAY;YACd,KAAK,MAAMC,aAAaD,WAAY;gBAClC,MAAME,oBAAoBD,UAAU;oBAAErC;gBAAM;gBAC5C,uCAAuC;gBACvC,KAAK,MAAMuC,WAAWD,kBAAmB;oBACvCjB,SAAS9C,IAAI,CACX,IAAIpC,QAAQ;wBACVsD,UAAUlD,qBAAqB4F,cAAcI,QAAQ9C,QAAQ;wBAC7DuB,SAASuB,QAAQvB,OAAO;oBAC1B;gBAEJ;YACF;QACF;QAEA,IAAIlE,YAAYC,QAAQ,CAACiD,QAAQ;YAC/B,MAAMwC,iBAAiB1F,YAAY0E,QAAQ,CAACxB;YAC5C,MAAMyC,oBAAoBrG,oBACxB+F,cACA,IAAIjG,gBAAgBsG;YAEtBnB,SAAS9C,IAAI,IAAIkE;QACnB;QAEA,OAAOpB;IACT;IAEA;;;GAGC,GACD,OAAeqB,sBACbtE,GAAW,EACX4B,KAAc,EACdC,OAAwB,EACb;QACX,MAAMoB,WAAsB,EAAE;QAC9B,MAAMjE,UAAU6C,SAAS0B,UAAU;QACnC,MAAMgB,gBAAgB1C,SAASE,gBAAgB;QAE/C,IAAIwC,iBAAiB,CAACvF,SAAS;YAC7B,MAAMwF,gBAAgB,IAAI,CAACV,qBAAqB,CAC9C9D,KACA4B,OACAC,QAAQmC,UAAU;YAEpBf,SAAS9C,IAAI,IAAIqE;QACnB,OAAO;YACLlG,GAAGS,MAAMC,OAAO,CAAC4C,QAAQ;YAEzB,MAAM6C,kBAAkB5C,QAAQ4C,eAAe,IAAI,EAAE;YACrD,KAAK,MAAMR,aAAaQ,gBAAiB;gBACvC,MAAMP,oBAAoBD,UAAU;oBAAErC;gBAAM;gBAC5C,KAAK,MAAMuC,WAAWD,kBAAmB;oBACvCjB,SAAS9C,IAAI,CACX,IAAIpC,QAAQ;wBACVsD,UAAUlD,qBAAqB6B,KAAKmE,QAAQ9C,QAAQ;wBACpDuB,SAASuB,QAAQvB,OAAO;oBAC1B;gBAEJ;YACF;YAEA,MAAMoB,aAAanC,QAAQmC,UAAU,IAAI,EAAE;YAC3C,IAAIA,WAAWpD,MAAM,GAAG,GAAG;gBACzB,IAAK,IAAI8D,IAAI,GAAGA,IAAI9C,MAAMhB,MAAM,EAAE8D,IAAK;oBACrC,MAAMC,UAAU/C,KAAK,CAAC8C,EAAE;oBACxB,IAAIC,YAAY,QAAQA,YAAYpE,WAAW;wBAC7C,MAAMqE,cAAc,GAAG5E,IAAI,CAAC,EAAE0E,EAAE,CAAC,CAAC;wBAClC,MAAMG,kBAAkB,IAAI,CAACf,qBAAqB,CAChDc,aACAD,SACAX;wBAEFf,SAAS9C,IAAI,IAAI0E;oBACnB;gBACF;YACF;QACF;QAEA,OAAO5B;IACT;IAEA;;;;;;;;;;;;;;;;;GAiBC,GACD,OAAOG,SAA2BF,QAAW,EAAa;QACxD,IAAI,CAAC,IAAI,CAACvE,QAAQ,CAACuE,WAAW;YAC5B,MAAM,IAAInC,MAAM;QAClB;QAEA,MAAMkC,WAAsB,EAAE;QAE9B,MAAMtD,OAAO,IAAI,CAACJ,eAAe,CAAC2D;QAClC,KAAK,MAAMlD,OAAOL,KAAM;YACtB,MAAMkC,UAAU,IAAI,CAACzB,kBAAkB,CAAC8C,UAAUlD;YAClD,IAAI6B,SAAS;gBACX,MAAMD,QAAQ,AAACsB,QAAgB,CAAClD,IAAI;gBACpC,IAAI4B,SAAS,MAAM;oBACjB,MAAMkD,qBAAqB,IAAI,CAACR,qBAAqB,CACnDtE,KACA4B,OACAC;oBAEFoB,SAAS9C,IAAI,IAAI2E;gBACnB;YACF;QACF;QAEA,MAAMC,mBAAmB,IAAI,CAACC,mBAAmB,CAAC9B;QAClD,KAAK,MAAM+B,mBAAmBF,iBAAkB;YAC9C,MAAMb,oBAAoB,AAAChB,QAAgB,CAAC+B,gBAAgB;YAC5D,IAAIlG,MAAMC,OAAO,CAACkF,oBAAoB;gBACpCjB,SAAS9C,IAAI,IAAI+D;YACnB;QACF;QAEA,OAAOjB;IACT;IAEA;;;;;;;;;;;;;;;;;GAiBC,GACD,OAAOA,SAA2BC,QAAW,EAAa;QACxD,OAAO3E,gBAAgB2G,GAAG,CAAChC,aAAa,EAAE;IAC5C;IAEA;;;;;;;;;;;;;;;;GAgBC,GACD,OAAOiC,YACLjC,QAAW,EAC0B;QACrC,OAAOzE,gBAAgByG,GAAG,CAAChC;IAC7B;IAEA;;;GAGC,GACD,OAAe8B,oBAAoBxF,MAAc,EAAY;QAC3D,IAAIC;QAEJ,IAAID,OAAO,WAAW,IAAIA,WAAWA,OAAO,WAAW,CAACE,SAAS,EAAE;YACjED,eAAeD;QACjB,OAAO;YACLC,eAAeP,OAAOC,cAAc,CAACK;QACvC;QAEA,MAAMwE,aAAuB,EAAE;QAC/B,MAAMpE,OAAO,IAAIC;QAEjB,MAAOJ,gBAAgBA,iBAAiBP,OAAOQ,SAAS,CAAE;YACxD,MAAM0F,kBACJvG,QAAQkB,cAAc,CAACrC,+BAA+B+B,iBACtD,EAAE;YAEJ,KAAK,MAAMwE,aAAamB,gBAAiB;gBACvC,IAAI,CAACxF,KAAKK,GAAG,CAACgE,YAAY;oBACxBrE,KAAKM,GAAG,CAAC+D;oBACTD,WAAW7D,IAAI,CAAC8D;gBAClB;YACF;YAEAxE,eAAeP,OAAOC,cAAc,CAACM;QACvC;QAEA,OAAOuE;IACT;AACF"}
1
+ {"version":3,"sources":["../../src/lib/entity-utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n ENTITY_METADATA_KEY,\n ENTITY_VALIDATOR_METADATA_KEY,\n PROPERTY_METADATA_KEY,\n PROPERTY_OPTIONS_METADATA_KEY,\n PropertyOptions,\n} from './types.js';\nimport { isEqualWith } from 'lodash-es';\nimport { ValidationError } from './validation-error.js';\nimport { Problem } from './problem.js';\nimport {\n prependPropertyPath,\n prependArrayIndex,\n createValidationError,\n combinePropertyPaths,\n} from './validation-utils.js';\nimport {\n isPrimitiveConstructor,\n deserializePrimitive,\n} from './primitive-deserializers.js';\nimport { ok } from 'assert';\n\n/**\n * WeakMap to store validation problems for entity instances\n */\nconst problemsStorage = new WeakMap<object, Problem[]>();\n\n/**\n * WeakMap to store raw input data for entity instances\n */\nconst rawInputStorage = new WeakMap<object, Record<string, unknown>>();\n\nexport class EntityUtils {\n /**\n * Checks if a given object is an instance of a class decorated with @Entity()\n * or if the provided value is an entity class itself\n *\n * @param obj - The object or class to check\n * @returns true if the object is an entity instance or entity class, false otherwise\n *\n * @example\n * ```typescript\n * @Entity()\n * class User {\n * name: string;\n * }\n *\n * const user = new User();\n * console.log(EntityUtils.isEntity(user)); // true\n * console.log(EntityUtils.isEntity(User)); // true\n * console.log(EntityUtils.isEntity({})); // false\n * ```\n */\n static isEntity(obj: unknown): obj is object {\n if (obj == null) {\n return false;\n }\n\n // Check if obj is a constructor function (class)\n if (typeof obj === 'function') {\n return Reflect.hasMetadata(ENTITY_METADATA_KEY, obj);\n }\n\n // Check if obj is an object instance\n if (typeof obj !== 'object' || Array.isArray(obj)) {\n return false;\n }\n\n const constructor = Object.getPrototypeOf(obj).constructor;\n return Reflect.hasMetadata(ENTITY_METADATA_KEY, constructor);\n }\n\n static sameEntity(a: object, b: object): boolean {\n if (!this.isEntity(a) || !this.isEntity(b)) {\n return false;\n }\n\n return Object.getPrototypeOf(a) === Object.getPrototypeOf(b);\n }\n\n static getPropertyKeys(target: object): string[] {\n // Determine if we're dealing with a prototype or an instance\n let currentProto: any;\n\n // Check if target is a prototype by checking if it has a constructor property\n // and if target === target.constructor.prototype\n if (target.constructor && target === target.constructor.prototype) {\n // target is already a prototype\n currentProto = target;\n } else {\n // target is an instance, get its prototype\n currentProto = Object.getPrototypeOf(target);\n }\n\n const keys: string[] = [];\n const seen = new Set<string>();\n\n // Walk the prototype chain to collect all inherited properties\n while (currentProto && currentProto !== Object.prototype) {\n // Use getOwnMetadata to only get metadata directly on this prototype\n const protoKeys: string[] =\n Reflect.getOwnMetadata(PROPERTY_METADATA_KEY, currentProto) || [];\n\n for (const key of protoKeys) {\n if (!seen.has(key)) {\n seen.add(key);\n keys.push(key);\n }\n }\n\n currentProto = Object.getPrototypeOf(currentProto);\n }\n\n return keys;\n }\n\n static getPropertyOptions(\n target: object,\n propertyKey: string,\n ): PropertyOptions | undefined {\n // Determine if we're dealing with a prototype or an instance\n let currentProto: any;\n\n // Check if target is a prototype by checking if it has a constructor property\n // and if target === target.constructor.prototype\n if (target.constructor && target === target.constructor.prototype) {\n // target is already a prototype\n currentProto = target;\n } else {\n // target is an instance, get its prototype\n currentProto = Object.getPrototypeOf(target);\n }\n\n // Walk the prototype chain to find the property options\n while (currentProto && currentProto !== Object.prototype) {\n const protoOptions: Record<string, PropertyOptions> =\n Reflect.getOwnMetadata(PROPERTY_OPTIONS_METADATA_KEY, currentProto) ||\n {};\n\n if (protoOptions[propertyKey]) {\n return protoOptions[propertyKey];\n }\n\n currentProto = Object.getPrototypeOf(currentProto);\n }\n\n return undefined;\n }\n\n static equals(a: unknown, b: unknown): boolean {\n return isEqualWith(a, b, (val1, val2) => {\n if (this.isEntity(val1)) {\n if (!this.sameEntity(val1, val2)) {\n return false;\n }\n\n const diff = this.diff(val1, val2);\n\n return diff.length === 0;\n } else if (\n val1 != null &&\n val2 != null &&\n typeof val1 === 'object' &&\n !Array.isArray(val1) &&\n typeof val2 === 'object' &&\n !Array.isArray(val2) &&\n 'equals' in val1 &&\n typeof val1.equals === 'function'\n ) {\n return val1.equals(val2);\n }\n\n return undefined;\n });\n }\n\n static diff<T extends object>(\n oldEntity: T,\n newEntity: T,\n ): { property: string; oldValue: unknown; newValue: unknown }[] {\n if (!this.sameEntity(oldEntity, newEntity)) {\n throw new Error('Entities must be of the same type to compute diff');\n }\n\n const diffs: { property: string; oldValue: unknown; newValue: unknown }[] =\n [];\n\n const keys = this.getPropertyKeys(oldEntity);\n\n for (const key of keys) {\n const oldValue = (oldEntity as any)[key];\n const newValue = (newEntity as any)[key];\n\n // Check if there's a custom equals function for this property\n const propertyOptions = this.getPropertyOptions(oldEntity, key);\n\n let areEqual: boolean;\n if (oldValue == null && newValue == null) {\n areEqual = oldValue === newValue;\n } else if (oldValue == null || newValue == null) {\n areEqual = false;\n } else {\n areEqual = propertyOptions?.equals\n ? propertyOptions.equals(oldValue, newValue)\n : this.equals(oldValue, newValue);\n }\n\n if (!areEqual) {\n diffs.push({ property: key, oldValue, newValue });\n }\n }\n\n return diffs;\n }\n\n static changes<T extends object>(oldEntity: T, newEntity: T): Partial<T> {\n if (!this.sameEntity(oldEntity, newEntity)) {\n throw new Error('Entities must be of the same type to compute changes');\n }\n\n const diff = this.diff(oldEntity, newEntity);\n\n return diff.reduce((acc, { property, newValue }) => {\n (acc as any)[property] = newValue;\n return acc;\n }, {} as Partial<T>);\n }\n\n /**\n * Serializes an entity to a plain object, converting only properties decorated with @Property()\n *\n * @param entity - The entity instance to serialize\n * @returns A plain object containing only the serialized decorated properties\n *\n * @remarks\n * Serialization rules:\n * - Only properties decorated with @Property() are included\n * - If a property has a custom toJSON() method, it will be used\n * - Nested entities are recursively serialized using EntityUtils.toJSON()\n * - Arrays are mapped with toJSON() applied to each element\n * - Date objects are serialized to ISO strings\n * - bigint values are serialized to strings\n * - undefined values are excluded from the output\n * - null values are included in the output\n * - Circular references are not supported (will cause stack overflow)\n *\n * @example\n * ```typescript\n * @Entity()\n * class Address {\n * @Property() street: string;\n * @Property() city: string;\n * }\n *\n * @Entity()\n * class User {\n * @Property() name: string;\n * @Property() address: Address;\n * @Property() createdAt: Date;\n * undecorated: string; // Will not be serialized\n * }\n *\n * const user = new User();\n * user.name = 'John';\n * user.address = new Address();\n * user.address.street = '123 Main St';\n * user.address.city = 'Boston';\n * user.createdAt = new Date('2024-01-01');\n * user.undecorated = 'ignored';\n *\n * const json = EntityUtils.toJSON(user);\n * // {\n * // name: 'John',\n * // address: { street: '123 Main St', city: 'Boston' },\n * // createdAt: '2024-01-01T00:00:00.000Z'\n * // }\n * ```\n */\n static toJSON<T extends object>(entity: T): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const keys = this.getPropertyKeys(entity);\n\n for (const key of keys) {\n const value = (entity as any)[key];\n\n // Skip undefined values\n if (value === undefined) {\n continue;\n }\n\n const options = this.getPropertyOptions(entity, key);\n result[key] = this.serializeValue(value, options);\n }\n\n return result;\n }\n\n /**\n * Serializes a single value according to the toJSON rules\n * @private\n */\n private static serializeValue(\n value: unknown,\n options?: PropertyOptions,\n ): unknown {\n if (value === null) {\n return null;\n }\n\n if (value === undefined) {\n return undefined;\n }\n\n const passthrough = options?.passthrough === true;\n if (passthrough) {\n return value;\n }\n\n if (Array.isArray(value)) {\n if (options?.serialize) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return value.map((item) => options.serialize!(item as any));\n }\n return value.map((item) => this.serializeValue(item));\n }\n\n if (options?.serialize) {\n return options.serialize(value as any);\n }\n\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n if (typeof value === 'bigint') {\n return value.toString();\n }\n\n if (this.isEntity(value)) {\n return this.toJSON(value);\n }\n\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n\n throw new Error(\n `Cannot serialize value of type '${typeof value}'. Use passthrough: true in @Property() to explicitly allow serialization of unknown types.`,\n );\n }\n\n /**\n * Deserializes a plain object to an entity instance\n *\n * @param entityClass - The entity class constructor. Must accept a data object parameter.\n * @param plainObject - The plain object to deserialize\n * @param options - Parse options (strict mode)\n * @returns Promise resolving to a new instance of the entity with deserialized values\n *\n * @remarks\n * Deserialization rules:\n * - All @Property() decorators must include type metadata for parse() to work\n * - Properties without type metadata will throw an error\n * - Required properties (optional !== true) must be present and not null/undefined\n * - Optional properties (optional === true) can be undefined or null\n * - Arrays are supported with the array: true option\n * - Nested entities are recursively deserialized\n * - Type conversion is strict (no coercion)\n * - Entity constructors must accept a required data parameter\n *\n * Validation behavior:\n * - If strict: true - both HARD and SOFT problems throw ValidationError\n * - If strict: false (default) - HARD problems throw ValidationError, SOFT problems stored\n * - Property validators run first, then entity validators\n * - Validators can be synchronous or asynchronous\n * - Problems are accessible via EntityUtils.problems()\n * - Raw input data is accessible via EntityUtils.getRawInput()\n *\n * @example\n * ```typescript\n * @Entity()\n * class User {\n * @Property({ type: () => String }) name!: string;\n * @Property({ type: () => Number }) age!: number;\n *\n * constructor(data: Partial<User>) {\n * Object.assign(this, data);\n * }\n * }\n *\n * const json = { name: 'John', age: 30 };\n * const user = await EntityUtils.parse(User, json);\n * const userStrict = await EntityUtils.parse(User, json, { strict: true });\n * ```\n */\n static async parse<T extends object>(\n entityClass: new (data: any) => T,\n plainObject: unknown,\n options?: { strict?: boolean },\n ): Promise<T> {\n if (plainObject == null) {\n throw createValidationError(\n `Expects an object but received ${typeof plainObject}`,\n );\n }\n if (Array.isArray(plainObject)) {\n throw createValidationError(`Expects an object but received array`);\n }\n if (typeof plainObject !== 'object') {\n throw createValidationError(\n `Expects an object but received ${typeof plainObject}`,\n );\n }\n\n const strict = options?.strict ?? false;\n const keys = this.getPropertyKeys(entityClass.prototype);\n const data: Record<string, unknown> = {};\n const hardProblems: Problem[] = [];\n\n for (const key of keys) {\n const propertyOptions = this.getPropertyOptions(\n entityClass.prototype,\n key,\n );\n\n if (!propertyOptions) {\n hardProblems.push(\n new Problem({\n property: key,\n message: `Property has no metadata. This should not happen if @Property() was used correctly.`,\n }),\n );\n continue;\n }\n\n const value = (plainObject as Record<string, unknown>)[key];\n\n if (propertyOptions.passthrough === true) {\n data[key] = value;\n continue;\n }\n\n const isOptional = propertyOptions.optional === true;\n\n if (!(key in plainObject)) {\n if (!isOptional) {\n hardProblems.push(\n new Problem({\n property: key,\n message: 'Required property is missing from input',\n }),\n );\n }\n continue;\n }\n\n if (value === null || value === undefined) {\n if (!isOptional) {\n hardProblems.push(\n new Problem({\n property: key,\n message: 'Cannot be null or undefined',\n }),\n );\n }\n data[key] = value;\n continue;\n }\n\n try {\n data[key] = await this.deserializeValue(value, propertyOptions);\n } catch (error) {\n if (error instanceof ValidationError) {\n const problems = prependPropertyPath(key, error);\n hardProblems.push(...problems);\n } else if (error instanceof Error) {\n hardProblems.push(\n new Problem({\n property: key,\n message: error.message,\n }),\n );\n } else {\n throw error;\n }\n }\n }\n\n if (hardProblems.length > 0) {\n throw new ValidationError(hardProblems);\n }\n\n const instance = new entityClass(data);\n\n rawInputStorage.set(instance, plainObject as Record<string, unknown>);\n\n const problems = await this.validate(instance);\n\n if (problems.length > 0) {\n if (strict) {\n throw new ValidationError(problems);\n } else {\n problemsStorage.set(instance, problems);\n }\n }\n\n return instance;\n }\n\n /**\n * Deserializes a single value according to the type metadata\n * @private\n */\n private static async deserializeValue(\n value: unknown,\n options: PropertyOptions,\n ): Promise<unknown> {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const typeConstructor = options.type!();\n const isArray = options.array === true;\n const isSparse = options.sparse === true;\n\n if (isArray) {\n if (!Array.isArray(value)) {\n throw createValidationError(\n `Expects an array but received ${typeof value}`,\n );\n }\n\n const arrayProblems: Problem[] = [];\n const result: unknown[] = [];\n\n for (let index = 0; index < value.length; index++) {\n const item = value[index];\n if (item === null || item === undefined) {\n if (!isSparse) {\n arrayProblems.push(\n new Problem({\n property: `[${index}]`,\n message: 'Cannot be null or undefined.',\n }),\n );\n }\n result.push(item);\n } else {\n try {\n if (options.deserialize) {\n result.push(options.deserialize(item));\n } else {\n result.push(\n await this.deserializeSingleValue(item, typeConstructor),\n );\n }\n } catch (error) {\n if (error instanceof ValidationError) {\n const problems = prependArrayIndex(index, error);\n arrayProblems.push(...problems);\n } else {\n throw error;\n }\n }\n }\n }\n\n if (arrayProblems.length > 0) {\n throw new ValidationError(arrayProblems);\n }\n\n return result;\n }\n\n if (options.deserialize) {\n return options.deserialize(value);\n }\n\n return await this.deserializeSingleValue(value, typeConstructor);\n }\n\n /**\n * Deserializes a single non-array value\n * Reports validation errors with empty property (caller will prepend context)\n * @private\n */\n private static async deserializeSingleValue(\n value: unknown,\n typeConstructor: any,\n ): Promise<unknown> {\n if (isPrimitiveConstructor(typeConstructor)) {\n return deserializePrimitive(value, typeConstructor);\n }\n\n if (this.isEntity(typeConstructor)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw createValidationError(\n `Expects an object but received ${typeof value}`,\n );\n }\n\n return await this.parse(\n typeConstructor as new (data: any) => object,\n value as Record<string, unknown>,\n );\n }\n\n throw createValidationError(\n `Has unknown type constructor. Supported types are: String, Number, Boolean, Date, BigInt, and @Entity() classes. Use passthrough: true to explicitly allow unknown types.`,\n );\n }\n\n /**\n * Validates a property value by running validators and nested entity validation.\n * Prepends the property path to all returned problems.\n * @private\n */\n private static async validatePropertyValue(\n propertyPath: string,\n value: unknown,\n validators: PropertyOptions['validators'],\n ): Promise<Problem[]> {\n const problems: Problem[] = [];\n\n if (validators) {\n for (const validator of validators) {\n const validatorProblems = await validator({ value });\n // Prepend propertyPath to all problems\n for (const problem of validatorProblems) {\n problems.push(\n new Problem({\n property: combinePropertyPaths(propertyPath, problem.property),\n message: problem.message,\n }),\n );\n }\n }\n }\n\n if (EntityUtils.isEntity(value)) {\n const nestedProblems = await EntityUtils.validate(value);\n const prependedProblems = prependPropertyPath(\n propertyPath,\n new ValidationError(nestedProblems),\n );\n problems.push(...prependedProblems);\n }\n\n return problems;\n }\n\n /**\n * Runs property validators for a given property value\n * @private\n */\n private static async runPropertyValidators(\n key: string,\n value: unknown,\n options: PropertyOptions,\n ): Promise<Problem[]> {\n const problems: Problem[] = [];\n const isArray = options?.array === true;\n const isPassthrough = options?.passthrough === true;\n\n if (isPassthrough || !isArray) {\n const valueProblems = await this.validatePropertyValue(\n key,\n value,\n options.validators,\n );\n problems.push(...valueProblems);\n } else {\n ok(Array.isArray(value), 'Value must be an array for array property');\n\n const arrayValidators = options.arrayValidators || [];\n for (const validator of arrayValidators) {\n const validatorProblems = await validator({ value });\n for (const problem of validatorProblems) {\n problems.push(\n new Problem({\n property: combinePropertyPaths(key, problem.property),\n message: problem.message,\n }),\n );\n }\n }\n\n const validators = options.validators || [];\n if (validators.length > 0) {\n for (let i = 0; i < value.length; i++) {\n const element = value[i];\n if (element !== null && element !== undefined) {\n const elementPath = `${key}[${i}]`;\n const elementProblems = await this.validatePropertyValue(\n elementPath,\n element,\n validators,\n );\n problems.push(...elementProblems);\n }\n }\n }\n }\n\n return problems;\n }\n\n /**\n * Validates an entity instance by running all property and entity validators\n *\n * @param instance - The entity instance to validate\n * @returns Promise resolving to array of Problems found during validation (empty if valid)\n *\n * @remarks\n * - Property validators run first, then entity validators\n * - Each validator can be synchronous or asynchronous\n * - Empty array means no problems found\n *\n * @example\n * ```typescript\n * const user = new User({ name: '', age: -5 });\n * const problems = await EntityUtils.validate(user);\n * console.log(problems); // [Problem, Problem, ...]\n * ```\n */\n static async validate<T extends object>(instance: T): Promise<Problem[]> {\n if (!this.isEntity(instance)) {\n throw new Error('Cannot validate non-entity instance');\n }\n\n const problems: Problem[] = [];\n\n const keys = this.getPropertyKeys(instance);\n for (const key of keys) {\n const options = this.getPropertyOptions(instance, key);\n if (options) {\n const value = (instance as any)[key];\n if (value != null) {\n const validationProblems = await this.runPropertyValidators(\n key,\n value,\n options,\n );\n problems.push(...validationProblems);\n }\n }\n }\n\n const entityValidators = this.getEntityValidators(instance);\n for (const validatorMethod of entityValidators) {\n const validatorProblems = await (instance as any)[validatorMethod]();\n if (Array.isArray(validatorProblems)) {\n problems.push(...validatorProblems);\n }\n }\n\n return problems;\n }\n\n /**\n * Gets the validation problems for an entity instance\n *\n * @param instance - The entity instance\n * @returns Array of Problems (empty if no problems or instance not parsed)\n *\n * @remarks\n * - Only returns problems from the last parse() call\n * - Returns empty array if instance was not created via parse()\n * - Returns empty array if parse() was called with strict: true\n *\n * @example\n * ```typescript\n * const user = EntityUtils.parse(User, data);\n * const problems = EntityUtils.problems(user);\n * console.log(problems); // [Problem, ...]\n * ```\n */\n static problems<T extends object>(instance: T): Problem[] {\n return problemsStorage.get(instance) || [];\n }\n\n /**\n * Gets the raw input data that was used to create an entity instance\n *\n * @param instance - The entity instance\n * @returns The raw input object, or undefined if not available\n *\n * @remarks\n * - Only available for instances created via parse()\n * - Returns a reference to the original input data (not a copy)\n *\n * @example\n * ```typescript\n * const user = EntityUtils.parse(User, { name: 'John', age: 30 });\n * const rawInput = EntityUtils.getRawInput(user);\n * console.log(rawInput); // { name: 'John', age: 30 }\n * ```\n */\n static getRawInput<T extends object>(\n instance: T,\n ): Record<string, unknown> | undefined {\n return rawInputStorage.get(instance);\n }\n\n /**\n * Gets all entity validator method names for an entity\n * @private\n */\n private static getEntityValidators(target: object): string[] {\n let currentProto: any;\n\n if (target.constructor && target === target.constructor.prototype) {\n currentProto = target;\n } else {\n currentProto = Object.getPrototypeOf(target);\n }\n\n const validators: string[] = [];\n const seen = new Set<string>();\n\n while (currentProto && currentProto !== Object.prototype) {\n const protoValidators: string[] =\n Reflect.getOwnMetadata(ENTITY_VALIDATOR_METADATA_KEY, currentProto) ||\n [];\n\n for (const validator of protoValidators) {\n if (!seen.has(validator)) {\n seen.add(validator);\n validators.push(validator);\n }\n }\n\n currentProto = Object.getPrototypeOf(currentProto);\n }\n\n return validators;\n }\n}\n"],"names":["ENTITY_METADATA_KEY","ENTITY_VALIDATOR_METADATA_KEY","PROPERTY_METADATA_KEY","PROPERTY_OPTIONS_METADATA_KEY","isEqualWith","ValidationError","Problem","prependPropertyPath","prependArrayIndex","createValidationError","combinePropertyPaths","isPrimitiveConstructor","deserializePrimitive","ok","problemsStorage","WeakMap","rawInputStorage","EntityUtils","isEntity","obj","Reflect","hasMetadata","Array","isArray","constructor","Object","getPrototypeOf","sameEntity","a","b","getPropertyKeys","target","currentProto","prototype","keys","seen","Set","protoKeys","getOwnMetadata","key","has","add","push","getPropertyOptions","propertyKey","protoOptions","undefined","equals","val1","val2","diff","length","oldEntity","newEntity","Error","diffs","oldValue","newValue","propertyOptions","areEqual","property","changes","reduce","acc","toJSON","entity","result","value","options","serializeValue","passthrough","serialize","map","item","Date","toISOString","toString","parse","entityClass","plainObject","strict","data","hardProblems","message","isOptional","optional","deserializeValue","error","problems","instance","set","validate","typeConstructor","type","array","isSparse","sparse","arrayProblems","index","deserialize","deserializeSingleValue","validatePropertyValue","propertyPath","validators","validator","validatorProblems","problem","nestedProblems","prependedProblems","runPropertyValidators","isPassthrough","valueProblems","arrayValidators","i","element","elementPath","elementProblems","validationProblems","entityValidators","getEntityValidators","validatorMethod","get","getRawInput","protoValidators"],"mappings":"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"}
@@ -1,12 +1,9 @@
1
1
  import 'reflect-metadata';
2
- /**
3
- * Represents a SOFT validation problem
4
- */
5
2
  export declare class Problem {
6
3
  readonly property: string;
7
4
  readonly message: string;
8
5
  constructor(data: {
9
- property: string;
6
+ property?: string;
10
7
  message: string;
11
8
  });
12
9
  toString(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"problem.d.ts","sourceRoot":"","sources":["../../src/lib/problem.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B;;GAEG;AACH,qBACa,OAAO;IAElB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAG1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAKvD,QAAQ,IAAI,MAAM;CAGnB"}
1
+ {"version":3,"file":"problem.d.ts","sourceRoot":"","sources":["../../src/lib/problem.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAI1B,qBACa,OAAO;IAElB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAG1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAKxD,QAAQ,IAAI,MAAM;CAGnB"}
@@ -5,7 +5,7 @@ import { Entity } from './entity.js';
5
5
  import { StringProperty } from './property.js';
6
6
  export class Problem {
7
7
  constructor(data){
8
- this.property = data.property;
8
+ this.property = data.property ?? '';
9
9
  this.message = data.message;
10
10
  }
11
11
  toString() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/problem.ts"],"sourcesContent":["import 'reflect-metadata';\nimport { Entity } from './entity.js';\nimport { StringProperty } from './property.js';\n\n/**\n * Represents a SOFT validation problem\n */\n@Entity()\nexport class Problem {\n @StringProperty()\n readonly property: string;\n\n @StringProperty()\n readonly message: string;\n\n constructor(data: { property: string; message: string }) {\n this.property = data.property;\n this.message = data.message;\n }\n\n toString(): string {\n return `${this.property}: ${this.message}`;\n }\n}\n"],"names":["Entity","StringProperty","Problem","data","property","message","toString"],"mappings":";;AAAA,OAAO,mBAAmB;AAC1B,SAASA,MAAM,QAAQ,cAAc;AACrC,SAASC,cAAc,QAAQ,gBAAgB;AAM/C,OAAO,MAAMC;IAOX,YAAYC,IAA2C,CAAE;QACvD,IAAI,CAACC,QAAQ,GAAGD,KAAKC,QAAQ;QAC7B,IAAI,CAACC,OAAO,GAAGF,KAAKE,OAAO;IAC7B;IAEAC,WAAmB;QACjB,OAAO,GAAG,IAAI,CAACF,QAAQ,CAAC,EAAE,EAAE,IAAI,CAACC,OAAO,EAAE;IAC5C;AACF"}
1
+ {"version":3,"sources":["../../src/lib/problem.ts"],"sourcesContent":["import 'reflect-metadata';\nimport { Entity } from './entity.js';\nimport { StringProperty } from './property.js';\n\n@Entity()\nexport class Problem {\n @StringProperty()\n readonly property: string;\n\n @StringProperty()\n readonly message: string;\n\n constructor(data: { property?: string; message: string }) {\n this.property = data.property ?? '';\n this.message = data.message;\n }\n\n toString(): string {\n return `${this.property}: ${this.message}`;\n }\n}\n"],"names":["Entity","StringProperty","Problem","data","property","message","toString"],"mappings":";;AAAA,OAAO,mBAAmB;AAC1B,SAASA,MAAM,QAAQ,cAAc;AACrC,SAASC,cAAc,QAAQ,gBAAgB;AAG/C,OAAO,MAAMC;IAOX,YAAYC,IAA4C,CAAE;QACxD,IAAI,CAACC,QAAQ,GAAGD,KAAKC,QAAQ,IAAI;QACjC,IAAI,CAACC,OAAO,GAAGF,KAAKE,OAAO;IAC7B;IAEAC,WAAmB;QACjB,OAAO,GAAG,IAAI,CAACF,QAAQ,CAAC,EAAE,EAAE,IAAI,CAACC,OAAO,EAAE;IAC5C;AACF"}
@@ -30,6 +30,26 @@ export declare function Property<T, C extends CtorLike<T>>(options: PropertyOpti
30
30
  * }
31
31
  */
32
32
  export declare function StringProperty(options?: Omit<PropertyOptions<string, StringConstructor>, 'type'>): PropertyDecorator;
33
+ /**
34
+ * Helper decorator for enum properties (string enums)
35
+ * Validates that the string value matches one of the enum values
36
+ * @param enumType - The enum object (e.g., MyEnum)
37
+ * @param options - Additional property options
38
+ * @example
39
+ * enum Status {
40
+ * Active = 'active',
41
+ * Inactive = 'inactive'
42
+ * }
43
+ *
44
+ * class User {
45
+ * @EnumProperty(Status)
46
+ * status!: Status;
47
+ *
48
+ * @EnumProperty(Status, { optional: true })
49
+ * previousStatus?: Status;
50
+ * }
51
+ */
52
+ export declare function EnumProperty<T extends Record<string, string>>(enumType: T, options?: Omit<PropertyOptions<string, StringConstructor>, 'type'>): PropertyDecorator;
33
53
  /**
34
54
  * Helper decorator for number properties
35
55
  * @example
@@ -42,6 +62,19 @@ export declare function StringProperty(options?: Omit<PropertyOptions<string, St
42
62
  * }
43
63
  */
44
64
  export declare function NumberProperty(options?: Omit<PropertyOptions<number, NumberConstructor>, 'type'>): PropertyDecorator;
65
+ /**
66
+ * Helper decorator for integer properties
67
+ * Validates that the number is an integer (no decimal places)
68
+ * @example
69
+ * class User {
70
+ * @IntProperty()
71
+ * age!: number;
72
+ *
73
+ * @IntProperty({ optional: true })
74
+ * count?: number;
75
+ * }
76
+ */
77
+ export declare function IntProperty(options?: Omit<PropertyOptions<number, NumberConstructor>, 'type'>): PropertyDecorator;
45
78
  /**
46
79
  * Helper decorator for boolean properties
47
80
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"property.d.ts","sourceRoot":"","sources":["../../src/lib/property.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"property.d.ts","sourceRoot":"","sources":["../../src/lib/property.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-wrapper-object-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { isEqual } from 'lodash-es';
2
2
  import { PROPERTY_METADATA_KEY, PROPERTY_OPTIONS_METADATA_KEY } from './types.js';
3
+ import { enumValidator, intValidator } from './validators.js';
3
4
  /**
4
5
  * Property decorator that marks class properties with metadata.
5
6
  * This decorator can be used to identify and track properties within classes.
@@ -74,6 +75,37 @@ import { PROPERTY_METADATA_KEY, PROPERTY_OPTIONS_METADATA_KEY } from './types.js
74
75
  type: ()=>String
75
76
  });
76
77
  }
78
+ /**
79
+ * Helper decorator for enum properties (string enums)
80
+ * Validates that the string value matches one of the enum values
81
+ * @param enumType - The enum object (e.g., MyEnum)
82
+ * @param options - Additional property options
83
+ * @example
84
+ * enum Status {
85
+ * Active = 'active',
86
+ * Inactive = 'inactive'
87
+ * }
88
+ *
89
+ * class User {
90
+ * @EnumProperty(Status)
91
+ * status!: Status;
92
+ *
93
+ * @EnumProperty(Status, { optional: true })
94
+ * previousStatus?: Status;
95
+ * }
96
+ */ export function EnumProperty(enumType, options) {
97
+ const validators = options?.validators ? [
98
+ enumValidator(enumType),
99
+ ...options.validators
100
+ ] : [
101
+ enumValidator(enumType)
102
+ ];
103
+ return Property({
104
+ ...options,
105
+ type: ()=>String,
106
+ validators
107
+ });
108
+ }
77
109
  /**
78
110
  * Helper decorator for number properties
79
111
  * @example
@@ -90,6 +122,30 @@ import { PROPERTY_METADATA_KEY, PROPERTY_OPTIONS_METADATA_KEY } from './types.js
90
122
  type: ()=>Number
91
123
  });
92
124
  }
125
+ /**
126
+ * Helper decorator for integer properties
127
+ * Validates that the number is an integer (no decimal places)
128
+ * @example
129
+ * class User {
130
+ * @IntProperty()
131
+ * age!: number;
132
+ *
133
+ * @IntProperty({ optional: true })
134
+ * count?: number;
135
+ * }
136
+ */ export function IntProperty(options) {
137
+ const validators = options?.validators ? [
138
+ intValidator(),
139
+ ...options.validators
140
+ ] : [
141
+ intValidator()
142
+ ];
143
+ return Property({
144
+ ...options,
145
+ type: ()=>Number,
146
+ validators
147
+ });
148
+ }
93
149
  /**
94
150
  * Helper decorator for boolean properties
95
151
  * @example
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/property.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-wrapper-object-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { isEqual } from 'lodash-es';\nimport {\n AnyCtor,\n type CtorLike,\n type InstanceOfCtorLike,\n PROPERTY_METADATA_KEY,\n PROPERTY_OPTIONS_METADATA_KEY,\n PropertyOptions,\n} from './types.js';\n\n/**\n * Property decorator that marks class properties with metadata.\n * This decorator can be used to identify and track properties within classes.\n *\n * @param options - Configuration for the property (type is required)\n *\n * @example\n * class User {\n * @Property({ type: () => String })\n * name: string;\n *\n * @Property({ type: () => String, equals: (a, b) => a.toLowerCase() === b.toLowerCase() })\n * email: string;\n *\n * @Property({ type: () => Number })\n * age: number;\n * }\n */\nexport function Property<T, C extends CtorLike<T>>(\n options: PropertyOptions<T, C>,\n): PropertyDecorator {\n return (target: object, propertyKey: string | symbol): void => {\n if (typeof propertyKey !== 'string') {\n return;\n }\n\n const existingProperties: string[] =\n Reflect.getOwnMetadata(PROPERTY_METADATA_KEY, target) || [];\n\n if (!existingProperties.includes(propertyKey)) {\n existingProperties.push(propertyKey);\n }\n\n Reflect.defineMetadata(PROPERTY_METADATA_KEY, existingProperties, target);\n\n if (options.passthrough === true) {\n if (options.array === true) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and array: true. Passthrough cannot be combined with array.`,\n );\n }\n if (options.optional === true) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and optional: true. Passthrough cannot be combined with optional.`,\n );\n }\n if (options.sparse === true) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and sparse: true. Passthrough cannot be combined with sparse.`,\n );\n }\n if (\n options.serialize !== undefined ||\n options.deserialize !== undefined\n ) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and custom serialize/deserialize functions. Passthrough cannot be combined with serialize or deserialize.`,\n );\n }\n }\n\n if (options.sparse === true && options.array !== true) {\n throw new Error(\n `Property '${propertyKey}' has sparse: true but array is not true. The sparse option only applies to arrays.`,\n );\n }\n\n if (options.arrayValidators && options.array !== true) {\n throw new Error(\n `Property '${propertyKey}' has arrayValidators defined but array is not true. The arrayValidators option only applies to arrays.`,\n );\n }\n\n // Validate serialize/deserialize pairing\n const hasSerialize = options.serialize !== undefined;\n const hasDeserialize = options.deserialize !== undefined;\n if (hasSerialize !== hasDeserialize) {\n throw new Error(\n `Property '${propertyKey}' must define both serialize and deserialize functions, or neither. Found only ${hasSerialize ? 'serialize' : 'deserialize'}.`,\n );\n }\n\n const existingOptions: Record<\n string,\n PropertyOptions<any, any>\n > = Reflect.getOwnMetadata(PROPERTY_OPTIONS_METADATA_KEY, target) || {};\n\n existingOptions[propertyKey] = options;\n\n Reflect.defineMetadata(\n PROPERTY_OPTIONS_METADATA_KEY,\n existingOptions,\n target,\n );\n };\n}\n\n/**\n * Helper decorator for string properties\n * @example\n * class User {\n * @StringProperty()\n * name!: string;\n *\n * @StringProperty({ optional: true })\n * nickname?: string;\n * }\n */\nexport function StringProperty(\n options?: Omit<PropertyOptions<string, StringConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => String });\n}\n\n/**\n * Helper decorator for number properties\n * @example\n * class User {\n * @NumberProperty()\n * age!: number;\n *\n * @NumberProperty({ optional: true })\n * score?: number;\n * }\n */\nexport function NumberProperty(\n options?: Omit<PropertyOptions<number, NumberConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => Number });\n}\n\n/**\n * Helper decorator for boolean properties\n * @example\n * class User {\n * @BooleanProperty()\n * active!: boolean;\n *\n * @BooleanProperty({ optional: true })\n * verified?: boolean;\n * }\n */\nexport function BooleanProperty(\n options?: Omit<PropertyOptions<boolean, BooleanConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => Boolean });\n}\n\n/**\n * Helper decorator for Date properties\n * @example\n * class User {\n * @DateProperty()\n * createdAt!: Date;\n *\n * @DateProperty({ optional: true })\n * deletedAt?: Date;\n * }\n */\nexport function DateProperty(\n options?: Omit<PropertyOptions<Date, DateConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => Date });\n}\n\n/**\n * Helper decorator for BigInt properties\n * @example\n * class User {\n * @BigIntProperty()\n * id!: bigint;\n *\n * @BigIntProperty({ optional: true })\n * balance?: bigint;\n * }\n */\nexport function BigIntProperty(\n options?: Omit<PropertyOptions<bigint, BigIntConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => BigInt });\n}\n\n/**\n * Helper decorator for entity properties\n * @example\n * class User {\n * @EntityProperty(() => Address)\n * address!: Address;\n *\n * @EntityProperty(() => Profile, { optional: true })\n * profile?: Profile;\n * }\n */\nexport function EntityProperty<\n T,\n C extends AnyCtor<T> & { new (data: any): T },\n>(\n type: () => C,\n options?: Omit<PropertyOptions<T, C>, 'type'>,\n): PropertyDecorator {\n return Property<T, C>({ ...options, type });\n}\n\n/**\n * Helper decorator for array properties\n * @example\n * class User {\n * @ArrayProperty(() => String)\n * tags!: string[];\n *\n * @ArrayProperty(() => Phone)\n * phones!: Phone[];\n *\n * @ArrayProperty(() => Number, { optional: true })\n * scores?: number[];\n *\n * @ArrayProperty(() => String, { sparse: true })\n * sparseList!: (string | null)[];\n * }\n */\nexport function ArrayProperty<T, C extends CtorLike<T>>(\n type: () => C,\n options?: Omit<PropertyOptions<T, C>, 'type' | 'array'>,\n): PropertyDecorator {\n return Property({ ...options, type, array: true });\n}\n\n/**\n * Helper decorator for passthrough properties that bypass type validation.\n * Use this for generic types like Record<string, unknown>, any, or custom objects.\n * @example\n * class Config {\n * @PassthroughProperty()\n * metadata!: Record<string, unknown>;\n *\n * @PassthroughProperty()\n * customData!: any;\n * }\n */\nexport function PassthroughProperty(): PropertyDecorator {\n // Use a dummy type since type is mandatory but not used with passthrough\n return Property({ type: () => Object, passthrough: true });\n}\n\nexport const StringifiableProperty = <\n T extends { equals?(other: T): boolean; toString(): string },\n C extends CtorLike<T> & { parse(value: string): T },\n>(\n type: () => C,\n data: Omit<\n PropertyOptions<T, C>,\n 'serialize' | 'deserialize' | 'passthrough' | 'type' | 'equals'\n > = {},\n): PropertyDecorator =>\n Property<T, C>({\n ...data,\n type,\n equals: (a, b) => (a.equals ? a.equals(b) : a.toString() === b.toString()),\n serialize: (value) => value.toString(),\n deserialize: (value) => {\n if (typeof value === 'string') {\n return type().parse(value) as InstanceOfCtorLike<C>;\n }\n throw new Error(`Invalid value ${type().name}: ${String(value)}`);\n },\n });\n\nexport const SerializableProperty = <\n T extends { equals?(other: T): boolean; toJSON(): unknown },\n C extends CtorLike<T> & { parse(value: unknown): T },\n>(\n type: () => C,\n data: Omit<\n PropertyOptions<T, C>,\n 'serialize' | 'deserialize' | 'passthrough' | 'type' | 'equals'\n > = {},\n) =>\n Property({\n ...data,\n type,\n equals: (a: T, b: T) =>\n a.equals ? a.equals(b) : isEqual(a.toJSON(), b.toJSON()),\n serialize: (value: T) => value.toJSON(),\n deserialize: (value: unknown) => {\n return type().parse(value) as InstanceOfCtorLike<C>;\n },\n });\n"],"names":["isEqual","PROPERTY_METADATA_KEY","PROPERTY_OPTIONS_METADATA_KEY","Property","options","target","propertyKey","existingProperties","Reflect","getOwnMetadata","includes","push","defineMetadata","passthrough","array","Error","optional","sparse","serialize","undefined","deserialize","arrayValidators","hasSerialize","hasDeserialize","existingOptions","StringProperty","type","String","NumberProperty","Number","BooleanProperty","Boolean","DateProperty","Date","BigIntProperty","BigInt","EntityProperty","ArrayProperty","PassthroughProperty","Object","StringifiableProperty","data","equals","a","b","toString","value","parse","name","SerializableProperty","toJSON"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/lib/property.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-wrapper-object-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { isEqual } from 'lodash-es';\nimport {\n AnyCtor,\n type CtorLike,\n type InstanceOfCtorLike,\n PROPERTY_METADATA_KEY,\n PROPERTY_OPTIONS_METADATA_KEY,\n PropertyOptions,\n} from './types.js';\nimport { enumValidator, intValidator } from './validators.js';\n\n/**\n * Property decorator that marks class properties with metadata.\n * This decorator can be used to identify and track properties within classes.\n *\n * @param options - Configuration for the property (type is required)\n *\n * @example\n * class User {\n * @Property({ type: () => String })\n * name: string;\n *\n * @Property({ type: () => String, equals: (a, b) => a.toLowerCase() === b.toLowerCase() })\n * email: string;\n *\n * @Property({ type: () => Number })\n * age: number;\n * }\n */\nexport function Property<T, C extends CtorLike<T>>(\n options: PropertyOptions<T, C>,\n): PropertyDecorator {\n return (target: object, propertyKey: string | symbol): void => {\n if (typeof propertyKey !== 'string') {\n return;\n }\n\n const existingProperties: string[] =\n Reflect.getOwnMetadata(PROPERTY_METADATA_KEY, target) || [];\n\n if (!existingProperties.includes(propertyKey)) {\n existingProperties.push(propertyKey);\n }\n\n Reflect.defineMetadata(PROPERTY_METADATA_KEY, existingProperties, target);\n\n if (options.passthrough === true) {\n if (options.array === true) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and array: true. Passthrough cannot be combined with array.`,\n );\n }\n if (options.optional === true) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and optional: true. Passthrough cannot be combined with optional.`,\n );\n }\n if (options.sparse === true) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and sparse: true. Passthrough cannot be combined with sparse.`,\n );\n }\n if (\n options.serialize !== undefined ||\n options.deserialize !== undefined\n ) {\n throw new Error(\n `Property '${propertyKey}' has passthrough: true and custom serialize/deserialize functions. Passthrough cannot be combined with serialize or deserialize.`,\n );\n }\n }\n\n if (options.sparse === true && options.array !== true) {\n throw new Error(\n `Property '${propertyKey}' has sparse: true but array is not true. The sparse option only applies to arrays.`,\n );\n }\n\n if (options.arrayValidators && options.array !== true) {\n throw new Error(\n `Property '${propertyKey}' has arrayValidators defined but array is not true. The arrayValidators option only applies to arrays.`,\n );\n }\n\n // Validate serialize/deserialize pairing\n const hasSerialize = options.serialize !== undefined;\n const hasDeserialize = options.deserialize !== undefined;\n if (hasSerialize !== hasDeserialize) {\n throw new Error(\n `Property '${propertyKey}' must define both serialize and deserialize functions, or neither. Found only ${hasSerialize ? 'serialize' : 'deserialize'}.`,\n );\n }\n\n const existingOptions: Record<\n string,\n PropertyOptions<any, any>\n > = Reflect.getOwnMetadata(PROPERTY_OPTIONS_METADATA_KEY, target) || {};\n\n existingOptions[propertyKey] = options;\n\n Reflect.defineMetadata(\n PROPERTY_OPTIONS_METADATA_KEY,\n existingOptions,\n target,\n );\n };\n}\n\n/**\n * Helper decorator for string properties\n * @example\n * class User {\n * @StringProperty()\n * name!: string;\n *\n * @StringProperty({ optional: true })\n * nickname?: string;\n * }\n */\nexport function StringProperty(\n options?: Omit<PropertyOptions<string, StringConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => String });\n}\n\n/**\n * Helper decorator for enum properties (string enums)\n * Validates that the string value matches one of the enum values\n * @param enumType - The enum object (e.g., MyEnum)\n * @param options - Additional property options\n * @example\n * enum Status {\n * Active = 'active',\n * Inactive = 'inactive'\n * }\n *\n * class User {\n * @EnumProperty(Status)\n * status!: Status;\n *\n * @EnumProperty(Status, { optional: true })\n * previousStatus?: Status;\n * }\n */\nexport function EnumProperty<T extends Record<string, string>>(\n enumType: T,\n options?: Omit<PropertyOptions<string, StringConstructor>, 'type'>,\n): PropertyDecorator {\n const validators = options?.validators\n ? [enumValidator(enumType), ...options.validators]\n : [enumValidator(enumType)];\n\n return Property({ ...options, type: () => String, validators });\n}\n\n/**\n * Helper decorator for number properties\n * @example\n * class User {\n * @NumberProperty()\n * age!: number;\n *\n * @NumberProperty({ optional: true })\n * score?: number;\n * }\n */\nexport function NumberProperty(\n options?: Omit<PropertyOptions<number, NumberConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => Number });\n}\n\n/**\n * Helper decorator for integer properties\n * Validates that the number is an integer (no decimal places)\n * @example\n * class User {\n * @IntProperty()\n * age!: number;\n *\n * @IntProperty({ optional: true })\n * count?: number;\n * }\n */\nexport function IntProperty(\n options?: Omit<PropertyOptions<number, NumberConstructor>, 'type'>,\n): PropertyDecorator {\n const validators = options?.validators\n ? [intValidator(), ...options.validators]\n : [intValidator()];\n\n return Property({ ...options, type: () => Number, validators });\n}\n\n/**\n * Helper decorator for boolean properties\n * @example\n * class User {\n * @BooleanProperty()\n * active!: boolean;\n *\n * @BooleanProperty({ optional: true })\n * verified?: boolean;\n * }\n */\nexport function BooleanProperty(\n options?: Omit<PropertyOptions<boolean, BooleanConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => Boolean });\n}\n\n/**\n * Helper decorator for Date properties\n * @example\n * class User {\n * @DateProperty()\n * createdAt!: Date;\n *\n * @DateProperty({ optional: true })\n * deletedAt?: Date;\n * }\n */\nexport function DateProperty(\n options?: Omit<PropertyOptions<Date, DateConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => Date });\n}\n\n/**\n * Helper decorator for BigInt properties\n * @example\n * class User {\n * @BigIntProperty()\n * id!: bigint;\n *\n * @BigIntProperty({ optional: true })\n * balance?: bigint;\n * }\n */\nexport function BigIntProperty(\n options?: Omit<PropertyOptions<bigint, BigIntConstructor>, 'type'>,\n): PropertyDecorator {\n return Property({ ...options, type: () => BigInt });\n}\n\n/**\n * Helper decorator for entity properties\n * @example\n * class User {\n * @EntityProperty(() => Address)\n * address!: Address;\n *\n * @EntityProperty(() => Profile, { optional: true })\n * profile?: Profile;\n * }\n */\nexport function EntityProperty<\n T,\n C extends AnyCtor<T> & { new (data: any): T },\n>(\n type: () => C,\n options?: Omit<PropertyOptions<T, C>, 'type'>,\n): PropertyDecorator {\n return Property<T, C>({ ...options, type });\n}\n\n/**\n * Helper decorator for array properties\n * @example\n * class User {\n * @ArrayProperty(() => String)\n * tags!: string[];\n *\n * @ArrayProperty(() => Phone)\n * phones!: Phone[];\n *\n * @ArrayProperty(() => Number, { optional: true })\n * scores?: number[];\n *\n * @ArrayProperty(() => String, { sparse: true })\n * sparseList!: (string | null)[];\n * }\n */\nexport function ArrayProperty<T, C extends CtorLike<T>>(\n type: () => C,\n options?: Omit<PropertyOptions<T, C>, 'type' | 'array'>,\n): PropertyDecorator {\n return Property({ ...options, type, array: true });\n}\n\n/**\n * Helper decorator for passthrough properties that bypass type validation.\n * Use this for generic types like Record<string, unknown>, any, or custom objects.\n * @example\n * class Config {\n * @PassthroughProperty()\n * metadata!: Record<string, unknown>;\n *\n * @PassthroughProperty()\n * customData!: any;\n * }\n */\nexport function PassthroughProperty(): PropertyDecorator {\n // Use a dummy type since type is mandatory but not used with passthrough\n return Property({ type: () => Object, passthrough: true });\n}\n\nexport const StringifiableProperty = <\n T extends { equals?(other: T): boolean; toString(): string },\n C extends CtorLike<T> & { parse(value: string): T },\n>(\n type: () => C,\n data: Omit<\n PropertyOptions<T, C>,\n 'serialize' | 'deserialize' | 'passthrough' | 'type' | 'equals'\n > = {},\n): PropertyDecorator =>\n Property<T, C>({\n ...data,\n type,\n equals: (a, b) => (a.equals ? a.equals(b) : a.toString() === b.toString()),\n serialize: (value) => value.toString(),\n deserialize: (value) => {\n if (typeof value === 'string') {\n return type().parse(value) as InstanceOfCtorLike<C>;\n }\n throw new Error(`Invalid value ${type().name}: ${String(value)}`);\n },\n });\n\nexport const SerializableProperty = <\n T extends { equals?(other: T): boolean; toJSON(): unknown },\n C extends CtorLike<T> & { parse(value: unknown): T },\n>(\n type: () => C,\n data: Omit<\n PropertyOptions<T, C>,\n 'serialize' | 'deserialize' | 'passthrough' | 'type' | 'equals'\n > = {},\n) =>\n Property({\n ...data,\n type,\n equals: (a: T, b: T) =>\n a.equals ? a.equals(b) : isEqual(a.toJSON(), b.toJSON()),\n serialize: (value: T) => value.toJSON(),\n deserialize: (value: unknown) => {\n return type().parse(value) as InstanceOfCtorLike<C>;\n },\n });\n"],"names":["isEqual","PROPERTY_METADATA_KEY","PROPERTY_OPTIONS_METADATA_KEY","enumValidator","intValidator","Property","options","target","propertyKey","existingProperties","Reflect","getOwnMetadata","includes","push","defineMetadata","passthrough","array","Error","optional","sparse","serialize","undefined","deserialize","arrayValidators","hasSerialize","hasDeserialize","existingOptions","StringProperty","type","String","EnumProperty","enumType","validators","NumberProperty","Number","IntProperty","BooleanProperty","Boolean","DateProperty","Date","BigIntProperty","BigInt","EntityProperty","ArrayProperty","PassthroughProperty","Object","StringifiableProperty","data","equals","a","b","toString","value","parse","name","SerializableProperty","toJSON"],"mappings":"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"}
@@ -151,34 +151,36 @@ export interface PropertyOptions<T = any, C extends CtorLike<T> = AnyCtor<T> | B
151
151
  /**
152
152
  * A validator function for a property.
153
153
  * The validator receives the value and returns Problems with property paths relative to the value.
154
+ * Can be synchronous or asynchronous.
154
155
  * The calling code will prepend the actual property key to all returned problems.
155
156
  *
156
157
  * @param data - Object containing the value to validate
157
158
  * @param data.value - The value to validate
158
- * @returns Array of Problems (empty if valid). Problems should have empty property for the value itself,
159
+ * @returns Array of Problems (empty if valid) or Promise resolving to Problems.
160
+ * Problems should have empty property for the value itself,
159
161
  * or relative paths for nested properties (e.g., 'name', '[0]', 'address.street')
160
162
  *
161
163
  * @example
162
164
  * ```typescript
163
- * // Validator that checks the value itself
165
+ * // Synchronous validator
164
166
  * (({ value }) =>
165
167
  * value.length < 3 ? [new Problem({ property: '', message: 'Too short' })] : [])
166
168
  *
167
- * // Validator that checks nested properties
168
- * (({ value }) => {
169
- * const problems = [];
170
- * if (value.street === '') problems.push(new Problem({ property: 'street', message: 'Required' }));
171
- * return problems;
172
- * })
169
+ * // Asynchronous validator
170
+ * async ({ value }) => {
171
+ * const exists = await checkDatabase(value);
172
+ * return exists ? [] : [new Problem({ property: '', message: 'Not found' })];
173
+ * }
173
174
  * ```
174
175
  */
175
176
  export type PropertyValidator<T> = (data: {
176
177
  value: T;
177
- }) => Problem[];
178
+ }) => Problem[] | Promise<Problem[]>;
178
179
  /**
179
- * A validator function for an entity
180
+ * A validator function for an entity.
181
+ * Can be synchronous or asynchronous.
180
182
  * @param instance - The entity instance to validate
181
- * @returns Array of Problems (empty if valid)
183
+ * @returns Array of Problems (empty if valid) or Promise resolving to Problems
182
184
  */
183
- export type EntityValidatorFn<T = any> = (instance: T) => Problem[];
185
+ export type EntityValidatorFn<T = any> = (instance: T) => Problem[] | Promise<Problem[]>;
184
186
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,qBAAqB,eAA8B,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,6BAA6B,eAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAA4B,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,6BAA6B,eAEzC,CAAC;AAGF,MAAM,MAAM,OAAO,CAAC,CAAC,GAAG,GAAG,IAAI,QAAQ,GAAG;IAAE,SAAS,EAAE,CAAC,CAAA;CAAE,CAAC;AAE3D,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,CAAC;AAEpB;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC5B,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,CAAC;AAEpB,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC;AAEpD,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,CAAC,SAAS,iBAAiB,GAC3D,MAAM,GACN,CAAC,SAAS,iBAAiB,GACzB,MAAM,GACN,CAAC,SAAS,kBAAkB,GAC1B,OAAO,GACP,CAAC,SAAS,iBAAiB,GACzB,MAAM,GACN,CAAC,SAAS,iBAAiB,GACzB,MAAM,GACN,CAAC,SAAS,eAAe,GACvB,IAAI,GACJ,CAAC,SAAS,OAAO,CAAC,MAAM,CAAC,CAAC,GACxB,CAAC,GACD,KAAK,CAAC;AAEtB;;GAEG;AACH,MAAM,WAAW,eAAe,CAC9B,CAAC,GAAG,GAAG,EACP,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY;IAEjD;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;IAEzE;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC,CAAC;IAEd;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC;IAEtD;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,KAAK,kBAAkB,CAAC,CAAC,CAAC,CAAC;IAE7D;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAExD;;;;;;;;;;;;;;;;OAgBG;IACH,eAAe,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;CAChE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,CAAC,CAAA;CAAE,KAAK,OAAO,EAAE,CAAC;AAErE;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-wrapper-object-types */\nimport type { Problem } from './problem.js';\n\n/**\n * Metadata key used to store property information\n */\nexport const PROPERTY_METADATA_KEY = Symbol('property:metadata');\n\n/**\n * Metadata key used to store property options\n */\nexport const PROPERTY_OPTIONS_METADATA_KEY = Symbol(\n 'property:options:metadata',\n);\n\n/**\n * Metadata key used to store entity information\n */\nexport const ENTITY_METADATA_KEY = Symbol('entity:metadata');\n\n/**\n * Metadata key used to store entity validator methods\n */\nexport const ENTITY_VALIDATOR_METADATA_KEY = Symbol(\n 'entity:validator:metadata',\n);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type AnyCtor<T = any> = Function & { prototype: T };\n\nexport type BuiltinCtors =\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | BigIntConstructor\n | SymbolConstructor\n | DateConstructor;\n\n/**\n * Type constructors for primitive types that can be deserialized\n * (excludes Symbol which cannot be deserialized from JSON)\n */\nexport type PrimitiveConstructor =\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | BigIntConstructor\n | DateConstructor;\n\nexport type CtorLike<T> = AnyCtor<T> | BuiltinCtors;\n\nexport type InstanceOfCtorLike<C> = C extends StringConstructor\n ? string\n : C extends NumberConstructor\n ? number\n : C extends BooleanConstructor\n ? boolean\n : C extends BigIntConstructor\n ? bigint\n : C extends SymbolConstructor\n ? symbol\n : C extends DateConstructor\n ? Date\n : C extends AnyCtor<infer T>\n ? T\n : never;\n\n/**\n * Options for the Property decorator\n */\nexport interface PropertyOptions<\n T = any,\n C extends CtorLike<T> = AnyCtor<T> | BuiltinCtors,\n> {\n /**\n * Custom equality comparison function for this property\n * @param a - First value to compare\n * @param b - Second value to compare\n * @returns true if values are equal, false otherwise\n */\n equals?: (a: InstanceOfCtorLike<C>, b: InstanceOfCtorLike<C>) => boolean;\n\n /**\n * Type constructor for this property. Required for EntityUtils.parse() support.\n * Use a function that returns the type constructor to support forward references.\n * @example\n * @Property({ type: () => String })\n * name!: string;\n *\n * @Property({ type: () => Address })\n * address!: Address;\n */\n type: () => C;\n\n /**\n * Whether this property is an array. Defaults to false.\n * When true, the deserializer will map over array elements.\n * @example\n * @Property({ type: () => String, array: true })\n * tags!: string[];\n */\n array?: boolean;\n\n /**\n * Whether this property is optional. Defaults to false.\n * When true, the property can be undefined or null.\n * When false, the property must be present and not null/undefined.\n * @example\n * @Property({ type: () => String, optional: true })\n * nickname?: string;\n */\n optional?: boolean;\n\n /**\n * Whether the array can contain null/undefined elements. Defaults to false.\n * Only applicable when array is true.\n * When false (default), null/undefined elements will cause an error.\n * When true, null/undefined elements are allowed in the array.\n * @example\n * @Property({ type: () => String, array: true, sparse: true })\n * tags!: (string | null)[];\n */\n sparse?: boolean;\n\n /**\n * Whether to bypass type validation and pass values through as-is.\n * Use this for generic types like Record<string, unknown> or any.\n * When true, no type checking or transformation is performed.\n * Also bypasses any custom serialize/deserialize callbacks.\n * @example\n * @Property({ passthrough: true })\n * metadata!: Record<string, unknown>;\n */\n passthrough?: boolean;\n\n /**\n * Custom serialization function to convert the property value to JSON-compatible format.\n * Must be paired with deserialize - both must be defined together or both omitted.\n * Not used when passthrough is true.\n * @example\n * @Property({\n * type: () => MyClass,\n * serialize: (value) => ({ data: value.toData() }),\n * deserialize: (json) => MyClass.fromData(json.data)\n * })\n * myProperty!: MyClass;\n */\n serialize?: (value: InstanceOfCtorLike<C>) => unknown;\n\n /**\n * Custom deserialization function to convert JSON data back to the property type.\n * Must be paired with serialize - both must be defined together or both omitted.\n * Not used when passthrough is true.\n * @example\n * @Property({\n * type: () => MyClass,\n * serialize: (value) => ({ data: value.toData() }),\n * deserialize: (json) => MyClass.fromData(json.data)\n * })\n * myProperty!: MyClass;\n */\n deserialize?: (serialized: unknown) => InstanceOfCtorLike<C>;\n\n /**\n * Array of validator functions for this property.\n * Each validator receives the property value and validation context.\n * Empty array means validation passed.\n * If the property is an array (array: true), these validators will run against each item.\n * Use arrayValidators instead to validate the array as a whole.\n * If passthrough is true, validators will run against the raw value.\n * @example\n * @Property({\n * type: () => String,\n * validators: [\n * (value, { createProblem }) =>\n * value.length > 10 ? [createProblem('Too long')] : []\n * ]\n * })\n * name!: string;\n */\n validators?: PropertyValidator<InstanceOfCtorLike<C>>[];\n\n /**\n * Array of validator functions for this property when it is an array.\n * Each validator receives the array value and validation context.\n * Empty array means validation passed.\n * Only applicable when array is true.\n * Not applicable when passthrough is true.\n * @example\n * @Property({\n * type: () => Number,\n * array: true,\n * arrayValidators: [\n * (value, { createProblem }) =>\n * value.length === 0 ? [createProblem('Array cannot be empty')] : []\n * ]\n * })\n * scores!: number[];\n */\n arrayValidators?: PropertyValidator<InstanceOfCtorLike<C>[]>[];\n}\n\n/**\n * A validator function for a property.\n * The validator receives the value and returns Problems with property paths relative to the value.\n * The calling code will prepend the actual property key to all returned problems.\n *\n * @param data - Object containing the value to validate\n * @param data.value - The value to validate\n * @returns Array of Problems (empty if valid). Problems should have empty property for the value itself,\n * or relative paths for nested properties (e.g., 'name', '[0]', 'address.street')\n *\n * @example\n * ```typescript\n * // Validator that checks the value itself\n * (({ value }) =>\n * value.length < 3 ? [new Problem({ property: '', message: 'Too short' })] : [])\n *\n * // Validator that checks nested properties\n * (({ value }) => {\n * const problems = [];\n * if (value.street === '') problems.push(new Problem({ property: 'street', message: 'Required' }));\n * return problems;\n * })\n * ```\n */\nexport type PropertyValidator<T> = (data: { value: T }) => Problem[];\n\n/**\n * A validator function for an entity\n * @param instance - The entity instance to validate\n * @returns Array of Problems (empty if valid)\n */\nexport type EntityValidatorFn<T = any> = (instance: T) => Problem[];\n"],"names":["PROPERTY_METADATA_KEY","Symbol","PROPERTY_OPTIONS_METADATA_KEY","ENTITY_METADATA_KEY","ENTITY_VALIDATOR_METADATA_KEY"],"mappings":"AAAA,qDAAqD,GACrD,6DAA6D,GAG7D;;CAEC,GACD,OAAO,MAAMA,wBAAwBC,OAAO,qBAAqB;AAEjE;;CAEC,GACD,OAAO,MAAMC,gCAAgCD,OAC3C,6BACA;AAEF;;CAEC,GACD,OAAO,MAAME,sBAAsBF,OAAO,mBAAmB;AAE7D;;CAEC,GACD,OAAO,MAAMG,gCAAgCH,OAC3C,6BACA"}
1
+ {"version":3,"sources":["../../src/lib/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-wrapper-object-types */\nimport type { Problem } from './problem.js';\n\n/**\n * Metadata key used to store property information\n */\nexport const PROPERTY_METADATA_KEY = Symbol('property:metadata');\n\n/**\n * Metadata key used to store property options\n */\nexport const PROPERTY_OPTIONS_METADATA_KEY = Symbol(\n 'property:options:metadata',\n);\n\n/**\n * Metadata key used to store entity information\n */\nexport const ENTITY_METADATA_KEY = Symbol('entity:metadata');\n\n/**\n * Metadata key used to store entity validator methods\n */\nexport const ENTITY_VALIDATOR_METADATA_KEY = Symbol(\n 'entity:validator:metadata',\n);\n\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport type AnyCtor<T = any> = Function & { prototype: T };\n\nexport type BuiltinCtors =\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | BigIntConstructor\n | SymbolConstructor\n | DateConstructor;\n\n/**\n * Type constructors for primitive types that can be deserialized\n * (excludes Symbol which cannot be deserialized from JSON)\n */\nexport type PrimitiveConstructor =\n | StringConstructor\n | NumberConstructor\n | BooleanConstructor\n | BigIntConstructor\n | DateConstructor;\n\nexport type CtorLike<T> = AnyCtor<T> | BuiltinCtors;\n\nexport type InstanceOfCtorLike<C> = C extends StringConstructor\n ? string\n : C extends NumberConstructor\n ? number\n : C extends BooleanConstructor\n ? boolean\n : C extends BigIntConstructor\n ? bigint\n : C extends SymbolConstructor\n ? symbol\n : C extends DateConstructor\n ? Date\n : C extends AnyCtor<infer T>\n ? T\n : never;\n\n/**\n * Options for the Property decorator\n */\nexport interface PropertyOptions<\n T = any,\n C extends CtorLike<T> = AnyCtor<T> | BuiltinCtors,\n> {\n /**\n * Custom equality comparison function for this property\n * @param a - First value to compare\n * @param b - Second value to compare\n * @returns true if values are equal, false otherwise\n */\n equals?: (a: InstanceOfCtorLike<C>, b: InstanceOfCtorLike<C>) => boolean;\n\n /**\n * Type constructor for this property. Required for EntityUtils.parse() support.\n * Use a function that returns the type constructor to support forward references.\n * @example\n * @Property({ type: () => String })\n * name!: string;\n *\n * @Property({ type: () => Address })\n * address!: Address;\n */\n type: () => C;\n\n /**\n * Whether this property is an array. Defaults to false.\n * When true, the deserializer will map over array elements.\n * @example\n * @Property({ type: () => String, array: true })\n * tags!: string[];\n */\n array?: boolean;\n\n /**\n * Whether this property is optional. Defaults to false.\n * When true, the property can be undefined or null.\n * When false, the property must be present and not null/undefined.\n * @example\n * @Property({ type: () => String, optional: true })\n * nickname?: string;\n */\n optional?: boolean;\n\n /**\n * Whether the array can contain null/undefined elements. Defaults to false.\n * Only applicable when array is true.\n * When false (default), null/undefined elements will cause an error.\n * When true, null/undefined elements are allowed in the array.\n * @example\n * @Property({ type: () => String, array: true, sparse: true })\n * tags!: (string | null)[];\n */\n sparse?: boolean;\n\n /**\n * Whether to bypass type validation and pass values through as-is.\n * Use this for generic types like Record<string, unknown> or any.\n * When true, no type checking or transformation is performed.\n * Also bypasses any custom serialize/deserialize callbacks.\n * @example\n * @Property({ passthrough: true })\n * metadata!: Record<string, unknown>;\n */\n passthrough?: boolean;\n\n /**\n * Custom serialization function to convert the property value to JSON-compatible format.\n * Must be paired with deserialize - both must be defined together or both omitted.\n * Not used when passthrough is true.\n * @example\n * @Property({\n * type: () => MyClass,\n * serialize: (value) => ({ data: value.toData() }),\n * deserialize: (json) => MyClass.fromData(json.data)\n * })\n * myProperty!: MyClass;\n */\n serialize?: (value: InstanceOfCtorLike<C>) => unknown;\n\n /**\n * Custom deserialization function to convert JSON data back to the property type.\n * Must be paired with serialize - both must be defined together or both omitted.\n * Not used when passthrough is true.\n * @example\n * @Property({\n * type: () => MyClass,\n * serialize: (value) => ({ data: value.toData() }),\n * deserialize: (json) => MyClass.fromData(json.data)\n * })\n * myProperty!: MyClass;\n */\n deserialize?: (serialized: unknown) => InstanceOfCtorLike<C>;\n\n /**\n * Array of validator functions for this property.\n * Each validator receives the property value and validation context.\n * Empty array means validation passed.\n * If the property is an array (array: true), these validators will run against each item.\n * Use arrayValidators instead to validate the array as a whole.\n * If passthrough is true, validators will run against the raw value.\n * @example\n * @Property({\n * type: () => String,\n * validators: [\n * (value, { createProblem }) =>\n * value.length > 10 ? [createProblem('Too long')] : []\n * ]\n * })\n * name!: string;\n */\n validators?: PropertyValidator<InstanceOfCtorLike<C>>[];\n\n /**\n * Array of validator functions for this property when it is an array.\n * Each validator receives the array value and validation context.\n * Empty array means validation passed.\n * Only applicable when array is true.\n * Not applicable when passthrough is true.\n * @example\n * @Property({\n * type: () => Number,\n * array: true,\n * arrayValidators: [\n * (value, { createProblem }) =>\n * value.length === 0 ? [createProblem('Array cannot be empty')] : []\n * ]\n * })\n * scores!: number[];\n */\n arrayValidators?: PropertyValidator<InstanceOfCtorLike<C>[]>[];\n}\n\n/**\n * A validator function for a property.\n * The validator receives the value and returns Problems with property paths relative to the value.\n * Can be synchronous or asynchronous.\n * The calling code will prepend the actual property key to all returned problems.\n *\n * @param data - Object containing the value to validate\n * @param data.value - The value to validate\n * @returns Array of Problems (empty if valid) or Promise resolving to Problems.\n * Problems should have empty property for the value itself,\n * or relative paths for nested properties (e.g., 'name', '[0]', 'address.street')\n *\n * @example\n * ```typescript\n * // Synchronous validator\n * (({ value }) =>\n * value.length < 3 ? [new Problem({ property: '', message: 'Too short' })] : [])\n *\n * // Asynchronous validator\n * async ({ value }) => {\n * const exists = await checkDatabase(value);\n * return exists ? [] : [new Problem({ property: '', message: 'Not found' })];\n * }\n * ```\n */\nexport type PropertyValidator<T> = (data: {\n value: T;\n}) => Problem[] | Promise<Problem[]>;\n\n/**\n * A validator function for an entity.\n * Can be synchronous or asynchronous.\n * @param instance - The entity instance to validate\n * @returns Array of Problems (empty if valid) or Promise resolving to Problems\n */\nexport type EntityValidatorFn<T = any> = (\n instance: T,\n) => Problem[] | Promise<Problem[]>;\n"],"names":["PROPERTY_METADATA_KEY","Symbol","PROPERTY_OPTIONS_METADATA_KEY","ENTITY_METADATA_KEY","ENTITY_VALIDATOR_METADATA_KEY"],"mappings":"AAAA,qDAAqD,GACrD,6DAA6D,GAG7D;;CAEC,GACD,OAAO,MAAMA,wBAAwBC,OAAO,qBAAqB;AAEjE;;CAEC,GACD,OAAO,MAAMC,gCAAgCD,OAC3C,6BACA;AAEF;;CAEC,GACD,OAAO,MAAME,sBAAsBF,OAAO,mBAAmB;AAE7D;;CAEC,GACD,OAAO,MAAMG,gCAAgCH,OAC3C,6BACA"}
@@ -0,0 +1,18 @@
1
+ import type { PropertyValidator } from './types.js';
2
+ /**
3
+ * Creates a validator that checks if a string value is one of the allowed enum values
4
+ * @param enumType - The enum object containing valid values
5
+ * @returns A validator function that validates enum values
6
+ * @example
7
+ * enum Status { Active = 'active', Inactive = 'inactive' }
8
+ * const validator = enumValidator(Status);
9
+ */
10
+ export declare function enumValidator<T extends Record<string, string>>(enumType: T): PropertyValidator<string>;
11
+ /**
12
+ * Creates a validator that checks if a number is an integer (no decimal places)
13
+ * @returns A validator function that validates integer values
14
+ * @example
15
+ * const validator = intValidator();
16
+ */
17
+ export declare function intValidator(): PropertyValidator<number>;
18
+ //# sourceMappingURL=validators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/lib/validators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5D,QAAQ,EAAE,CAAC,GACV,iBAAiB,CAAC,MAAM,CAAC,CAa3B;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAYxD"}
@@ -0,0 +1,42 @@
1
+ import { Problem } from './problem.js';
2
+ /**
3
+ * Creates a validator that checks if a string value is one of the allowed enum values
4
+ * @param enumType - The enum object containing valid values
5
+ * @returns A validator function that validates enum values
6
+ * @example
7
+ * enum Status { Active = 'active', Inactive = 'inactive' }
8
+ * const validator = enumValidator(Status);
9
+ */ export function enumValidator(enumType) {
10
+ const validValues = Object.values(enumType);
11
+ return ({ value })=>{
12
+ if (!validValues.includes(value)) {
13
+ return [
14
+ new Problem({
15
+ property: '',
16
+ message: `Expected one of [${validValues.join(', ')}] but received "${value}"`
17
+ })
18
+ ];
19
+ }
20
+ return [];
21
+ };
22
+ }
23
+ /**
24
+ * Creates a validator that checks if a number is an integer (no decimal places)
25
+ * @returns A validator function that validates integer values
26
+ * @example
27
+ * const validator = intValidator();
28
+ */ export function intValidator() {
29
+ return ({ value })=>{
30
+ if (!Number.isInteger(value)) {
31
+ return [
32
+ new Problem({
33
+ property: '',
34
+ message: `Expected an integer but received ${value}`
35
+ })
36
+ ];
37
+ }
38
+ return [];
39
+ };
40
+ }
41
+
42
+ //# sourceMappingURL=validators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/lib/validators.ts"],"sourcesContent":["import { Problem } from './problem.js';\nimport type { PropertyValidator } from './types.js';\n\n/**\n * Creates a validator that checks if a string value is one of the allowed enum values\n * @param enumType - The enum object containing valid values\n * @returns A validator function that validates enum values\n * @example\n * enum Status { Active = 'active', Inactive = 'inactive' }\n * const validator = enumValidator(Status);\n */\nexport function enumValidator<T extends Record<string, string>>(\n enumType: T,\n): PropertyValidator<string> {\n const validValues = Object.values(enumType);\n return ({ value }: { value: string }) => {\n if (!validValues.includes(value)) {\n return [\n new Problem({\n property: '',\n message: `Expected one of [${validValues.join(', ')}] but received \"${value}\"`,\n }),\n ];\n }\n return [];\n };\n}\n\n/**\n * Creates a validator that checks if a number is an integer (no decimal places)\n * @returns A validator function that validates integer values\n * @example\n * const validator = intValidator();\n */\nexport function intValidator(): PropertyValidator<number> {\n return ({ value }: { value: number }) => {\n if (!Number.isInteger(value)) {\n return [\n new Problem({\n property: '',\n message: `Expected an integer but received ${value}`,\n }),\n ];\n }\n return [];\n };\n}\n"],"names":["Problem","enumValidator","enumType","validValues","Object","values","value","includes","property","message","join","intValidator","Number","isInteger"],"mappings":"AAAA,SAASA,OAAO,QAAQ,eAAe;AAGvC;;;;;;;CAOC,GACD,OAAO,SAASC,cACdC,QAAW;IAEX,MAAMC,cAAcC,OAAOC,MAAM,CAACH;IAClC,OAAO,CAAC,EAAEI,KAAK,EAAqB;QAClC,IAAI,CAACH,YAAYI,QAAQ,CAACD,QAAQ;YAChC,OAAO;gBACL,IAAIN,QAAQ;oBACVQ,UAAU;oBACVC,SAAS,CAAC,iBAAiB,EAAEN,YAAYO,IAAI,CAAC,MAAM,gBAAgB,EAAEJ,MAAM,CAAC,CAAC;gBAChF;aACD;QACH;QACA,OAAO,EAAE;IACX;AACF;AAEA;;;;;CAKC,GACD,OAAO,SAASK;IACd,OAAO,CAAC,EAAEL,KAAK,EAAqB;QAClC,IAAI,CAACM,OAAOC,SAAS,CAACP,QAAQ;YAC5B,OAAO;gBACL,IAAIN,QAAQ;oBACVQ,UAAU;oBACVC,SAAS,CAAC,iCAAiC,EAAEH,OAAO;gBACtD;aACD;QACH;QACA,OAAO,EAAE;IACX;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtpaulino/entity",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",