@rtpaulino/entity 0.12.0 → 0.14.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 +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/entity-utils.d.ts +92 -4
- package/dist/lib/entity-utils.d.ts.map +1 -1
- package/dist/lib/entity-utils.js +279 -66
- package/dist/lib/entity-utils.js.map +1 -1
- package/dist/lib/entity.d.ts +26 -0
- package/dist/lib/entity.d.ts.map +1 -1
- package/dist/lib/entity.js +37 -1
- package/dist/lib/entity.js.map +1 -1
- package/dist/lib/primitive-deserializers.d.ts +15 -0
- package/dist/lib/primitive-deserializers.d.ts.map +1 -0
- package/dist/lib/primitive-deserializers.js +87 -0
- package/dist/lib/primitive-deserializers.js.map +1 -0
- package/dist/lib/problem.d.ts +14 -0
- package/dist/lib/problem.d.ts.map +1 -0
- package/dist/lib/problem.js +31 -0
- package/dist/lib/problem.js.map +1 -0
- package/dist/lib/property.d.ts +15 -1
- package/dist/lib/property.d.ts.map +1 -1
- package/dist/lib/property.js +26 -1
- package/dist/lib/property.js.map +1 -1
- package/dist/lib/types.d.ts +82 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/validation-error.d.ts +9 -0
- package/dist/lib/validation-error.d.ts.map +1 -0
- package/dist/lib/validation-error.js +12 -0
- package/dist/lib/validation-error.js.map +1 -0
- package/dist/lib/validation-utils.d.ts +86 -0
- package/dist/lib/validation-utils.d.ts.map +1 -0
- package/dist/lib/validation-utils.js +112 -0
- package/dist/lib/validation-utils.js.map +1 -0
- package/package.json +1 -1
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Problem } from './problem.js';
|
|
1
2
|
/**
|
|
2
3
|
* Metadata key used to store property information
|
|
3
4
|
*/
|
|
@@ -10,8 +11,19 @@ export declare const PROPERTY_OPTIONS_METADATA_KEY: unique symbol;
|
|
|
10
11
|
* Metadata key used to store entity information
|
|
11
12
|
*/
|
|
12
13
|
export declare const ENTITY_METADATA_KEY: unique symbol;
|
|
13
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Metadata key used to store entity validator methods
|
|
16
|
+
*/
|
|
17
|
+
export declare const ENTITY_VALIDATOR_METADATA_KEY: unique symbol;
|
|
18
|
+
export type AnyCtor<T = any> = Function & {
|
|
19
|
+
prototype: T;
|
|
20
|
+
};
|
|
14
21
|
export type BuiltinCtors = StringConstructor | NumberConstructor | BooleanConstructor | BigIntConstructor | SymbolConstructor | DateConstructor;
|
|
22
|
+
/**
|
|
23
|
+
* Type constructors for primitive types that can be deserialized
|
|
24
|
+
* (excludes Symbol which cannot be deserialized from JSON)
|
|
25
|
+
*/
|
|
26
|
+
export type PrimitiveConstructor = StringConstructor | NumberConstructor | BooleanConstructor | BigIntConstructor | DateConstructor;
|
|
15
27
|
export type CtorLike<T> = AnyCtor<T> | BuiltinCtors;
|
|
16
28
|
export type InstanceOfCtorLike<C> = C extends StringConstructor ? string : C extends NumberConstructor ? number : C extends BooleanConstructor ? boolean : C extends BigIntConstructor ? bigint : C extends SymbolConstructor ? symbol : C extends DateConstructor ? Date : C extends AnyCtor<infer T> ? T : never;
|
|
17
29
|
/**
|
|
@@ -99,5 +111,74 @@ export interface PropertyOptions<T = any, C extends CtorLike<T> = AnyCtor<T> | B
|
|
|
99
111
|
* myProperty!: MyClass;
|
|
100
112
|
*/
|
|
101
113
|
deserialize?: (serialized: unknown) => InstanceOfCtorLike<C>;
|
|
114
|
+
/**
|
|
115
|
+
* Array of validator functions for this property.
|
|
116
|
+
* Each validator receives the property value and validation context.
|
|
117
|
+
* Empty array means validation passed.
|
|
118
|
+
* If the property is an array (array: true), these validators will run against each item.
|
|
119
|
+
* Use arrayValidators instead to validate the array as a whole.
|
|
120
|
+
* If passthrough is true, validators will run against the raw value.
|
|
121
|
+
* @example
|
|
122
|
+
* @Property({
|
|
123
|
+
* type: () => String,
|
|
124
|
+
* validators: [
|
|
125
|
+
* (value, { createProblem }) =>
|
|
126
|
+
* value.length > 10 ? [createProblem('Too long')] : []
|
|
127
|
+
* ]
|
|
128
|
+
* })
|
|
129
|
+
* name!: string;
|
|
130
|
+
*/
|
|
131
|
+
validators?: PropertyValidator<InstanceOfCtorLike<C>>[];
|
|
132
|
+
/**
|
|
133
|
+
* Array of validator functions for this property when it is an array.
|
|
134
|
+
* Each validator receives the array value and validation context.
|
|
135
|
+
* Empty array means validation passed.
|
|
136
|
+
* Only applicable when array is true.
|
|
137
|
+
* Not applicable when passthrough is true.
|
|
138
|
+
* @example
|
|
139
|
+
* @Property({
|
|
140
|
+
* type: () => Number,
|
|
141
|
+
* array: true,
|
|
142
|
+
* arrayValidators: [
|
|
143
|
+
* (value, { createProblem }) =>
|
|
144
|
+
* value.length === 0 ? [createProblem('Array cannot be empty')] : []
|
|
145
|
+
* ]
|
|
146
|
+
* })
|
|
147
|
+
* scores!: number[];
|
|
148
|
+
*/
|
|
149
|
+
arrayValidators?: PropertyValidator<InstanceOfCtorLike<C>[]>[];
|
|
102
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* A validator function for a property.
|
|
153
|
+
* The validator receives the value and returns Problems with property paths relative to the value.
|
|
154
|
+
* The calling code will prepend the actual property key to all returned problems.
|
|
155
|
+
*
|
|
156
|
+
* @param data - Object containing the value to validate
|
|
157
|
+
* @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
|
+
* or relative paths for nested properties (e.g., 'name', '[0]', 'address.street')
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* // Validator that checks the value itself
|
|
164
|
+
* (({ value }) =>
|
|
165
|
+
* value.length < 3 ? [new Problem({ property: '', message: 'Too short' })] : [])
|
|
166
|
+
*
|
|
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
|
+
* })
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export type PropertyValidator<T> = (data: {
|
|
176
|
+
value: T;
|
|
177
|
+
}) => Problem[];
|
|
178
|
+
/**
|
|
179
|
+
* A validator function for an entity
|
|
180
|
+
* @param instance - The entity instance to validate
|
|
181
|
+
* @returns Array of Problems (empty if valid)
|
|
182
|
+
*/
|
|
183
|
+
export type EntityValidatorFn<T = any> = (instance: T) => Problem[];
|
|
103
184
|
//# 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":"AAEA;;GAEG;AACH,eAAO,MAAM,qBAAqB,eAA8B,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,6BAA6B,eAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,eAA4B,CAAC;AAE7D,MAAM,MAAM,OAAO,CAAC,CAAC,GAAG,GAAG,IAAI,QAAQ,
|
|
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"}
|
package/dist/lib/types.js
CHANGED
|
@@ -7,5 +7,8 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Metadata key used to store entity information
|
|
9
9
|
*/ export const ENTITY_METADATA_KEY = Symbol('entity:metadata');
|
|
10
|
+
/**
|
|
11
|
+
* Metadata key used to store entity validator methods
|
|
12
|
+
*/ export const ENTITY_VALIDATOR_METADATA_KEY = Symbol('entity:validator:metadata');
|
|
10
13
|
|
|
11
14
|
//# 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 */\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\nexport type AnyCtor<T = any> =
|
|
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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Problem } from './problem.js';
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when HARD validation errors occur (type mismatches, missing required fields)
|
|
4
|
+
*/
|
|
5
|
+
export declare class ValidationError extends Error {
|
|
6
|
+
readonly problems: Problem[];
|
|
7
|
+
constructor(problems: Problem[]);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=validation-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-error.d.ts","sourceRoot":"","sources":["../../src/lib/validation-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;gBAEjB,QAAQ,EAAE,OAAO,EAAE;CAQhC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when HARD validation errors occur (type mismatches, missing required fields)
|
|
3
|
+
*/ export class ValidationError extends Error {
|
|
4
|
+
constructor(problems){
|
|
5
|
+
super(`Validation failed with ${problems.length} error(s): ${problems.map((p)=>p.toString()).join('; ')}`);
|
|
6
|
+
this.name = 'ValidationError';
|
|
7
|
+
this.problems = problems;
|
|
8
|
+
Object.setPrototypeOf(this, ValidationError.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=validation-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/validation-error.ts"],"sourcesContent":["import { Problem } from './problem.js';\n\n/**\n * Error thrown when HARD validation errors occur (type mismatches, missing required fields)\n */\nexport class ValidationError extends Error {\n readonly problems: Problem[];\n\n constructor(problems: Problem[]) {\n super(\n `Validation failed with ${problems.length} error(s): ${problems.map((p) => p.toString()).join('; ')}`,\n );\n this.name = 'ValidationError';\n this.problems = problems;\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n"],"names":["ValidationError","Error","problems","length","map","p","toString","join","name","Object","setPrototypeOf","prototype"],"mappings":"AAEA;;CAEC,GACD,OAAO,MAAMA,wBAAwBC;IAGnC,YAAYC,QAAmB,CAAE;QAC/B,KAAK,CACH,CAAC,uBAAuB,EAAEA,SAASC,MAAM,CAAC,WAAW,EAAED,SAASE,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ,IAAIC,IAAI,CAAC,OAAO;QAEvG,IAAI,CAACC,IAAI,GAAG;QACZ,IAAI,CAACN,QAAQ,GAAGA;QAChBO,OAAOC,cAAc,CAAC,IAAI,EAAEV,gBAAgBW,SAAS;IACvD;AACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Problem } from './problem.js';
|
|
2
|
+
import { ValidationError } from './validation-error.js';
|
|
3
|
+
/**
|
|
4
|
+
* Combines a property path prefix with a suffix according to deterministic rules:
|
|
5
|
+
* - If suffix is empty, returns prefix
|
|
6
|
+
* - If suffix starts with '[', concatenates without separator (e.g., 'items' + '[0]' → 'items[0]')
|
|
7
|
+
* - Otherwise, concatenates with dot separator (e.g., 'user' + 'name' → 'user.name')
|
|
8
|
+
*
|
|
9
|
+
* @param prefix - The property path to prepend
|
|
10
|
+
* @param suffix - The property path to append
|
|
11
|
+
* @returns The combined property path
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* combinePropertyPaths('user', '') // 'user'
|
|
16
|
+
* combinePropertyPaths('user', 'name') // 'user.name'
|
|
17
|
+
* combinePropertyPaths('items', '[0]') // 'items[0]'
|
|
18
|
+
* combinePropertyPaths('[0]', 'name') // '[0].name'
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function combinePropertyPaths(prefix: string, suffix: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a ValidationError with a single problem that has an empty property.
|
|
24
|
+
* This is used when reporting errors at the current scope level, where the caller
|
|
25
|
+
* will prepend the appropriate context path.
|
|
26
|
+
*
|
|
27
|
+
* @param message - The error message
|
|
28
|
+
* @returns A ValidationError with a single problem with empty property
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* throw createValidationError('Expects a string but received number');
|
|
33
|
+
* // Creates: ValidationError([{ property: '', message: 'Expects a string but received number' }])
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function createValidationError(message: string): ValidationError;
|
|
37
|
+
/**
|
|
38
|
+
* Prepends a property path to all problems in a ValidationError.
|
|
39
|
+
* Problems with empty property names get the path directly.
|
|
40
|
+
* Problems starting with '[' get the path without a dot separator.
|
|
41
|
+
* Other problems get the path with a dot separator.
|
|
42
|
+
*
|
|
43
|
+
* @param propertyPath - The property path to prepend (e.g., 'user', 'items[0]')
|
|
44
|
+
* @param error - The ValidationError containing problems to process
|
|
45
|
+
* @returns Array of Problems with the property path prepended
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const error = new ValidationError([
|
|
50
|
+
* new Problem({ property: '', message: 'Invalid type' }),
|
|
51
|
+
* new Problem({ property: 'name', message: 'Required' }),
|
|
52
|
+
* new Problem({ property: '[0]', message: 'Invalid element' })
|
|
53
|
+
* ]);
|
|
54
|
+
* const problems = prependPropertyPath('user', error);
|
|
55
|
+
* // [
|
|
56
|
+
* // { property: 'user', message: 'Invalid type' },
|
|
57
|
+
* // { property: 'user.name', message: 'Required' },
|
|
58
|
+
* // { property: 'user[0]', message: 'Invalid element' }
|
|
59
|
+
* // ]
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function prependPropertyPath(propertyPath: string, error: ValidationError): Problem[];
|
|
63
|
+
/**
|
|
64
|
+
* Prepends an array index to all problems in a ValidationError.
|
|
65
|
+
* Problems with empty property get `[index]` directly.
|
|
66
|
+
* Problems with non-empty property get `[index].property` format.
|
|
67
|
+
*
|
|
68
|
+
* @param index - The array index to prepend
|
|
69
|
+
* @param error - The ValidationError containing problems to process
|
|
70
|
+
* @returns Array of Problems with the array index prepended
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* const error = new ValidationError([
|
|
75
|
+
* new Problem({ property: '', message: 'Invalid type' }),
|
|
76
|
+
* new Problem({ property: 'name', message: 'Required' })
|
|
77
|
+
* ]);
|
|
78
|
+
* const problems = prependArrayIndex(0, error);
|
|
79
|
+
* // [
|
|
80
|
+
* // { property: '[0]', message: 'Invalid type' },
|
|
81
|
+
* // { property: '[0].name', message: 'Required' }
|
|
82
|
+
* // ]
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function prependArrayIndex(index: number, error: ValidationError): Problem[];
|
|
86
|
+
//# sourceMappingURL=validation-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-utils.d.ts","sourceRoot":"","sources":["../../src/lib/validation-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQ3E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAOtE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,eAAe,GACrB,OAAO,EAAE,CAOX;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,eAAe,GACrB,OAAO,EAAE,CAOX"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Problem } from './problem.js';
|
|
2
|
+
import { ValidationError } from './validation-error.js';
|
|
3
|
+
/**
|
|
4
|
+
* Combines a property path prefix with a suffix according to deterministic rules:
|
|
5
|
+
* - If suffix is empty, returns prefix
|
|
6
|
+
* - If suffix starts with '[', concatenates without separator (e.g., 'items' + '[0]' → 'items[0]')
|
|
7
|
+
* - Otherwise, concatenates with dot separator (e.g., 'user' + 'name' → 'user.name')
|
|
8
|
+
*
|
|
9
|
+
* @param prefix - The property path to prepend
|
|
10
|
+
* @param suffix - The property path to append
|
|
11
|
+
* @returns The combined property path
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* combinePropertyPaths('user', '') // 'user'
|
|
16
|
+
* combinePropertyPaths('user', 'name') // 'user.name'
|
|
17
|
+
* combinePropertyPaths('items', '[0]') // 'items[0]'
|
|
18
|
+
* combinePropertyPaths('[0]', 'name') // '[0].name'
|
|
19
|
+
* ```
|
|
20
|
+
*/ export function combinePropertyPaths(prefix, suffix) {
|
|
21
|
+
if (suffix === '') {
|
|
22
|
+
return prefix;
|
|
23
|
+
}
|
|
24
|
+
if (suffix.startsWith('[')) {
|
|
25
|
+
return `${prefix}${suffix}`;
|
|
26
|
+
}
|
|
27
|
+
return `${prefix}.${suffix}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a ValidationError with a single problem that has an empty property.
|
|
31
|
+
* This is used when reporting errors at the current scope level, where the caller
|
|
32
|
+
* will prepend the appropriate context path.
|
|
33
|
+
*
|
|
34
|
+
* @param message - The error message
|
|
35
|
+
* @returns A ValidationError with a single problem with empty property
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* throw createValidationError('Expects a string but received number');
|
|
40
|
+
* // Creates: ValidationError([{ property: '', message: 'Expects a string but received number' }])
|
|
41
|
+
* ```
|
|
42
|
+
*/ export function createValidationError(message) {
|
|
43
|
+
return new ValidationError([
|
|
44
|
+
new Problem({
|
|
45
|
+
property: '',
|
|
46
|
+
message
|
|
47
|
+
})
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Prepends a property path to all problems in a ValidationError.
|
|
52
|
+
* Problems with empty property names get the path directly.
|
|
53
|
+
* Problems starting with '[' get the path without a dot separator.
|
|
54
|
+
* Other problems get the path with a dot separator.
|
|
55
|
+
*
|
|
56
|
+
* @param propertyPath - The property path to prepend (e.g., 'user', 'items[0]')
|
|
57
|
+
* @param error - The ValidationError containing problems to process
|
|
58
|
+
* @returns Array of Problems with the property path prepended
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const error = new ValidationError([
|
|
63
|
+
* new Problem({ property: '', message: 'Invalid type' }),
|
|
64
|
+
* new Problem({ property: 'name', message: 'Required' }),
|
|
65
|
+
* new Problem({ property: '[0]', message: 'Invalid element' })
|
|
66
|
+
* ]);
|
|
67
|
+
* const problems = prependPropertyPath('user', error);
|
|
68
|
+
* // [
|
|
69
|
+
* // { property: 'user', message: 'Invalid type' },
|
|
70
|
+
* // { property: 'user.name', message: 'Required' },
|
|
71
|
+
* // { property: 'user[0]', message: 'Invalid element' }
|
|
72
|
+
* // ]
|
|
73
|
+
* ```
|
|
74
|
+
*/ export function prependPropertyPath(propertyPath, error) {
|
|
75
|
+
return error.problems.map((problem)=>{
|
|
76
|
+
return new Problem({
|
|
77
|
+
property: combinePropertyPaths(propertyPath, problem.property),
|
|
78
|
+
message: problem.message
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Prepends an array index to all problems in a ValidationError.
|
|
84
|
+
* Problems with empty property get `[index]` directly.
|
|
85
|
+
* Problems with non-empty property get `[index].property` format.
|
|
86
|
+
*
|
|
87
|
+
* @param index - The array index to prepend
|
|
88
|
+
* @param error - The ValidationError containing problems to process
|
|
89
|
+
* @returns Array of Problems with the array index prepended
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const error = new ValidationError([
|
|
94
|
+
* new Problem({ property: '', message: 'Invalid type' }),
|
|
95
|
+
* new Problem({ property: 'name', message: 'Required' })
|
|
96
|
+
* ]);
|
|
97
|
+
* const problems = prependArrayIndex(0, error);
|
|
98
|
+
* // [
|
|
99
|
+
* // { property: '[0]', message: 'Invalid type' },
|
|
100
|
+
* // { property: '[0].name', message: 'Required' }
|
|
101
|
+
* // ]
|
|
102
|
+
* ```
|
|
103
|
+
*/ export function prependArrayIndex(index, error) {
|
|
104
|
+
return error.problems.map((problem)=>{
|
|
105
|
+
return new Problem({
|
|
106
|
+
property: combinePropertyPaths(`[${index}]`, problem.property),
|
|
107
|
+
message: problem.message
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//# sourceMappingURL=validation-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/validation-utils.ts"],"sourcesContent":["import { Problem } from './problem.js';\nimport { ValidationError } from './validation-error.js';\n\n/**\n * Combines a property path prefix with a suffix according to deterministic rules:\n * - If suffix is empty, returns prefix\n * - If suffix starts with '[', concatenates without separator (e.g., 'items' + '[0]' → 'items[0]')\n * - Otherwise, concatenates with dot separator (e.g., 'user' + 'name' → 'user.name')\n *\n * @param prefix - The property path to prepend\n * @param suffix - The property path to append\n * @returns The combined property path\n *\n * @example\n * ```typescript\n * combinePropertyPaths('user', '') // 'user'\n * combinePropertyPaths('user', 'name') // 'user.name'\n * combinePropertyPaths('items', '[0]') // 'items[0]'\n * combinePropertyPaths('[0]', 'name') // '[0].name'\n * ```\n */\nexport function combinePropertyPaths(prefix: string, suffix: string): string {\n if (suffix === '') {\n return prefix;\n }\n if (suffix.startsWith('[')) {\n return `${prefix}${suffix}`;\n }\n return `${prefix}.${suffix}`;\n}\n\n/**\n * Creates a ValidationError with a single problem that has an empty property.\n * This is used when reporting errors at the current scope level, where the caller\n * will prepend the appropriate context path.\n *\n * @param message - The error message\n * @returns A ValidationError with a single problem with empty property\n *\n * @example\n * ```typescript\n * throw createValidationError('Expects a string but received number');\n * // Creates: ValidationError([{ property: '', message: 'Expects a string but received number' }])\n * ```\n */\nexport function createValidationError(message: string): ValidationError {\n return new ValidationError([\n new Problem({\n property: '',\n message,\n }),\n ]);\n}\n\n/**\n * Prepends a property path to all problems in a ValidationError.\n * Problems with empty property names get the path directly.\n * Problems starting with '[' get the path without a dot separator.\n * Other problems get the path with a dot separator.\n *\n * @param propertyPath - The property path to prepend (e.g., 'user', 'items[0]')\n * @param error - The ValidationError containing problems to process\n * @returns Array of Problems with the property path prepended\n *\n * @example\n * ```typescript\n * const error = new ValidationError([\n * new Problem({ property: '', message: 'Invalid type' }),\n * new Problem({ property: 'name', message: 'Required' }),\n * new Problem({ property: '[0]', message: 'Invalid element' })\n * ]);\n * const problems = prependPropertyPath('user', error);\n * // [\n * // { property: 'user', message: 'Invalid type' },\n * // { property: 'user.name', message: 'Required' },\n * // { property: 'user[0]', message: 'Invalid element' }\n * // ]\n * ```\n */\nexport function prependPropertyPath(\n propertyPath: string,\n error: ValidationError,\n): Problem[] {\n return error.problems.map((problem) => {\n return new Problem({\n property: combinePropertyPaths(propertyPath, problem.property),\n message: problem.message,\n });\n });\n}\n\n/**\n * Prepends an array index to all problems in a ValidationError.\n * Problems with empty property get `[index]` directly.\n * Problems with non-empty property get `[index].property` format.\n *\n * @param index - The array index to prepend\n * @param error - The ValidationError containing problems to process\n * @returns Array of Problems with the array index prepended\n *\n * @example\n * ```typescript\n * const error = new ValidationError([\n * new Problem({ property: '', message: 'Invalid type' }),\n * new Problem({ property: 'name', message: 'Required' })\n * ]);\n * const problems = prependArrayIndex(0, error);\n * // [\n * // { property: '[0]', message: 'Invalid type' },\n * // { property: '[0].name', message: 'Required' }\n * // ]\n * ```\n */\nexport function prependArrayIndex(\n index: number,\n error: ValidationError,\n): Problem[] {\n return error.problems.map((problem) => {\n return new Problem({\n property: combinePropertyPaths(`[${index}]`, problem.property),\n message: problem.message,\n });\n });\n}\n"],"names":["Problem","ValidationError","combinePropertyPaths","prefix","suffix","startsWith","createValidationError","message","property","prependPropertyPath","propertyPath","error","problems","map","problem","prependArrayIndex","index"],"mappings":"AAAA,SAASA,OAAO,QAAQ,eAAe;AACvC,SAASC,eAAe,QAAQ,wBAAwB;AAExD;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASC,qBAAqBC,MAAc,EAAEC,MAAc;IACjE,IAAIA,WAAW,IAAI;QACjB,OAAOD;IACT;IACA,IAAIC,OAAOC,UAAU,CAAC,MAAM;QAC1B,OAAO,GAAGF,SAASC,QAAQ;IAC7B;IACA,OAAO,GAAGD,OAAO,CAAC,EAAEC,QAAQ;AAC9B;AAEA;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASE,sBAAsBC,OAAe;IACnD,OAAO,IAAIN,gBAAgB;QACzB,IAAID,QAAQ;YACVQ,UAAU;YACVD;QACF;KACD;AACH;AAEA;;;;;;;;;;;;;;;;;;;;;;;;CAwBC,GACD,OAAO,SAASE,oBACdC,YAAoB,EACpBC,KAAsB;IAEtB,OAAOA,MAAMC,QAAQ,CAACC,GAAG,CAAC,CAACC;QACzB,OAAO,IAAId,QAAQ;YACjBQ,UAAUN,qBAAqBQ,cAAcI,QAAQN,QAAQ;YAC7DD,SAASO,QAAQP,OAAO;QAC1B;IACF;AACF;AAEA;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASQ,kBACdC,KAAa,EACbL,KAAsB;IAEtB,OAAOA,MAAMC,QAAQ,CAACC,GAAG,CAAC,CAACC;QACzB,OAAO,IAAId,QAAQ;YACjBQ,UAAUN,qBAAqB,CAAC,CAAC,EAAEc,MAAM,CAAC,CAAC,EAAEF,QAAQN,QAAQ;YAC7DD,SAASO,QAAQP,OAAO;QAC1B;IACF;AACF"}
|