@digitaldefiance/branded-enum 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +149 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/lib/accessors.cjs +55 -0
- package/dist/cjs/lib/accessors.cjs.map +1 -0
- package/dist/cjs/lib/advanced.cjs +558 -0
- package/dist/cjs/lib/advanced.cjs.map +1 -0
- package/dist/cjs/lib/branded-enum.cjs +15 -0
- package/dist/cjs/lib/branded-enum.cjs.map +1 -0
- package/dist/cjs/lib/decorators.cjs +202 -0
- package/dist/cjs/lib/decorators.cjs.map +1 -0
- package/dist/cjs/lib/factory.cjs +45 -0
- package/dist/cjs/lib/factory.cjs.map +1 -0
- package/dist/cjs/lib/guards.cjs +119 -0
- package/dist/cjs/lib/guards.cjs.map +1 -0
- package/dist/cjs/lib/merge.cjs +47 -0
- package/dist/cjs/lib/merge.cjs.map +1 -0
- package/dist/cjs/lib/registry.cjs +85 -0
- package/dist/cjs/lib/registry.cjs.map +1 -0
- package/dist/cjs/lib/types.cjs +38 -0
- package/dist/cjs/lib/types.cjs.map +1 -0
- package/dist/cjs/lib/utils.cjs +80 -0
- package/dist/cjs/lib/utils.cjs.map +1 -0
- package/dist/esm/index.d.ts +21 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/accessors.d.ts +79 -0
- package/dist/esm/lib/accessors.d.ts.map +1 -0
- package/dist/esm/lib/accessors.js.map +1 -0
- package/dist/esm/lib/advanced.d.ts +1422 -0
- package/dist/esm/lib/advanced.d.ts.map +1 -0
- package/dist/esm/lib/advanced.js.map +1 -0
- package/dist/esm/lib/branded-enum.d.ts +2 -0
- package/dist/esm/lib/branded-enum.d.ts.map +1 -0
- package/dist/esm/lib/branded-enum.js.map +1 -0
- package/dist/esm/lib/decorators.d.ts +147 -0
- package/dist/esm/lib/decorators.d.ts.map +1 -0
- package/dist/esm/lib/decorators.js.map +1 -0
- package/dist/esm/lib/factory.d.ts +52 -0
- package/dist/esm/lib/factory.d.ts.map +1 -0
- package/dist/esm/lib/factory.js.map +1 -0
- package/dist/esm/lib/guards.d.ts +297 -0
- package/dist/esm/lib/guards.d.ts.map +1 -0
- package/dist/esm/lib/guards.js.map +1 -0
- package/dist/esm/lib/merge.d.ts +64 -0
- package/dist/esm/lib/merge.d.ts.map +1 -0
- package/dist/esm/lib/merge.js.map +1 -0
- package/dist/esm/lib/registry.d.ts +93 -0
- package/dist/esm/lib/registry.d.ts.map +1 -0
- package/dist/esm/lib/registry.js.map +1 -0
- package/dist/esm/lib/types.d.ts +258 -0
- package/dist/esm/lib/types.d.ts.map +1 -0
- package/dist/esm/lib/types.js.map +1 -0
- package/dist/esm/lib/utils.d.ts +121 -0
- package/dist/esm/lib/utils.d.ts.map +1 -0
- package/dist/esm/lib/utils.js.map +1 -0
- package/package.json +31 -18
- package/dist/index.js.map +0 -1
- package/dist/lib/accessors.js.map +0 -1
- package/dist/lib/advanced.js.map +0 -1
- package/dist/lib/branded-enum.js.map +0 -1
- package/dist/lib/decorators.js.map +0 -1
- package/dist/lib/factory.js.map +0 -1
- package/dist/lib/guards.js.map +0 -1
- package/dist/lib/merge.js.map +0 -1
- package/dist/lib/registry.js.map +0 -1
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/utils.js.map +0 -1
- package/dist/package.json +0 -120
- /package/dist/{index.js → esm/index.js} +0 -0
- /package/dist/{lib → esm/lib}/accessors.js +0 -0
- /package/dist/{lib → esm/lib}/advanced.js +0 -0
- /package/dist/{lib → esm/lib}/branded-enum.js +0 -0
- /package/dist/{lib → esm/lib}/decorators.js +0 -0
- /package/dist/{lib → esm/lib}/factory.js +0 -0
- /package/dist/{lib → esm/lib}/guards.js +0 -0
- /package/dist/{lib → esm/lib}/merge.js +0 -0
- /package/dist/{lib → esm/lib}/registry.js +0 -0
- /package/dist/{lib → esm/lib}/types.js +0 -0
- /package/dist/{lib → esm/lib}/utils.js +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guards for branded enums.
|
|
3
|
+
*
|
|
4
|
+
* Provides runtime type checking and assertion functions
|
|
5
|
+
* for validating values against branded enums.
|
|
6
|
+
*/ "use strict";
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
function _export(target, all) {
|
|
11
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: all[name]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
_export(exports, {
|
|
17
|
+
assertFromEnum: function() {
|
|
18
|
+
return assertFromEnum;
|
|
19
|
+
},
|
|
20
|
+
isFromEnum: function() {
|
|
21
|
+
return isFromEnum;
|
|
22
|
+
},
|
|
23
|
+
parseEnum: function() {
|
|
24
|
+
return parseEnum;
|
|
25
|
+
},
|
|
26
|
+
safeParseEnum: function() {
|
|
27
|
+
return safeParseEnum;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const _types = require("./types.js");
|
|
31
|
+
/**
|
|
32
|
+
* Checks if an object is a branded enum (has Symbol metadata).
|
|
33
|
+
*
|
|
34
|
+
* @param obj - The object to check
|
|
35
|
+
* @returns true if obj is a branded enum
|
|
36
|
+
*/ function isBrandedEnum(obj) {
|
|
37
|
+
return obj !== null && typeof obj === 'object' && _types.ENUM_ID in obj && _types.ENUM_VALUES in obj && typeof obj[_types.ENUM_ID] === 'string' && obj[_types.ENUM_VALUES] instanceof Set;
|
|
38
|
+
}
|
|
39
|
+
function isFromEnum(value, enumObj) {
|
|
40
|
+
// Return false for non-string values
|
|
41
|
+
if (typeof value !== 'string') {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
// Return false if enumObj is not a branded enum
|
|
45
|
+
if (!isBrandedEnum(enumObj)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
// Check if value exists in enum's value Set
|
|
49
|
+
return enumObj[_types.ENUM_VALUES].has(value);
|
|
50
|
+
}
|
|
51
|
+
function assertFromEnum(value, enumObj) {
|
|
52
|
+
// Check if enumObj is a branded enum
|
|
53
|
+
if (!isBrandedEnum(enumObj)) {
|
|
54
|
+
throw new Error('Second argument is not a branded enum');
|
|
55
|
+
}
|
|
56
|
+
// Check if value is in the enum
|
|
57
|
+
if (!isFromEnum(value, enumObj)) {
|
|
58
|
+
const enumId = enumObj[_types.ENUM_ID];
|
|
59
|
+
throw new Error(`Value "${value}" is not a member of enum "${enumId}"`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
function parseEnum(value, enumObj, defaultValue) {
|
|
64
|
+
// If the value is valid, return it
|
|
65
|
+
if (isFromEnum(value, enumObj)) {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
// Otherwise return the default
|
|
69
|
+
return defaultValue;
|
|
70
|
+
}
|
|
71
|
+
function safeParseEnum(value, enumObj) {
|
|
72
|
+
// Check if enumObj is a branded enum
|
|
73
|
+
if (!isBrandedEnum(enumObj)) {
|
|
74
|
+
return {
|
|
75
|
+
success: false,
|
|
76
|
+
error: {
|
|
77
|
+
message: 'Second argument is not a branded enum',
|
|
78
|
+
code: 'INVALID_ENUM_OBJECT',
|
|
79
|
+
input: value
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const enumId = enumObj[_types.ENUM_ID];
|
|
84
|
+
const validValues = Array.from(enumObj[_types.ENUM_VALUES]).sort();
|
|
85
|
+
// Check if value is a string
|
|
86
|
+
if (typeof value !== 'string') {
|
|
87
|
+
const valueType = value === null ? 'null' : typeof value;
|
|
88
|
+
return {
|
|
89
|
+
success: false,
|
|
90
|
+
error: {
|
|
91
|
+
message: `Expected a string value, received ${valueType}`,
|
|
92
|
+
code: 'INVALID_VALUE_TYPE',
|
|
93
|
+
input: value,
|
|
94
|
+
enumId,
|
|
95
|
+
validValues
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Check if value is in the enum
|
|
100
|
+
if (!enumObj[_types.ENUM_VALUES].has(value)) {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: {
|
|
104
|
+
message: `Value "${value}" is not a member of enum "${enumId}"`,
|
|
105
|
+
code: 'VALUE_NOT_IN_ENUM',
|
|
106
|
+
input: value,
|
|
107
|
+
enumId,
|
|
108
|
+
validValues
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// Success case
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
value: value
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//# sourceMappingURL=guards.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/guards.ts"],"sourcesContent":["/**\n * Type guards for branded enums.\n *\n * Provides runtime type checking and assertion functions\n * for validating values against branded enums.\n */\n\nimport {\n AnyBrandedEnum,\n BrandedEnum,\n BrandedEnumValue,\n ENUM_ID,\n ENUM_VALUES,\n EnumValues,\n} from './types.js';\n\n/**\n * Checks if an object is a branded enum (has Symbol metadata).\n *\n * @param obj - The object to check\n * @returns true if obj is a branded enum\n */\nfunction isBrandedEnum(obj: unknown): obj is AnyBrandedEnum {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n ENUM_ID in obj &&\n ENUM_VALUES in obj &&\n typeof (obj as AnyBrandedEnum)[ENUM_ID] === 'string' &&\n (obj as AnyBrandedEnum)[ENUM_VALUES] instanceof Set\n );\n}\n\n/**\n * Checks if a value belongs to a specific branded enum.\n *\n * Returns true if and only if:\n * - enumObj is a valid branded enum (has Symbol metadata)\n * - value is a string\n * - value exists in the enum's value Set\n *\n * This function provides TypeScript type narrowing - when it returns true,\n * the value's type is narrowed to the enum's value type.\n *\n * @template E - The branded enum type\n * @param value - The value to check. Can be any type; non-strings return false.\n * @param enumObj - The branded enum to check against\n * @returns `true` if value is in the enum (with type narrowing), `false` otherwise.\n * Returns `false` for non-string values, null, undefined, or if enumObj\n * is not a branded enum.\n *\n * @example\n * // Basic type guard usage\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n *\n * function handleStatus(value: unknown) {\n * if (isFromEnum(value, Status)) {\n * // value is narrowed to 'active' | 'inactive'\n * console.log('Valid status:', value);\n * } else {\n * console.log('Invalid status');\n * }\n * }\n *\n * @example\n * // Returns false for non-string values\n * isFromEnum(123, Status); // false\n * isFromEnum(null, Status); // false\n * isFromEnum(undefined, Status); // false\n *\n * @example\n * // Returns false for non-branded enum objects\n * isFromEnum('active', { Active: 'active' }); // false (not a branded enum)\n */\nexport function isFromEnum<E extends AnyBrandedEnum>(\n value: unknown,\n enumObj: E\n): value is EnumValues<E> {\n // Return false for non-string values\n if (typeof value !== 'string') {\n return false;\n }\n\n // Return false if enumObj is not a branded enum\n if (!isBrandedEnum(enumObj)) {\n return false;\n }\n\n // Check if value exists in enum's value Set\n return enumObj[ENUM_VALUES].has(value);\n}\n\n/**\n * Asserts that a value belongs to a branded enum, throwing if not.\n *\n * Use this function when you want to validate a value and throw an error\n * if it's invalid, rather than handling the false case manually.\n *\n * @template E - The branded enum type\n * @param value - The value to check. Can be any type.\n * @param enumObj - The branded enum to check against\n * @returns The value with narrowed type if valid\n * @throws {Error} Throws `Error` with message `Second argument is not a branded enum`\n * if enumObj is not a valid branded enum.\n * @throws {Error} Throws `Error` with message `Value \"${value}\" is not a member of enum \"${enumId}\"`\n * if the value is not found in the enum.\n *\n * @example\n * // Successful assertion\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * const validated = assertFromEnum('active', Status);\n * // validated is typed as 'active' | 'inactive'\n *\n * @example\n * // Throws for invalid value\n * try {\n * assertFromEnum('unknown', Status);\n * } catch (e) {\n * console.log(e.message); // 'Value \"unknown\" is not a member of enum \"status\"'\n * }\n *\n * @example\n * // Throws for non-branded enum\n * try {\n * assertFromEnum('active', { Active: 'active' });\n * } catch (e) {\n * console.log(e.message); // 'Second argument is not a branded enum'\n * }\n */\nexport function assertFromEnum<E extends AnyBrandedEnum>(\n value: unknown,\n enumObj: E\n): EnumValues<E> {\n // Check if enumObj is a branded enum\n if (!isBrandedEnum(enumObj)) {\n throw new Error('Second argument is not a branded enum');\n }\n\n // Check if value is in the enum\n if (!isFromEnum(value, enumObj)) {\n const enumId = enumObj[ENUM_ID];\n throw new Error(`Value \"${value}\" is not a member of enum \"${enumId}\"`);\n }\n\n return value as EnumValues<E>;\n}\n\n/**\n * Safely parses a value against a branded enum, returning a default if invalid.\n *\n * This is a non-throwing alternative to `assertFromEnum`. Instead of throwing\n * an error when the value is not in the enum, it returns the provided default value.\n *\n * Use this function when you want to handle invalid values gracefully without\n * try/catch blocks, such as when parsing user input or external data.\n *\n * @template E - The branded enum type\n * @param value - The value to parse. Can be any type; non-strings will return the default.\n * @param enumObj - The branded enum to validate against\n * @param defaultValue - The value to return if parsing fails. Must be a valid enum value.\n * @returns The original value if it exists in the enum, otherwise the default value.\n * The return type is narrowed to the enum's value type.\n *\n * @example\n * // Basic usage with default fallback\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * // Valid value returns as-is\n * parseEnum('active', Status, Status.Pending); // 'active'\n *\n * // Invalid value returns default\n * parseEnum('unknown', Status, Status.Pending); // 'pending'\n *\n * // Non-string value returns default\n * parseEnum(null, Status, Status.Inactive); // 'inactive'\n * parseEnum(123, Status, Status.Inactive); // 'inactive'\n *\n * @example\n * // Parsing user input safely\n * function handleUserStatus(input: unknown): void {\n * const status = parseEnum(input, Status, Status.Pending);\n * // status is guaranteed to be 'active' | 'inactive' | 'pending'\n * console.log('Processing status:', status);\n * }\n *\n * @example\n * // Parsing API response with fallback\n * interface ApiResponse {\n * status?: string;\n * }\n *\n * function processResponse(response: ApiResponse) {\n * const status = parseEnum(response.status, Status, Status.Inactive);\n * // Handles undefined, null, or invalid status values gracefully\n * return { status };\n * }\n *\n * @example\n * // Chaining with optional values\n * const userStatus = parseEnum(\n * localStorage.getItem('userStatus'),\n * Status,\n * Status.Active\n * );\n */\nexport function parseEnum<E extends AnyBrandedEnum>(\n value: unknown,\n enumObj: E,\n defaultValue: EnumValues<E>\n): EnumValues<E> {\n // If the value is valid, return it\n if (isFromEnum(value, enumObj)) {\n return value;\n }\n\n // Otherwise return the default\n return defaultValue;\n}\n\n// =============================================================================\n// Safe Parse Result Types\n// =============================================================================\n\n/**\n * Represents a successful parse result from safeParseEnum.\n *\n * @template T - The type of the successfully parsed value\n */\nexport interface SafeParseSuccess<T> {\n /** Indicates the parse was successful */\n readonly success: true;\n /** The validated enum value */\n readonly value: T;\n}\n\n/**\n * Represents a failed parse result from safeParseEnum.\n *\n * Contains detailed error information for debugging and user feedback.\n */\nexport interface SafeParseFailure {\n /** Indicates the parse failed */\n readonly success: false;\n /** Detailed error information */\n readonly error: SafeParseError;\n}\n\n/**\n * Detailed error information for a failed parse.\n */\nexport interface SafeParseError {\n /** Human-readable error message */\n readonly message: string;\n /** The code identifying the type of error */\n readonly code: SafeParseErrorCode;\n /** The input value that failed validation */\n readonly input: unknown;\n /** The enum ID (if available) */\n readonly enumId?: string;\n /** The valid values for the enum (if available) */\n readonly validValues?: readonly string[];\n}\n\n/**\n * Error codes for safe parse failures.\n */\nexport type SafeParseErrorCode =\n | 'INVALID_ENUM_OBJECT'\n | 'INVALID_VALUE_TYPE'\n | 'VALUE_NOT_IN_ENUM';\n\n/**\n * Union type representing the result of safeParseEnum.\n *\n * @template T - The type of the successfully parsed value\n */\nexport type SafeParseResult<T> = SafeParseSuccess<T> | SafeParseFailure;\n\n/**\n * Safely parses a value against a branded enum, returning a result object.\n *\n * This function provides validated deserialization with detailed error information.\n * Unlike `parseEnum` which returns a default value on failure, or `assertFromEnum`\n * which throws an error, `safeParseEnum` returns a discriminated union result\n * that allows for explicit success/failure handling.\n *\n * The result is either:\n * - `{ success: true, value: T }` - The value is valid and typed correctly\n * - `{ success: false, error: SafeParseError }` - The value is invalid with details\n *\n * Error codes:\n * - `INVALID_ENUM_OBJECT` - The enumObj is not a valid branded enum\n * - `INVALID_VALUE_TYPE` - The value is not a string\n * - `VALUE_NOT_IN_ENUM` - The value is a string but not in the enum\n *\n * @template E - The branded enum type\n * @param value - The value to parse. Can be any type.\n * @param enumObj - The branded enum to validate against\n * @returns A SafeParseResult containing either the validated value or error details\n *\n * @example\n * // Basic usage with success\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * } as const);\n *\n * const result = safeParseEnum('active', Status);\n * if (result.success) {\n * console.log('Valid status:', result.value); // 'active'\n * } else {\n * console.log('Error:', result.error.message);\n * }\n *\n * @example\n * // Handling invalid value\n * const result = safeParseEnum('unknown', Status);\n * if (!result.success) {\n * console.log(result.error.code); // 'VALUE_NOT_IN_ENUM'\n * console.log(result.error.message); // 'Value \"unknown\" is not a member of enum \"status\"'\n * console.log(result.error.validValues); // ['active', 'inactive']\n * }\n *\n * @example\n * // Handling non-string input\n * const result = safeParseEnum(123, Status);\n * if (!result.success) {\n * console.log(result.error.code); // 'INVALID_VALUE_TYPE'\n * console.log(result.error.message); // 'Expected a string value, received number'\n * }\n *\n * @example\n * // Parsing API response\n * interface ApiResponse {\n * status?: string;\n * }\n *\n * function processResponse(response: ApiResponse) {\n * const result = safeParseEnum(response.status, Status);\n * if (result.success) {\n * return { status: result.value };\n * } else {\n * // Log detailed error for debugging\n * console.error('Invalid status:', result.error);\n * return { status: Status.Inactive }; // fallback\n * }\n * }\n *\n * @example\n * // Form validation with detailed errors\n * function validateForm(data: Record<string, unknown>) {\n * const statusResult = safeParseEnum(data.status, Status);\n * const errors: string[] = [];\n *\n * if (!statusResult.success) {\n * errors.push(`Status: ${statusResult.error.message}`);\n * }\n *\n * return {\n * isValid: errors.length === 0,\n * errors,\n * data: statusResult.success ? { status: statusResult.value } : null,\n * };\n * }\n *\n * @example\n * // Type narrowing with result\n * const result = safeParseEnum(userInput, Status);\n * if (result.success) {\n * // result.value is typed as 'active' | 'inactive'\n * handleStatus(result.value);\n * } else {\n * // result.error is typed as SafeParseError\n * showError(result.error.message);\n * }\n */\nexport function safeParseEnum<E extends AnyBrandedEnum>(\n value: unknown,\n enumObj: E\n): SafeParseResult<EnumValues<E>> {\n // Check if enumObj is a branded enum\n if (!isBrandedEnum(enumObj)) {\n return {\n success: false,\n error: {\n message: 'Second argument is not a branded enum',\n code: 'INVALID_ENUM_OBJECT',\n input: value,\n },\n };\n }\n\n const enumId = enumObj[ENUM_ID];\n const validValues = Array.from(enumObj[ENUM_VALUES]).sort();\n\n // Check if value is a string\n if (typeof value !== 'string') {\n const valueType = value === null ? 'null' : typeof value;\n return {\n success: false,\n error: {\n message: `Expected a string value, received ${valueType}`,\n code: 'INVALID_VALUE_TYPE',\n input: value,\n enumId,\n validValues,\n },\n };\n }\n\n // Check if value is in the enum\n if (!enumObj[ENUM_VALUES].has(value)) {\n return {\n success: false,\n error: {\n message: `Value \"${value}\" is not a member of enum \"${enumId}\"`,\n code: 'VALUE_NOT_IN_ENUM',\n input: value,\n enumId,\n validValues,\n },\n };\n }\n\n // Success case\n return {\n success: true,\n value: value as EnumValues<E>,\n };\n}\n"],"names":["assertFromEnum","isFromEnum","parseEnum","safeParseEnum","isBrandedEnum","obj","ENUM_ID","ENUM_VALUES","Set","value","enumObj","has","Error","enumId","defaultValue","success","error","message","code","input","validValues","Array","from","sort","valueType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC;;;;;;;;;;;IA4HeA,cAAc;eAAdA;;IAvDAC,UAAU;eAAVA;;IAuIAC,SAAS;eAATA;;IA2KAC,aAAa;eAAbA;;;uBA9WT;AAEP;;;;;CAKC,GACD,SAASC,cAAcC,GAAY;IACjC,OACEA,QAAQ,QACR,OAAOA,QAAQ,YACfC,cAAO,IAAID,OACXE,kBAAW,IAAIF,OACf,OAAO,AAACA,GAAsB,CAACC,cAAO,CAAC,KAAK,YAC5C,AAACD,GAAsB,CAACE,kBAAW,CAAC,YAAYC;AAEpD;AA2CO,SAASP,WACdQ,KAAc,EACdC,OAAU;IAEV,qCAAqC;IACrC,IAAI,OAAOD,UAAU,UAAU;QAC7B,OAAO;IACT;IAEA,gDAAgD;IAChD,IAAI,CAACL,cAAcM,UAAU;QAC3B,OAAO;IACT;IAEA,4CAA4C;IAC5C,OAAOA,OAAO,CAACH,kBAAW,CAAC,CAACI,GAAG,CAACF;AAClC;AAuCO,SAAST,eACdS,KAAc,EACdC,OAAU;IAEV,qCAAqC;IACrC,IAAI,CAACN,cAAcM,UAAU;QAC3B,MAAM,IAAIE,MAAM;IAClB;IAEA,gCAAgC;IAChC,IAAI,CAACX,WAAWQ,OAAOC,UAAU;QAC/B,MAAMG,SAASH,OAAO,CAACJ,cAAO,CAAC;QAC/B,MAAM,IAAIM,MAAM,CAAC,OAAO,EAAEH,MAAM,2BAA2B,EAAEI,OAAO,CAAC,CAAC;IACxE;IAEA,OAAOJ;AACT;AAgEO,SAASP,UACdO,KAAc,EACdC,OAAU,EACVI,YAA2B;IAE3B,mCAAmC;IACnC,IAAIb,WAAWQ,OAAOC,UAAU;QAC9B,OAAOD;IACT;IAEA,+BAA+B;IAC/B,OAAOK;AACT;AA+JO,SAASX,cACdM,KAAc,EACdC,OAAU;IAEV,qCAAqC;IACrC,IAAI,CAACN,cAAcM,UAAU;QAC3B,OAAO;YACLK,SAAS;YACTC,OAAO;gBACLC,SAAS;gBACTC,MAAM;gBACNC,OAAOV;YACT;QACF;IACF;IAEA,MAAMI,SAASH,OAAO,CAACJ,cAAO,CAAC;IAC/B,MAAMc,cAAcC,MAAMC,IAAI,CAACZ,OAAO,CAACH,kBAAW,CAAC,EAAEgB,IAAI;IAEzD,6BAA6B;IAC7B,IAAI,OAAOd,UAAU,UAAU;QAC7B,MAAMe,YAAYf,UAAU,OAAO,SAAS,OAAOA;QACnD,OAAO;YACLM,SAAS;YACTC,OAAO;gBACLC,SAAS,CAAC,kCAAkC,EAAEO,UAAU,CAAC;gBACzDN,MAAM;gBACNC,OAAOV;gBACPI;gBACAO;YACF;QACF;IACF;IAEA,gCAAgC;IAChC,IAAI,CAACV,OAAO,CAACH,kBAAW,CAAC,CAACI,GAAG,CAACF,QAAQ;QACpC,OAAO;YACLM,SAAS;YACTC,OAAO;gBACLC,SAAS,CAAC,OAAO,EAAER,MAAM,2BAA2B,EAAEI,OAAO,CAAC,CAAC;gBAC/DK,MAAM;gBACNC,OAAOV;gBACPI;gBACAO;YACF;QACF;IACF;IAEA,eAAe;IACf,OAAO;QACLL,SAAS;QACTN,OAAOA;IACT;AACF"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum composition functions for branded enums.
|
|
3
|
+
*
|
|
4
|
+
* Enables merging multiple branded enums into a new combined enum
|
|
5
|
+
* while maintaining type safety and registry tracking.
|
|
6
|
+
*/ "use strict";
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
Object.defineProperty(exports, "mergeEnums", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function() {
|
|
13
|
+
return mergeEnums;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
const _types = require("./types.js");
|
|
17
|
+
const _factory = require("./factory.js");
|
|
18
|
+
/**
|
|
19
|
+
* Checks if an object is a branded enum.
|
|
20
|
+
*/ function isBrandedEnum(obj) {
|
|
21
|
+
return typeof obj === 'object' && obj !== null && _types.ENUM_ID in obj && _types.ENUM_VALUES in obj;
|
|
22
|
+
}
|
|
23
|
+
function mergeEnums(newId, ...enums) {
|
|
24
|
+
// Collect all key-value pairs, checking for duplicate keys
|
|
25
|
+
const mergedValues = {};
|
|
26
|
+
const seenKeys = new Map(); // key -> source enumId
|
|
27
|
+
for (const enumObj of enums){
|
|
28
|
+
if (!isBrandedEnum(enumObj)) {
|
|
29
|
+
throw new Error('All arguments must be branded enums');
|
|
30
|
+
}
|
|
31
|
+
const sourceEnumId = enumObj[_types.ENUM_ID];
|
|
32
|
+
// Iterate over enumerable properties (user-defined keys only)
|
|
33
|
+
for (const [key, value] of Object.entries(enumObj)){
|
|
34
|
+
// Check for duplicate keys
|
|
35
|
+
if (seenKeys.has(key)) {
|
|
36
|
+
const originalEnumId = seenKeys.get(key);
|
|
37
|
+
throw new Error(`Cannot merge enums: duplicate key "${key}" found in enums "${originalEnumId}" and "${sourceEnumId}"`);
|
|
38
|
+
}
|
|
39
|
+
seenKeys.set(key, sourceEnumId);
|
|
40
|
+
mergedValues[key] = value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Create and return the new branded enum (this handles registration)
|
|
44
|
+
return (0, _factory.createBrandedEnum)(newId, mergedValues);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=merge.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/merge.ts"],"sourcesContent":["/**\n * Enum composition functions for branded enums.\n *\n * Enables merging multiple branded enums into a new combined enum\n * while maintaining type safety and registry tracking.\n */\n\nimport { AnyBrandedEnum, BrandedEnum, ENUM_ID, ENUM_VALUES } from './types.js';\nimport { createBrandedEnum } from './factory.js';\n\n/**\n * Type helper to extract the values type from a branded enum.\n */\ntype ExtractValues<E> = E extends BrandedEnum<infer T> ? T : never;\n\n/**\n * Type helper to merge multiple branded enum value types into one.\n */\ntype MergedValues<T extends AnyBrandedEnum[]> = {\n [K in keyof T]: ExtractValues<T[K]>;\n}[number];\n\n/**\n * Checks if an object is a branded enum.\n */\nfunction isBrandedEnum(obj: unknown): obj is AnyBrandedEnum {\n return (\n typeof obj === 'object' &&\n obj !== null &&\n ENUM_ID in obj &&\n ENUM_VALUES in obj\n );\n}\n\n/**\n * Merges multiple branded enums into a new branded enum.\n *\n * Creates a new branded enum that contains all key-value pairs from all\n * source enums. The merged enum is registered in the global registry\n * as a new independent enum.\n *\n * Key collision handling:\n * - Duplicate keys (same key in multiple enums) throw an error\n * - Duplicate values (same value in multiple enums) are allowed\n *\n * @template T - Tuple of branded enum types being merged\n * @param newId - Unique identifier for the merged enum. Must not already\n * be registered.\n * @param enums - One or more branded enums to merge\n * @returns A new branded enum containing all values from source enums\n * @throws {Error} Throws `Error` with message\n * `Cannot merge enums: duplicate key \"${key}\" found in enums \"${enumId1}\" and \"${enumId2}\"`\n * if the same key exists in multiple source enums.\n * @throws {Error} Throws `Error` with message\n * `Branded enum with ID \"${newId}\" already exists` if newId is already registered.\n * @throws {Error} Throws `Error` with message `All arguments must be branded enums`\n * if any argument is not a valid branded enum.\n *\n * @example\n * // Basic merge\n * const Colors = createBrandedEnum('colors', { Red: 'red', Blue: 'blue' } as const);\n * const Sizes = createBrandedEnum('sizes', { Small: 'small', Large: 'large' } as const);\n *\n * const Combined = mergeEnums('combined', Colors, Sizes);\n * // Combined has: Red, Blue, Small, Large\n *\n * Combined.Red; // 'red'\n * Combined.Small; // 'small'\n *\n * @example\n * // Duplicate values are allowed\n * const Status1 = createBrandedEnum('status1', { Active: 'active' } as const);\n * const Status2 = createBrandedEnum('status2', { Enabled: 'active' } as const);\n *\n * const Merged = mergeEnums('merged', Status1, Status2);\n * // Both Active and Enabled have value 'active' - this is allowed\n *\n * @example\n * // Duplicate keys throw an error\n * const Enum1 = createBrandedEnum('enum1', { Key: 'value1' } as const);\n * const Enum2 = createBrandedEnum('enum2', { Key: 'value2' } as const);\n *\n * try {\n * mergeEnums('merged', Enum1, Enum2);\n * } catch (e) {\n * console.log(e.message);\n * // 'Cannot merge enums: duplicate key \"Key\" found in enums \"enum1\" and \"enum2\"'\n * }\n */\nexport function mergeEnums<T extends readonly AnyBrandedEnum[]>(\n newId: string,\n ...enums: T\n): BrandedEnum<Record<string, string>> {\n // Collect all key-value pairs, checking for duplicate keys\n const mergedValues: Record<string, string> = {};\n const seenKeys = new Map<string, string>(); // key -> source enumId\n\n for (const enumObj of enums) {\n if (!isBrandedEnum(enumObj)) {\n throw new Error('All arguments must be branded enums');\n }\n\n const sourceEnumId = enumObj[ENUM_ID];\n\n // Iterate over enumerable properties (user-defined keys only)\n for (const [key, value] of Object.entries(enumObj)) {\n // Check for duplicate keys\n if (seenKeys.has(key)) {\n const originalEnumId = seenKeys.get(key);\n throw new Error(\n `Cannot merge enums: duplicate key \"${key}\" found in enums \"${originalEnumId}\" and \"${sourceEnumId}\"`\n );\n }\n\n seenKeys.set(key, sourceEnumId);\n mergedValues[key] = value as string;\n }\n }\n\n // Create and return the new branded enum (this handles registration)\n return createBrandedEnum(newId, mergedValues) as BrandedEnum<MergedValues<[...T]>>;\n}\n"],"names":["mergeEnums","isBrandedEnum","obj","ENUM_ID","ENUM_VALUES","newId","enums","mergedValues","seenKeys","Map","enumObj","Error","sourceEnumId","key","value","Object","entries","has","originalEnumId","get","set","createBrandedEnum"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC;;;;+BAoFeA;;;eAAAA;;;uBAlFkD;yBAChC;AAclC;;CAEC,GACD,SAASC,cAAcC,GAAY;IACjC,OACE,OAAOA,QAAQ,YACfA,QAAQ,QACRC,cAAO,IAAID,OACXE,kBAAW,IAAIF;AAEnB;AAyDO,SAASF,WACdK,KAAa,EACb,GAAGC,KAAQ;IAEX,2DAA2D;IAC3D,MAAMC,eAAuC,CAAC;IAC9C,MAAMC,WAAW,IAAIC,OAAuB,uBAAuB;IAEnE,KAAK,MAAMC,WAAWJ,MAAO;QAC3B,IAAI,CAACL,cAAcS,UAAU;YAC3B,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAMC,eAAeF,OAAO,CAACP,cAAO,CAAC;QAErC,8DAA8D;QAC9D,KAAK,MAAM,CAACU,KAAKC,MAAM,IAAIC,OAAOC,OAAO,CAACN,SAAU;YAClD,2BAA2B;YAC3B,IAAIF,SAASS,GAAG,CAACJ,MAAM;gBACrB,MAAMK,iBAAiBV,SAASW,GAAG,CAACN;gBACpC,MAAM,IAAIF,MACR,CAAC,mCAAmC,EAAEE,IAAI,kBAAkB,EAAEK,eAAe,OAAO,EAAEN,aAAa,CAAC,CAAC;YAEzG;YAEAJ,SAASY,GAAG,CAACP,KAAKD;YAClBL,YAAY,CAACM,IAAI,GAAGC;QACtB;IACF;IAEA,qEAAqE;IACrE,OAAOO,IAAAA,0BAAiB,EAAChB,OAAOE;AAClC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
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
|
+
*/ "use strict";
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
function _export(target, all) {
|
|
11
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: all[name]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
_export(exports, {
|
|
17
|
+
findEnumSources: function() {
|
|
18
|
+
return findEnumSources;
|
|
19
|
+
},
|
|
20
|
+
getAllEnumIds: function() {
|
|
21
|
+
return getAllEnumIds;
|
|
22
|
+
},
|
|
23
|
+
getEnumById: function() {
|
|
24
|
+
return getEnumById;
|
|
25
|
+
},
|
|
26
|
+
getRegistry: function() {
|
|
27
|
+
return getRegistry;
|
|
28
|
+
},
|
|
29
|
+
registerEnum: function() {
|
|
30
|
+
return registerEnum;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const _types = require("./types.js");
|
|
34
|
+
function getRegistry() {
|
|
35
|
+
const global = globalThis;
|
|
36
|
+
if (!(_types.REGISTRY_KEY in global) || !global[_types.REGISTRY_KEY]) {
|
|
37
|
+
global[_types.REGISTRY_KEY] = {
|
|
38
|
+
enums: new Map(),
|
|
39
|
+
valueIndex: new Map()
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return global[_types.REGISTRY_KEY];
|
|
43
|
+
}
|
|
44
|
+
function registerEnum(enumObj) {
|
|
45
|
+
const registry = getRegistry();
|
|
46
|
+
const enumId = enumObj[_types.ENUM_ID];
|
|
47
|
+
const values = enumObj[_types.ENUM_VALUES];
|
|
48
|
+
// Check for duplicate ID
|
|
49
|
+
if (registry.enums.has(enumId)) {
|
|
50
|
+
throw new Error(`Branded enum with ID "${enumId}" already exists`);
|
|
51
|
+
}
|
|
52
|
+
// Create registry entry
|
|
53
|
+
const entry = {
|
|
54
|
+
enumId,
|
|
55
|
+
enumObj: enumObj,
|
|
56
|
+
values
|
|
57
|
+
};
|
|
58
|
+
// Add to enums map
|
|
59
|
+
registry.enums.set(enumId, entry);
|
|
60
|
+
// Update value index for reverse lookups
|
|
61
|
+
for (const value of values){
|
|
62
|
+
let enumIds = registry.valueIndex.get(value);
|
|
63
|
+
if (!enumIds) {
|
|
64
|
+
enumIds = new Set();
|
|
65
|
+
registry.valueIndex.set(value, enumIds);
|
|
66
|
+
}
|
|
67
|
+
enumIds.add(enumId);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function getAllEnumIds() {
|
|
71
|
+
const registry = getRegistry();
|
|
72
|
+
return Array.from(registry.enums.keys());
|
|
73
|
+
}
|
|
74
|
+
function getEnumById(enumId) {
|
|
75
|
+
const registry = getRegistry();
|
|
76
|
+
const entry = registry.enums.get(enumId);
|
|
77
|
+
return entry?.enumObj;
|
|
78
|
+
}
|
|
79
|
+
function findEnumSources(value) {
|
|
80
|
+
const registry = getRegistry();
|
|
81
|
+
const enumIds = registry.valueIndex.get(value);
|
|
82
|
+
return enumIds ? Array.from(enumIds) : [];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//# sourceMappingURL=registry.cjs.map
|
|
@@ -0,0 +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 * @throws Error if an enum with the same ID is already registered\n */\nexport function registerEnum<T extends Record<string, string>>(\n enumObj: BrandedEnum<T>\n): void {\n const registry = getRegistry();\n const enumId = enumObj[ENUM_ID];\n const values = enumObj[ENUM_VALUES];\n\n // Check for duplicate ID\n if (registry.enums.has(enumId)) {\n throw new Error(`Branded enum with ID \"${enumId}\" already exists`);\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\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"],"names":["findEnumSources","getAllEnumIds","getEnumById","getRegistry","registerEnum","global","globalThis","REGISTRY_KEY","enums","Map","valueIndex","enumObj","registry","enumId","ENUM_ID","values","ENUM_VALUES","has","Error","entry","set","value","enumIds","get","Set","add","Array","from","keys"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC;;;;;;;;;;;IAwJeA,eAAe;eAAfA;;IAzDAC,aAAa;eAAbA;;IAwBAC,WAAW;eAAXA;;IA9FAC,WAAW;eAAXA;;IAsBAC,YAAY;eAAZA;;;uBAtCT;AAgBA,SAASD;IACd,MAAME,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;AASO,SAASH,aACdO,OAAuB;IAEvB,MAAMC,WAAWT;IACjB,MAAMU,SAASF,OAAO,CAACG,cAAO,CAAC;IAC/B,MAAMC,SAASJ,OAAO,CAACK,kBAAW,CAAC;IAEnC,yBAAyB;IACzB,IAAIJ,SAASJ,KAAK,CAACS,GAAG,CAACJ,SAAS;QAC9B,MAAM,IAAIK,MAAM,CAAC,sBAAsB,EAAEL,OAAO,gBAAgB,CAAC;IACnE;IAEA,wBAAwB;IACxB,MAAMM,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,CAACa,GAAG,CAACF;QACtC,IAAI,CAACC,SAAS;YACZA,UAAU,IAAIE;YACdZ,SAASF,UAAU,CAACU,GAAG,CAACC,OAAOC;QACjC;QACAA,QAAQG,GAAG,CAACZ;IACd;AACF;AAiBO,SAASZ;IACd,MAAMW,WAAWT;IACjB,OAAOuB,MAAMC,IAAI,CAACf,SAASJ,KAAK,CAACoB,IAAI;AACvC;AAqBO,SAAS1B,YACdW,MAAc;IAEd,MAAMD,WAAWT;IACjB,MAAMgB,QAAQP,SAASJ,KAAK,CAACe,GAAG,CAACV;IACjC,OAAOM,OAAOR;AAChB;AA2BO,SAASX,gBAAgBqB,KAAa;IAC3C,MAAMT,WAAWT;IACjB,MAAMmB,UAAUV,SAASF,UAAU,CAACa,GAAG,CAACF;IACxC,OAAOC,UAAUI,MAAMC,IAAI,CAACL,WAAW,EAAE;AAC3C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
* Symbol key for storing the enum ID metadata.
|
|
8
|
+
* Using a Symbol prevents collision with user-defined keys.
|
|
9
|
+
*/ "use strict";
|
|
10
|
+
Object.defineProperty(exports, "__esModule", {
|
|
11
|
+
value: true
|
|
12
|
+
});
|
|
13
|
+
function _export(target, all) {
|
|
14
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: all[name]
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
_export(exports, {
|
|
20
|
+
CONSUMER_REGISTRY_KEY: function() {
|
|
21
|
+
return CONSUMER_REGISTRY_KEY;
|
|
22
|
+
},
|
|
23
|
+
ENUM_ID: function() {
|
|
24
|
+
return ENUM_ID;
|
|
25
|
+
},
|
|
26
|
+
ENUM_VALUES: function() {
|
|
27
|
+
return ENUM_VALUES;
|
|
28
|
+
},
|
|
29
|
+
REGISTRY_KEY: function() {
|
|
30
|
+
return REGISTRY_KEY;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
const ENUM_ID = Symbol('ENUM_ID');
|
|
34
|
+
const ENUM_VALUES = Symbol('ENUM_VALUES');
|
|
35
|
+
const REGISTRY_KEY = '__brandedEnumRegistry__';
|
|
36
|
+
const CONSUMER_REGISTRY_KEY = '__brandedEnumConsumerRegistry__';
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=types.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/types.ts"],"sourcesContent":["/**\n * Core type definitions for branded-enum library\n *\n * These types enable runtime-identifiable enum-like objects in TypeScript\n * with zero runtime overhead for value access.\n */\n\n/**\n * Symbol key for storing the enum ID metadata.\n * Using a Symbol prevents collision with user-defined keys.\n */\nexport const ENUM_ID: unique symbol = Symbol('ENUM_ID');\n\n/**\n * Symbol key for storing the enum values Set.\n * Using a Symbol prevents collision with user-defined keys.\n */\nexport const ENUM_VALUES: unique symbol = Symbol('ENUM_VALUES');\n\n/**\n * Metadata attached to branded enums via Symbol properties.\n * These properties are non-enumerable and won't appear in\n * Object.keys(), Object.values(), or JSON serialization.\n */\nexport interface BrandedEnumMetadata {\n readonly [ENUM_ID]: string;\n readonly [ENUM_VALUES]: Set<string>;\n}\n\n/**\n * A branded enum object - combines the user's values object with metadata.\n * The object is frozen (Readonly) to prevent modification after creation.\n *\n * @template T - The shape of the enum values object (Record<string, string>)\n */\nexport type BrandedEnum<T extends Record<string, string>> = Readonly<T> &\n BrandedEnumMetadata;\n\n/**\n * Base constraint type for branded enums that works with both\n * `as const` objects and regular Record<string, string> objects.\n *\n * This type is more permissive than `BrandedEnum<Record<string, string>>`\n * and allows literal types from `as const` assertions.\n */\nexport type AnyBrandedEnum = {\n readonly [ENUM_ID]: string;\n readonly [ENUM_VALUES]: Set<string>;\n};\n\n/**\n * Utility type to extract the union of all value types from a branded enum.\n * Useful for typing variables that can hold any value from the enum.\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * type StatusValue = BrandedEnumValue<typeof Status>; // 'active' | 'inactive'\n */\nexport type BrandedEnumValue<E extends AnyBrandedEnum> =\n E extends BrandedEnum<infer T> ? T[keyof T] : never;\n\n/**\n * Registry entry for tracking a single branded enum in the global registry.\n */\nexport interface RegistryEntry {\n /** The unique identifier for this enum */\n readonly enumId: string;\n /** The branded enum object itself */\n readonly enumObj: BrandedEnum<Record<string, string>>;\n /** Set of all values in this enum for O(1) lookup */\n readonly values: Set<string>;\n}\n\n/**\n * Global registry structure stored on globalThis.\n * Enables cross-bundle tracking of all branded enums.\n */\nexport interface BrandedEnumRegistry {\n /** Map from enumId to registry entry */\n readonly enums: Map<string, RegistryEntry>;\n /** Reverse index: value -> Set of enumIds containing that value */\n readonly valueIndex: Map<string, Set<string>>;\n}\n\n/**\n * The key used to store the registry on globalThis.\n * Namespaced to avoid collisions with other libraries.\n */\nexport const REGISTRY_KEY = '__brandedEnumRegistry__' as const;\n\n/**\n * The key used to store the enum consumer registry on globalThis.\n * Tracks which classes consume which branded enums.\n */\nexport const CONSUMER_REGISTRY_KEY = '__brandedEnumConsumerRegistry__' as const;\n\n/**\n * Entry tracking a class that consumes branded enums.\n */\nexport interface EnumConsumerEntry {\n /** The class constructor function */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n readonly classRef: new (...args: any[]) => any;\n /** The class name */\n readonly className: string;\n /** Set of enum IDs that this class consumes */\n readonly enumIds: Set<string>;\n}\n\n/**\n * Global registry for tracking enum consumers (classes decorated with @EnumClass).\n * Enables debugging and introspection of enum usage across the codebase.\n */\nexport interface EnumConsumerRegistry {\n /** Map from class name to consumer entry */\n readonly consumers: Map<string, EnumConsumerEntry>;\n /** Reverse index: enumId -> Set of class names consuming that enum */\n readonly enumToConsumers: Map<string, Set<string>>;\n}\n\n// =============================================================================\n// Compile-Time Validation Types\n// =============================================================================\n\n/**\n * Extracts the union of all keys from a branded enum.\n *\n * This utility type provides compile-time access to all key names of a branded enum,\n * excluding the Symbol metadata keys (ENUM_ID and ENUM_VALUES).\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * type StatusKeys = EnumKeys<typeof Status>;\n * // StatusKeys = 'Active' | 'Inactive' | 'Pending'\n *\n * @example\n * // Use in function parameters\n * function getStatusLabel<E extends AnyBrandedEnum>(\n * enumObj: E,\n * key: EnumKeys<E>\n * ): string {\n * return enumObj[key] as string;\n * }\n */\nexport type EnumKeys<E> = E extends BrandedEnum<infer T>\n ? keyof T & string\n : E extends AnyBrandedEnum\n ? Exclude<keyof E, typeof ENUM_ID | typeof ENUM_VALUES> & string\n : never;\n\n/**\n * Extracts the union of all values from a branded enum.\n *\n * This is an alias for BrandedEnumValue that provides a more intuitive name\n * when working with compile-time type utilities.\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * type StatusValues = EnumValues<typeof Status>;\n * // StatusValues = 'active' | 'inactive' | 'pending'\n *\n * @example\n * // Use for type-safe value handling\n * function processStatus(value: EnumValues<typeof Status>) {\n * // value is 'active' | 'inactive' | 'pending'\n * }\n */\nexport type EnumValues<E> = E extends BrandedEnum<infer T>\n ? T[keyof T]\n : E extends AnyBrandedEnum\n ? Exclude<E[Exclude<keyof E, typeof ENUM_ID | typeof ENUM_VALUES>], Set<string>> & string\n : never;\n\n/**\n * Validates that a value type V is a valid value of branded enum E at compile time.\n *\n * If V is a valid value of E, this type resolves to V.\n * If V is NOT a valid value of E, this type resolves to `never`, causing a compile error\n * when used in contexts that expect a non-never type.\n *\n * This enables compile-time validation of enum values without runtime overhead.\n *\n * @template E - A BrandedEnum type\n * @template V - The value type to validate\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * } as const);\n *\n * // Valid - 'active' is in Status\n * type Valid = ValidEnumValue<typeof Status, 'active'>; // 'active'\n *\n * // Invalid - 'unknown' is not in Status\n * type Invalid = ValidEnumValue<typeof Status, 'unknown'>; // never\n *\n * @example\n * // Use in function to enforce valid values at compile time\n * function setStatus<V extends string>(\n * value: ValidEnumValue<typeof Status, V>\n * ): void {\n * // Only compiles if value is 'active' | 'inactive'\n * }\n *\n * setStatus('active'); // OK\n * setStatus('inactive'); // OK\n * // setStatus('unknown'); // Compile error: Argument of type 'never' is not assignable\n *\n * @example\n * // Type-level assertion\n * type AssertActive = ValidEnumValue<typeof Status, 'active'>; // 'active' - OK\n * type AssertBad = ValidEnumValue<typeof Status, 'bad'>; // never - indicates invalid\n */\nexport type ValidEnumValue<E, V extends string> = V extends EnumValues<E>\n ? V\n : never;\n\n/**\n * Creates a strict parameter type that only accepts valid values from a branded enum.\n *\n * This utility type is designed for function parameters where you want to enforce\n * that only values from a specific branded enum are accepted at compile time.\n *\n * Unlike using `BrandedEnumValue<E>` directly, `StrictEnumParam` provides better\n * error messages and works well with generic functions.\n *\n * @template E - A BrandedEnum type\n *\n * @example\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive',\n * Pending: 'pending',\n * } as const);\n *\n * // Function that only accepts Status values\n * function updateStatus(newStatus: StrictEnumParam<typeof Status>): void {\n * console.log(`Status updated to: ${newStatus}`);\n * }\n *\n * updateStatus(Status.Active); // OK\n * updateStatus('active'); // OK (literal type matches)\n * // updateStatus('unknown'); // Compile error\n *\n * @example\n * // Use with multiple enum parameters\n * const Priority = createBrandedEnum('priority', {\n * High: 'high',\n * Medium: 'medium',\n * Low: 'low',\n * } as const);\n *\n * function createTask(\n * status: StrictEnumParam<typeof Status>,\n * priority: StrictEnumParam<typeof Priority>\n * ): void {\n * // Both parameters are type-safe\n * }\n *\n * createTask(Status.Active, Priority.High); // OK\n * createTask('active', 'high'); // OK\n * // createTask('active', 'invalid'); // Compile error on second param\n *\n * @example\n * // Generic function with strict enum constraint\n * function processValue<E extends AnyBrandedEnum>(\n * enumObj: E,\n * value: StrictEnumParam<E>\n * ): void {\n * // value is guaranteed to be a valid value of enumObj\n * }\n */\nexport type StrictEnumParam<E> = EnumValues<E>;\n"],"names":["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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
*/ "use strict";
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
function _export(target, all) {
|
|
11
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: all[name]
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
_export(exports, {
|
|
17
|
+
enumEntries: function() {
|
|
18
|
+
return enumEntries;
|
|
19
|
+
},
|
|
20
|
+
getKeyForValue: function() {
|
|
21
|
+
return getKeyForValue;
|
|
22
|
+
},
|
|
23
|
+
hasValue: function() {
|
|
24
|
+
return hasValue;
|
|
25
|
+
},
|
|
26
|
+
isValidKey: function() {
|
|
27
|
+
return isValidKey;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const _types = require("./types.js");
|
|
31
|
+
/**
|
|
32
|
+
* Checks if an object is a branded enum (has Symbol metadata).
|
|
33
|
+
*
|
|
34
|
+
* @param obj - The object to check
|
|
35
|
+
* @returns true if obj is a branded enum
|
|
36
|
+
*/ function isBrandedEnum(obj) {
|
|
37
|
+
return obj !== null && typeof obj === 'object' && _types.ENUM_ID in obj && _types.ENUM_VALUES in obj && typeof obj[_types.ENUM_ID] === 'string' && obj[_types.ENUM_VALUES] instanceof Set;
|
|
38
|
+
}
|
|
39
|
+
function hasValue(enumObj, value) {
|
|
40
|
+
if (!isBrandedEnum(enumObj)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value !== 'string') {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return enumObj[_types.ENUM_VALUES].has(value);
|
|
47
|
+
}
|
|
48
|
+
function getKeyForValue(enumObj, value) {
|
|
49
|
+
if (!isBrandedEnum(enumObj)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
for (const key of Object.keys(enumObj)){
|
|
53
|
+
if (enumObj[key] === value) {
|
|
54
|
+
return key;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
function isValidKey(enumObj, key) {
|
|
60
|
+
if (!isBrandedEnum(enumObj)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (typeof key !== 'string') {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
return Object.prototype.hasOwnProperty.call(enumObj, key);
|
|
67
|
+
}
|
|
68
|
+
function* enumEntries(enumObj) {
|
|
69
|
+
if (!isBrandedEnum(enumObj)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
for (const [key, value] of Object.entries(enumObj)){
|
|
73
|
+
yield [
|
|
74
|
+
key,
|
|
75
|
+
value
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/utils.ts"],"sourcesContent":["/**\n * Utility functions for branded enums.\n *\n * Provides additional functionality beyond standard enum operations,\n * including reverse lookup, key validation, and iteration.\n */\n\nimport {\n AnyBrandedEnum,\n BrandedEnum,\n BrandedEnumValue,\n ENUM_ID,\n ENUM_VALUES,\n EnumKeys,\n EnumValues,\n} from './types.js';\n\n/**\n * Checks if an object is a branded enum (has Symbol metadata).\n *\n * @param obj - The object to check\n * @returns true if obj is a branded enum\n */\nfunction isBrandedEnum(obj: unknown): obj is AnyBrandedEnum {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n ENUM_ID in obj &&\n ENUM_VALUES in obj &&\n typeof (obj as AnyBrandedEnum)[ENUM_ID] === 'string' &&\n (obj as AnyBrandedEnum)[ENUM_VALUES] instanceof Set\n );\n}\n\n/**\n * Checks if a value exists in a branded enum (reverse lookup).\n *\n * Similar to `isFromEnum`, but with arguments in a different order that\n * may be more natural for some use cases. Also provides type narrowing.\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to search in\n * @param value - The value to check. Can be any type; non-strings return false.\n * @returns `true` if the value exists in the enum (with type narrowing),\n * `false` otherwise. Returns `false` for non-string values or if\n * enumObj is not a branded enum.\n *\n * @example\n * // Check if value exists\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * hasValue(Status, 'active'); // true\n * hasValue(Status, 'unknown'); // false\n *\n * @example\n * // Returns false for non-string values\n * hasValue(Status, 123); // false\n * hasValue(Status, null); // false\n */\nexport function hasValue<E extends AnyBrandedEnum>(\n enumObj: E,\n value: unknown\n): value is EnumValues<E> {\n if (!isBrandedEnum(enumObj)) {\n return false;\n }\n if (typeof value !== 'string') {\n return false;\n }\n return enumObj[ENUM_VALUES].has(value);\n}\n\n/**\n * Gets the key name for a value in a branded enum.\n *\n * Performs a reverse lookup to find which key maps to a given value.\n * If multiple keys have the same value, returns the first one found\n * (order is not guaranteed).\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to search in\n * @param value - The string value to look up\n * @returns The key name that maps to the value, or `undefined` if the\n * value is not found or enumObj is not a branded enum.\n *\n * @example\n * // Find key for value\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * getKeyForValue(Status, 'active'); // 'Active'\n * getKeyForValue(Status, 'inactive'); // 'Inactive'\n *\n * @example\n * // Returns undefined for unknown values\n * getKeyForValue(Status, 'unknown'); // undefined\n *\n * @example\n * // Roundtrip: value -> key -> value\n * const key = getKeyForValue(Status, 'active'); // 'Active'\n * Status[key]; // 'active'\n */\nexport function getKeyForValue<E extends AnyBrandedEnum>(\n enumObj: E,\n value: string\n): EnumKeys<E> | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n for (const key of Object.keys(enumObj)) {\n if ((enumObj as Record<string, unknown>)[key] === value) {\n return key as EnumKeys<E>;\n }\n }\n return undefined;\n}\n\n/**\n * Checks if a key exists in a branded enum.\n *\n * Validates whether a given key is a valid member of the enum.\n * Returns false for Symbol keys (metadata) and non-string keys.\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to check\n * @param key - The key to validate. Can be any type; non-strings return false.\n * @returns `true` if the key exists in the enum (with type narrowing),\n * `false` otherwise. Returns `false` for metadata Symbol keys or if\n * enumObj is not a branded enum.\n *\n * @example\n * // Check if key exists\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n * isValidKey(Status, 'Active'); // true\n * isValidKey(Status, 'Inactive'); // true\n * isValidKey(Status, 'Unknown'); // false\n *\n * @example\n * // Returns false for non-string keys\n * isValidKey(Status, 123); // false\n * isValidKey(Status, Symbol('test')); // false\n */\nexport function isValidKey<E extends AnyBrandedEnum>(\n enumObj: E,\n key: unknown\n): key is EnumKeys<E> {\n if (!isBrandedEnum(enumObj)) {\n return false;\n }\n if (typeof key !== 'string') {\n return false;\n }\n return Object.prototype.hasOwnProperty.call(enumObj, key);\n}\n\n/**\n * Returns an iterator of [key, value] pairs for a branded enum.\n *\n * Provides a way to iterate over all key-value pairs in the enum using\n * a for...of loop. Only yields user-defined entries, not metadata.\n * Equivalent to `Object.entries(enumObj)` but with proper typing.\n *\n * @template E - The branded enum type\n * @param enumObj - The branded enum to iterate over\n * @returns An iterator yielding [key, value] tuples. Returns an empty\n * iterator if enumObj is not a branded enum.\n *\n * @example\n * // Iterate over entries\n * const Status = createBrandedEnum('status', { Active: 'active', Inactive: 'inactive' } as const);\n *\n * for (const [key, value] of enumEntries(Status)) {\n * console.log(`${key}: ${value}`);\n * }\n * // Output:\n * // Active: active\n * // Inactive: inactive\n *\n * @example\n * // Convert to array\n * const entries = [...enumEntries(Status)];\n * // [['Active', 'active'], ['Inactive', 'inactive']]\n *\n * @example\n * // Use with Array.from\n * const entriesArray = Array.from(enumEntries(Status));\n */\nexport function* enumEntries<E extends AnyBrandedEnum>(\n enumObj: E\n): IterableIterator<[EnumKeys<E>, EnumValues<E>]> {\n if (!isBrandedEnum(enumObj)) {\n return;\n }\n for (const [key, value] of Object.entries(enumObj)) {\n yield [key as EnumKeys<E>, value as EnumValues<E>];\n }\n}\n"],"names":["enumEntries","getKeyForValue","hasValue","isValidKey","isBrandedEnum","obj","ENUM_ID","ENUM_VALUES","Set","enumObj","value","has","undefined","key","Object","keys","prototype","hasOwnProperty","call","entries"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC;;;;;;;;;;;IAmLgBA,WAAW;eAAXA;;IArFDC,cAAc;eAAdA;;IAzCAC,QAAQ;eAARA;;IAiFAC,UAAU;eAAVA;;;uBA5HT;AAEP;;;;;CAKC,GACD,SAASC,cAAcC,GAAY;IACjC,OACEA,QAAQ,QACR,OAAOA,QAAQ,YACfC,cAAO,IAAID,OACXE,kBAAW,IAAIF,OACf,OAAO,AAACA,GAAsB,CAACC,cAAO,CAAC,KAAK,YAC5C,AAACD,GAAsB,CAACE,kBAAW,CAAC,YAAYC;AAEpD;AA0BO,SAASN,SACdO,OAAU,EACVC,KAAc;IAEd,IAAI,CAACN,cAAcK,UAAU;QAC3B,OAAO;IACT;IACA,IAAI,OAAOC,UAAU,UAAU;QAC7B,OAAO;IACT;IACA,OAAOD,OAAO,CAACF,kBAAW,CAAC,CAACI,GAAG,CAACD;AAClC;AA8BO,SAAST,eACdQ,OAAU,EACVC,KAAa;IAEb,IAAI,CAACN,cAAcK,UAAU;QAC3B,OAAOG;IACT;IACA,KAAK,MAAMC,OAAOC,OAAOC,IAAI,CAACN,SAAU;QACtC,IAAI,AAACA,OAAmC,CAACI,IAAI,KAAKH,OAAO;YACvD,OAAOG;QACT;IACF;IACA,OAAOD;AACT;AA2BO,SAAST,WACdM,OAAU,EACVI,GAAY;IAEZ,IAAI,CAACT,cAAcK,UAAU;QAC3B,OAAO;IACT;IACA,IAAI,OAAOI,QAAQ,UAAU;QAC3B,OAAO;IACT;IACA,OAAOC,OAAOE,SAAS,CAACC,cAAc,CAACC,IAAI,CAACT,SAASI;AACvD;AAkCO,UAAUb,YACfS,OAAU;IAEV,IAAI,CAACL,cAAcK,UAAU;QAC3B;IACF;IACA,KAAK,MAAM,CAACI,KAAKH,MAAM,IAAII,OAAOK,OAAO,CAACV,SAAU;QAClD,MAAM;YAACI;YAAoBH;SAAuB;IACpD;AACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* branded-enum - Runtime-identifiable enum-like types for TypeScript
|
|
3
|
+
*
|
|
4
|
+
* This library provides enum-like objects with embedded metadata for runtime
|
|
5
|
+
* identification, enabling you to determine which enum a string value belongs to.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export type { BrandedEnumMetadata, BrandedEnum, BrandedEnumValue, RegistryEntry, BrandedEnumRegistry, EnumConsumerEntry, EnumConsumerRegistry, AnyBrandedEnum, EnumKeys, EnumValues, ValidEnumValue, StrictEnumParam, } from './lib/types.js';
|
|
10
|
+
export { createBrandedEnum } from './lib/factory.js';
|
|
11
|
+
export { getRegistry, getAllEnumIds, getEnumById, findEnumSources, } from './lib/registry.js';
|
|
12
|
+
export { isFromEnum, assertFromEnum, parseEnum, safeParseEnum } from './lib/guards.js';
|
|
13
|
+
export type { SafeParseSuccess, SafeParseFailure, SafeParseError, SafeParseErrorCode, SafeParseResult } from './lib/guards.js';
|
|
14
|
+
export { getEnumId, getEnumValues, enumSize } from './lib/accessors.js';
|
|
15
|
+
export { hasValue, getKeyForValue, isValidKey, enumEntries, } from './lib/utils.js';
|
|
16
|
+
export { mergeEnums } from './lib/merge.js';
|
|
17
|
+
export { enumSubset, enumExclude, enumMap, enumFromKeys, enumDiff, enumIntersect, enumToRecord, watchEnum, watchAllEnums, clearAllEnumWatchers, getEnumWatcherCount, getGlobalWatcherCount, exhaustive, exhaustiveGuard, toJsonSchema, toZodSchema, enumSerializer } from './lib/advanced.js';
|
|
18
|
+
export type { EnumDiffResult, EnumIntersectEntry, EnumAccessType, EnumAccessEvent, EnumWatchCallback, WatchEnumResult, ToJsonSchemaOptions, EnumJsonSchema, ToZodSchemaOptions, ZodEnumSchemaDefinition, EnumSerializerOptions, DeserializeSuccess, DeserializeFailure, DeserializeResult, EnumSerializer } from './lib/advanced.js';
|
|
19
|
+
export { EnumValue, EnumClass, getEnumConsumers, getConsumedEnums, getAllEnumConsumers, } from './lib/decorators.js';
|
|
20
|
+
export type { EnumValueOptions } from './lib/decorators.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,QAAQ,EACR,UAAU,EACV,cAAc,EACd,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAMrD,OAAO,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACvF,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAM/H,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAMxE,OAAO,EACL,QAAQ,EACR,cAAc,EACd,UAAU,EACV,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAM5C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC9R,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,cAAc,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMrU,OAAO,EACL,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/**\n * branded-enum - Runtime-identifiable enum-like types for TypeScript\n *\n * This library provides enum-like objects with embedded metadata for runtime\n * identification, enabling you to determine which enum a string value belongs to.\n *\n * @packageDocumentation\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type {\n BrandedEnumMetadata,\n BrandedEnum,\n BrandedEnumValue,\n RegistryEntry,\n BrandedEnumRegistry,\n EnumConsumerEntry,\n EnumConsumerRegistry,\n AnyBrandedEnum,\n EnumKeys,\n EnumValues,\n ValidEnumValue,\n StrictEnumParam,\n} from './lib/types.js';\n\n// =============================================================================\n// Factory\n// =============================================================================\n\nexport { createBrandedEnum } from './lib/factory.js';\n\n// =============================================================================\n// Registry\n// =============================================================================\n\nexport {\n getRegistry,\n getAllEnumIds,\n getEnumById,\n findEnumSources,\n} from './lib/registry.js';\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport { isFromEnum, assertFromEnum, parseEnum, safeParseEnum } from './lib/guards.js';\nexport type { SafeParseSuccess, SafeParseFailure, SafeParseError, SafeParseErrorCode, SafeParseResult } from './lib/guards.js';\n\n// =============================================================================\n// Metadata Accessors\n// =============================================================================\n\nexport { getEnumId, getEnumValues, enumSize } from './lib/accessors.js';\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\nexport {\n hasValue,\n getKeyForValue,\n isValidKey,\n enumEntries,\n} from './lib/utils.js';\n\n// =============================================================================\n// Composition\n// =============================================================================\n\nexport { mergeEnums } from './lib/merge.js';\n\n// =============================================================================\n// Advanced Operations\n// =============================================================================\n\nexport { enumSubset, enumExclude, enumMap, enumFromKeys, enumDiff, enumIntersect, enumToRecord, watchEnum, watchAllEnums, clearAllEnumWatchers, getEnumWatcherCount, getGlobalWatcherCount, exhaustive, exhaustiveGuard, toJsonSchema, toZodSchema, enumSerializer } from './lib/advanced.js';\nexport type { EnumDiffResult, EnumIntersectEntry, EnumAccessType, EnumAccessEvent, EnumWatchCallback, WatchEnumResult, ToJsonSchemaOptions, EnumJsonSchema, ToZodSchemaOptions, ZodEnumSchemaDefinition, EnumSerializerOptions, DeserializeSuccess, DeserializeFailure, DeserializeResult, EnumSerializer } from './lib/advanced.js';\n\n// =============================================================================\n// Decorators\n// =============================================================================\n\nexport {\n EnumValue,\n EnumClass,\n getEnumConsumers,\n getConsumedEnums,\n getAllEnumConsumers,\n} from './lib/decorators.js';\nexport type { EnumValueOptions } from './lib/decorators.js';\n"],"names":["createBrandedEnum","getRegistry","getAllEnumIds","getEnumById","findEnumSources","isFromEnum","assertFromEnum","parseEnum","safeParseEnum","getEnumId","getEnumValues","enumSize","hasValue","getKeyForValue","isValidKey","enumEntries","mergeEnums","enumSubset","enumExclude","enumMap","enumFromKeys","enumDiff","enumIntersect","enumToRecord","watchEnum","watchAllEnums","clearAllEnumWatchers","getEnumWatcherCount","getGlobalWatcherCount","exhaustive","exhaustiveGuard","toJsonSchema","toZodSchema","enumSerializer","EnumValue","EnumClass","getEnumConsumers","getConsumedEnums","getAllEnumConsumers"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;;;CAOC,GAED,gFAAgF;AAChF,QAAQ;AACR,gFAAgF;AAiBhF,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,SAASA,iBAAiB,QAAQ,mBAAmB;AAErD,gFAAgF;AAChF,WAAW;AACX,gFAAgF;AAEhF,SACEC,WAAW,EACXC,aAAa,EACbC,WAAW,EACXC,eAAe,QACV,oBAAoB;AAE3B,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF,SAASC,UAAU,EAAEC,cAAc,EAAEC,SAAS,EAAEC,aAAa,QAAQ,kBAAkB;AAGvF,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF,SAASC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAQ,qBAAqB;AAExE,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF,SACEC,QAAQ,EACRC,cAAc,EACdC,UAAU,EACVC,WAAW,QACN,iBAAiB;AAExB,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF,SAASC,UAAU,QAAQ,iBAAiB;AAE5C,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF,SAASC,UAAU,EAAEC,WAAW,EAAEC,OAAO,EAAEC,YAAY,EAAEC,QAAQ,EAAEC,aAAa,EAAEC,YAAY,EAAEC,SAAS,EAAEC,aAAa,EAAEC,oBAAoB,EAAEC,mBAAmB,EAAEC,qBAAqB,EAAEC,UAAU,EAAEC,eAAe,EAAEC,YAAY,EAAEC,WAAW,EAAEC,cAAc,QAAQ,oBAAoB;AAG9R,gFAAgF;AAChF,aAAa;AACb,gFAAgF;AAEhF,SACEC,SAAS,EACTC,SAAS,EACTC,gBAAgB,EAChBC,gBAAgB,EAChBC,mBAAmB,QACd,sBAAsB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata accessors for branded enums.
|
|
3
|
+
*
|
|
4
|
+
* Provides functions to retrieve metadata from branded enum objects,
|
|
5
|
+
* including enum ID, values array, and size.
|
|
6
|
+
*/
|
|
7
|
+
import { AnyBrandedEnum, EnumValues } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Gets the enum ID from a branded enum.
|
|
10
|
+
*
|
|
11
|
+
* Retrieves the unique identifier that was assigned when the enum was created.
|
|
12
|
+
* Returns undefined for objects that are not branded enums.
|
|
13
|
+
*
|
|
14
|
+
* @param enumObj - The object to get the enum ID from. Can be any type.
|
|
15
|
+
* @returns The enum ID string if enumObj is a branded enum, `undefined` otherwise.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Get ID from branded enum
|
|
19
|
+
* const Status = createBrandedEnum('status', { Active: 'active' } as const);
|
|
20
|
+
* getEnumId(Status); // 'status'
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Returns undefined for non-branded objects
|
|
24
|
+
* getEnumId({}); // undefined
|
|
25
|
+
* getEnumId({ Active: 'active' }); // undefined
|
|
26
|
+
* getEnumId(null); // undefined
|
|
27
|
+
*/
|
|
28
|
+
export declare function getEnumId(enumObj: unknown): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Gets all values from a branded enum as an array.
|
|
31
|
+
*
|
|
32
|
+
* Returns an array containing all the string values in the enum.
|
|
33
|
+
* The order of values is not guaranteed.
|
|
34
|
+
*
|
|
35
|
+
* @template E - The branded enum type
|
|
36
|
+
* @param enumObj - The object to get values from. Can be any type.
|
|
37
|
+
* @returns Array of all enum values if enumObj is a branded enum,
|
|
38
|
+
* `undefined` otherwise.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // Get values from branded enum
|
|
42
|
+
* const Status = createBrandedEnum('status', {
|
|
43
|
+
* Active: 'active',
|
|
44
|
+
* Inactive: 'inactive'
|
|
45
|
+
* } as const);
|
|
46
|
+
* getEnumValues(Status); // ['active', 'inactive']
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* // Returns undefined for non-branded objects
|
|
50
|
+
* getEnumValues({}); // undefined
|
|
51
|
+
* getEnumValues({ Active: 'active' }); // undefined
|
|
52
|
+
*/
|
|
53
|
+
export declare function getEnumValues<E extends AnyBrandedEnum>(enumObj: E): EnumValues<E>[] | undefined;
|
|
54
|
+
export declare function getEnumValues(enumObj: unknown): string[] | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Gets the number of values in a branded enum.
|
|
57
|
+
*
|
|
58
|
+
* Returns the count of unique values in the enum. This is equivalent to
|
|
59
|
+
* the number of key-value pairs defined when the enum was created.
|
|
60
|
+
*
|
|
61
|
+
* @param enumObj - The object to get the size of. Can be any type.
|
|
62
|
+
* @returns The number of values in the enum if enumObj is a branded enum,
|
|
63
|
+
* `undefined` otherwise.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* // Get size of branded enum
|
|
67
|
+
* const Status = createBrandedEnum('status', {
|
|
68
|
+
* Active: 'active',
|
|
69
|
+
* Inactive: 'inactive'
|
|
70
|
+
* } as const);
|
|
71
|
+
* enumSize(Status); // 2
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // Returns undefined for non-branded objects
|
|
75
|
+
* enumSize({}); // undefined
|
|
76
|
+
* enumSize({ Active: 'active' }); // undefined
|
|
77
|
+
*/
|
|
78
|
+
export declare function enumSize(enumObj: unknown): number | undefined;
|
|
79
|
+
//# sourceMappingURL=accessors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accessors.d.ts","sourceRoot":"","sources":["../../../src/lib/accessors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,cAAc,EAKd,UAAU,EACX,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK9D;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,cAAc,EACpD,OAAO,EAAE,CAAC,GACT,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;AAC/B,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;AAQtE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/lib/accessors.ts"],"sourcesContent":["/**\n * Metadata accessors for branded enums.\n *\n * Provides functions to retrieve metadata from branded enum objects,\n * including enum ID, values array, and size.\n */\n\nimport {\n AnyBrandedEnum,\n BrandedEnum,\n BrandedEnumValue,\n ENUM_ID,\n ENUM_VALUES,\n EnumValues,\n} from './types.js';\n\n/**\n * Checks if an object is a branded enum (has Symbol metadata).\n *\n * @param obj - The object to check\n * @returns true if obj is a branded enum\n */\nfunction isBrandedEnum(obj: unknown): obj is AnyBrandedEnum {\n return (\n obj !== null &&\n typeof obj === 'object' &&\n ENUM_ID in obj &&\n ENUM_VALUES in obj &&\n typeof (obj as AnyBrandedEnum)[ENUM_ID] === 'string' &&\n (obj as AnyBrandedEnum)[ENUM_VALUES] instanceof Set\n );\n}\n\n/**\n * Gets the enum ID from a branded enum.\n *\n * Retrieves the unique identifier that was assigned when the enum was created.\n * Returns undefined for objects that are not branded enums.\n *\n * @param enumObj - The object to get the enum ID from. Can be any type.\n * @returns The enum ID string if enumObj is a branded enum, `undefined` otherwise.\n *\n * @example\n * // Get ID from branded enum\n * const Status = createBrandedEnum('status', { Active: 'active' } as const);\n * getEnumId(Status); // 'status'\n *\n * @example\n * // Returns undefined for non-branded objects\n * getEnumId({}); // undefined\n * getEnumId({ Active: 'active' }); // undefined\n * getEnumId(null); // undefined\n */\nexport function getEnumId(enumObj: unknown): string | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n return enumObj[ENUM_ID];\n}\n\n/**\n * Gets all values from a branded enum as an array.\n *\n * Returns an array containing all the string values in the enum.\n * The order of values is not guaranteed.\n *\n * @template E - The branded enum type\n * @param enumObj - The object to get values from. Can be any type.\n * @returns Array of all enum values if enumObj is a branded enum,\n * `undefined` otherwise.\n *\n * @example\n * // Get values from branded enum\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive'\n * } as const);\n * getEnumValues(Status); // ['active', 'inactive']\n *\n * @example\n * // Returns undefined for non-branded objects\n * getEnumValues({}); // undefined\n * getEnumValues({ Active: 'active' }); // undefined\n */\nexport function getEnumValues<E extends AnyBrandedEnum>(\n enumObj: E\n): EnumValues<E>[] | undefined;\nexport function getEnumValues(enumObj: unknown): string[] | undefined;\nexport function getEnumValues(enumObj: unknown): string[] | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n return Array.from(enumObj[ENUM_VALUES]);\n}\n\n/**\n * Gets the number of values in a branded enum.\n *\n * Returns the count of unique values in the enum. This is equivalent to\n * the number of key-value pairs defined when the enum was created.\n *\n * @param enumObj - The object to get the size of. Can be any type.\n * @returns The number of values in the enum if enumObj is a branded enum,\n * `undefined` otherwise.\n *\n * @example\n * // Get size of branded enum\n * const Status = createBrandedEnum('status', {\n * Active: 'active',\n * Inactive: 'inactive'\n * } as const);\n * enumSize(Status); // 2\n *\n * @example\n * // Returns undefined for non-branded objects\n * enumSize({}); // undefined\n * enumSize({ Active: 'active' }); // undefined\n */\nexport function enumSize(enumObj: unknown): number | undefined {\n if (!isBrandedEnum(enumObj)) {\n return undefined;\n }\n return enumObj[ENUM_VALUES].size;\n}\n"],"names":["ENUM_ID","ENUM_VALUES","isBrandedEnum","obj","Set","getEnumId","enumObj","undefined","getEnumValues","Array","from","enumSize","size"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA;;;;;CAKC,GAED,SAIEA,OAAO,EACPC,WAAW,QAEN,aAAa;AAEpB;;;;;CAKC,GACD,SAASC,cAAcC,GAAY;IACjC,OACEA,QAAQ,QACR,OAAOA,QAAQ,YACfH,WAAWG,OACXF,eAAeE,OACf,OAAO,AAACA,GAAsB,CAACH,QAAQ,KAAK,YAC5C,AAACG,GAAsB,CAACF,YAAY,YAAYG;AAEpD;AAEA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,SAASC,UAAUC,OAAgB;IACxC,IAAI,CAACJ,cAAcI,UAAU;QAC3B,OAAOC;IACT;IACA,OAAOD,OAAO,CAACN,QAAQ;AACzB;AA8BA,OAAO,SAASQ,cAAcF,OAAgB;IAC5C,IAAI,CAACJ,cAAcI,UAAU;QAC3B,OAAOC;IACT;IACA,OAAOE,MAAMC,IAAI,CAACJ,OAAO,CAACL,YAAY;AACxC;AAEA;;;;;;;;;;;;;;;;;;;;;;CAsBC,GACD,OAAO,SAASU,SAASL,OAAgB;IACvC,IAAI,CAACJ,cAAcI,UAAU;QAC3B,OAAOC;IACT;IACA,OAAOD,OAAO,CAACL,YAAY,CAACW,IAAI;AAClC"}
|