@digitaldefiance/branded-enum 0.0.1 → 0.0.3
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/cjs/index.cjs +149 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/lib/accessors.cjs +55 -0
- package/dist/cjs/lib/accessors.cjs.map +1 -0
- package/dist/cjs/lib/advanced.cjs +558 -0
- package/dist/cjs/lib/advanced.cjs.map +1 -0
- package/dist/cjs/lib/branded-enum.cjs +15 -0
- package/dist/cjs/lib/branded-enum.cjs.map +1 -0
- package/dist/cjs/lib/decorators.cjs +202 -0
- package/dist/cjs/lib/decorators.cjs.map +1 -0
- package/dist/cjs/lib/factory.cjs +45 -0
- package/dist/cjs/lib/factory.cjs.map +1 -0
- package/dist/cjs/lib/guards.cjs +119 -0
- package/dist/cjs/lib/guards.cjs.map +1 -0
- package/dist/cjs/lib/merge.cjs +47 -0
- package/dist/cjs/lib/merge.cjs.map +1 -0
- package/dist/cjs/lib/registry.cjs +85 -0
- package/dist/cjs/lib/registry.cjs.map +1 -0
- package/dist/cjs/lib/types.cjs +38 -0
- package/dist/cjs/lib/types.cjs.map +1 -0
- package/dist/cjs/lib/utils.cjs +80 -0
- package/dist/cjs/lib/utils.cjs.map +1 -0
- package/dist/esm/index.d.ts +21 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/accessors.d.ts +79 -0
- package/dist/esm/lib/accessors.d.ts.map +1 -0
- package/dist/esm/lib/accessors.js.map +1 -0
- package/dist/esm/lib/advanced.d.ts +1422 -0
- package/dist/esm/lib/advanced.d.ts.map +1 -0
- package/dist/esm/lib/advanced.js.map +1 -0
- package/dist/esm/lib/branded-enum.d.ts +2 -0
- package/dist/esm/lib/branded-enum.d.ts.map +1 -0
- package/dist/esm/lib/branded-enum.js.map +1 -0
- package/dist/esm/lib/decorators.d.ts +147 -0
- package/dist/esm/lib/decorators.d.ts.map +1 -0
- package/dist/esm/lib/decorators.js.map +1 -0
- package/dist/esm/lib/factory.d.ts +52 -0
- package/dist/esm/lib/factory.d.ts.map +1 -0
- package/dist/esm/lib/factory.js.map +1 -0
- package/dist/esm/lib/guards.d.ts +297 -0
- package/dist/esm/lib/guards.d.ts.map +1 -0
- package/dist/esm/lib/guards.js.map +1 -0
- package/dist/esm/lib/merge.d.ts +64 -0
- package/dist/esm/lib/merge.d.ts.map +1 -0
- package/dist/esm/lib/merge.js.map +1 -0
- package/dist/esm/lib/registry.d.ts +93 -0
- package/dist/esm/lib/registry.d.ts.map +1 -0
- package/dist/esm/lib/registry.js.map +1 -0
- package/dist/esm/lib/types.d.ts +258 -0
- package/dist/esm/lib/types.d.ts.map +1 -0
- package/dist/esm/lib/types.js.map +1 -0
- package/dist/esm/lib/utils.d.ts +121 -0
- package/dist/esm/lib/utils.d.ts.map +1 -0
- package/dist/esm/lib/utils.js.map +1 -0
- package/package.json +31 -18
- package/dist/index.js.map +0 -1
- package/dist/lib/accessors.js.map +0 -1
- package/dist/lib/advanced.js.map +0 -1
- package/dist/lib/branded-enum.js.map +0 -1
- package/dist/lib/decorators.js.map +0 -1
- package/dist/lib/factory.js.map +0 -1
- package/dist/lib/guards.js.map +0 -1
- package/dist/lib/merge.js.map +0 -1
- package/dist/lib/registry.js.map +0 -1
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
- package/dist/package.json +0 -120
- /package/dist/{index.js → esm/index.js} +0 -0
- /package/dist/{lib → esm/lib}/accessors.js +0 -0
- /package/dist/{lib → esm/lib}/advanced.js +0 -0
- /package/dist/{lib → esm/lib}/branded-enum.js +0 -0
- /package/dist/{lib → esm/lib}/decorators.js +0 -0
- /package/dist/{lib → esm/lib}/factory.js +0 -0
- /package/dist/{lib → esm/lib}/guards.js +0 -0
- /package/dist/{lib → esm/lib}/merge.js +0 -0
- /package/dist/{lib → esm/lib}/registry.js +0 -0
- /package/dist/{lib → esm/lib}/types.js +0 -0
- /package/dist/{lib → esm/lib}/utils.js +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for branded-enum library
|
|
3
|
+
*
|
|
4
|
+
* These types enable runtime-identifiable enum-like objects in TypeScript
|
|
5
|
+
* with zero runtime overhead for value access.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Symbol key for storing the enum ID metadata.
|
|
9
|
+
* Using a Symbol prevents collision with user-defined keys.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ENUM_ID: unique symbol;
|
|
12
|
+
/**
|
|
13
|
+
* Symbol key for storing the enum values Set.
|
|
14
|
+
* Using a Symbol prevents collision with user-defined keys.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ENUM_VALUES: unique symbol;
|
|
17
|
+
/**
|
|
18
|
+
* Metadata attached to branded enums via Symbol properties.
|
|
19
|
+
* These properties are non-enumerable and won't appear in
|
|
20
|
+
* Object.keys(), Object.values(), or JSON serialization.
|
|
21
|
+
*/
|
|
22
|
+
export interface BrandedEnumMetadata {
|
|
23
|
+
readonly [ENUM_ID]: string;
|
|
24
|
+
readonly [ENUM_VALUES]: Set<string>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A branded enum object - combines the user's values object with metadata.
|
|
28
|
+
* The object is frozen (Readonly) to prevent modification after creation.
|
|
29
|
+
*
|
|
30
|
+
* @template T - The shape of the enum values object (Record<string, string>)
|
|
31
|
+
*/
|
|
32
|
+
export type BrandedEnum<T extends Record<string, string>> = Readonly<T> & BrandedEnumMetadata;
|
|
33
|
+
/**
|
|
34
|
+
* Base constraint type for branded enums that works with both
|
|
35
|
+
* `as const` objects and regular Record<string, string> objects.
|
|
36
|
+
*
|
|
37
|
+
* This type is more permissive than `BrandedEnum<Record<string, string>>`
|
|
38
|
+
* and allows literal types from `as const` assertions.
|
|
39
|
+
*/
|
|
40
|
+
export type AnyBrandedEnum = {
|
|
41
|
+
readonly [ENUM_ID]: string;
|
|
42
|
+
readonly [ENUM_VALUES]: Set<string>;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Utility type to extract the union of all value types from a branded enum.
|
|
46
|
+
* Useful for typing variables that can hold any value from the enum.
|
|
47
|
+
*
|
|
48
|
+
* @template E - A BrandedEnum type
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);
|
|
52
|
+
* type StatusValue = BrandedEnumValue<typeof Status>; // 'active' | 'inactive'
|
|
53
|
+
*/
|
|
54
|
+
export type BrandedEnumValue<E extends AnyBrandedEnum> = E extends BrandedEnum<infer T> ? T[keyof T] : never;
|
|
55
|
+
/**
|
|
56
|
+
* Registry entry for tracking a single branded enum in the global registry.
|
|
57
|
+
*/
|
|
58
|
+
export interface RegistryEntry {
|
|
59
|
+
/** The unique identifier for this enum */
|
|
60
|
+
readonly enumId: string;
|
|
61
|
+
/** The branded enum object itself */
|
|
62
|
+
readonly enumObj: BrandedEnum<Record<string, string>>;
|
|
63
|
+
/** Set of all values in this enum for O(1) lookup */
|
|
64
|
+
readonly values: Set<string>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Global registry structure stored on globalThis.
|
|
68
|
+
* Enables cross-bundle tracking of all branded enums.
|
|
69
|
+
*/
|
|
70
|
+
export interface BrandedEnumRegistry {
|
|
71
|
+
/** Map from enumId to registry entry */
|
|
72
|
+
readonly enums: Map<string, RegistryEntry>;
|
|
73
|
+
/** Reverse index: value -> Set of enumIds containing that value */
|
|
74
|
+
readonly valueIndex: Map<string, Set<string>>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The key used to store the registry on globalThis.
|
|
78
|
+
* Namespaced to avoid collisions with other libraries.
|
|
79
|
+
*/
|
|
80
|
+
export declare const REGISTRY_KEY: "__brandedEnumRegistry__";
|
|
81
|
+
/**
|
|
82
|
+
* The key used to store the enum consumer registry on globalThis.
|
|
83
|
+
* Tracks which classes consume which branded enums.
|
|
84
|
+
*/
|
|
85
|
+
export declare const CONSUMER_REGISTRY_KEY: "__brandedEnumConsumerRegistry__";
|
|
86
|
+
/**
|
|
87
|
+
* Entry tracking a class that consumes branded enums.
|
|
88
|
+
*/
|
|
89
|
+
export interface EnumConsumerEntry {
|
|
90
|
+
/** The class constructor function */
|
|
91
|
+
readonly classRef: new (...args: any[]) => any;
|
|
92
|
+
/** The class name */
|
|
93
|
+
readonly className: string;
|
|
94
|
+
/** Set of enum IDs that this class consumes */
|
|
95
|
+
readonly enumIds: Set<string>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Global registry for tracking enum consumers (classes decorated with @EnumClass).
|
|
99
|
+
* Enables debugging and introspection of enum usage across the codebase.
|
|
100
|
+
*/
|
|
101
|
+
export interface EnumConsumerRegistry {
|
|
102
|
+
/** Map from class name to consumer entry */
|
|
103
|
+
readonly consumers: Map<string, EnumConsumerEntry>;
|
|
104
|
+
/** Reverse index: enumId -> Set of class names consuming that enum */
|
|
105
|
+
readonly enumToConsumers: Map<string, Set<string>>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Extracts the union of all keys from a branded enum.
|
|
109
|
+
*
|
|
110
|
+
* This utility type provides compile-time access to all key names of a branded enum,
|
|
111
|
+
* excluding the Symbol metadata keys (ENUM_ID and ENUM_VALUES).
|
|
112
|
+
*
|
|
113
|
+
* @template E - A BrandedEnum type
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* const Status = createBrandedEnum('status', {
|
|
117
|
+
* Active: 'active',
|
|
118
|
+
* Inactive: 'inactive',
|
|
119
|
+
* Pending: 'pending',
|
|
120
|
+
* } as const);
|
|
121
|
+
*
|
|
122
|
+
* type StatusKeys = EnumKeys<typeof Status>;
|
|
123
|
+
* // StatusKeys = 'Active' | 'Inactive' | 'Pending'
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* // Use in function parameters
|
|
127
|
+
* function getStatusLabel<E extends AnyBrandedEnum>(
|
|
128
|
+
* enumObj: E,
|
|
129
|
+
* key: EnumKeys<E>
|
|
130
|
+
* ): string {
|
|
131
|
+
* return enumObj[key] as string;
|
|
132
|
+
* }
|
|
133
|
+
*/
|
|
134
|
+
export type EnumKeys<E> = E extends BrandedEnum<infer T> ? keyof T & string : E extends AnyBrandedEnum ? Exclude<keyof E, typeof ENUM_ID | typeof ENUM_VALUES> & string : never;
|
|
135
|
+
/**
|
|
136
|
+
* Extracts the union of all values from a branded enum.
|
|
137
|
+
*
|
|
138
|
+
* This is an alias for BrandedEnumValue that provides a more intuitive name
|
|
139
|
+
* when working with compile-time type utilities.
|
|
140
|
+
*
|
|
141
|
+
* @template E - A BrandedEnum type
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* const Status = createBrandedEnum('status', {
|
|
145
|
+
* Active: 'active',
|
|
146
|
+
* Inactive: 'inactive',
|
|
147
|
+
* Pending: 'pending',
|
|
148
|
+
* } as const);
|
|
149
|
+
*
|
|
150
|
+
* type StatusValues = EnumValues<typeof Status>;
|
|
151
|
+
* // StatusValues = 'active' | 'inactive' | 'pending'
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* // Use for type-safe value handling
|
|
155
|
+
* function processStatus(value: EnumValues<typeof Status>) {
|
|
156
|
+
* // value is 'active' | 'inactive' | 'pending'
|
|
157
|
+
* }
|
|
158
|
+
*/
|
|
159
|
+
export type EnumValues<E> = E extends BrandedEnum<infer T> ? T[keyof T] : E extends AnyBrandedEnum ? Exclude<E[Exclude<keyof E, typeof ENUM_ID | typeof ENUM_VALUES>], Set<string>> & string : never;
|
|
160
|
+
/**
|
|
161
|
+
* Validates that a value type V is a valid value of branded enum E at compile time.
|
|
162
|
+
*
|
|
163
|
+
* If V is a valid value of E, this type resolves to V.
|
|
164
|
+
* If V is NOT a valid value of E, this type resolves to `never`, causing a compile error
|
|
165
|
+
* when used in contexts that expect a non-never type.
|
|
166
|
+
*
|
|
167
|
+
* This enables compile-time validation of enum values without runtime overhead.
|
|
168
|
+
*
|
|
169
|
+
* @template E - A BrandedEnum type
|
|
170
|
+
* @template V - The value type to validate
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* const Status = createBrandedEnum('status', {
|
|
174
|
+
* Active: 'active',
|
|
175
|
+
* Inactive: 'inactive',
|
|
176
|
+
* } as const);
|
|
177
|
+
*
|
|
178
|
+
* // Valid - 'active' is in Status
|
|
179
|
+
* type Valid = ValidEnumValue<typeof Status, 'active'>; // 'active'
|
|
180
|
+
*
|
|
181
|
+
* // Invalid - 'unknown' is not in Status
|
|
182
|
+
* type Invalid = ValidEnumValue<typeof Status, 'unknown'>; // never
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* // Use in function to enforce valid values at compile time
|
|
186
|
+
* function setStatus<V extends string>(
|
|
187
|
+
* value: ValidEnumValue<typeof Status, V>
|
|
188
|
+
* ): void {
|
|
189
|
+
* // Only compiles if value is 'active' | 'inactive'
|
|
190
|
+
* }
|
|
191
|
+
*
|
|
192
|
+
* setStatus('active'); // OK
|
|
193
|
+
* setStatus('inactive'); // OK
|
|
194
|
+
* // setStatus('unknown'); // Compile error: Argument of type 'never' is not assignable
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* // Type-level assertion
|
|
198
|
+
* type AssertActive = ValidEnumValue<typeof Status, 'active'>; // 'active' - OK
|
|
199
|
+
* type AssertBad = ValidEnumValue<typeof Status, 'bad'>; // never - indicates invalid
|
|
200
|
+
*/
|
|
201
|
+
export type ValidEnumValue<E, V extends string> = V extends EnumValues<E> ? V : never;
|
|
202
|
+
/**
|
|
203
|
+
* Creates a strict parameter type that only accepts valid values from a branded enum.
|
|
204
|
+
*
|
|
205
|
+
* This utility type is designed for function parameters where you want to enforce
|
|
206
|
+
* that only values from a specific branded enum are accepted at compile time.
|
|
207
|
+
*
|
|
208
|
+
* Unlike using `BrandedEnumValue<E>` directly, `StrictEnumParam` provides better
|
|
209
|
+
* error messages and works well with generic functions.
|
|
210
|
+
*
|
|
211
|
+
* @template E - A BrandedEnum type
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* const Status = createBrandedEnum('status', {
|
|
215
|
+
* Active: 'active',
|
|
216
|
+
* Inactive: 'inactive',
|
|
217
|
+
* Pending: 'pending',
|
|
218
|
+
* } as const);
|
|
219
|
+
*
|
|
220
|
+
* // Function that only accepts Status values
|
|
221
|
+
* function updateStatus(newStatus: StrictEnumParam<typeof Status>): void {
|
|
222
|
+
* console.log(`Status updated to: ${newStatus}`);
|
|
223
|
+
* }
|
|
224
|
+
*
|
|
225
|
+
* updateStatus(Status.Active); // OK
|
|
226
|
+
* updateStatus('active'); // OK (literal type matches)
|
|
227
|
+
* // updateStatus('unknown'); // Compile error
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* // Use with multiple enum parameters
|
|
231
|
+
* const Priority = createBrandedEnum('priority', {
|
|
232
|
+
* High: 'high',
|
|
233
|
+
* Medium: 'medium',
|
|
234
|
+
* Low: 'low',
|
|
235
|
+
* } as const);
|
|
236
|
+
*
|
|
237
|
+
* function createTask(
|
|
238
|
+
* status: StrictEnumParam<typeof Status>,
|
|
239
|
+
* priority: StrictEnumParam<typeof Priority>
|
|
240
|
+
* ): void {
|
|
241
|
+
* // Both parameters are type-safe
|
|
242
|
+
* }
|
|
243
|
+
*
|
|
244
|
+
* createTask(Status.Active, Priority.High); // OK
|
|
245
|
+
* createTask('active', 'high'); // OK
|
|
246
|
+
* // createTask('active', 'invalid'); // Compile error on second param
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* // Generic function with strict enum constraint
|
|
250
|
+
* function processValue<E extends AnyBrandedEnum>(
|
|
251
|
+
* enumObj: E,
|
|
252
|
+
* value: StrictEnumParam<E>
|
|
253
|
+
* ): void {
|
|
254
|
+
* // value is guaranteed to be a valid value of enumObj
|
|
255
|
+
* }
|
|
256
|
+
*/
|
|
257
|
+
export type StrictEnumParam<E> = EnumValues<E>;
|
|
258
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/types.ts"],"sourcesContent":["/**\n * Core type definitions for branded-enum library\n *\n * These types enable runtime-identifiable enum-like objects in TypeScript\n * with zero runtime overhead for value access.\n */\n\n/**\n * Symbol key for storing the enum ID metadata.\n * Using a Symbol prevents collision with user-defined keys.\n */\nexport const ENUM_ID: unique symbol = Symbol('ENUM_ID');\n\n/**\n * Symbol key for storing the enum values Set.\n * Using a Symbol prevents collision with user-defined keys.\n */\nexport const ENUM_VALUES: unique symbol = Symbol('ENUM_VALUES');\n\n/**\n * Metadata attached to branded enums via Symbol properties.\n * These properties are non-enumerable and won't appear in\n * Object.keys(), Object.values(), or JSON serialization.\n */\nexport interface BrandedEnumMetadata {\n readonly [ENUM_ID]: string;\n readonly [ENUM_VALUES]: Set<string>;\n}\n\n/**\n * A branded enum object - combines the user's values object with metadata.\n * The object is frozen (Readonly) to prevent modification after creation.\n *\n * @template T - The shape of the enum values object (Record<string, string>)\n */\nexport type BrandedEnum<T extends Record<string, string>> = Readonly<T> &\n BrandedEnumMetadata;\n\n/**\n * Base constraint type for branded enums that works with both\n * `as const` objects and regular Record<string, string> objects.\n *\n * This type is more permissive than `BrandedEnum<Record<string, string>>`\n * and allows literal types from `as const` assertions.\n */\nexport type AnyBrandedEnum = {\n readonly [ENUM_ID]: string;\n readonly [ENUM_VALUES]: Set<string>;\n};\n\n/**\n * Utility type to extract the union of all value types from a branded enum.\n * Useful for typing variables that can hold any value from the enum.\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * type StatusValue = BrandedEnumValue<typeof Status>; // 'active' | 'inactive'\n */\nexport type BrandedEnumValue<E extends AnyBrandedEnum> =\n E extends BrandedEnum<infer T> ? T[keyof T] : never;\n\n/**\n * Registry entry for tracking a single branded enum in the global registry.\n */\nexport interface RegistryEntry {\n /** The unique identifier for this enum */\n readonly enumId: string;\n /** The branded enum object itself */\n readonly enumObj: BrandedEnum<Record<string, string>>;\n /** Set of all values in this enum for O(1) lookup */\n readonly values: Set<string>;\n}\n\n/**\n * Global registry structure stored on globalThis.\n * Enables cross-bundle tracking of all branded enums.\n */\nexport interface BrandedEnumRegistry {\n /** Map from enumId to registry entry */\n readonly enums: Map<string, RegistryEntry>;\n /** Reverse index: value -> Set of enumIds containing that value */\n readonly valueIndex: Map<string, Set<string>>;\n}\n\n/**\n * The key used to store the registry on globalThis.\n * Namespaced to avoid collisions with other libraries.\n */\nexport const REGISTRY_KEY = '__brandedEnumRegistry__' as const;\n\n/**\n * The key used to store the enum consumer registry on globalThis.\n * Tracks which classes consume which branded enums.\n */\nexport const CONSUMER_REGISTRY_KEY = '__brandedEnumConsumerRegistry__' as const;\n\n/**\n * Entry tracking a class that consumes branded enums.\n */\nexport interface EnumConsumerEntry {\n /** The class constructor function */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly classRef: new (...args: any[]) => any;\n /** The class name */\n readonly className: string;\n /** Set of enum IDs that this class consumes */\n readonly enumIds: Set<string>;\n}\n\n/**\n * Global registry for tracking enum consumers (classes decorated with @EnumClass).\n * Enables debugging and introspection of enum usage across the codebase.\n */\nexport interface EnumConsumerRegistry {\n /** Map from class name to consumer entry */\n readonly consumers: Map<string, EnumConsumerEntry>;\n /** Reverse index: enumId -> Set of class names consuming that enum */\n readonly enumToConsumers: Map<string, Set<string>>;\n}\n\n// =============================================================================\n// Compile-Time Validation Types\n// =============================================================================\n\n/**\n * Extracts the union of all keys from a branded enum.\n *\n * This utility type provides compile-time access to all key names of a branded enum,\n * excluding the Symbol metadata keys (ENUM_ID and ENUM_VALUES).\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * type StatusKeys = EnumKeys<typeof Status>;\n * // StatusKeys = 'Active' | 'Inactive' | 'Pending'\n *\n * @example\n * // Use in function parameters\n * function getStatusLabel<E extends AnyBrandedEnum>(\n * enumObj: E,\n * key: EnumKeys<E>\n * ): string {\n * return enumObj[key] as string;\n * }\n */\nexport type EnumKeys<E> = E extends BrandedEnum<infer T>\n ? keyof T & string\n : E extends AnyBrandedEnum\n ? Exclude<keyof E, typeof ENUM_ID | typeof ENUM_VALUES> & string\n : never;\n\n/**\n * Extracts the union of all values from a branded enum.\n *\n * This is an alias for BrandedEnumValue that provides a more intuitive name\n * when working with compile-time type utilities.\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * type StatusValues = EnumValues<typeof Status>;\n * // StatusValues = 'active' | 'inactive' | 'pending'\n *\n * @example\n * // Use for type-safe value handling\n * function processStatus(value: EnumValues<typeof Status>) {\n * // value is 'active' | 'inactive' | 'pending'\n * }\n */\nexport type EnumValues<E> = E extends BrandedEnum<infer T>\n ? T[keyof T]\n : E extends AnyBrandedEnum\n ? Exclude<E[Exclude<keyof E, typeof ENUM_ID | typeof ENUM_VALUES>], Set<string>> & string\n : never;\n\n/**\n * Validates that a value type V is a valid value of branded enum E at compile time.\n *\n * If V is a valid value of E, this type resolves to V.\n * If V is NOT a valid value of E, this type resolves to `never`, causing a compile error\n * when used in contexts that expect a non-never type.\n *\n * This enables compile-time validation of enum values without runtime overhead.\n *\n * @template E - A BrandedEnum type\n * @template V - The value type to validate\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * } as const);\n *\n * // Valid - 'active' is in Status\n * type Valid = ValidEnumValue<typeof Status, 'active'>; // 'active'\n *\n * // Invalid - 'unknown' is not in Status\n * type Invalid = ValidEnumValue<typeof Status, 'unknown'>; // never\n *\n * @example\n * // Use in function to enforce valid values at compile time\n * function setStatus<V extends string>(\n * value: ValidEnumValue<typeof Status, V>\n * ): void {\n * // Only compiles if value is 'active' | 'inactive'\n * }\n *\n * setStatus('active'); // OK\n * setStatus('inactive'); // OK\n * // setStatus('unknown'); // Compile error: Argument of type 'never' is not assignable\n *\n * @example\n * // Type-level assertion\n * type AssertActive = ValidEnumValue<typeof Status, 'active'>; // 'active' - OK\n * type AssertBad = ValidEnumValue<typeof Status, 'bad'>; // never - indicates invalid\n */\nexport type ValidEnumValue<E, V extends string> = V extends EnumValues<E>\n ? V\n : never;\n\n/**\n * Creates a strict parameter type that only accepts valid values from a branded enum.\n *\n * This utility type is designed for function parameters where you want to enforce\n * that only values from a specific branded enum are accepted at compile time.\n *\n * Unlike using `BrandedEnumValue<E>` directly, `StrictEnumParam` provides better\n * error messages and works well with generic functions.\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * // Function that only accepts Status values\n * function updateStatus(newStatus: StrictEnumParam<typeof Status>): void {\n * console.log(`Status updated to: ${newStatus}`);\n * }\n *\n * updateStatus(Status.Active); // OK\n * updateStatus('active'); // OK (literal type matches)\n * // updateStatus('unknown'); // Compile error\n *\n * @example\n * // Use with multiple enum parameters\n * const Priority = createBrandedEnum('priority', {\n * High: 'high',\n * Medium: 'medium',\n * Low: 'low',\n * } as const);\n *\n * function createTask(\n * status: StrictEnumParam<typeof Status>,\n * priority: StrictEnumParam<typeof Priority>\n * ): void {\n * // Both parameters are type-safe\n * }\n *\n * createTask(Status.Active, Priority.High); // OK\n * createTask('active', 'high'); // OK\n * // createTask('active', 'invalid'); // Compile error on second param\n *\n * @example\n * // Generic function with strict enum constraint\n * function processValue<E extends AnyBrandedEnum>(\n * enumObj: E,\n * value: StrictEnumParam<E>\n * ): void {\n * // value is guaranteed to be a valid value of enumObj\n * }\n */\nexport type StrictEnumParam<E> = EnumValues<E>;\n"],"names":["ENUM_ID","Symbol","ENUM_VALUES","REGISTRY_KEY","CONSUMER_REGISTRY_KEY"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED;;;CAGC,GACD,OAAO,MAAMA,UAAyBC,OAAO,WAAW;AAExD;;;CAGC,GACD,OAAO,MAAMC,cAA6BD,OAAO,eAAe;AAqEhE;;;CAGC,GACD,OAAO,MAAME,eAAe,0BAAmC;AAE/D;;;CAGC,GACD,OAAO,MAAMC,wBAAwB,kCAA2C"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for branded enums.
|
|
3
|
+
*
|
|
4
|
+
* Provides additional functionality beyond standard enum operations,
|
|
5
|
+
* including reverse lookup, key validation, and iteration.
|
|
6
|
+
*/
|
|
7
|
+
import { AnyBrandedEnum, EnumKeys, EnumValues } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a value exists in a branded enum (reverse lookup).
|
|
10
|
+
*
|
|
11
|
+
* Similar to `isFromEnum`, but with arguments in a different order that
|
|
12
|
+
* may be more natural for some use cases. Also provides type narrowing.
|
|
13
|
+
*
|
|
14
|
+
* @template E - The branded enum type
|
|
15
|
+
* @param enumObj - The branded enum to search in
|
|
16
|
+
* @param value - The value to check. Can be any type; non-strings return false.
|
|
17
|
+
* @returns `true` if the value exists in the enum (with type narrowing),
|
|
18
|
+
* `false` otherwise. Returns `false` for non-string values or if
|
|
19
|
+
* enumObj is not a branded enum.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Check if value exists
|
|
23
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);
|
|
24
|
+
* hasValue(Status, 'active'); // true
|
|
25
|
+
* hasValue(Status, 'unknown'); // false
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Returns false for non-string values
|
|
29
|
+
* hasValue(Status, 123); // false
|
|
30
|
+
* hasValue(Status, null); // false
|
|
31
|
+
*/
|
|
32
|
+
export declare function hasValue<E extends AnyBrandedEnum>(enumObj: E, value: unknown): value is EnumValues<E>;
|
|
33
|
+
/**
|
|
34
|
+
* Gets the key name for a value in a branded enum.
|
|
35
|
+
*
|
|
36
|
+
* Performs a reverse lookup to find which key maps to a given value.
|
|
37
|
+
* If multiple keys have the same value, returns the first one found
|
|
38
|
+
* (order is not guaranteed).
|
|
39
|
+
*
|
|
40
|
+
* @template E - The branded enum type
|
|
41
|
+
* @param enumObj - The branded enum to search in
|
|
42
|
+
* @param value - The string value to look up
|
|
43
|
+
* @returns The key name that maps to the value, or `undefined` if the
|
|
44
|
+
* value is not found or enumObj is not a branded enum.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // Find key for value
|
|
48
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);
|
|
49
|
+
* getKeyForValue(Status, 'active'); // 'Active'
|
|
50
|
+
* getKeyForValue(Status, 'inactive'); // 'Inactive'
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* // Returns undefined for unknown values
|
|
54
|
+
* getKeyForValue(Status, 'unknown'); // undefined
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // Roundtrip: value -> key -> value
|
|
58
|
+
* const key = getKeyForValue(Status, 'active'); // 'Active'
|
|
59
|
+
* Status[key]; // 'active'
|
|
60
|
+
*/
|
|
61
|
+
export declare function getKeyForValue<E extends AnyBrandedEnum>(enumObj: E, value: string): EnumKeys<E> | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Checks if a key exists in a branded enum.
|
|
64
|
+
*
|
|
65
|
+
* Validates whether a given key is a valid member of the enum.
|
|
66
|
+
* Returns false for Symbol keys (metadata) and non-string keys.
|
|
67
|
+
*
|
|
68
|
+
* @template E - The branded enum type
|
|
69
|
+
* @param enumObj - The branded enum to check
|
|
70
|
+
* @param key - The key to validate. Can be any type; non-strings return false.
|
|
71
|
+
* @returns `true` if the key exists in the enum (with type narrowing),
|
|
72
|
+
* `false` otherwise. Returns `false` for metadata Symbol keys or if
|
|
73
|
+
* enumObj is not a branded enum.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Check if key exists
|
|
77
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);
|
|
78
|
+
* isValidKey(Status, 'Active'); // true
|
|
79
|
+
* isValidKey(Status, 'Inactive'); // true
|
|
80
|
+
* isValidKey(Status, 'Unknown'); // false
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // Returns false for non-string keys
|
|
84
|
+
* isValidKey(Status, 123); // false
|
|
85
|
+
* isValidKey(Status, Symbol('test')); // false
|
|
86
|
+
*/
|
|
87
|
+
export declare function isValidKey<E extends AnyBrandedEnum>(enumObj: E, key: unknown): key is EnumKeys<E>;
|
|
88
|
+
/**
|
|
89
|
+
* Returns an iterator of [key, value] pairs for a branded enum.
|
|
90
|
+
*
|
|
91
|
+
* Provides a way to iterate over all key-value pairs in the enum using
|
|
92
|
+
* a for...of loop. Only yields user-defined entries, not metadata.
|
|
93
|
+
* Equivalent to `Object.entries(enumObj)` but with proper typing.
|
|
94
|
+
*
|
|
95
|
+
* @template E - The branded enum type
|
|
96
|
+
* @param enumObj - The branded enum to iterate over
|
|
97
|
+
* @returns An iterator yielding [key, value] tuples. Returns an empty
|
|
98
|
+
* iterator if enumObj is not a branded enum.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* // Iterate over entries
|
|
102
|
+
* const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);
|
|
103
|
+
*
|
|
104
|
+
* for (const [key, value] of enumEntries(Status)) {
|
|
105
|
+
* console.log(`${key}: ${value}`);
|
|
106
|
+
* }
|
|
107
|
+
* // Output:
|
|
108
|
+
* // Active: active
|
|
109
|
+
* // Inactive: inactive
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* // Convert to array
|
|
113
|
+
* const entries = [...enumEntries(Status)];
|
|
114
|
+
* // [['Active', 'active'], ['Inactive', 'inactive']]
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* // Use with Array.from
|
|
118
|
+
* const entriesArray = Array.from(enumEntries(Status));
|
|
119
|
+
*/
|
|
120
|
+
export declare function enumEntries<E extends AnyBrandedEnum>(enumObj: E): IterableIterator<[EnumKeys<E>, EnumValues<E>]>;
|
|
121
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,cAAc,EAKd,QAAQ,EACR,UAAU,EACX,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,cAAc,EAC/C,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,CAQxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,EACrD,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,MAAM,GACZ,QAAQ,CAAC,CAAC,CAAC,GAAG,SAAS,CAUzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,cAAc,EACjD,OAAO,EAAE,CAAC,EACV,GAAG,EAAE,OAAO,GACX,GAAG,IAAI,QAAQ,CAAC,CAAC,CAAC,CAQpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAiB,WAAW,CAAC,CAAC,SAAS,cAAc,EACnD,OAAO,EAAE,CAAC,GACT,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAOhD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils.ts"],"sourcesContent":["/**\n * Utility functions for branded enums.\n *\n * Provides additional functionality beyond standard enum operations,\n * including reverse lookup, key validation, and iteration.\n */\n\nimport {\n AnyBrandedEnum,\n BrandedEnum,\n BrandedEnumValue,\n ENUM_ID,\n ENUM_VALUES,\n EnumKeys,\n EnumValues,\n} from './types.js';\n\n/**\n * Checks if an object is a branded enum (has Symbol metadata).\n *\n * @param obj - The object to check\n * @returns true if obj is a branded enum\n */\nfunction isBrandedEnum(obj: unknown): obj is AnyBrandedEnum {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n ENUM_ID in obj &&\n ENUM_VALUES in obj &&\n typeof (obj as AnyBrandedEnum)[ENUM_ID] === 'string' &&\n (obj as AnyBrandedEnum)[ENUM_VALUES] instanceof Set\n );\n}\n\n/**\n * Checks if a value exists in a branded enum (reverse lookup).\n *\n * Similar to `isFromEnum`, but with arguments in a different order that\n * may be more natural for some use cases. Also provides type narrowing.\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to search in\n * @param value - The value to check. Can be any type; non-strings return false.\n * @returns `true` if the value exists in the enum (with type narrowing),\n * `false` otherwise. Returns `false` for non-string values or if\n * enumObj is not a branded enum.\n *\n * @example\n * // Check if value exists\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * hasValue(Status, 'active'); // true\n * hasValue(Status, 'unknown'); // false\n *\n * @example\n * // Returns false for non-string values\n * hasValue(Status, 123); // false\n * hasValue(Status, null); // false\n */\nexport function hasValue<E extends AnyBrandedEnum>(\n enumObj: E,\n value: unknown\n): value is EnumValues<E> {\n if (!isBrandedEnum(enumObj)) {\n return false;\n }\n if (typeof value !== 'string') {\n return false;\n }\n return enumObj[ENUM_VALUES].has(value);\n}\n\n/**\n * Gets the key name for a value in a branded enum.\n *\n * Performs a reverse lookup to find which key maps to a given value.\n * If multiple keys have the same value, returns the first one found\n * (order is not guaranteed).\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to search in\n * @param value - The string value to look up\n * @returns The key name that maps to the value, or `undefined` if the\n * value is not found or enumObj is not a branded enum.\n *\n * @example\n * // Find key for value\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * getKeyForValue(Status, 'active'); // 'Active'\n * getKeyForValue(Status, 'inactive'); // 'Inactive'\n *\n * @example\n * // Returns undefined for unknown values\n * getKeyForValue(Status, 'unknown'); // undefined\n *\n * @example\n * // Roundtrip: value -> key -> value\n * const key = getKeyForValue(Status, 'active'); // 'Active'\n * Status[key]; // 'active'\n */\nexport function getKeyForValue<E extends AnyBrandedEnum>(\n enumObj: E,\n value: string\n): EnumKeys<E> | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n for (const key of Object.keys(enumObj)) {\n if ((enumObj as Record<string, unknown>)[key] === value) {\n return key as EnumKeys<E>;\n }\n }\n return undefined;\n}\n\n/**\n * Checks if a key exists in a branded enum.\n *\n * Validates whether a given key is a valid member of the enum.\n * Returns false for Symbol keys (metadata) and non-string keys.\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to check\n * @param key - The key to validate. Can be any type; non-strings return false.\n * @returns `true` if the key exists in the enum (with type narrowing),\n * `false` otherwise. Returns `false` for metadata Symbol keys or if\n * enumObj is not a branded enum.\n *\n * @example\n * // Check if key exists\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * isValidKey(Status, 'Active'); // true\n * isValidKey(Status, 'Inactive'); // true\n * isValidKey(Status, 'Unknown'); // false\n *\n * @example\n * // Returns false for non-string keys\n * isValidKey(Status, 123); // false\n * isValidKey(Status, Symbol('test')); // false\n */\nexport function isValidKey<E extends AnyBrandedEnum>(\n enumObj: E,\n key: unknown\n): key is EnumKeys<E> {\n if (!isBrandedEnum(enumObj)) {\n return false;\n }\n if (typeof key !== 'string') {\n return false;\n }\n return Object.prototype.hasOwnProperty.call(enumObj, key);\n}\n\n/**\n * Returns an iterator of [key, value] pairs for a branded enum.\n *\n * Provides a way to iterate over all key-value pairs in the enum using\n * a for...of loop. Only yields user-defined entries, not metadata.\n * Equivalent to `Object.entries(enumObj)` but with proper typing.\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to iterate over\n * @returns An iterator yielding [key, value] tuples. Returns an empty\n * iterator if enumObj is not a branded enum.\n *\n * @example\n * // Iterate over entries\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n *\n * for (const [key, value] of enumEntries(Status)) {\n * console.log(`${key}: ${value}`);\n * }\n * // Output:\n * // Active: active\n * // Inactive: inactive\n *\n * @example\n * // Convert to array\n * const entries = [...enumEntries(Status)];\n * // [['Active', 'active'], ['Inactive', 'inactive']]\n *\n * @example\n * // Use with Array.from\n * const entriesArray = Array.from(enumEntries(Status));\n */\nexport function* enumEntries<E extends AnyBrandedEnum>(\n enumObj: E\n): IterableIterator<[EnumKeys<E>, EnumValues<E>]> {\n if (!isBrandedEnum(enumObj)) {\n return;\n }\n for (const [key, value] of Object.entries(enumObj)) {\n yield [key as EnumKeys<E>, value as EnumValues<E>];\n }\n}\n"],"names":["ENUM_ID","ENUM_VALUES","isBrandedEnum","obj","Set","hasValue","enumObj","value","has","getKeyForValue","undefined","key","Object","keys","isValidKey","prototype","hasOwnProperty","call","enumEntries","entries"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED,SAIEA,OAAO,EACPC,WAAW,QAGN,aAAa;AAEpB;;;;;CAKC,GACD,SAASC,cAAcC,GAAY;IACjC,OACEA,QAAQ,QACR,OAAOA,QAAQ,YACfH,WAAWG,OACXF,eAAeE,OACf,OAAO,AAACA,GAAsB,CAACH,QAAQ,KAAK,YAC5C,AAACG,GAAsB,CAACF,YAAY,YAAYG;AAEpD;AAEA;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,OAAO,SAASC,SACdC,OAAU,EACVC,KAAc;IAEd,IAAI,CAACL,cAAcI,UAAU;QAC3B,OAAO;IACT;IACA,IAAI,OAAOC,UAAU,UAAU;QAC7B,OAAO;IACT;IACA,OAAOD,OAAO,CAACL,YAAY,CAACO,GAAG,CAACD;AAClC;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASE,eACdH,OAAU,EACVC,KAAa;IAEb,IAAI,CAACL,cAAcI,UAAU;QAC3B,OAAOI;IACT;IACA,KAAK,MAAMC,OAAOC,OAAOC,IAAI,CAACP,SAAU;QACtC,IAAI,AAACA,OAAmC,CAACK,IAAI,KAAKJ,OAAO;YACvD,OAAOI;QACT;IACF;IACA,OAAOD;AACT;AAEA;;;;;;;;;;;;;;;;;;;;;;;;CAwBC,GACD,OAAO,SAASI,WACdR,OAAU,EACVK,GAAY;IAEZ,IAAI,CAACT,cAAcI,UAAU;QAC3B,OAAO;IACT;IACA,IAAI,OAAOK,QAAQ,UAAU;QAC3B,OAAO;IACT;IACA,OAAOC,OAAOG,SAAS,CAACC,cAAc,CAACC,IAAI,CAACX,SAASK;AACvD;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BC,GACD,OAAO,UAAUO,YACfZ,OAAU;IAEV,IAAI,CAACJ,cAAcI,UAAU;QAC3B;IACF;IACA,KAAK,MAAM,CAACK,KAAKJ,MAAM,IAAIK,OAAOO,OAAO,CAACb,SAAU;QAClD,MAAM;YAACK;YAAoBJ;SAAuB;IACpD;AACF"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitaldefiance/branded-enum",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Runtime-identifiable enum-like types for TypeScript with zero runtime overhead",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "./dist/index.
|
|
8
|
-
"module": "./dist/index.js",
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
7
|
+
"main": "./dist/cjs/index.cjs",
|
|
8
|
+
"module": "./dist/esm/index.js",
|
|
9
|
+
"types": "./dist/esm/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
"./package.json": "./package.json",
|
|
12
12
|
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js",
|
|
15
|
-
"
|
|
13
|
+
"types": "./dist/esm/index.d.ts",
|
|
14
|
+
"import": "./dist/esm/index.js",
|
|
15
|
+
"require": "./dist/cjs/index.cjs",
|
|
16
|
+
"default": "./dist/esm/index.js"
|
|
16
17
|
}
|
|
17
18
|
},
|
|
18
19
|
"files": [
|
|
@@ -69,19 +70,25 @@
|
|
|
69
70
|
"sourceRoot": "src",
|
|
70
71
|
"targets": {
|
|
71
72
|
"build": {
|
|
72
|
-
"executor": "
|
|
73
|
-
"outputs": [
|
|
73
|
+
"executor": "nx:run-commands",
|
|
74
|
+
"outputs": [
|
|
75
|
+
"{projectRoot}/dist"
|
|
76
|
+
],
|
|
74
77
|
"options": {
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
"commands": [
|
|
79
|
+
"swc src -d dist/esm --config-file .swcrc --strip-leading-paths",
|
|
80
|
+
"swc src -d dist/cjs --config-file .swcrc.cjs --strip-leading-paths -C module.type=commonjs --out-file-extension cjs",
|
|
81
|
+
"tsc -p tsconfig.lib.json"
|
|
82
|
+
],
|
|
83
|
+
"cwd": "{projectRoot}",
|
|
84
|
+
"parallel": false
|
|
80
85
|
}
|
|
81
86
|
},
|
|
82
87
|
"test": {
|
|
83
88
|
"executor": "@nx/jest:jest",
|
|
84
|
-
"outputs": [
|
|
89
|
+
"outputs": [
|
|
90
|
+
"{projectRoot}/test-output/jest/coverage"
|
|
91
|
+
],
|
|
85
92
|
"options": {
|
|
86
93
|
"jestConfig": "jest.config.cts",
|
|
87
94
|
"passWithNoTests": true
|
|
@@ -89,18 +96,24 @@
|
|
|
89
96
|
},
|
|
90
97
|
"build-examples": {
|
|
91
98
|
"executor": "nx:run-commands",
|
|
92
|
-
"outputs": [
|
|
99
|
+
"outputs": [
|
|
100
|
+
"{projectRoot}/examples/dist"
|
|
101
|
+
],
|
|
93
102
|
"options": {
|
|
94
103
|
"command": "tsc -p examples/tsconfig.json"
|
|
95
104
|
},
|
|
96
|
-
"dependsOn": [
|
|
105
|
+
"dependsOn": [
|
|
106
|
+
"build"
|
|
107
|
+
]
|
|
97
108
|
},
|
|
98
109
|
"publish-public": {
|
|
99
110
|
"executor": "nx:run-commands",
|
|
100
111
|
"options": {
|
|
101
112
|
"command": "npm publish --access public"
|
|
102
113
|
},
|
|
103
|
-
"dependsOn": [
|
|
114
|
+
"dependsOn": [
|
|
115
|
+
"build"
|
|
116
|
+
]
|
|
104
117
|
}
|
|
105
118
|
}
|
|
106
119
|
},
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * branded-enum - Runtime-identifiable enum-like types for TypeScript\n *\n * This library provides enum-like objects with embedded metadata for runtime\n * identification, enabling you to determine which enum a string value belongs to.\n *\n * @packageDocumentation\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type {\n BrandedEnumMetadata,\n BrandedEnum,\n BrandedEnumValue,\n RegistryEntry,\n BrandedEnumRegistry,\n EnumConsumerEntry,\n EnumConsumerRegistry,\n AnyBrandedEnum,\n EnumKeys,\n EnumValues,\n ValidEnumValue,\n StrictEnumParam,\n} from './lib/types.js';\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nexport { createBrandedEnum } from './lib/factory.js';\n\n// =============================================================================\n// Registry\n// =============================================================================\n\nexport {\n getRegistry,\n getAllEnumIds,\n getEnumById,\n findEnumSources,\n} from './lib/registry.js';\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport { isFromEnum, assertFromEnum, parseEnum, safeParseEnum } from './lib/guards.js';\nexport type { SafeParseSuccess, SafeParseFailure, SafeParseError, SafeParseErrorCode, SafeParseResult } from './lib/guards.js';\n\n// =============================================================================\n// Metadata Accessors\n// =============================================================================\n\nexport { getEnumId, getEnumValues, enumSize } from './lib/accessors.js';\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\nexport {\n hasValue,\n getKeyForValue,\n isValidKey,\n enumEntries,\n} from './lib/utils.js';\n\n// =============================================================================\n// Composition\n// =============================================================================\n\nexport { mergeEnums } from './lib/merge.js';\n\n// =============================================================================\n// Advanced Operations\n// =============================================================================\n\nexport { enumSubset, enumExclude, enumMap, enumFromKeys, enumDiff, enumIntersect, enumToRecord, watchEnum, watchAllEnums, clearAllEnumWatchers, getEnumWatcherCount, getGlobalWatcherCount, exhaustive, exhaustiveGuard, toJsonSchema, toZodSchema, enumSerializer } from './lib/advanced.js';\nexport type { EnumDiffResult, EnumIntersectEntry, EnumAccessType, EnumAccessEvent, EnumWatchCallback, WatchEnumResult, ToJsonSchemaOptions, EnumJsonSchema, ToZodSchemaOptions, ZodEnumSchemaDefinition, EnumSerializerOptions, DeserializeSuccess, DeserializeFailure, DeserializeResult, EnumSerializer } from './lib/advanced.js';\n\n// =============================================================================\n// Decorators\n// =============================================================================\n\nexport {\n EnumValue,\n EnumClass,\n getEnumConsumers,\n getConsumedEnums,\n getAllEnumConsumers,\n} from './lib/decorators.js';\nexport type { EnumValueOptions } from './lib/decorators.js';\n"],"names":["createBrandedEnum","getRegistry","getAllEnumIds","getEnumById","findEnumSources","isFromEnum","assertFromEnum","parseEnum","safeParseEnum","getEnumId","getEnumValues","enumSize","hasValue","getKeyForValue","isValidKey","enumEntries","mergeEnums","enumSubset","enumExclude","enumMap","enumFromKeys","enumDiff","enumIntersect","enumToRecord","watchEnum","watchAllEnums","clearAllEnumWatchers","getEnumWatcherCount","getGlobalWatcherCount","exhaustive","exhaustiveGuard","toJsonSchema","toZodSchema","enumSerializer","EnumValue","EnumClass","getEnumConsumers","getConsumedEnums","getAllEnumConsumers"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;CAOC,GAED,gFAAgF;AAChF,QAAQ;AACR,gFAAgF;AAiBhF,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,SAASA,iBAAiB,QAAQ,mBAAmB;AAErD,gFAAgF;AAChF,WAAW;AACX,gFAAgF;AAEhF,SACEC,WAAW,EACXC,aAAa,EACbC,WAAW,EACXC,eAAe,QACV,oBAAoB;AAE3B,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF,SAASC,UAAU,EAAEC,cAAc,EAAEC,SAAS,EAAEC,aAAa,QAAQ,kBAAkB;AAGvF,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,SAASC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,qBAAqB;AAExE,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,SACEC,QAAQ,EACRC,cAAc,EACdC,UAAU,EACVC,WAAW,QACN,iBAAiB;AAExB,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF,SAASC,UAAU,QAAQ,iBAAiB;AAE5C,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF,SAASC,UAAU,EAAEC,WAAW,EAAEC,OAAO,EAAEC,YAAY,EAAEC,QAAQ,EAAEC,aAAa,EAAEC,YAAY,EAAEC,SAAS,EAAEC,aAAa,EAAEC,oBAAoB,EAAEC,mBAAmB,EAAEC,qBAAqB,EAAEC,UAAU,EAAEC,eAAe,EAAEC,YAAY,EAAEC,WAAW,EAAEC,cAAc,QAAQ,oBAAoB;AAG9R,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF,SACEC,SAAS,EACTC,SAAS,EACTC,gBAAgB,EAChBC,gBAAgB,EAChBC,mBAAmB,QACd,sBAAsB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/lib/accessors.ts"],"sourcesContent":["/**\n * Metadata accessors for branded enums.\n *\n * Provides functions to retrieve metadata from branded enum objects,\n * including enum ID, values array, and size.\n */\n\nimport {\n AnyBrandedEnum,\n BrandedEnum,\n BrandedEnumValue,\n ENUM_ID,\n ENUM_VALUES,\n EnumValues,\n} from './types.js';\n\n/**\n * Checks if an object is a branded enum (has Symbol metadata).\n *\n * @param obj - The object to check\n * @returns true if obj is a branded enum\n */\nfunction isBrandedEnum(obj: unknown): obj is AnyBrandedEnum {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n ENUM_ID in obj &&\n ENUM_VALUES in obj &&\n typeof (obj as AnyBrandedEnum)[ENUM_ID] === 'string' &&\n (obj as AnyBrandedEnum)[ENUM_VALUES] instanceof Set\n );\n}\n\n/**\n * Gets the enum ID from a branded enum.\n *\n * Retrieves the unique identifier that was assigned when the enum was created.\n * Returns undefined for objects that are not branded enums.\n *\n * @param enumObj - The object to get the enum ID from. Can be any type.\n * @returns The enum ID string if enumObj is a branded enum, `undefined` otherwise.\n *\n * @example\n * // Get ID from branded enum\n * const Status = createBrandedEnum('status', { Active: 'active' } as const);\n * getEnumId(Status); // 'status'\n *\n * @example\n * // Returns undefined for non-branded objects\n * getEnumId({}); // undefined\n * getEnumId({ Active: 'active' }); // undefined\n * getEnumId(null); // undefined\n */\nexport function getEnumId(enumObj: unknown): string | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n return enumObj[ENUM_ID];\n}\n\n/**\n * Gets all values from a branded enum as an array.\n *\n * Returns an array containing all the string values in the enum.\n * The order of values is not guaranteed.\n *\n * @template E - The branded enum type\n * @param enumObj - The object to get values from. Can be any type.\n * @returns Array of all enum values if enumObj is a branded enum,\n * `undefined` otherwise.\n *\n * @example\n * // Get values from branded enum\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive'\n * } as const);\n * getEnumValues(Status); // ['active', 'inactive']\n *\n * @example\n * // Returns undefined for non-branded objects\n * getEnumValues({}); // undefined\n * getEnumValues({ Active: 'active' }); // undefined\n */\nexport function getEnumValues<E extends AnyBrandedEnum>(\n enumObj: E\n): EnumValues<E>[] | undefined;\nexport function getEnumValues(enumObj: unknown): string[] | undefined;\nexport function getEnumValues(enumObj: unknown): string[] | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n return Array.from(enumObj[ENUM_VALUES]);\n}\n\n/**\n * Gets the number of values in a branded enum.\n *\n * Returns the count of unique values in the enum. This is equivalent to\n * the number of key-value pairs defined when the enum was created.\n *\n * @param enumObj - The object to get the size of. Can be any type.\n * @returns The number of values in the enum if enumObj is a branded enum,\n * `undefined` otherwise.\n *\n * @example\n * // Get size of branded enum\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive'\n * } as const);\n * enumSize(Status); // 2\n *\n * @example\n * // Returns undefined for non-branded objects\n * enumSize({}); // undefined\n * enumSize({ Active: 'active' }); // undefined\n */\nexport function enumSize(enumObj: unknown): number | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n return enumObj[ENUM_VALUES].size;\n}\n"],"names":["ENUM_ID","ENUM_VALUES","isBrandedEnum","obj","Set","getEnumId","enumObj","undefined","getEnumValues","Array","from","enumSize","size"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED,SAIEA,OAAO,EACPC,WAAW,QAEN,aAAa;AAEpB;;;;;CAKC,GACD,SAASC,cAAcC,GAAY;IACjC,OACEA,QAAQ,QACR,OAAOA,QAAQ,YACfH,WAAWG,OACXF,eAAeE,OACf,OAAO,AAACA,GAAsB,CAACH,QAAQ,KAAK,YAC5C,AAACG,GAAsB,CAACF,YAAY,YAAYG;AAEpD;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASC,UAAUC,OAAgB;IACxC,IAAI,CAACJ,cAAcI,UAAU;QAC3B,OAAOC;IACT;IACA,OAAOD,OAAO,CAACN,QAAQ;AACzB;AA8BA,OAAO,SAASQ,cAAcF,OAAgB;IAC5C,IAAI,CAACJ,cAAcI,UAAU;QAC3B,OAAOC;IACT;IACA,OAAOE,MAAMC,IAAI,CAACJ,OAAO,CAACL,YAAY;AACxC;AAEA;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASU,SAASL,OAAgB;IACvC,IAAI,CAACJ,cAAcI,UAAU;QAC3B,OAAOC;IACT;IACA,OAAOD,OAAO,CAACL,YAAY,CAACW,IAAI;AAClC"}
|