@digitaldefiance/branded-enum 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/accessors.d.ts +79 -0
- package/dist/lib/accessors.d.ts.map +1 -0
- package/dist/lib/advanced.d.ts +1422 -0
- package/dist/lib/advanced.d.ts.map +1 -0
- package/dist/lib/branded-enum.d.ts +2 -0
- package/dist/lib/branded-enum.d.ts.map +1 -0
- package/dist/lib/decorators.d.ts +147 -0
- package/dist/lib/decorators.d.ts.map +1 -0
- package/dist/lib/factory.d.ts +52 -0
- package/dist/lib/factory.d.ts.map +1 -0
- package/dist/lib/guards.d.ts +297 -0
- package/dist/lib/guards.d.ts.map +1 -0
- package/dist/lib/merge.d.ts +64 -0
- package/dist/lib/merge.d.ts.map +1 -0
- package/dist/lib/registry.d.ts +93 -0
- package/dist/lib/registry.d.ts.map +1 -0
- package/dist/lib/types.d.ts +258 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/utils.d.ts +121 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/package.json +23 -12
- package/dist/package.json +0 -120
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Global registry for branded enums.
|
|
3
|
+
*
|
|
4
|
+
* Uses globalThis to ensure cross-bundle compatibility - all instances
|
|
5
|
+
* of the library share the same registry regardless of how they're bundled.
|
|
6
|
+
*/
|
|
7
|
+
import { BrandedEnum, BrandedEnumRegistry } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Gets the global registry, initializing it lazily if needed.
|
|
10
|
+
* Uses globalThis for cross-bundle compatibility.
|
|
11
|
+
*
|
|
12
|
+
* The registry is shared across all instances of the library, even when
|
|
13
|
+
* bundled separately or loaded as different module formats (ESM/CJS).
|
|
14
|
+
*
|
|
15
|
+
* @returns The global branded enum registry containing all registered enums
|
|
16
|
+
* and a value index for reverse lookups.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const registry = getRegistry();
|
|
20
|
+
* console.log(registry.enums.size); // Number of registered enums
|
|
21
|
+
*/
|
|
22
|
+
export declare function getRegistry(): BrandedEnumRegistry;
|
|
23
|
+
/**
|
|
24
|
+
* Registers a branded enum in the global registry.
|
|
25
|
+
* Also updates the value index for reverse lookups.
|
|
26
|
+
*
|
|
27
|
+
* @param enumObj - The branded enum to register
|
|
28
|
+
* @throws Error if an enum with the same ID is already registered
|
|
29
|
+
*/
|
|
30
|
+
export declare function registerEnum<T extends Record<string, string>>(enumObj: BrandedEnum<T>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Gets all registered enum IDs.
|
|
33
|
+
*
|
|
34
|
+
* Returns an array of all enum IDs that have been registered via
|
|
35
|
+
* `createBrandedEnum`. Useful for debugging or introspection.
|
|
36
|
+
*
|
|
37
|
+
* @returns Array of all registered enum IDs. Returns empty array if no
|
|
38
|
+
* enums have been registered.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* createBrandedEnum('colors', { Red: 'red' } as const);
|
|
42
|
+
* createBrandedEnum('sizes', { Small: 'small' } as const);
|
|
43
|
+
*
|
|
44
|
+
* getAllEnumIds(); // ['colors', 'sizes']
|
|
45
|
+
*/
|
|
46
|
+
export declare function getAllEnumIds(): string[];
|
|
47
|
+
/**
|
|
48
|
+
* Gets a branded enum by its ID.
|
|
49
|
+
*
|
|
50
|
+
* Retrieves a previously registered branded enum from the global registry.
|
|
51
|
+
* Useful when you need to access an enum dynamically by its ID.
|
|
52
|
+
*
|
|
53
|
+
* @param enumId - The enum ID to look up
|
|
54
|
+
* @returns The branded enum object if found, or `undefined` if no enum
|
|
55
|
+
* with the given ID has been registered.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const Status = createBrandedEnum('status', { Active: 'active' } as const);
|
|
59
|
+
*
|
|
60
|
+
* const retrieved = getEnumById('status');
|
|
61
|
+
* console.log(retrieved === Status); // true
|
|
62
|
+
*
|
|
63
|
+
* const notFound = getEnumById('nonexistent');
|
|
64
|
+
* console.log(notFound); // undefined
|
|
65
|
+
*/
|
|
66
|
+
export declare function getEnumById(enumId: string): BrandedEnum<Record<string, string>> | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Finds all enum IDs that contain a given value.
|
|
69
|
+
*
|
|
70
|
+
* Performs a reverse lookup to find which enums contain a specific value.
|
|
71
|
+
* Useful for debugging value collisions or routing values to handlers.
|
|
72
|
+
*
|
|
73
|
+
* @param value - The string value to search for
|
|
74
|
+
* @returns Array of enum IDs that contain the value. Returns empty array
|
|
75
|
+
* if no enums contain the value.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Single enum containing value
|
|
79
|
+
* createBrandedEnum('colors', { Red: 'red', Blue: 'blue' } as const);
|
|
80
|
+
* findEnumSources('red'); // ['colors']
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // Multiple enums with same value (collision detection)
|
|
84
|
+
* createBrandedEnum('status1', { Active: 'active' } as const);
|
|
85
|
+
* createBrandedEnum('status2', { Enabled: 'active' } as const);
|
|
86
|
+
* findEnumSources('active'); // ['status1', 'status2']
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // Value not found
|
|
90
|
+
* findEnumSources('nonexistent'); // []
|
|
91
|
+
*/
|
|
92
|
+
export declare function findEnumSources(value: string): string[];
|
|
93
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,mBAAmB,EAKpB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,IAAI,mBAAmB,CAajD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3D,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GACtB,IAAI,CA6BN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAGxC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,GACb,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAIjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAIvD"}
|
|
@@ -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,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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitaldefiance/branded-enum",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Runtime-identifiable enum-like types for TypeScript with zero runtime overhead",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -69,19 +69,24 @@
|
|
|
69
69
|
"sourceRoot": "src",
|
|
70
70
|
"targets": {
|
|
71
71
|
"build": {
|
|
72
|
-
"executor": "
|
|
73
|
-
"outputs": [
|
|
72
|
+
"executor": "nx:run-commands",
|
|
73
|
+
"outputs": [
|
|
74
|
+
"{projectRoot}/dist"
|
|
75
|
+
],
|
|
74
76
|
"options": {
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
77
|
+
"commands": [
|
|
78
|
+
"swc src -d dist --config-file .swcrc --strip-leading-paths",
|
|
79
|
+
"tsc -p tsconfig.lib.json"
|
|
80
|
+
],
|
|
81
|
+
"cwd": "{projectRoot}",
|
|
82
|
+
"parallel": false
|
|
80
83
|
}
|
|
81
84
|
},
|
|
82
85
|
"test": {
|
|
83
86
|
"executor": "@nx/jest:jest",
|
|
84
|
-
"outputs": [
|
|
87
|
+
"outputs": [
|
|
88
|
+
"{projectRoot}/test-output/jest/coverage"
|
|
89
|
+
],
|
|
85
90
|
"options": {
|
|
86
91
|
"jestConfig": "jest.config.cts",
|
|
87
92
|
"passWithNoTests": true
|
|
@@ -89,18 +94,24 @@
|
|
|
89
94
|
},
|
|
90
95
|
"build-examples": {
|
|
91
96
|
"executor": "nx:run-commands",
|
|
92
|
-
"outputs": [
|
|
97
|
+
"outputs": [
|
|
98
|
+
"{projectRoot}/examples/dist"
|
|
99
|
+
],
|
|
93
100
|
"options": {
|
|
94
101
|
"command": "tsc -p examples/tsconfig.json"
|
|
95
102
|
},
|
|
96
|
-
"dependsOn": [
|
|
103
|
+
"dependsOn": [
|
|
104
|
+
"build"
|
|
105
|
+
]
|
|
97
106
|
},
|
|
98
107
|
"publish-public": {
|
|
99
108
|
"executor": "nx:run-commands",
|
|
100
109
|
"options": {
|
|
101
110
|
"command": "npm publish --access public"
|
|
102
111
|
},
|
|
103
|
-
"dependsOn": [
|
|
112
|
+
"dependsOn": [
|
|
113
|
+
"build"
|
|
114
|
+
]
|
|
104
115
|
}
|
|
105
116
|
}
|
|
106
117
|
},
|
package/dist/package.json
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@digitaldefiance/branded-enum",
|
|
3
|
-
"version": "0.0.1",
|
|
4
|
-
"description": "Runtime-identifiable enum-like types for TypeScript with zero runtime overhead",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"main": "./dist/index.js",
|
|
8
|
-
"module": "./dist/index.js",
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
10
|
-
"exports": {
|
|
11
|
-
"./package.json": "./package.json",
|
|
12
|
-
".": {
|
|
13
|
-
"types": "./dist/index.d.ts",
|
|
14
|
-
"import": "./dist/index.js",
|
|
15
|
-
"default": "./dist/index.js"
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"files": [
|
|
19
|
-
"dist",
|
|
20
|
-
"!**/*.tsbuildinfo"
|
|
21
|
-
],
|
|
22
|
-
"repository": {
|
|
23
|
-
"type": "git",
|
|
24
|
-
"url": "git+https://github.com/Digital-Defiance/branded-enum.git"
|
|
25
|
-
},
|
|
26
|
-
"keywords": [
|
|
27
|
-
"typescript",
|
|
28
|
-
"enum",
|
|
29
|
-
"branded",
|
|
30
|
-
"type-safe",
|
|
31
|
-
"runtime"
|
|
32
|
-
],
|
|
33
|
-
"author": "Digital Defiance, Jessica Mulein",
|
|
34
|
-
"bugs": {
|
|
35
|
-
"url": "https://github.com/Digital-Defiance/branded-enum/issues"
|
|
36
|
-
},
|
|
37
|
-
"homepage": "https://github.com/Digital-Defiance/branded-enum#readme",
|
|
38
|
-
"scripts": {
|
|
39
|
-
"build": "nx build branded-enum",
|
|
40
|
-
"build:examples": "nx build-examples branded-enum",
|
|
41
|
-
"test": "nx test branded-enum",
|
|
42
|
-
"lint": "nx lint branded-enum",
|
|
43
|
-
"publish:public": "yarn build && npm publish --access public"
|
|
44
|
-
},
|
|
45
|
-
"devDependencies": {
|
|
46
|
-
"@nx/jest": "22.4.2",
|
|
47
|
-
"@nx/js": "22.4.2",
|
|
48
|
-
"@swc-node/register": "~1.9.1",
|
|
49
|
-
"@swc/cli": "~0.6.0",
|
|
50
|
-
"@swc/core": "~1.5.7",
|
|
51
|
-
"@swc/helpers": "~0.5.11",
|
|
52
|
-
"@swc/jest": "~0.2.38",
|
|
53
|
-
"@types/jest": "^30.0.0",
|
|
54
|
-
"@types/node": "20.19.9",
|
|
55
|
-
"fast-check": "^4.5.3",
|
|
56
|
-
"jest": "^30.0.2",
|
|
57
|
-
"jest-environment-node": "^30.0.2",
|
|
58
|
-
"jest-util": "^30.0.2",
|
|
59
|
-
"nx": "22.4.2",
|
|
60
|
-
"prettier": "~3.6.2",
|
|
61
|
-
"ts-jest": "^29.4.0",
|
|
62
|
-
"ts-node": "10.9.1",
|
|
63
|
-
"tslib": "^2.3.0",
|
|
64
|
-
"typescript": "~5.9.2"
|
|
65
|
-
},
|
|
66
|
-
"packageManager": "yarn@4.12.0",
|
|
67
|
-
"nx": {
|
|
68
|
-
"name": "branded-enum",
|
|
69
|
-
"sourceRoot": "src",
|
|
70
|
-
"targets": {
|
|
71
|
-
"build": {
|
|
72
|
-
"executor": "@nx/js:swc",
|
|
73
|
-
"outputs": [
|
|
74
|
-
"{options.outputPath}"
|
|
75
|
-
],
|
|
76
|
-
"options": {
|
|
77
|
-
"outputPath": "dist",
|
|
78
|
-
"main": "src/index.ts",
|
|
79
|
-
"tsConfig": "tsconfig.lib.json",
|
|
80
|
-
"skipTypeCheck": true,
|
|
81
|
-
"stripLeadingPaths": true
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
"test": {
|
|
85
|
-
"executor": "@nx/jest:jest",
|
|
86
|
-
"outputs": [
|
|
87
|
-
"{projectRoot}/test-output/jest/coverage"
|
|
88
|
-
],
|
|
89
|
-
"options": {
|
|
90
|
-
"jestConfig": "jest.config.cts",
|
|
91
|
-
"passWithNoTests": true
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
"build-examples": {
|
|
95
|
-
"executor": "nx:run-commands",
|
|
96
|
-
"outputs": [
|
|
97
|
-
"{projectRoot}/examples/dist"
|
|
98
|
-
],
|
|
99
|
-
"options": {
|
|
100
|
-
"command": "tsc -p examples/tsconfig.json"
|
|
101
|
-
},
|
|
102
|
-
"dependsOn": [
|
|
103
|
-
"build"
|
|
104
|
-
]
|
|
105
|
-
},
|
|
106
|
-
"publish-public": {
|
|
107
|
-
"executor": "nx:run-commands",
|
|
108
|
-
"options": {
|
|
109
|
-
"command": "npm publish --access public"
|
|
110
|
-
},
|
|
111
|
-
"dependsOn": [
|
|
112
|
-
"build"
|
|
113
|
-
]
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
"engines": {
|
|
118
|
-
"node": ">=18"
|
|
119
|
-
}
|
|
120
|
-
}
|