@digitaldefiance/branded-enum 0.0.6 → 0.0.7
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/lib/registry.js +5 -3
- package/dist/cjs/lib/registry.js.map +1 -1
- package/dist/cjs/lib/types.js +2 -2
- package/dist/cjs/lib/types.js.map +1 -1
- package/dist/esm/lib/registry.d.ts +8 -3
- package/dist/esm/lib/registry.d.ts.map +1 -1
- package/dist/esm/lib/registry.js +11 -4
- package/dist/esm/lib/registry.js.map +1 -1
- package/dist/esm/lib/types.d.ts.map +1 -1
- package/dist/esm/lib/types.js +2 -2
- package/dist/esm/lib/types.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/lib/registry.js
CHANGED
|
@@ -48,9 +48,10 @@ function registerEnum(enumObj) {
|
|
|
48
48
|
const registry = getRegistry();
|
|
49
49
|
const enumId = enumObj[_types.ENUM_ID];
|
|
50
50
|
const values = enumObj[_types.ENUM_VALUES];
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// If already registered, return existing entry (idempotent)
|
|
52
|
+
const existing = registry.enums.get(enumId);
|
|
53
|
+
if (existing) {
|
|
54
|
+
return existing;
|
|
54
55
|
}
|
|
55
56
|
// Create registry entry
|
|
56
57
|
const entry = {
|
|
@@ -69,6 +70,7 @@ function registerEnum(enumObj) {
|
|
|
69
70
|
}
|
|
70
71
|
enumIds.add(enumId);
|
|
71
72
|
}
|
|
73
|
+
return entry;
|
|
72
74
|
}
|
|
73
75
|
function getAllEnumIds() {
|
|
74
76
|
const registry = getRegistry();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/registry.ts"],"sourcesContent":["/**\n * Global registry for branded enums.\n *\n * Uses globalThis to ensure cross-bundle compatibility - all instances\n * of the library share the same registry regardless of how they're bundled.\n */\n\nimport {\n BrandedEnum,\n BrandedEnumRegistry,\n RegistryEntry,\n REGISTRY_KEY,\n ENUM_ID,\n ENUM_VALUES,\n} from './types.js';\n\n/**\n * Gets the global registry, initializing it lazily if needed.\n * Uses globalThis for cross-bundle compatibility.\n *\n * The registry is shared across all instances of the library, even when\n * bundled separately or loaded as different module formats (ESM/CJS).\n *\n * @returns The global branded enum registry containing all registered enums\n * and a value index for reverse lookups.\n *\n * @example\n * const registry = getRegistry();\n * console.log(registry.enums.size); // Number of registered enums\n */\nexport function getRegistry(): BrandedEnumRegistry {\n const global = globalThis as typeof globalThis & {\n [REGISTRY_KEY]?: BrandedEnumRegistry;\n };\n\n if (!(REGISTRY_KEY in global) || !global[REGISTRY_KEY]) {\n global[REGISTRY_KEY] = {\n enums: new Map<string, RegistryEntry>(),\n valueIndex: new Map<string, Set<string>>(),\n };\n }\n\n return global[REGISTRY_KEY];\n}\n\n/**\n * Registers a branded enum in the global registry.\n * Also updates the value index for reverse lookups.\n *\n * @param enumObj - The branded enum to register\n * @
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/registry.ts"],"sourcesContent":["/**\n * Global registry for branded enums.\n *\n * Uses globalThis to ensure cross-bundle compatibility - all instances\n * of the library share the same registry regardless of how they're bundled.\n */\n\nimport {\n BrandedEnum,\n BrandedEnumRegistry,\n RegistryEntry,\n REGISTRY_KEY,\n ENUM_ID,\n ENUM_VALUES,\n} from './types.js';\n\n/**\n * Gets the global registry, initializing it lazily if needed.\n * Uses globalThis for cross-bundle compatibility.\n *\n * The registry is shared across all instances of the library, even when\n * bundled separately or loaded as different module formats (ESM/CJS).\n *\n * @returns The global branded enum registry containing all registered enums\n * and a value index for reverse lookups.\n *\n * @example\n * const registry = getRegistry();\n * console.log(registry.enums.size); // Number of registered enums\n */\nexport function getRegistry(): BrandedEnumRegistry {\n const global = globalThis as typeof globalThis & {\n [REGISTRY_KEY]?: BrandedEnumRegistry;\n };\n\n if (!(REGISTRY_KEY in global) || !global[REGISTRY_KEY]) {\n global[REGISTRY_KEY] = {\n enums: new Map<string, RegistryEntry>(),\n valueIndex: new Map<string, Set<string>>(),\n };\n }\n\n return global[REGISTRY_KEY];\n}\n\n/**\n * Registers a branded enum in the global registry.\n * Also updates the value index for reverse lookups.\n *\n * This function is idempotent - if an enum with the same ID is already\n * registered, it returns the existing entry instead of throwing an error.\n * This enables safe usage in module-scoped code that may be re-executed\n * in test environments or hot-reload scenarios.\n *\n * @param enumObj - The branded enum to register\n * @returns The registered entry (either new or existing)\n */\nexport function registerEnum<T extends Record<string, string>>(\n enumObj: BrandedEnum<T>\n): RegistryEntry {\n const registry = getRegistry();\n const enumId = enumObj[ENUM_ID];\n const values = enumObj[ENUM_VALUES];\n\n // If already registered, return existing entry (idempotent)\n const existing = registry.enums.get(enumId);\n if (existing) {\n return existing;\n }\n\n // Create registry entry\n const entry: RegistryEntry = {\n enumId,\n enumObj: enumObj as BrandedEnum<Record<string, string>>,\n values,\n };\n\n // Add to enums map\n registry.enums.set(enumId, entry);\n\n // Update value index for reverse lookups\n for (const value of values) {\n let enumIds = registry.valueIndex.get(value);\n if (!enumIds) {\n enumIds = new Set<string>();\n registry.valueIndex.set(value, enumIds);\n }\n enumIds.add(enumId);\n }\n\n return entry;\n}\n\n/**\n * Gets all registered enum IDs.\n *\n * Returns an array of all enum IDs that have been registered via\n * `createBrandedEnum`. Useful for debugging or introspection.\n *\n * @returns Array of all registered enum IDs. Returns empty array if no\n * enums have been registered.\n *\n * @example\n * createBrandedEnum('colors', { Red: 'red' } as const);\n * createBrandedEnum('sizes', { Small: 'small' } as const);\n *\n * getAllEnumIds(); // ['colors', 'sizes']\n */\nexport function getAllEnumIds(): string[] {\n const registry = getRegistry();\n return Array.from(registry.enums.keys());\n}\n\n/**\n * Gets a branded enum by its ID.\n *\n * Retrieves a previously registered branded enum from the global registry.\n * Useful when you need to access an enum dynamically by its ID.\n *\n * @param enumId - The enum ID to look up\n * @returns The branded enum object if found, or `undefined` if no enum\n * with the given ID has been registered.\n *\n * @example\n * const Status = createBrandedEnum('status', { Active: 'active' } as const);\n *\n * const retrieved = getEnumById('status');\n * console.log(retrieved === Status); // true\n *\n * const notFound = getEnumById('nonexistent');\n * console.log(notFound); // undefined\n */\nexport function getEnumById(\n enumId: string\n): BrandedEnum<Record<string, string>> | undefined {\n const registry = getRegistry();\n const entry = registry.enums.get(enumId);\n return entry?.enumObj;\n}\n\n/**\n * Finds all enum IDs that contain a given value.\n *\n * Performs a reverse lookup to find which enums contain a specific value.\n * Useful for debugging value collisions or routing values to handlers.\n *\n * @param value - The string value to search for\n * @returns Array of enum IDs that contain the value. Returns empty array\n * if no enums contain the value.\n *\n * @example\n * // Single enum containing value\n * createBrandedEnum('colors', { Red: 'red', Blue: 'blue' } as const);\n * findEnumSources('red'); // ['colors']\n *\n * @example\n * // Multiple enums with same value (collision detection)\n * createBrandedEnum('status1', { Active: 'active' } as const);\n * createBrandedEnum('status2', { Enabled: 'active' } as const);\n * findEnumSources('active'); // ['status1', 'status2']\n *\n * @example\n * // Value not found\n * findEnumSources('nonexistent'); // []\n */\nexport function findEnumSources(value: string): string[] {\n const registry = getRegistry();\n const enumIds = registry.valueIndex.get(value);\n return enumIds ? Array.from(enumIds) : [];\n}\n\n/**\n * Resets the global branded enum registry, clearing all registered enums.\n *\n * **WARNING**: This function is intended for testing purposes only.\n * Using it in production code will break any code that depends on\n * previously registered enums.\n *\n * Clears all entries from:\n * - The enums map (ID -> enum object)\n * - The value index (value -> set of enum IDs)\n *\n * @example\n * // In test setup/teardown\n * beforeEach(() => {\n * resetRegistry();\n * });\n *\n * @example\n * // Clear and verify\n * resetRegistry();\n * getAllEnumIds(); // []\n */\nexport function resetRegistry(): void {\n const registry = getRegistry();\n registry.enums.clear();\n registry.valueIndex.clear();\n}\n"],"names":["findEnumSources","getAllEnumIds","getEnumById","getRegistry","registerEnum","resetRegistry","global","globalThis","REGISTRY_KEY","enums","Map","valueIndex","enumObj","registry","enumId","ENUM_ID","values","ENUM_VALUES","existing","get","entry","set","value","enumIds","Set","add","Array","from","keys","clear"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC;;;;;;;;;;;IAgKeA,eAAe;eAAfA;;IAzDAC,aAAa;eAAbA;;IAwBAC,WAAW;eAAXA;;IAtGAC,WAAW;eAAXA;;IA2BAC,YAAY;eAAZA;;IAwIAC,aAAa;eAAbA;;;uBAnLT;AAgBA,SAASF;IACd,MAAMG,SAASC;IAIf,IAAI,CAAEC,CAAAA,mBAAY,IAAIF,MAAK,KAAM,CAACA,MAAM,CAACE,mBAAY,CAAC,EAAE;QACtDF,MAAM,CAACE,mBAAY,CAAC,GAAG;YACrBC,OAAO,IAAIC;YACXC,YAAY,IAAID;QAClB;IACF;IAEA,OAAOJ,MAAM,CAACE,mBAAY,CAAC;AAC7B;AAcO,SAASJ,aACdQ,OAAuB;IAEvB,MAAMC,WAAWV;IACjB,MAAMW,SAASF,OAAO,CAACG,cAAO,CAAC;IAC/B,MAAMC,SAASJ,OAAO,CAACK,kBAAW,CAAC;IAEnC,4DAA4D;IAC5D,MAAMC,WAAWL,SAASJ,KAAK,CAACU,GAAG,CAACL;IACpC,IAAII,UAAU;QACZ,OAAOA;IACT;IAEA,wBAAwB;IACxB,MAAME,QAAuB;QAC3BN;QACAF,SAASA;QACTI;IACF;IAEA,mBAAmB;IACnBH,SAASJ,KAAK,CAACY,GAAG,CAACP,QAAQM;IAE3B,yCAAyC;IACzC,KAAK,MAAME,SAASN,OAAQ;QAC1B,IAAIO,UAAUV,SAASF,UAAU,CAACQ,GAAG,CAACG;QACtC,IAAI,CAACC,SAAS;YACZA,UAAU,IAAIC;YACdX,SAASF,UAAU,CAACU,GAAG,CAACC,OAAOC;QACjC;QACAA,QAAQE,GAAG,CAACX;IACd;IAEA,OAAOM;AACT;AAiBO,SAASnB;IACd,MAAMY,WAAWV;IACjB,OAAOuB,MAAMC,IAAI,CAACd,SAASJ,KAAK,CAACmB,IAAI;AACvC;AAqBO,SAAS1B,YACdY,MAAc;IAEd,MAAMD,WAAWV;IACjB,MAAMiB,QAAQP,SAASJ,KAAK,CAACU,GAAG,CAACL;IACjC,OAAOM,OAAOR;AAChB;AA2BO,SAASZ,gBAAgBsB,KAAa;IAC3C,MAAMT,WAAWV;IACjB,MAAMoB,UAAUV,SAASF,UAAU,CAACQ,GAAG,CAACG;IACxC,OAAOC,UAAUG,MAAMC,IAAI,CAACJ,WAAW,EAAE;AAC3C;AAwBO,SAASlB;IACd,MAAMQ,WAAWV;IACjBU,SAASJ,KAAK,CAACoB,KAAK;IACpBhB,SAASF,UAAU,CAACkB,KAAK;AAC3B"}
|
package/dist/cjs/lib/types.js
CHANGED
|
@@ -30,8 +30,8 @@ _export(exports, {
|
|
|
30
30
|
return REGISTRY_KEY;
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
|
-
const ENUM_ID = Symbol('ENUM_ID');
|
|
34
|
-
const ENUM_VALUES = Symbol('ENUM_VALUES');
|
|
33
|
+
const ENUM_ID = Symbol.for('@digitaldefiance/branded-enum:ENUM_ID');
|
|
34
|
+
const ENUM_VALUES = Symbol.for('@digitaldefiance/branded-enum:ENUM_VALUES');
|
|
35
35
|
const REGISTRY_KEY = '__brandedEnumRegistry__';
|
|
36
36
|
const CONSUMER_REGISTRY_KEY = '__brandedEnumConsumerRegistry__';
|
|
37
37
|
|
|
@@ -1 +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":["CONSUMER_REGISTRY_KEY","ENUM_ID","ENUM_VALUES","REGISTRY_KEY","Symbol"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED;;;CAGC;;;;;;;;;;;IAsFYA,qBAAqB;eAArBA;;IArFAC,OAAO;eAAPA;;IAMAC,WAAW;eAAXA;;IAyEAC,YAAY;eAAZA;;;AA/EN,MAAMF,UAAyBG,OAAO;AAMtC,MAAMF,cAA6BE,OAAO;AAyE1C,MAAMD,eAAe;AAMrB,MAAMH,wBAAwB"}
|
|
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.for('@digitaldefiance/branded-enum: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.for('@digitaldefiance/branded-enum: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":["CONSUMER_REGISTRY_KEY","ENUM_ID","ENUM_VALUES","REGISTRY_KEY","Symbol","for"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED;;;CAGC;;;;;;;;;;;IAsFYA,qBAAqB;eAArBA;;IArFAC,OAAO;eAAPA;;IAMAC,WAAW;eAAXA;;IAyEAC,YAAY;eAAZA;;;AA/EN,MAAMF,UAAyBG,OAAOC,GAAG,CAAC;AAM1C,MAAMH,cAA6BE,OAAOC,GAAG,CAAC;AAyE9C,MAAMF,eAAe;AAMrB,MAAMH,wBAAwB"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Uses globalThis to ensure cross-bundle compatibility - all instances
|
|
5
5
|
* of the library share the same registry regardless of how they're bundled.
|
|
6
6
|
*/
|
|
7
|
-
import { BrandedEnum, BrandedEnumRegistry } from './types.js';
|
|
7
|
+
import { BrandedEnum, BrandedEnumRegistry, RegistryEntry } from './types.js';
|
|
8
8
|
/**
|
|
9
9
|
* Gets the global registry, initializing it lazily if needed.
|
|
10
10
|
* Uses globalThis for cross-bundle compatibility.
|
|
@@ -24,10 +24,15 @@ export declare function getRegistry(): BrandedEnumRegistry;
|
|
|
24
24
|
* Registers a branded enum in the global registry.
|
|
25
25
|
* Also updates the value index for reverse lookups.
|
|
26
26
|
*
|
|
27
|
+
* This function is idempotent - if an enum with the same ID is already
|
|
28
|
+
* registered, it returns the existing entry instead of throwing an error.
|
|
29
|
+
* This enables safe usage in module-scoped code that may be re-executed
|
|
30
|
+
* in test environments or hot-reload scenarios.
|
|
31
|
+
*
|
|
27
32
|
* @param enumObj - The branded enum to register
|
|
28
|
-
* @
|
|
33
|
+
* @returns The registered entry (either new or existing)
|
|
29
34
|
*/
|
|
30
|
-
export declare function registerEnum<T extends Record<string, string>>(enumObj: BrandedEnum<T>):
|
|
35
|
+
export declare function registerEnum<T extends Record<string, string>>(enumObj: BrandedEnum<T>): RegistryEntry;
|
|
31
36
|
/**
|
|
32
37
|
* Gets all registered enum IDs.
|
|
33
38
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/lib/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,mBAAmB,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/lib/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,aAAa,EAId,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,IAAI,mBAAmB,CAajD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3D,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GACtB,aAAa,CAgCf;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;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
|
package/dist/esm/lib/registry.js
CHANGED
|
@@ -31,15 +31,21 @@
|
|
|
31
31
|
* Registers a branded enum in the global registry.
|
|
32
32
|
* Also updates the value index for reverse lookups.
|
|
33
33
|
*
|
|
34
|
+
* This function is idempotent - if an enum with the same ID is already
|
|
35
|
+
* registered, it returns the existing entry instead of throwing an error.
|
|
36
|
+
* This enables safe usage in module-scoped code that may be re-executed
|
|
37
|
+
* in test environments or hot-reload scenarios.
|
|
38
|
+
*
|
|
34
39
|
* @param enumObj - The branded enum to register
|
|
35
|
-
* @
|
|
40
|
+
* @returns The registered entry (either new or existing)
|
|
36
41
|
*/ export function registerEnum(enumObj) {
|
|
37
42
|
const registry = getRegistry();
|
|
38
43
|
const enumId = enumObj[ENUM_ID];
|
|
39
44
|
const values = enumObj[ENUM_VALUES];
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
// If already registered, return existing entry (idempotent)
|
|
46
|
+
const existing = registry.enums.get(enumId);
|
|
47
|
+
if (existing) {
|
|
48
|
+
return existing;
|
|
43
49
|
}
|
|
44
50
|
// Create registry entry
|
|
45
51
|
const entry = {
|
|
@@ -58,6 +64,7 @@
|
|
|
58
64
|
}
|
|
59
65
|
enumIds.add(enumId);
|
|
60
66
|
}
|
|
67
|
+
return entry;
|
|
61
68
|
}
|
|
62
69
|
/**
|
|
63
70
|
* Gets all registered enum IDs.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/lib/registry.ts"],"sourcesContent":["/**\n * Global registry for branded enums.\n *\n * Uses globalThis to ensure cross-bundle compatibility - all instances\n * of the library share the same registry regardless of how they're bundled.\n */\n\nimport {\n BrandedEnum,\n BrandedEnumRegistry,\n RegistryEntry,\n REGISTRY_KEY,\n ENUM_ID,\n ENUM_VALUES,\n} from './types.js';\n\n/**\n * Gets the global registry, initializing it lazily if needed.\n * Uses globalThis for cross-bundle compatibility.\n *\n * The registry is shared across all instances of the library, even when\n * bundled separately or loaded as different module formats (ESM/CJS).\n *\n * @returns The global branded enum registry containing all registered enums\n * and a value index for reverse lookups.\n *\n * @example\n * const registry = getRegistry();\n * console.log(registry.enums.size); // Number of registered enums\n */\nexport function getRegistry(): BrandedEnumRegistry {\n const global = globalThis as typeof globalThis & {\n [REGISTRY_KEY]?: BrandedEnumRegistry;\n };\n\n if (!(REGISTRY_KEY in global) || !global[REGISTRY_KEY]) {\n global[REGISTRY_KEY] = {\n enums: new Map<string, RegistryEntry>(),\n valueIndex: new Map<string, Set<string>>(),\n };\n }\n\n return global[REGISTRY_KEY];\n}\n\n/**\n * Registers a branded enum in the global registry.\n * Also updates the value index for reverse lookups.\n *\n * @param enumObj - The branded enum to register\n * @
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/registry.ts"],"sourcesContent":["/**\n * Global registry for branded enums.\n *\n * Uses globalThis to ensure cross-bundle compatibility - all instances\n * of the library share the same registry regardless of how they're bundled.\n */\n\nimport {\n BrandedEnum,\n BrandedEnumRegistry,\n RegistryEntry,\n REGISTRY_KEY,\n ENUM_ID,\n ENUM_VALUES,\n} from './types.js';\n\n/**\n * Gets the global registry, initializing it lazily if needed.\n * Uses globalThis for cross-bundle compatibility.\n *\n * The registry is shared across all instances of the library, even when\n * bundled separately or loaded as different module formats (ESM/CJS).\n *\n * @returns The global branded enum registry containing all registered enums\n * and a value index for reverse lookups.\n *\n * @example\n * const registry = getRegistry();\n * console.log(registry.enums.size); // Number of registered enums\n */\nexport function getRegistry(): BrandedEnumRegistry {\n const global = globalThis as typeof globalThis & {\n [REGISTRY_KEY]?: BrandedEnumRegistry;\n };\n\n if (!(REGISTRY_KEY in global) || !global[REGISTRY_KEY]) {\n global[REGISTRY_KEY] = {\n enums: new Map<string, RegistryEntry>(),\n valueIndex: new Map<string, Set<string>>(),\n };\n }\n\n return global[REGISTRY_KEY];\n}\n\n/**\n * Registers a branded enum in the global registry.\n * Also updates the value index for reverse lookups.\n *\n * This function is idempotent - if an enum with the same ID is already\n * registered, it returns the existing entry instead of throwing an error.\n * This enables safe usage in module-scoped code that may be re-executed\n * in test environments or hot-reload scenarios.\n *\n * @param enumObj - The branded enum to register\n * @returns The registered entry (either new or existing)\n */\nexport function registerEnum<T extends Record<string, string>>(\n enumObj: BrandedEnum<T>\n): RegistryEntry {\n const registry = getRegistry();\n const enumId = enumObj[ENUM_ID];\n const values = enumObj[ENUM_VALUES];\n\n // If already registered, return existing entry (idempotent)\n const existing = registry.enums.get(enumId);\n if (existing) {\n return existing;\n }\n\n // Create registry entry\n const entry: RegistryEntry = {\n enumId,\n enumObj: enumObj as BrandedEnum<Record<string, string>>,\n values,\n };\n\n // Add to enums map\n registry.enums.set(enumId, entry);\n\n // Update value index for reverse lookups\n for (const value of values) {\n let enumIds = registry.valueIndex.get(value);\n if (!enumIds) {\n enumIds = new Set<string>();\n registry.valueIndex.set(value, enumIds);\n }\n enumIds.add(enumId);\n }\n\n return entry;\n}\n\n/**\n * Gets all registered enum IDs.\n *\n * Returns an array of all enum IDs that have been registered via\n * `createBrandedEnum`. Useful for debugging or introspection.\n *\n * @returns Array of all registered enum IDs. Returns empty array if no\n * enums have been registered.\n *\n * @example\n * createBrandedEnum('colors', { Red: 'red' } as const);\n * createBrandedEnum('sizes', { Small: 'small' } as const);\n *\n * getAllEnumIds(); // ['colors', 'sizes']\n */\nexport function getAllEnumIds(): string[] {\n const registry = getRegistry();\n return Array.from(registry.enums.keys());\n}\n\n/**\n * Gets a branded enum by its ID.\n *\n * Retrieves a previously registered branded enum from the global registry.\n * Useful when you need to access an enum dynamically by its ID.\n *\n * @param enumId - The enum ID to look up\n * @returns The branded enum object if found, or `undefined` if no enum\n * with the given ID has been registered.\n *\n * @example\n * const Status = createBrandedEnum('status', { Active: 'active' } as const);\n *\n * const retrieved = getEnumById('status');\n * console.log(retrieved === Status); // true\n *\n * const notFound = getEnumById('nonexistent');\n * console.log(notFound); // undefined\n */\nexport function getEnumById(\n enumId: string\n): BrandedEnum<Record<string, string>> | undefined {\n const registry = getRegistry();\n const entry = registry.enums.get(enumId);\n return entry?.enumObj;\n}\n\n/**\n * Finds all enum IDs that contain a given value.\n *\n * Performs a reverse lookup to find which enums contain a specific value.\n * Useful for debugging value collisions or routing values to handlers.\n *\n * @param value - The string value to search for\n * @returns Array of enum IDs that contain the value. Returns empty array\n * if no enums contain the value.\n *\n * @example\n * // Single enum containing value\n * createBrandedEnum('colors', { Red: 'red', Blue: 'blue' } as const);\n * findEnumSources('red'); // ['colors']\n *\n * @example\n * // Multiple enums with same value (collision detection)\n * createBrandedEnum('status1', { Active: 'active' } as const);\n * createBrandedEnum('status2', { Enabled: 'active' } as const);\n * findEnumSources('active'); // ['status1', 'status2']\n *\n * @example\n * // Value not found\n * findEnumSources('nonexistent'); // []\n */\nexport function findEnumSources(value: string): string[] {\n const registry = getRegistry();\n const enumIds = registry.valueIndex.get(value);\n return enumIds ? Array.from(enumIds) : [];\n}\n\n/**\n * Resets the global branded enum registry, clearing all registered enums.\n *\n * **WARNING**: This function is intended for testing purposes only.\n * Using it in production code will break any code that depends on\n * previously registered enums.\n *\n * Clears all entries from:\n * - The enums map (ID -> enum object)\n * - The value index (value -> set of enum IDs)\n *\n * @example\n * // In test setup/teardown\n * beforeEach(() => {\n * resetRegistry();\n * });\n *\n * @example\n * // Clear and verify\n * resetRegistry();\n * getAllEnumIds(); // []\n */\nexport function resetRegistry(): void {\n const registry = getRegistry();\n registry.enums.clear();\n registry.valueIndex.clear();\n}\n"],"names":["REGISTRY_KEY","ENUM_ID","ENUM_VALUES","getRegistry","global","globalThis","enums","Map","valueIndex","registerEnum","enumObj","registry","enumId","values","existing","get","entry","set","value","enumIds","Set","add","getAllEnumIds","Array","from","keys","getEnumById","findEnumSources","resetRegistry","clear"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED,SAIEA,YAAY,EACZC,OAAO,EACPC,WAAW,QACN,aAAa;AAEpB;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASC;IACd,MAAMC,SAASC;IAIf,IAAI,CAAEL,CAAAA,gBAAgBI,MAAK,KAAM,CAACA,MAAM,CAACJ,aAAa,EAAE;QACtDI,MAAM,CAACJ,aAAa,GAAG;YACrBM,OAAO,IAAIC;YACXC,YAAY,IAAID;QAClB;IACF;IAEA,OAAOH,MAAM,CAACJ,aAAa;AAC7B;AAEA;;;;;;;;;;;CAWC,GACD,OAAO,SAASS,aACdC,OAAuB;IAEvB,MAAMC,WAAWR;IACjB,MAAMS,SAASF,OAAO,CAACT,QAAQ;IAC/B,MAAMY,SAASH,OAAO,CAACR,YAAY;IAEnC,4DAA4D;IAC5D,MAAMY,WAAWH,SAASL,KAAK,CAACS,GAAG,CAACH;IACpC,IAAIE,UAAU;QACZ,OAAOA;IACT;IAEA,wBAAwB;IACxB,MAAME,QAAuB;QAC3BJ;QACAF,SAASA;QACTG;IACF;IAEA,mBAAmB;IACnBF,SAASL,KAAK,CAACW,GAAG,CAACL,QAAQI;IAE3B,yCAAyC;IACzC,KAAK,MAAME,SAASL,OAAQ;QAC1B,IAAIM,UAAUR,SAASH,UAAU,CAACO,GAAG,CAACG;QACtC,IAAI,CAACC,SAAS;YACZA,UAAU,IAAIC;YACdT,SAASH,UAAU,CAACS,GAAG,CAACC,OAAOC;QACjC;QACAA,QAAQE,GAAG,CAACT;IACd;IAEA,OAAOI;AACT;AAEA;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASM;IACd,MAAMX,WAAWR;IACjB,OAAOoB,MAAMC,IAAI,CAACb,SAASL,KAAK,CAACmB,IAAI;AACvC;AAEA;;;;;;;;;;;;;;;;;;CAkBC,GACD,OAAO,SAASC,YACdd,MAAc;IAEd,MAAMD,WAAWR;IACjB,MAAMa,QAAQL,SAASL,KAAK,CAACS,GAAG,CAACH;IACjC,OAAOI,OAAON;AAChB;AAEA;;;;;;;;;;;;;;;;;;;;;;;;CAwBC,GACD,OAAO,SAASiB,gBAAgBT,KAAa;IAC3C,MAAMP,WAAWR;IACjB,MAAMgB,UAAUR,SAASH,UAAU,CAACO,GAAG,CAACG;IACxC,OAAOC,UAAUI,MAAMC,IAAI,CAACL,WAAW,EAAE;AAC3C;AAEA;;;;;;;;;;;;;;;;;;;;;CAqBC,GACD,OAAO,SAASS;IACd,MAAMjB,WAAWR;IACjBQ,SAASL,KAAK,CAACuB,KAAK;IACpBlB,SAASH,UAAU,CAACqB,KAAK;AAC3B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,OAAO,MAA4D,CAAC;AAE1F;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,OAAO,MAAgE,CAAC;AAElG;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACrC;AAED;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,GACrE,mBAAmB,CAAC;AAEtB;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACrC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,cAAc,IACnD,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,qDAAqD;IACrD,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,mEAAmE;IACnE,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CAC/C;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAG,yBAAkC,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAG,iCAA0C,CAAC;AAEhF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IAErC,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;IAC/C,qBAAqB;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACnD,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;CACpD;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GACpD,MAAM,CAAC,GAAG,MAAM,GAChB,CAAC,SAAS,cAAc,GACtB,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,OAAO,GAAG,OAAO,WAAW,CAAC,GAAG,MAAM,GAC9D,KAAK,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GACtD,CAAC,CAAC,MAAM,CAAC,CAAC,GACV,CAAC,SAAS,cAAc,GACtB,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,OAAO,GAAG,OAAO,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,GACvF,KAAK,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GACrE,CAAC,GACD,KAAK,CAAC;AAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/esm/lib/types.js
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*/ /**
|
|
7
7
|
* Symbol key for storing the enum ID metadata.
|
|
8
8
|
* Using a Symbol prevents collision with user-defined keys.
|
|
9
|
-
*/ export const ENUM_ID = Symbol('ENUM_ID');
|
|
9
|
+
*/ export const ENUM_ID = Symbol.for('@digitaldefiance/branded-enum:ENUM_ID');
|
|
10
10
|
/**
|
|
11
11
|
* Symbol key for storing the enum values Set.
|
|
12
12
|
* Using a Symbol prevents collision with user-defined keys.
|
|
13
|
-
*/ export const ENUM_VALUES = Symbol('ENUM_VALUES');
|
|
13
|
+
*/ export const ENUM_VALUES = Symbol.for('@digitaldefiance/branded-enum:ENUM_VALUES');
|
|
14
14
|
/**
|
|
15
15
|
* The key used to store the registry on globalThis.
|
|
16
16
|
* Namespaced to avoid collisions with other libraries.
|
|
@@ -1 +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"}
|
|
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.for('@digitaldefiance/branded-enum: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.for('@digitaldefiance/branded-enum: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","for","ENUM_VALUES","REGISTRY_KEY","CONSUMER_REGISTRY_KEY"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED;;;CAGC,GACD,OAAO,MAAMA,UAAyBC,OAAOC,GAAG,CAAC,yCAAyC;AAE1F;;;CAGC,GACD,OAAO,MAAMC,cAA6BF,OAAOC,GAAG,CAAC,6CAA6C;AAqElG;;;CAGC,GACD,OAAO,MAAME,eAAe,0BAAmC;AAE/D;;;CAGC,GACD,OAAO,MAAMC,wBAAwB,kCAA2C"}
|