@rtpaulino/entity 0.16.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/entity-di.d.ts +16 -0
- package/dist/lib/entity-di.d.ts.map +1 -0
- package/dist/lib/entity-di.js +40 -0
- package/dist/lib/entity-di.js.map +1 -0
- package/dist/lib/entity-utils.d.ts +1 -0
- package/dist/lib/entity-utils.d.ts.map +1 -1
- package/dist/lib/entity-utils.js +17 -0
- package/dist/lib/entity-utils.js.map +1 -1
- package/dist/lib/injected-property.d.ts +45 -0
- package/dist/lib/injected-property.d.ts.map +1 -0
- package/dist/lib/injected-property.js +61 -0
- package/dist/lib/injected-property.js.map +1 -0
- package/dist/lib/types.d.ts +22 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +7 -1
- package/dist/lib/types.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
export * from './lib/entity.js';
|
|
3
3
|
export * from './lib/entity-utils.js';
|
|
4
|
+
export * from './lib/entity-di.js';
|
|
4
5
|
export * from './lib/types.js';
|
|
5
6
|
export * from './lib/property.js';
|
|
6
7
|
export * from './lib/validation-error.js';
|
|
@@ -9,4 +10,5 @@ export * from './lib/validation-utils.js';
|
|
|
9
10
|
export * from './lib/primitive-deserializers.js';
|
|
10
11
|
export * from './lib/validators.js';
|
|
11
12
|
export * from './lib/zod-property.js';
|
|
13
|
+
export * from './lib/injected-property.js';
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;AACjD,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,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,oBAAoB,CAAC;AACnC,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;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
export * from './lib/entity.js';
|
|
3
3
|
export * from './lib/entity-utils.js';
|
|
4
|
+
export * from './lib/entity-di.js';
|
|
4
5
|
export * from './lib/types.js';
|
|
5
6
|
export * from './lib/property.js';
|
|
6
7
|
export * from './lib/validation-error.js';
|
|
@@ -9,5 +10,6 @@ export * from './lib/validation-utils.js';
|
|
|
9
10
|
export * from './lib/primitive-deserializers.js';
|
|
10
11
|
export * from './lib/validators.js';
|
|
11
12
|
export * from './lib/zod-property.js';
|
|
13
|
+
export * from './lib/injected-property.js';
|
|
12
14
|
|
|
13
15
|
//# 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';\nexport * from './lib/validators.js';\nexport * from './lib/zod-property.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;AACpC,cAAc,wBAAwB"}
|
|
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/entity-di.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';\nexport * from './lib/zod-property.js';\nexport * from './lib/injected-property.js';\n"],"names":[],"mappings":"AAAA,OAAO,mBAAmB;AAE1B,cAAc,kBAAkB;AAChC,cAAc,wBAAwB;AACtC,cAAc,qBAAqB;AACnC,cAAc,iBAAiB;AAC/B,cAAc,oBAAoB;AAClC,cAAc,4BAA4B;AAC1C,cAAc,mBAAmB;AACjC,cAAc,4BAA4B;AAC1C,cAAc,mCAAmC;AACjD,cAAc,sBAAsB;AACpC,cAAc,wBAAwB;AACtC,cAAc,6BAA6B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EntityDIFallbackFn, EntityDIProvider, EntityDIToken } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Dependency Injection container for Entities
|
|
4
|
+
* This is a simple implementation, it does not cache instances.
|
|
5
|
+
* When using "factory", it will always be called.
|
|
6
|
+
*/
|
|
7
|
+
export declare class EntityDI {
|
|
8
|
+
private static providers;
|
|
9
|
+
private static fallbackFn;
|
|
10
|
+
static configure({ providers, fallbackFn, }: {
|
|
11
|
+
providers?: EntityDIProvider[];
|
|
12
|
+
fallbackFn?: EntityDIFallbackFn;
|
|
13
|
+
}): void;
|
|
14
|
+
static get<T>(token: EntityDIToken<T>): Promise<T>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=entity-di.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-di.d.ts","sourceRoot":"","sources":["../../src/lib/entity-di.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAC,SAAS,CAA0B;IAElD,OAAO,CAAC,MAAM,CAAC,UAAU,CAA6C;IAEtE,MAAM,CAAC,SAAS,CAAC,EACf,SAAS,EACT,UAAU,GACX,EAAE;QACD,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;QAC/B,UAAU,CAAC,EAAE,kBAAkB,CAAC;KACjC;WASY,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAyBzD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Injection container for Entities
|
|
3
|
+
* This is a simple implementation, it does not cache instances.
|
|
4
|
+
* When using "factory", it will always be called.
|
|
5
|
+
*/ export class EntityDI {
|
|
6
|
+
static{
|
|
7
|
+
this.providers = [];
|
|
8
|
+
}
|
|
9
|
+
static{
|
|
10
|
+
this.fallbackFn = undefined;
|
|
11
|
+
}
|
|
12
|
+
static configure({ providers, fallbackFn }) {
|
|
13
|
+
if (providers) {
|
|
14
|
+
EntityDI.providers = providers;
|
|
15
|
+
}
|
|
16
|
+
if (fallbackFn) {
|
|
17
|
+
EntityDI.fallbackFn = fallbackFn;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
static async get(token) {
|
|
21
|
+
const provider = EntityDI.providers.find((p)=>p.provide === token);
|
|
22
|
+
if (provider) {
|
|
23
|
+
if (provider.useValue !== undefined) {
|
|
24
|
+
return provider.useValue;
|
|
25
|
+
} else if (provider.useFactory) {
|
|
26
|
+
return await provider.useFactory();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (EntityDI.fallbackFn) {
|
|
30
|
+
const result = await EntityDI.fallbackFn(token);
|
|
31
|
+
if (result) {
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const tokenName = (typeof token === 'object' || typeof token === 'function') && 'name' in token ? token.name : String(token);
|
|
36
|
+
throw new Error(`No provider found for token: ${tokenName}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=entity-di.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/entity-di.ts"],"sourcesContent":["import {\n EntityDIFallbackFn,\n EntityDIProvider,\n EntityDIToken,\n} from './types.js';\n\n/**\n * Dependency Injection container for Entities\n * This is a simple implementation, it does not cache instances.\n * When using \"factory\", it will always be called.\n */\nexport class EntityDI {\n private static providers: EntityDIProvider[] = [];\n\n private static fallbackFn: EntityDIFallbackFn | undefined = undefined;\n\n static configure({\n providers,\n fallbackFn,\n }: {\n providers?: EntityDIProvider[];\n fallbackFn?: EntityDIFallbackFn;\n }) {\n if (providers) {\n EntityDI.providers = providers;\n }\n if (fallbackFn) {\n EntityDI.fallbackFn = fallbackFn;\n }\n }\n\n static async get<T>(token: EntityDIToken<T>): Promise<T> {\n const provider = EntityDI.providers.find((p) => p.provide === token);\n if (provider) {\n if (provider.useValue !== undefined) {\n return provider.useValue;\n } else if (provider.useFactory) {\n return await provider.useFactory();\n }\n }\n\n if (EntityDI.fallbackFn) {\n const result = await EntityDI.fallbackFn(token);\n if (result) {\n return result;\n }\n }\n\n const tokenName =\n (typeof token === 'object' || typeof token === 'function') &&\n 'name' in token\n ? token.name\n : String(token);\n\n throw new Error(`No provider found for token: ${tokenName}`);\n }\n}\n"],"names":["EntityDI","providers","fallbackFn","undefined","configure","get","token","provider","find","p","provide","useValue","useFactory","result","tokenName","name","String","Error"],"mappings":"AAMA;;;;CAIC,GACD,OAAO,MAAMA;;aACIC,YAAgC,EAAE;;;aAElCC,aAA6CC;;IAE5D,OAAOC,UAAU,EACfH,SAAS,EACTC,UAAU,EAIX,EAAE;QACD,IAAID,WAAW;YACbD,SAASC,SAAS,GAAGA;QACvB;QACA,IAAIC,YAAY;YACdF,SAASE,UAAU,GAAGA;QACxB;IACF;IAEA,aAAaG,IAAOC,KAAuB,EAAc;QACvD,MAAMC,WAAWP,SAASC,SAAS,CAACO,IAAI,CAAC,CAACC,IAAMA,EAAEC,OAAO,KAAKJ;QAC9D,IAAIC,UAAU;YACZ,IAAIA,SAASI,QAAQ,KAAKR,WAAW;gBACnC,OAAOI,SAASI,QAAQ;YAC1B,OAAO,IAAIJ,SAASK,UAAU,EAAE;gBAC9B,OAAO,MAAML,SAASK,UAAU;YAClC;QACF;QAEA,IAAIZ,SAASE,UAAU,EAAE;YACvB,MAAMW,SAAS,MAAMb,SAASE,UAAU,CAACI;YACzC,IAAIO,QAAQ;gBACV,OAAOA;YACT;QACF;QAEA,MAAMC,YACJ,AAAC,CAAA,OAAOR,UAAU,YAAY,OAAOA,UAAU,UAAS,KACxD,UAAUA,QACNA,MAAMS,IAAI,GACVC,OAAOV;QAEb,MAAM,IAAIW,MAAM,CAAC,6BAA6B,EAAEH,WAAW;IAC7D;AACF"}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"entity-utils.d.ts","sourceRoot":"","sources":["../../src/lib/entity-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/entity-utils.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */ import { ENTITY_METADATA_KEY, ENTITY_VALIDATOR_METADATA_KEY, PROPERTY_METADATA_KEY, PROPERTY_OPTIONS_METADATA_KEY } from './types.js';
|
|
2
|
+
import { getInjectedPropertyNames, getInjectedPropertyOptions } from './injected-property.js';
|
|
3
|
+
import { EntityDI } from './entity-di.js';
|
|
2
4
|
import { isEqualWith } from 'lodash-es';
|
|
3
5
|
import { ValidationError } from './validation-error.js';
|
|
4
6
|
import { Problem } from './problem.js';
|
|
@@ -366,6 +368,7 @@ export class EntityUtils {
|
|
|
366
368
|
if (hardProblems.length > 0) {
|
|
367
369
|
throw new ValidationError(hardProblems);
|
|
368
370
|
}
|
|
371
|
+
await this.addInjectedDependencies(data, entityClass.prototype);
|
|
369
372
|
const instance = new entityClass(data);
|
|
370
373
|
rawInputStorage.set(instance, plainObject);
|
|
371
374
|
const problems = await this.validate(instance);
|
|
@@ -564,6 +567,20 @@ export class EntityUtils {
|
|
|
564
567
|
}
|
|
565
568
|
return problems;
|
|
566
569
|
}
|
|
570
|
+
static async addInjectedDependencies(data, prototype) {
|
|
571
|
+
const injectedPropertyNames = getInjectedPropertyNames(prototype);
|
|
572
|
+
if (injectedPropertyNames.length === 0) {
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const injectedPropertyOptions = getInjectedPropertyOptions(prototype);
|
|
576
|
+
for (const propertyName of injectedPropertyNames){
|
|
577
|
+
const token = injectedPropertyOptions[propertyName];
|
|
578
|
+
if (token) {
|
|
579
|
+
const dependency = await EntityDI.get(token);
|
|
580
|
+
data[propertyName] = dependency;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
567
584
|
/**
|
|
568
585
|
* Validates an entity instance by running all property and entity validators
|
|
569
586
|
*
|
|
@@ -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 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.getProblems()\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 && strict) {\n throw new ValidationError(problems);\n }\n\n return instance;\n }\n\n /**\n * Safely deserializes a plain object to an entity instance without throwing errors\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 result object with success flag, data, and problems\n *\n * @remarks\n * Similar to parse() but returns a result object instead of throwing errors:\n * - On success with strict: true - returns { success: true, data, problems: [] }\n * - On success with strict: false - returns { success: true, data, problems: [...] } (may include soft problems)\n * - On failure - returns { success: false, data: undefined, problems: [...] }\n *\n * All deserialization and validation rules from parse() apply.\n * See parse() documentation for detailed deserialization behavior.\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 result = await EntityUtils.safeParse(User, { name: 'John', age: 30 });\n * if (result.success) {\n * console.log(result.data); // User instance\n * console.log(result.problems); // [] or soft problems if not strict\n * } else {\n * console.log(result.problems); // Hard problems\n * }\n * ```\n */\n static async safeParse<T extends object>(\n entityClass: new (data: any) => T,\n plainObject: unknown,\n options?: { strict?: boolean },\n ): Promise<\n | {\n success: true;\n data: T;\n problems: Problem[];\n }\n | {\n success: false;\n data: undefined;\n problems: Problem[];\n }\n > {\n try {\n const data = await this.parse(entityClass, plainObject, options);\n const problems = this.getProblems(data);\n\n return {\n success: true,\n data,\n problems,\n };\n } catch (error) {\n if (error instanceof ValidationError) {\n return {\n success: false,\n data: undefined,\n problems: error.problems,\n };\n }\n throw error;\n }\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 existingProblems = problemsStorage.get(value);\n const nestedProblems =\n existingProblems && existingProblems.length > 0\n ? existingProblems\n : await EntityUtils.validate(value);\n\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 EntityUtils.setProblems(instance, problems);\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.getProblems(user);\n * console.log(problems); // [Problem, ...]\n * ```\n */\n static getProblems<T extends object>(instance: T): Problem[] {\n return problemsStorage.get(instance) || [];\n }\n\n /**\n * Sets the validation problems for an entity instance\n *\n * @param instance - The entity instance\n * @param problems - Array of Problems to associate with the instance\n *\n * @remarks\n * - Overwrites any existing problems for the instance\n * - Pass an empty array to clear problems\n *\n * @example\n * ```typescript\n * const user = new User({ name: 'John' });\n * EntityUtils.setProblems(user, [new Problem({ property: 'name', message: 'Invalid name' })]);\n * ```\n */\n static setProblems<T extends object>(instance: T, problems: Problem[]): void {\n if (problems.length === 0) {\n problemsStorage.delete(instance);\n } else {\n problemsStorage.set(instance, problems);\n }\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 * Sets the raw input data for an entity instance\n *\n * @param instance - The entity instance\n * @param rawInput - The raw input object to associate with the instance\n *\n * @remarks\n * - Overwrites any existing raw input for the instance\n * - Pass undefined to clear the raw input\n *\n * @example\n * ```typescript\n * const user = new User({ name: 'John' });\n * EntityUtils.setRawInput(user, { name: 'John', age: 30 });\n * ```\n */\n static setRawInput<T extends object>(\n instance: T,\n rawInput: Record<string, unknown> | undefined,\n ): void {\n if (rawInput === undefined) {\n rawInputStorage.delete(instance);\n } else {\n rawInputStorage.set(instance, rawInput);\n }\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","safeParse","getProblems","success","typeConstructor","type","array","isSparse","sparse","arrayProblems","index","deserialize","deserializeSingleValue","validatePropertyValue","propertyPath","validators","validator","validatorProblems","problem","existingProblems","get","nestedProblems","prependedProblems","runPropertyValidators","isPassthrough","valueProblems","arrayValidators","i","element","elementPath","elementProblems","validationProblems","entityValidators","getEntityValidators","validatorMethod","setProblems","delete","getRawInput","setRawInput","rawInput","protoValidators"],"mappings":"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"}
|
|
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 {\n getInjectedPropertyNames,\n getInjectedPropertyOptions,\n} from './injected-property.js';\nimport { EntityDI } from './entity-di.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.getProblems()\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 await this.addInjectedDependencies(data, entityClass.prototype);\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 && strict) {\n throw new ValidationError(problems);\n }\n\n return instance;\n }\n\n /**\n * Safely deserializes a plain object to an entity instance without throwing errors\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 result object with success flag, data, and problems\n *\n * @remarks\n * Similar to parse() but returns a result object instead of throwing errors:\n * - On success with strict: true - returns { success: true, data, problems: [] }\n * - On success with strict: false - returns { success: true, data, problems: [...] } (may include soft problems)\n * - On failure - returns { success: false, data: undefined, problems: [...] }\n *\n * All deserialization and validation rules from parse() apply.\n * See parse() documentation for detailed deserialization behavior.\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 result = await EntityUtils.safeParse(User, { name: 'John', age: 30 });\n * if (result.success) {\n * console.log(result.data); // User instance\n * console.log(result.problems); // [] or soft problems if not strict\n * } else {\n * console.log(result.problems); // Hard problems\n * }\n * ```\n */\n static async safeParse<T extends object>(\n entityClass: new (data: any) => T,\n plainObject: unknown,\n options?: { strict?: boolean },\n ): Promise<\n | {\n success: true;\n data: T;\n problems: Problem[];\n }\n | {\n success: false;\n data: undefined;\n problems: Problem[];\n }\n > {\n try {\n const data = await this.parse(entityClass, plainObject, options);\n const problems = this.getProblems(data);\n\n return {\n success: true,\n data,\n problems,\n };\n } catch (error) {\n if (error instanceof ValidationError) {\n return {\n success: false,\n data: undefined,\n problems: error.problems,\n };\n }\n throw error;\n }\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 existingProblems = problemsStorage.get(value);\n const nestedProblems =\n existingProblems && existingProblems.length > 0\n ? existingProblems\n : await EntityUtils.validate(value);\n\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 private static async addInjectedDependencies(\n data: Record<string, unknown>,\n prototype: object,\n ): Promise<void> {\n const injectedPropertyNames = getInjectedPropertyNames(prototype);\n if (injectedPropertyNames.length === 0) {\n return;\n }\n\n const injectedPropertyOptions = getInjectedPropertyOptions(prototype);\n\n for (const propertyName of injectedPropertyNames) {\n const token = injectedPropertyOptions[propertyName];\n if (token) {\n const dependency = await EntityDI.get(token);\n data[propertyName] = dependency;\n }\n }\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 EntityUtils.setProblems(instance, problems);\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.getProblems(user);\n * console.log(problems); // [Problem, ...]\n * ```\n */\n static getProblems<T extends object>(instance: T): Problem[] {\n return problemsStorage.get(instance) || [];\n }\n\n /**\n * Sets the validation problems for an entity instance\n *\n * @param instance - The entity instance\n * @param problems - Array of Problems to associate with the instance\n *\n * @remarks\n * - Overwrites any existing problems for the instance\n * - Pass an empty array to clear problems\n *\n * @example\n * ```typescript\n * const user = new User({ name: 'John' });\n * EntityUtils.setProblems(user, [new Problem({ property: 'name', message: 'Invalid name' })]);\n * ```\n */\n static setProblems<T extends object>(instance: T, problems: Problem[]): void {\n if (problems.length === 0) {\n problemsStorage.delete(instance);\n } else {\n problemsStorage.set(instance, problems);\n }\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 * Sets the raw input data for an entity instance\n *\n * @param instance - The entity instance\n * @param rawInput - The raw input object to associate with the instance\n *\n * @remarks\n * - Overwrites any existing raw input for the instance\n * - Pass undefined to clear the raw input\n *\n * @example\n * ```typescript\n * const user = new User({ name: 'John' });\n * EntityUtils.setRawInput(user, { name: 'John', age: 30 });\n * ```\n */\n static setRawInput<T extends object>(\n instance: T,\n rawInput: Record<string, unknown> | undefined,\n ): void {\n if (rawInput === undefined) {\n rawInputStorage.delete(instance);\n } else {\n rawInputStorage.set(instance, rawInput);\n }\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","getInjectedPropertyNames","getInjectedPropertyOptions","EntityDI","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","addInjectedDependencies","instance","set","validate","safeParse","getProblems","success","typeConstructor","type","array","isSparse","sparse","arrayProblems","index","deserialize","deserializeSingleValue","validatePropertyValue","propertyPath","validators","validator","validatorProblems","problem","existingProblems","get","nestedProblems","prependedProblems","runPropertyValidators","isPassthrough","valueProblems","arrayValidators","i","element","elementPath","elementProblems","injectedPropertyNames","injectedPropertyOptions","propertyName","token","dependency","validationProblems","entityValidators","getEntityValidators","validatorMethod","setProblems","delete","getRawInput","setRawInput","rawInput","protoValidators"],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type EntityDIToken } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that marks a class property as an injected dependency.
|
|
4
|
+
* Injected properties are not part of JSON serialization/deserialization,
|
|
5
|
+
* but are manually injected into the object after construction.
|
|
6
|
+
*
|
|
7
|
+
* The decorated property will be accepted via the constructor just like
|
|
8
|
+
* other properties, and will be injected via EntityDI when needed.
|
|
9
|
+
*
|
|
10
|
+
* @param token - The EntityDI token to use for resolving this dependency
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @Entity()
|
|
15
|
+
* class UserService {
|
|
16
|
+
* @Property({ type: () => String })
|
|
17
|
+
* name!: string;
|
|
18
|
+
*
|
|
19
|
+
* @InjectedProperty(DatabaseToken)
|
|
20
|
+
* db!: Database;
|
|
21
|
+
*
|
|
22
|
+
* constructor(data: { name: string; db: Database }) {
|
|
23
|
+
* this.name = data.name;
|
|
24
|
+
* this.db = data.db;
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // When parsing JSON, the db property is ignored and injected afterwards
|
|
29
|
+
* const json = { name: 'John' }; // No db field
|
|
30
|
+
* const service = await EntityUtils.parse(UserService, json);
|
|
31
|
+
* // service.db is injected via EntityDI
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function InjectedProperty<T = any>(token: EntityDIToken<T>): PropertyDecorator;
|
|
35
|
+
/**
|
|
36
|
+
* Get the list of injected property names for a class
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function getInjectedPropertyNames(target: any): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Get the injected property options (tokens) for a class
|
|
42
|
+
* @internal
|
|
43
|
+
*/
|
|
44
|
+
export declare function getInjectedPropertyOptions(target: any): Record<string, EntityDIToken<any>>;
|
|
45
|
+
//# sourceMappingURL=injected-property.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injected-property.d.ts","sourceRoot":"","sources":["../../src/lib/injected-property.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,GAAG,GAAG,EACtC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GACtB,iBAAiB,CAmCnB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,EAAE,CAE9D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,GAAG,GACV,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAIpC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */ import { INJECTED_PROPERTY_METADATA_KEY, INJECTED_PROPERTY_OPTIONS_METADATA_KEY } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decorator that marks a class property as an injected dependency.
|
|
4
|
+
* Injected properties are not part of JSON serialization/deserialization,
|
|
5
|
+
* but are manually injected into the object after construction.
|
|
6
|
+
*
|
|
7
|
+
* The decorated property will be accepted via the constructor just like
|
|
8
|
+
* other properties, and will be injected via EntityDI when needed.
|
|
9
|
+
*
|
|
10
|
+
* @param token - The EntityDI token to use for resolving this dependency
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @Entity()
|
|
15
|
+
* class UserService {
|
|
16
|
+
* @Property({ type: () => String })
|
|
17
|
+
* name!: string;
|
|
18
|
+
*
|
|
19
|
+
* @InjectedProperty(DatabaseToken)
|
|
20
|
+
* db!: Database;
|
|
21
|
+
*
|
|
22
|
+
* constructor(data: { name: string; db: Database }) {
|
|
23
|
+
* this.name = data.name;
|
|
24
|
+
* this.db = data.db;
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* // When parsing JSON, the db property is ignored and injected afterwards
|
|
29
|
+
* const json = { name: 'John' }; // No db field
|
|
30
|
+
* const service = await EntityUtils.parse(UserService, json);
|
|
31
|
+
* // service.db is injected via EntityDI
|
|
32
|
+
* ```
|
|
33
|
+
*/ export function InjectedProperty(token) {
|
|
34
|
+
return (target, propertyKey)=>{
|
|
35
|
+
if (typeof propertyKey !== 'string') {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const existingProperties = Reflect.getOwnMetadata(INJECTED_PROPERTY_METADATA_KEY, target) || [];
|
|
39
|
+
if (!existingProperties.includes(propertyKey)) {
|
|
40
|
+
existingProperties.push(propertyKey);
|
|
41
|
+
}
|
|
42
|
+
Reflect.defineMetadata(INJECTED_PROPERTY_METADATA_KEY, existingProperties, target);
|
|
43
|
+
const existingOptions = Reflect.getOwnMetadata(INJECTED_PROPERTY_OPTIONS_METADATA_KEY, target) || {};
|
|
44
|
+
existingOptions[propertyKey] = token;
|
|
45
|
+
Reflect.defineMetadata(INJECTED_PROPERTY_OPTIONS_METADATA_KEY, existingOptions, target);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the list of injected property names for a class
|
|
50
|
+
* @internal
|
|
51
|
+
*/ export function getInjectedPropertyNames(target) {
|
|
52
|
+
return Reflect.getOwnMetadata(INJECTED_PROPERTY_METADATA_KEY, target) || [];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the injected property options (tokens) for a class
|
|
56
|
+
* @internal
|
|
57
|
+
*/ export function getInjectedPropertyOptions(target) {
|
|
58
|
+
return Reflect.getOwnMetadata(INJECTED_PROPERTY_OPTIONS_METADATA_KEY, target) || {};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=injected-property.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/injected-property.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n INJECTED_PROPERTY_METADATA_KEY,\n INJECTED_PROPERTY_OPTIONS_METADATA_KEY,\n type EntityDIToken,\n} from './types.js';\n\n/**\n * Decorator that marks a class property as an injected dependency.\n * Injected properties are not part of JSON serialization/deserialization,\n * but are manually injected into the object after construction.\n *\n * The decorated property will be accepted via the constructor just like\n * other properties, and will be injected via EntityDI when needed.\n *\n * @param token - The EntityDI token to use for resolving this dependency\n *\n * @example\n * ```typescript\n * @Entity()\n * class UserService {\n * @Property({ type: () => String })\n * name!: string;\n *\n * @InjectedProperty(DatabaseToken)\n * db!: Database;\n *\n * constructor(data: { name: string; db: Database }) {\n * this.name = data.name;\n * this.db = data.db;\n * }\n * }\n *\n * // When parsing JSON, the db property is ignored and injected afterwards\n * const json = { name: 'John' }; // No db field\n * const service = await EntityUtils.parse(UserService, json);\n * // service.db is injected via EntityDI\n * ```\n */\nexport function InjectedProperty<T = any>(\n token: EntityDIToken<T>,\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(INJECTED_PROPERTY_METADATA_KEY, target) || [];\n\n if (!existingProperties.includes(propertyKey)) {\n existingProperties.push(propertyKey);\n }\n\n Reflect.defineMetadata(\n INJECTED_PROPERTY_METADATA_KEY,\n existingProperties,\n target,\n );\n\n const existingOptions: Record<\n string,\n EntityDIToken<any>\n > = Reflect.getOwnMetadata(\n INJECTED_PROPERTY_OPTIONS_METADATA_KEY,\n target,\n ) || {};\n\n existingOptions[propertyKey] = token;\n\n Reflect.defineMetadata(\n INJECTED_PROPERTY_OPTIONS_METADATA_KEY,\n existingOptions,\n target,\n );\n };\n}\n\n/**\n * Get the list of injected property names for a class\n * @internal\n */\nexport function getInjectedPropertyNames(target: any): string[] {\n return Reflect.getOwnMetadata(INJECTED_PROPERTY_METADATA_KEY, target) || [];\n}\n\n/**\n * Get the injected property options (tokens) for a class\n * @internal\n */\nexport function getInjectedPropertyOptions(\n target: any,\n): Record<string, EntityDIToken<any>> {\n return (\n Reflect.getOwnMetadata(INJECTED_PROPERTY_OPTIONS_METADATA_KEY, target) || {}\n );\n}\n"],"names":["INJECTED_PROPERTY_METADATA_KEY","INJECTED_PROPERTY_OPTIONS_METADATA_KEY","InjectedProperty","token","target","propertyKey","existingProperties","Reflect","getOwnMetadata","includes","push","defineMetadata","existingOptions","getInjectedPropertyNames","getInjectedPropertyOptions"],"mappings":"AAAA,qDAAqD,GACrD,SACEA,8BAA8B,EAC9BC,sCAAsC,QAEjC,aAAa;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BC,GACD,OAAO,SAASC,iBACdC,KAAuB;IAEvB,OAAO,CAACC,QAAgBC;QACtB,IAAI,OAAOA,gBAAgB,UAAU;YACnC;QACF;QAEA,MAAMC,qBACJC,QAAQC,cAAc,CAACR,gCAAgCI,WAAW,EAAE;QAEtE,IAAI,CAACE,mBAAmBG,QAAQ,CAACJ,cAAc;YAC7CC,mBAAmBI,IAAI,CAACL;QAC1B;QAEAE,QAAQI,cAAc,CACpBX,gCACAM,oBACAF;QAGF,MAAMQ,kBAGFL,QAAQC,cAAc,CACxBP,wCACAG,WACG,CAAC;QAENQ,eAAe,CAACP,YAAY,GAAGF;QAE/BI,QAAQI,cAAc,CACpBV,wCACAW,iBACAR;IAEJ;AACF;AAEA;;;CAGC,GACD,OAAO,SAASS,yBAAyBT,MAAW;IAClD,OAAOG,QAAQC,cAAc,CAACR,gCAAgCI,WAAW,EAAE;AAC7E;AAEA;;;CAGC,GACD,OAAO,SAASU,2BACdV,MAAW;IAEX,OACEG,QAAQC,cAAc,CAACP,wCAAwCG,WAAW,CAAC;AAE/E"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -15,6 +15,14 @@ export declare const ENTITY_METADATA_KEY: unique symbol;
|
|
|
15
15
|
* Metadata key used to store entity validator methods
|
|
16
16
|
*/
|
|
17
17
|
export declare const ENTITY_VALIDATOR_METADATA_KEY: unique symbol;
|
|
18
|
+
/**
|
|
19
|
+
* Metadata key used to store injected property information
|
|
20
|
+
*/
|
|
21
|
+
export declare const INJECTED_PROPERTY_METADATA_KEY: unique symbol;
|
|
22
|
+
/**
|
|
23
|
+
* Metadata key used to store injected property options (tokens)
|
|
24
|
+
*/
|
|
25
|
+
export declare const INJECTED_PROPERTY_OPTIONS_METADATA_KEY: unique symbol;
|
|
18
26
|
export type AnyCtor<T = any> = Function & {
|
|
19
27
|
prototype: T;
|
|
20
28
|
};
|
|
@@ -183,4 +191,18 @@ export type PropertyValidator<T> = (data: {
|
|
|
183
191
|
* @returns Array of Problems (empty if valid) or Promise resolving to Problems
|
|
184
192
|
*/
|
|
185
193
|
export type EntityValidatorFn<T = any> = (instance: T) => Problem[] | Promise<Problem[]>;
|
|
194
|
+
export interface Type<T = any> extends Function {
|
|
195
|
+
new (...args: any[]): T;
|
|
196
|
+
}
|
|
197
|
+
export type EntityDIToken<T = any> = string | symbol | Function | AnyCtor<T> | Type<T>;
|
|
198
|
+
export type EntityDIProvider<T = any> = {
|
|
199
|
+
provide: EntityDIToken<T>;
|
|
200
|
+
useValue?: T;
|
|
201
|
+
useFactory?: never;
|
|
202
|
+
} | {
|
|
203
|
+
provide: EntityDIToken<T>;
|
|
204
|
+
useValue?: never;
|
|
205
|
+
useFactory?: () => T | Promise<T>;
|
|
206
|
+
};
|
|
207
|
+
export type EntityDIFallbackFn = (token: EntityDIToken) => Promise<any>;
|
|
186
208
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-wrapper-object-types */ /**
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-function-type */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-wrapper-object-types */ /**
|
|
2
2
|
* Metadata key used to store property information
|
|
3
3
|
*/ export const PROPERTY_METADATA_KEY = Symbol('property:metadata');
|
|
4
4
|
/**
|
|
@@ -10,5 +10,11 @@
|
|
|
10
10
|
/**
|
|
11
11
|
* Metadata key used to store entity validator methods
|
|
12
12
|
*/ export const ENTITY_VALIDATOR_METADATA_KEY = Symbol('entity:validator:metadata');
|
|
13
|
+
/**
|
|
14
|
+
* Metadata key used to store injected property information
|
|
15
|
+
*/ export const INJECTED_PROPERTY_METADATA_KEY = Symbol('injected-property:metadata');
|
|
16
|
+
/**
|
|
17
|
+
* Metadata key used to store injected property options (tokens)
|
|
18
|
+
*/ export const INJECTED_PROPERTY_OPTIONS_METADATA_KEY = Symbol('injected-property:options:metadata');
|
|
13
19
|
|
|
14
20
|
//# sourceMappingURL=types.js.map
|
package/dist/lib/types.js.map
CHANGED
|
@@ -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
|
|
1
|
+
{"version":3,"sources":["../../src/lib/types.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-function-type */\n/* 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/**\n * Metadata key used to store injected property information\n */\nexport const INJECTED_PROPERTY_METADATA_KEY = Symbol(\n 'injected-property:metadata',\n);\n\n/**\n * Metadata key used to store injected property options (tokens)\n */\nexport const INJECTED_PROPERTY_OPTIONS_METADATA_KEY = Symbol(\n 'injected-property:options:metadata',\n);\n\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\nexport interface Type<T = any> extends Function {\n new (...args: any[]): T;\n}\n\nexport type EntityDIToken<T = any> =\n | string\n | symbol\n | Function\n | AnyCtor<T>\n | Type<T>;\n\nexport type EntityDIProvider<T = any> =\n | {\n provide: EntityDIToken<T>;\n useValue?: T;\n useFactory?: never;\n }\n | {\n provide: EntityDIToken<T>;\n useValue?: never;\n useFactory?: () => T | Promise<T>;\n };\n\nexport type EntityDIFallbackFn = (token: EntityDIToken) => Promise<any>;\n"],"names":["PROPERTY_METADATA_KEY","Symbol","PROPERTY_OPTIONS_METADATA_KEY","ENTITY_METADATA_KEY","ENTITY_VALIDATOR_METADATA_KEY","INJECTED_PROPERTY_METADATA_KEY","INJECTED_PROPERTY_OPTIONS_METADATA_KEY"],"mappings":"AAAA,6DAA6D,GAC7D,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;AAEF;;CAEC,GACD,OAAO,MAAMI,iCAAiCJ,OAC5C,8BACA;AAEF;;CAEC,GACD,OAAO,MAAMK,yCAAyCL,OACpD,sCACA"}
|