@reharik/smart-enum 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs +22 -23
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +22 -23
- package/dist/core.js.map +1 -1
- package/dist/database.cjs +22 -23
- package/dist/database.cjs.map +1 -1
- package/dist/database.d.cts +2 -2
- package/dist/database.d.ts +2 -2
- package/dist/database.js +22 -23
- package/dist/database.js.map +1 -1
- package/dist/index.cjs +22 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +22 -23
- package/dist/index.js.map +1 -1
- package/dist/{transformation-CrXfK1cB.d.cts → transformation-CuTsvU5q.d.cts} +32 -7
- package/dist/{transformation-CrXfK1cB.d.ts → transformation-CuTsvU5q.d.ts} +32 -7
- package/dist/transport.cjs +22 -23
- package/dist/transport.cjs.map +1 -1
- package/dist/transport.d.cts +2 -2
- package/dist/transport.d.ts +2 -2
- package/dist/transport.js +22 -23
- package/dist/transport.js.map +1 -1
- package/package.json +1 -1
package/dist/database.cjs
CHANGED
|
@@ -34,25 +34,18 @@ module.exports = __toCommonJS(database_exports);
|
|
|
34
34
|
// src/enumerations.ts
|
|
35
35
|
var import_case_anything = require("case-anything");
|
|
36
36
|
|
|
37
|
-
// src/types.ts
|
|
38
|
-
var SMART_ENUM_ITEM = Symbol("smart-enum-item");
|
|
39
|
-
var SMART_ENUM_ID = Symbol("smart-enum-id");
|
|
40
|
-
var SMART_ENUM = Symbol("smart-enum");
|
|
41
|
-
|
|
42
37
|
// src/utilities/typeGuards.ts
|
|
43
38
|
var isSmartEnumItem = (x) => {
|
|
44
|
-
return !!x && typeof x === "object" && Reflect.get(x,
|
|
39
|
+
return !!x && typeof x === "object" && Reflect.get(x, "__smart_enum_brand") === true && typeof Reflect.get(x, "__smart_enum_type") === "string" && typeof Reflect.get(x, "value") === "string";
|
|
45
40
|
};
|
|
46
41
|
var isSmartEnum = (x) => {
|
|
47
|
-
return !!x && typeof x === "object" && Reflect.get(x,
|
|
42
|
+
return !!x && typeof x === "object" && Reflect.get(x, "__smart_enum") === true;
|
|
48
43
|
};
|
|
49
44
|
|
|
50
45
|
// src/utilities/enumItemsEqual.ts
|
|
51
46
|
var enumItemsEqual = (a, b) => {
|
|
52
|
-
if (!isSmartEnumItem(a) || !isSmartEnumItem(b))
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
return Reflect.get(a, SMART_ENUM_ID) === Reflect.get(b, SMART_ENUM_ID) && a.value === b.value;
|
|
47
|
+
if (!isSmartEnumItem(a) || !isSmartEnumItem(b)) return false;
|
|
48
|
+
return a.__smart_enum_type === b.__smart_enum_type && a.value === b.value;
|
|
56
49
|
};
|
|
57
50
|
|
|
58
51
|
// src/extensionMethods.ts
|
|
@@ -71,6 +64,7 @@ var addExtensionMethods = (enumItems) => {
|
|
|
71
64
|
fromKey: (key) => requireBy("key", key, "key"),
|
|
72
65
|
tryFromKey: (key) => key ? findBy("key", key) : void 0,
|
|
73
66
|
equals: enumItemsEqual,
|
|
67
|
+
has: (x) => enumItems.some((item) => enumItemsEqual(item, x)),
|
|
74
68
|
items: () => [...enumItems],
|
|
75
69
|
values: () => enumItems.map((item) => item.value),
|
|
76
70
|
keys: () => enumItems.map((item) => item.key)
|
|
@@ -82,6 +76,17 @@ var globalDefault;
|
|
|
82
76
|
var resolveSerializationMode = (perEnum) => perEnum ?? globalDefault ?? "wrapped";
|
|
83
77
|
|
|
84
78
|
// src/enumerations.ts
|
|
79
|
+
var registeredEnumSignatures = /* @__PURE__ */ new Map();
|
|
80
|
+
var registerEnumName = (enumType, items) => {
|
|
81
|
+
const signature = items.map((item) => `${item.key}=${item.value}`).sort().join("|");
|
|
82
|
+
const existing = registeredEnumSignatures.get(enumType);
|
|
83
|
+
if (existing !== void 0 && existing !== signature) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Enum name '${enumType}' is already defined with different members; enum names must be unique because they are the wire/identity key (equality and revival key on __smart_enum_type + value).`
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
registeredEnumSignatures.set(enumType, signature);
|
|
89
|
+
};
|
|
85
90
|
function normalizeInput(input) {
|
|
86
91
|
if (Array.isArray(input)) {
|
|
87
92
|
return Object.fromEntries(
|
|
@@ -90,15 +95,7 @@ function normalizeInput(input) {
|
|
|
90
95
|
}
|
|
91
96
|
return input;
|
|
92
97
|
}
|
|
93
|
-
var finalizeEnumItem = (item, enumType,
|
|
94
|
-
Object.defineProperty(item, SMART_ENUM_ITEM, {
|
|
95
|
-
value: true,
|
|
96
|
-
enumerable: false
|
|
97
|
-
});
|
|
98
|
-
Object.defineProperty(item, SMART_ENUM_ID, {
|
|
99
|
-
value: enumInstanceId,
|
|
100
|
-
enumerable: false
|
|
101
|
-
});
|
|
98
|
+
var finalizeEnumItem = (item, enumType, serializeAs) => {
|
|
102
99
|
Object.defineProperty(item, "__smart_enum_brand", {
|
|
103
100
|
value: true,
|
|
104
101
|
enumerable: false
|
|
@@ -156,7 +153,6 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
156
153
|
...propertyAutoFormatters ?? []
|
|
157
154
|
];
|
|
158
155
|
const rawEnumItems = {};
|
|
159
|
-
const enumInstanceId = Symbol("smart-enum-instance");
|
|
160
156
|
let index = 0;
|
|
161
157
|
for (const key in input) {
|
|
162
158
|
if (Object.prototype.hasOwnProperty.call(input, key)) {
|
|
@@ -171,7 +167,6 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
171
167
|
const enumItem = finalizeEnumItem(
|
|
172
168
|
enumItemBase,
|
|
173
169
|
enumType,
|
|
174
|
-
enumInstanceId,
|
|
175
170
|
serializeAs
|
|
176
171
|
);
|
|
177
172
|
Object.freeze(enumItem);
|
|
@@ -179,6 +174,10 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
179
174
|
index++;
|
|
180
175
|
}
|
|
181
176
|
}
|
|
177
|
+
registerEnumName(
|
|
178
|
+
enumType,
|
|
179
|
+
Object.values(rawEnumItems)
|
|
180
|
+
);
|
|
182
181
|
const extensionMethods = addExtensionMethods(
|
|
183
182
|
Object.values(rawEnumItems)
|
|
184
183
|
);
|
|
@@ -186,7 +185,7 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
186
185
|
...rawEnumItems,
|
|
187
186
|
...extensionMethods
|
|
188
187
|
};
|
|
189
|
-
Object.defineProperty(enumObject,
|
|
188
|
+
Object.defineProperty(enumObject, "__smart_enum", {
|
|
190
189
|
value: true,
|
|
191
190
|
enumerable: false
|
|
192
191
|
});
|
package/dist/database.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/database.ts","../src/enumerations.ts","../src/types.ts","../src/utilities/typeGuards.ts","../src/utilities/enumItemsEqual.ts","../src/extensionMethods.ts","../src/utilities/serializationMode.ts","../src/utilities/transformation.ts","../src/db/prepareForDatabase.ts","../src/db/enumRevivalError.ts","../src/db/reviveRowFromDatabase.ts","../src/db/revivePayloadFromDatabase.ts"],"sourcesContent":["/**\n * Smart Enums — database persistence helpers (`src/db`).\n *\n * Transport wire revival (`initializeSmartEnumMappings`, `reviveAfterTransport`)\n * is exported from `@reharik/smart-enum/transport` and `@reharik/smart-enum` root.\n *\n * @example\n * ```typescript\n * import {\n * enumeration,\n * prepareForDatabase,\n * reviveEnumField,\n * reviveRowFromDatabase,\n * } from '@reharik/smart-enum/database';\n * ```\n */\n\nexport { enumeration } from './enumerations.js';\nexport { isSmartEnumItem, isSmartEnum } from './utilities/typeGuards.js';\nexport { reviveEnumField } from './utilities/transformation.js';\nexport {\n prepareForDatabase,\n reviveRowFromDatabase,\n revivePayloadFromDatabase,\n EnumRevivalError,\n} from './db/index.js';\nexport type { Logger } from './utilities/logger.js';\nexport type {\n Enumeration,\n AnyEnumLike,\n DatabaseFormat,\n SmartApiHelperConfig,\n LogLevel,\n SmartEnumMappingsConfig,\n EnumLikeBase,\n SmartEnumLike,\n FieldEnumMapping,\n ReviveRowOptions,\n PathEnumMapping,\n RevivePayloadOptions,\n StandardEnumItemBase,\n StandardEnumItem,\n} from './types.js';\n","import { capitalCase, constantCase } from 'case-anything';\n\nimport { addExtensionMethods } from './extensionMethods.js';\nimport {\n SMART_ENUM,\n SMART_ENUM_ID,\n SMART_ENUM_ITEM,\n SerializationMode,\n type EnumFromNormalizedObject,\n type EnumItemFromNormalizedObject,\n type EnumMemberUnionFromNormalizedObject,\n type EnumerationProps,\n type FinalizableEnumItem,\n type FinalizedEnumFields,\n type NormalizedInputType,\n type ObjectEnumInput,\n type PropertyAutoFormatter,\n type StandardEnumItem,\n} from './types.js';\nimport { enumItemsEqual } from './utilities/enumItemsEqual.js';\nimport { resolveSerializationMode } from './utilities/serializationMode.js';\n\nexport type EnumItem<TEnum> = {\n [K in keyof TEnum]: TEnum[K] extends { __smart_enum_brand: true }\n ? TEnum[K]\n : never;\n}[keyof TEnum];\n\nfunction normalizeInput<TInput extends readonly string[] | ObjectEnumInput>(\n input: TInput,\n): NormalizedInputType<TInput> {\n if (Array.isArray(input)) {\n return Object.fromEntries(\n input.map(k => [k, {}]),\n ) as NormalizedInputType<TInput>;\n }\n\n return input as NormalizedInputType<TInput>;\n}\n\nconst finalizeEnumItem = <T extends { value: string; key: string }>(\n item: T,\n enumType: string,\n enumInstanceId: symbol,\n serializeAs: SerializationMode | undefined,\n): T & FinalizedEnumFields => {\n Object.defineProperty(item, SMART_ENUM_ITEM, {\n value: true,\n enumerable: false,\n });\n\n Object.defineProperty(item, SMART_ENUM_ID, {\n value: enumInstanceId,\n enumerable: false,\n });\n\n Object.defineProperty(item, '__smart_enum_brand', {\n value: true,\n enumerable: false,\n });\n\n Object.defineProperty(item, '__smart_enum_type', {\n value: enumType,\n enumerable: false,\n });\n\n Object.defineProperty(item, 'toJSON', {\n value: () => {\n const mode = resolveSerializationMode(serializeAs);\n if (mode === 'value') {\n return item.value;\n }\n return { __smart_enum_type: enumType, value: item.value };\n },\n enumerable: false,\n });\n\n Object.defineProperty(item, 'toPostgres', {\n value: () => item.value,\n enumerable: false,\n });\n\n Object.defineProperty(item, 'equals', {\n value: (other: StandardEnumItem) => enumItemsEqual(item, other),\n enumerable: false,\n });\n\n Object.defineProperty(item, 'match', {\n value: (handlers: Record<string, (i: unknown) => unknown>) => {\n const handler = handlers[item.key];\n if (!handler) {\n throw new Error(\n `match: no handler for '${item.key}' on enum '${enumType}'`,\n );\n }\n return handler(item);\n },\n enumerable: false,\n });\n return item as T & FinalizedEnumFields;\n};\n\nconst formatProperties = (\n k: string,\n formatters: PropertyAutoFormatter[],\n): { value: string; display: string } & Record<string, string> =>\n formatters.reduce(\n (acc, formatter) => {\n acc[formatter.key] = formatter.format(k);\n return acc;\n },\n {\n value: constantCase(k),\n display: capitalCase(k),\n } as { value: string; display: string } & Record<string, string>,\n );\n\nfunction buildEnumFromObject<\n TName extends string,\n TObj extends ObjectEnumInput,\n>(\n enumType: TName,\n input: TObj,\n propertyAutoFormatters?: PropertyAutoFormatter[],\n serializeAs?: SerializationMode,\n): EnumFromNormalizedObject<TObj, TName> {\n const formattersWithDefaults: PropertyAutoFormatter[] = [\n { key: 'value', format: constantCase },\n { key: 'display', format: capitalCase },\n ...(propertyAutoFormatters ?? []),\n ];\n\n type TItem = EnumMemberUnionFromNormalizedObject<TObj, TName>;\n\n const rawEnumItems: Partial<{\n [K in keyof TObj]: EnumItemFromNormalizedObject<TObj, K, TName>;\n }> = {};\n\n const enumInstanceId = Symbol('smart-enum-instance');\n let index = 0;\n\n for (const key in input) {\n if (Object.prototype.hasOwnProperty.call(input, key)) {\n const typedKey = key;\n const value = input[typedKey];\n\n const enumItemBase = {\n index,\n key: typedKey,\n ...formatProperties(typedKey, formattersWithDefaults),\n ...value,\n } as FinalizableEnumItem & TObj[typeof typedKey];\n\n const enumItem = finalizeEnumItem(\n enumItemBase,\n enumType,\n enumInstanceId,\n serializeAs,\n ) as unknown as TItem;\n\n Object.freeze(enumItem);\n rawEnumItems[typedKey as keyof TObj] = enumItem;\n index++;\n }\n }\n\n const extensionMethods = addExtensionMethods<TItem>(\n Object.values(rawEnumItems) as TItem[],\n );\n\n const enumObject = {\n ...rawEnumItems,\n ...extensionMethods,\n } as EnumFromNormalizedObject<TObj, TName>;\n\n Object.defineProperty(enumObject, SMART_ENUM, {\n value: true,\n enumerable: false,\n });\n\n Object.freeze(enumObject);\n\n return enumObject;\n}\n\nexport function enumeration<\n const TArr extends readonly string[],\n const TName extends string = string,\n>(\n enumType: TName,\n props: EnumerationProps<TArr>,\n): EnumFromNormalizedObject<NormalizedInputType<TArr>, TName>;\n\nexport function enumeration<\n const TObj extends ObjectEnumInput,\n const TName extends string = string,\n>(\n enumType: TName,\n props: EnumerationProps<TObj>,\n): EnumFromNormalizedObject<NormalizedInputType<TObj>, TName>;\n\nexport function enumeration<const TName extends string = string>(\n enumType: TName,\n props: EnumerationProps<readonly string[] | ObjectEnumInput>,\n): EnumFromNormalizedObject<\n NormalizedInputType<readonly string[] | ObjectEnumInput>,\n TName\n> {\n const normalized = normalizeInput(props.input);\n return buildEnumFromObject(\n enumType,\n normalized,\n props.propertyAutoFormatters,\n props.serializeAs,\n );\n}\n","/**\n * Type guard to check if a value is not null or undefined\n * @param value - The value to check\n * @returns True if the value is defined and not null\n */\nexport const notEmpty = <X>(\n value: X | null | undefined,\n): value is NonNullable<X> => {\n // eslint-disable-next-line unicorn/no-null\n return value != null;\n};\n\n// Public symbols used at runtime for detection/identity (not used in type keys)\nexport const SMART_ENUM_ITEM = Symbol('smart-enum-item');\nexport const SMART_ENUM_ID = Symbol('smart-enum-id');\nexport const SMART_ENUM = Symbol('smart-enum');\n\n/**\n * Options for filtering enum items in various methods\n */\nexport type EnumFilterOptions = {\n /** Include items with null/undefined values (default: false) */\n showEmpty?: boolean;\n /** Include deprecated items (default: false) */\n showDeprecated?: boolean;\n};\n\n// export type EnumInput = readonly string[] | ObjectEnumInput;\n\n/**\n * Compile-time transformer: replaces Smart Enum items with string values,\n * recursively over arrays and objects. Structural detection checks for\n * presence of `key` and `value`.\n */\nexport type SerializedSmartEnums<T> = T extends { value: string; key: unknown }\n ? string\n : T extends ReadonlyArray<infer U>\n ? ReadonlyArray<SerializedSmartEnums<U>>\n : T extends Array<infer U>\n ? SerializedSmartEnums<U>[]\n : T extends object\n ? { [K in keyof T]: SerializedSmartEnums<T[K]> }\n : T;\n\n/**\n * Revived shape: for keys present in mapping M, the string becomes the\n * corresponding enum item type (derived from the provided enum object);\n * other fields recurse.\n */\nexport type EnumItemFromEnum<TEnum> =\n TEnum extends Record<string, infer V>\n ? V extends { __smart_enum_brand: true }\n ? V\n : never\n : never;\n\n/**\n * Structural constraint for smart enum instances (registry entries, `reviveSmartEnums`, etc.).\n * `T` is the enum item type returned by `tryFromValue` / `tryFromKey` (default `unknown` when heterogeneous).\n */\nexport type AnyEnumLike<T = unknown> = {\n tryFromValue: (value?: string | null) => T | undefined;\n tryFromKey: (key?: string | null) => T | undefined;\n} & Record<string, unknown>;\n\nexport type RevivedSmartEnums<T, M extends Record<string, AnyEnumLike>> =\n T extends ReadonlyArray<infer U>\n ? RevivedSmartEnums<U, M>[]\n : T extends Array<infer U>\n ? RevivedSmartEnums<U, M>[]\n : T extends object\n ? {\n [K in keyof T]: K extends Extract<keyof M, string>\n ? Enumeration<M[K]>\n : RevivedSmartEnums<T[K], M>;\n }\n : T;\n\nexport type SmartEnumItemSerialized = {\n __smart_enum_type: string;\n value: string;\n};\n\n/** Example shape for transport tests (`reviveAfterTransport` registry). */\nexport type SmartApiHelperConfig = {\n enumRegistry: Record<string, AnyEnumLike>;\n};\n\n/**\n * Compile-time transformer: replaces Smart Enum items with string values,\n * recursively over arrays and objects. Used for database storage.\n */\nexport type DatabaseFormat<T> = T extends { value: string; key: unknown }\n ? string\n : T extends ReadonlyArray<infer U>\n ? ReadonlyArray<DatabaseFormat<U>>\n : T extends Array<infer U>\n ? DatabaseFormat<U>[]\n : T extends object\n ? { [K in keyof T]: DatabaseFormat<T[K]> }\n : T;\n\n/**\n * Log levels for smart enum mappings\n */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Configuration for smart enum mappings initialization\n */\nexport type SmartEnumMappingsConfig = {\n enumRegistry: Record<string, AnyEnumLike>;\n logLevel?: LogLevel;\n logger?: import('./utilities/logger.js').Logger;\n};\n\ntype BuiltInOverrideKeys =\n | 'key'\n | 'value'\n | 'display'\n | 'deprecated'\n | 'index'\n | '__smart_enum_brand'\n | '__smart_enum_type';\n\n/**\n * Structural fields shared by every enum member (key, value, display, index, optional deprecated).\n * Does not include smart-enum branding or database helpers; see {@link StandardEnumItem}.\n */\nexport type StandardEnumItemBase = {\n readonly key: string;\n readonly value: string;\n readonly display: string;\n readonly index: number;\n readonly deprecated?: boolean;\n};\n\n/**\n * Branded item produced by `enumeration()`: {@link StandardEnumItemBase} plus runtime identity\n * (`__smart_enum_brand`, `__smart_enum_type`) and `toPostgres()`.\n */\nexport type StandardEnumItem = StandardEnumItemBase & {\n readonly __smart_enum_brand: true;\n readonly __smart_enum_type: string;\n readonly toPostgres: () => string;\n readonly toJSON: () => string | { __smart_enum_type: string; value: string };\n readonly equals: <\n This extends { __smart_enum_type: string },\n T extends {\n __smart_enum_type: This['__smart_enum_type'];\n } & StandardEnumItem,\n >(\n this: This,\n other: T,\n ) => this is T;\n};\n\nexport type EnumInputItem = Partial<{\n key: string;\n value: string;\n display: string;\n deprecated: boolean;\n}> &\n Record<string, unknown>;\n\nexport type ObjectEnumInput = Record<string, EnumInputItem>;\n\nexport type EmptyEnumInputItem = Record<never, never>;\n\ntype Separator = '-' | '_' | ' ' | '.';\n\ntype IsUpperChar<C extends string> =\n C extends Uppercase<C> ? (C extends Lowercase<C> ? false : true) : false;\n\ntype IsLowerChar<C extends string> =\n C extends Lowercase<C> ? (C extends Uppercase<C> ? false : true) : false;\n\ntype PushUnderscore<S extends string> = S extends '' | `${string}_`\n ? S\n : `${S}_`;\n\ntype TrimUnderscore<S extends string> = S extends `_${infer R}`\n ? TrimUnderscore<R>\n : S extends `${infer R}_`\n ? TrimUnderscore<R>\n : S;\n\ntype CollapseUnderscores<S extends string> = S extends `${infer A}__${infer B}`\n ? CollapseUnderscores<`${A}_${B}`>\n : S;\n\ntype ConstantCaseInternal<\n S extends string,\n Prev extends string = '',\n Out extends string = '',\n> = S extends `${infer C}${infer Rest}`\n ? C extends Separator\n ? ConstantCaseInternal<Rest, C, PushUnderscore<Out>>\n : IsUpperChar<C> extends true\n ? IsLowerChar<Prev> extends true\n ? ConstantCaseInternal<Rest, C, `${PushUnderscore<Out>}${Uppercase<C>}`>\n : ConstantCaseInternal<Rest, C, `${Out}${Uppercase<C>}`>\n : ConstantCaseInternal<Rest, C, `${Out}${Uppercase<C>}`>\n : CollapseUnderscores<TrimUnderscore<Out>>;\n\ntype ConstantCase<S extends string> = string extends S\n ? string\n : ConstantCaseInternal<S>;\n\n/** Segments of a `ConstantCase` string (underscore-separated ALL CAPS words). */\ntype SplitConstantCaseSegments<S extends string> =\n S extends `${infer A}_${infer B}`\n ? [A, ...SplitConstantCaseSegments<B>]\n : [S];\n\n/** First character upper, remainder lower (for ALL-CAPS words from `ConstantCase`). */\ntype TitleCaseAllCapsWord<W extends string> = W extends ''\n ? ''\n : W extends `${infer F}${infer R}`\n ? `${Uppercase<F>}${Lowercase<R>}`\n : W;\n\ntype JoinDisplaySegments<T extends readonly string[]> = T extends readonly [\n infer A extends string,\n ...infer Rest extends readonly string[],\n]\n ? Rest extends readonly []\n ? TitleCaseAllCapsWord<A>\n : `${TitleCaseAllCapsWord<A>} ${JoinDisplaySegments<Rest>}`\n : '';\n\n/**\n * Display string derived from the enum member key: `ConstantCase` → split → title-case words → join with spaces.\n * Matches default runtime `capitalCase(key)` for typical PascalCase / camelCase keys. Member keys that already\n * contain separators may differ from `capitalCase` at runtime; custom `propertyAutoFormatters` for `display`\n * are not reflected in this type.\n */\ntype DisplayCaseFromEnumKey<K extends string> = string extends K\n ? string\n : JoinDisplaySegments<SplitConstantCaseSegments<ConstantCase<K>>>;\n\nexport type ArrayToObjectType<T extends readonly string[]> = {\n [K in T[number]]: EmptyEnumInputItem & { readonly value?: ConstantCase<K> };\n};\n\nexport type NormalizedInputType<TInput> = TInput extends readonly string[]\n ? ArrayToObjectType<TInput>\n : TInput extends ObjectEnumInput\n ? TInput\n : never;\n\n/** Input-derived fields for one member key (excludes built-ins filled by `enumeration()`). */\nexport type EnumMemberExtra<\n TObj extends ObjectEnumInput,\n K extends keyof TObj,\n> = Omit<TObj[K], BuiltInOverrideKeys>;\n\nexport type EnumItemFromNormalizedObject<\n TObj extends ObjectEnumInput,\n K extends keyof TObj = keyof TObj,\n TName extends string = string,\n> = Omit<\n StandardEnumItem,\n 'key' | 'value' | 'display' | '__smart_enum_type'\n> & { __smart_enum_type: TName } & SmartEnumMatch &\n EnumMemberExtra<TObj, K> & {\n readonly key: Extract<K, string>;\n readonly value: TObj[K] extends { value?: infer V }\n ? [Extract<V, string>] extends [never]\n ? ConstantCase<Extract<K, string>>\n : Extract<V, string>\n : ConstantCase<Extract<K, string>>;\n readonly display: TObj[K] extends { display?: infer D }\n ? [Extract<D, string>] extends [never]\n ? DisplayCaseFromEnumKey<Extract<K, string>>\n : Extract<D, string>\n : DisplayCaseFromEnumKey<Extract<K, string>>;\n };\n\nexport type EnumMemberUnionFromNormalizedObject<\n TObj extends ObjectEnumInput,\n TName extends string = string,\n> = {\n [K in keyof TObj]: EnumItemFromNormalizedObject<TObj, K, TName>;\n}[keyof TObj];\n\nexport type EnumFromNormalizedObject<\n TObj extends ObjectEnumInput,\n TName extends string = string,\n> = {\n [K in keyof TObj]: EnumItemFromNormalizedObject<TObj, K, TName>;\n} & CoreEnumMethods<EnumMemberUnionFromNormalizedObject<TObj, TName>>;\n\nexport type UnionKeys<T> = T extends T ? keyof T : never;\n\n/*\nTo widen the type of the OptionalObject from literals to their actual types,\ne.g.\nshape?: \"round\" | \"square\" | \"long\";\nslices?: true;\nlayers?: 2;\n--turns into:--\nshape: string | undefined;\nslices: boolean| undefined;\nlayers: number| undefined;\n\nwe can use the following code:\ntype Widen<T> = T extends string\n ? string\n : T extends number\n ? number\n : T extends boolean\n ? boolean\n : T;\n\ntype MergeUnionToObject<T> = {\n [K in UnionKeys<T>]: T extends Record<K, infer V> ? Widen<V> : undefined;\n};\n*/\n\ntype MergeUnionToObject<T> = {\n [K in UnionKeys<T>]: T extends Record<K, infer V> ? V : undefined;\n};\n\ntype ExtraShapeUnion<TObj extends ObjectEnumInput> = {\n [K in keyof TObj]: Omit<TObj[K], BuiltInOverrideKeys>;\n}[keyof TObj];\n\nexport type InferredExtraFields<TObj extends ObjectEnumInput> =\n MergeUnionToObject<ExtraShapeUnion<TObj>>;\n\nexport type PropertyAutoFormatter = {\n /** The property name to generate */\n key: string;\n /** Function to transform the key into the property value */\n format: (k: string) => string;\n};\n\nexport type CoreEnumMethods<TItem extends StandardEnumItem> = {\n fromValue(value: string): TItem;\n tryFromValue(value?: string | null): TItem | undefined;\n fromKey(key: string): TItem;\n tryFromKey(key?: string | null): TItem | undefined;\n equals(a: TItem, b: TItem): boolean;\n items(): readonly TItem[];\n /** Matches runtime: `items.map(i => i.value)` (see {@link EnumLikeBase}). */\n values(): readonly TItem['value'][];\n /** Matches runtime: `items.map(i => i.key)` (see {@link EnumLikeBase}). */\n keys(): readonly TItem['key'][];\n};\n\n/**\n * Structural shape of a smart-style enum object: lookup by value/key, list items/values/keys,\n * plus an index signature so registry and mapping types can treat instances as records.\n * Use {@link SmartEnumLike} when items are full {@link StandardEnumItem}s (the usual case).\n */\nexport type EnumLikeBase<\n TItem extends StandardEnumItemBase = StandardEnumItemBase,\n> = {\n fromValue(value: string): TItem;\n tryFromValue(value?: string | null): TItem | undefined;\n fromKey(key: string): TItem;\n tryFromKey(key?: string | null): TItem | undefined;\n equals(a: TItem, b: TItem): boolean;\n items(): readonly TItem[];\n values(): readonly TItem['value'][];\n keys(): readonly TItem['key'][];\n} & Record<string, unknown>;\n\n/**\n * A {@link EnumLikeBase} whose items are branded {@link StandardEnumItem}s (typical `enumeration()` result).\n */\nexport type SmartEnumLike<TItem extends StandardEnumItem = StandardEnumItem> =\n EnumLikeBase<TItem>;\n\n/** Union of branded enum member values on an enum object `T`. */\nexport type SmartEnumMemberUnion<T extends Record<string, unknown>> = {\n [K in keyof T]: T[K] extends StandardEnumItem ? T[K] : never;\n}[keyof T];\n\n/** Keys on `TEnum` whose member matches `Record<P, V>` within `ItemUnion`. */\nexport type SmartEnumSubsetKeys<\n TEnum extends Record<string, unknown>,\n ItemUnion extends StandardEnumItem,\n P extends keyof ItemUnion & string,\n V extends ItemUnion[P],\n> = {\n [K in keyof TEnum]: TEnum[K] extends Extract<ItemUnion, Record<P, V>>\n ? K\n : never;\n}[keyof TEnum];\n\nexport type SmartEnumSubsetItemUnion<\n ItemUnion extends StandardEnumItem,\n P extends keyof ItemUnion & string,\n V extends ItemUnion[P],\n> = Extract<ItemUnion, Record<P, V>>;\n\nexport type SmartEnumSubsetView<\n TEnum extends Record<string, unknown>,\n ItemUnion extends StandardEnumItem,\n P extends keyof ItemUnion & string,\n V extends ItemUnion[P],\n> = Pick<TEnum, SmartEnumSubsetKeys<TEnum, ItemUnion, P, V>> &\n CoreEnumMethods<SmartEnumSubsetItemUnion<ItemUnion, P, V>>;\n\n/** Return type of {@link getSubsetByProp} / {@link subsetByProp} for explicit consumer annotations. */\nexport type SubsetByPropResult<\n TEnum extends Record<string, unknown> &\n SmartEnumLike<SmartEnumMemberUnion<TEnum>>,\n P extends keyof SmartEnumMemberUnion<TEnum> & string,\n V extends SmartEnumMemberUnion<TEnum>[P],\n> = SmartEnumSubsetView<TEnum, SmartEnumMemberUnion<TEnum>, P, V>;\n\nexport type FieldEnumMapping = Record<string, SmartEnumLike>;\n\nexport type ReviveRowOptions = {\n fieldEnumMapping: FieldEnumMapping;\n strict?: boolean;\n};\n\nexport type PathEnumMapping = Record<string, SmartEnumLike>;\n\nexport type RevivePayloadOptions = {\n pathEnumMapping: PathEnumMapping;\n strict?: boolean;\n};\n\n/**\n * Serialization mode controls how smart-enum items are serialized to JSON.\n *\n * - 'wrapped' (default): toJSON returns { __smart_enum_type, value }.\n * Use this when payloads need to be self-describing for revival on the\n * receiving end (e.g. REST APIs with explicit revive middleware).\n *\n * - 'value': toJSON returns just the wire value string.\n * Use this when the receiving end already knows the enum types from\n * schema context (e.g. GraphQL boundaries).\n *\n * Resolution order at toJSON call time:\n * 1. Per-enum `serializeAs` option (if set on enumeration())\n * 2. Global default (set via setDefaultSerializationMode)\n * 3. 'wrapped' (built-in default, preserves backward compatibility)\n */\nexport type SerializationMode = 'wrapped' | 'value';\n\nexport type EnumerationProps<TInput> = {\n input: TInput;\n propertyAutoFormatters?: PropertyAutoFormatter[];\n serializeAs?: SerializationMode;\n};\n\nexport type Enumeration<TEnum> =\n TEnum extends Record<string, infer V>\n ? V extends { __smart_enum_brand: true }\n ? V\n : never\n : never;\n\nexport type FinalizedEnumFields = Pick<\n StandardEnumItem,\n '__smart_enum_brand' | '__smart_enum_type' | 'toJSON'\n>;\nexport type FinalizableEnumItem = {\n key: string;\n value: string;\n display: string;\n index: number;\n deprecated?: boolean;\n};\n\n/**\n * Exhaustive branch-on-member. One arm required per member of the *statically\n * known* receiver — miss one and it won't compile. Over a pickEnum view the\n * arms are exhaustive over just the picked members.\n */\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\nexport interface SmartEnumMatch {\n readonly key: string;\n match<R>(handlers: {\n [P in this['key']]: (item: Extract<this, { key: P }>) => R;\n }): R;\n}\n\n/** Member keys of an enum object (excludes the method keys). */\nexport type EnumMemberKeys<TEnum> = {\n [K in keyof TEnum]: TEnum[K] extends StandardEnumItem ? K : never;\n}[keyof TEnum];\n\n/**\n * Enum-like view over an explicit list of member keys. Reuses the parent's item\n * references; methods scope to the picked subset. See {@link pickEnum}.\n */\nexport type PickEnumView<\n TEnum extends Record<string, unknown>,\n K extends EnumMemberKeys<TEnum>,\n> = Pick<TEnum, K> & CoreEnumMethods<Extract<TEnum[K], StandardEnumItem>>;\n\nexport type EnumSubset<\n TItems extends StandardEnumItem,\n K extends TItems['key'],\n> = Extract<TItems, { key: K }>;\n","import {\n SMART_ENUM_ITEM,\n SMART_ENUM,\n SmartEnumItemSerialized,\n SmartEnumLike,\n} from '../types.js';\n\n/**\n * Runtime type guard to detect Smart Enum items created by this library.\n * Returns true if the value has the SMART_ENUM_ITEM symbol.\n *\n * @example\n * ```typescript\n * import { Status } from './status';\n * const item = Status.active;\n * isSmartEnumItem(item); // true\n * isSmartEnumItem({ key: 'active', value: 'ACTIVE' }); // false (plain object)\n * if (isSmartEnumItem(x)) {\n * console.log(x.value, x.__smart_enum_type); // narrowed to enum item\n * }\n * ```\n */\nexport const isSmartEnumItem = (\n x: unknown,\n): x is {\n key: string;\n value: string;\n index?: number;\n __smart_enum_type?: string;\n} => {\n return (\n !!x && typeof x === 'object' && Reflect.get(x, SMART_ENUM_ITEM) === true\n );\n};\n\n/**\n * Runtime type guard to detect a full Smart Enum object created by this library.\n * Returns true if the object has the SMART_ENUM property.\n *\n * @example\n * ```typescript\n * import { MyEnum } from './blah';\n * isSmartEnum(MyEnum) === true; // true\n * isSmartEnum(MyEnum.one) === false; // false (this is an item, not the enum)\n * ```\n */\nexport const isSmartEnum = (x: unknown): x is SmartEnumLike => {\n return !!x && typeof x === 'object' && Reflect.get(x, SMART_ENUM) === true;\n};\n\n/**\n * Runtime type guard to detect a serialized Smart Enum item created by this library.\n * Returns true if the value has `__smart_enum_type` and `value` (wire/database shape).\n *\n * @example\n * ```typescript\n * const wire = { __smart_enum_type: 'Status', value: 'ACTIVE' };\n * isSerializedSmartEnumItem(wire); // true\n * isSerializedSmartEnumItem(Status.active); // false (live enum item)\n * if (isSerializedSmartEnumItem(x)) {\n * reviveItem(x.__smart_enum_type, x.value); // narrowed to SmartEnumItemSerialized\n * }\n * ```\n */\nexport const isSerializedSmartEnumItem = (\n x: unknown,\n): x is SmartEnumItemSerialized => {\n return (\n !!x &&\n typeof x === 'object' &&\n Reflect.has(x, '__smart_enum_type') &&\n Reflect.has(x, 'value')\n );\n};\n","import { SMART_ENUM_ID } from '../types.js';\n\nimport { isSmartEnumItem } from './typeGuards.js';\n\n/** Value-based equality for smart enum items from the same enumeration instance. */\nexport const enumItemsEqual = (a: unknown, b: unknown): boolean => {\n if (!isSmartEnumItem(a) || !isSmartEnumItem(b)) {\n return false;\n }\n\n return (\n Reflect.get(a, SMART_ENUM_ID) === Reflect.get(b, SMART_ENUM_ID) &&\n a.value === b.value\n );\n};\n","import type { CoreEnumMethods, StandardEnumItem } from './types.js';\nimport { enumItemsEqual } from './utilities/enumItemsEqual.js';\nexport const addExtensionMethods = <TItem extends StandardEnumItem>(\n enumItems: readonly TItem[],\n): CoreEnumMethods<TItem> => {\n const findBy = <K extends keyof TItem>(field: K, target: TItem[K]) =>\n enumItems.find(item => item[field] === target);\n\n const requireBy = <K extends keyof TItem>(\n field: K,\n target: TItem[K],\n label: string,\n ) => {\n const item = findBy(field, target);\n if (!item) {\n throw new Error(`No enum ${label} found for '${String(target)}'`);\n }\n return item;\n };\n\n return {\n fromValue: value => requireBy('value', value as TItem['value'], 'value'),\n tryFromValue: value =>\n value ? findBy('value', value as TItem['value']) : undefined,\n\n fromKey: key => requireBy('key', key as TItem['key'], 'key'),\n tryFromKey: key => (key ? findBy('key', key as TItem['key']) : undefined),\n\n equals: enumItemsEqual,\n\n items: () => [...enumItems],\n values: () => enumItems.map(item => item.value),\n keys: () => enumItems.map(item => item.key),\n };\n};\n","import { SerializationMode } from '../types.js';\n\nlet globalDefault: SerializationMode | undefined;\n\n/**\n * Set the global default serialization mode for all smart-enum items\n * that don't have a per-enum serializeAs option.\n *\n * Call once at app startup, before any JSON.stringify happens on enum items.\n *\n * @example\n * setDefaultSerializationMode('value');\n */\nexport const setDefaultSerializationMode = (mode: SerializationMode): void => {\n globalDefault = mode;\n};\n\n/**\n * Reset the global default to its initial unset state.\n * Primarily useful for tests.\n */\nexport const resetDefaultSerializationMode = (): void => {\n globalDefault = undefined;\n};\n\n/**\n * Resolve the effective serialization mode for an enum item.\n * Per-enum option wins, then global, then 'wrapped'.\n */\nexport const resolveSerializationMode = (\n perEnum: SerializationMode | undefined,\n): SerializationMode => perEnum ?? globalDefault ?? 'wrapped';\n","// serializeSmartEnums.ts\nexport { isSmartEnumItem, isSmartEnum } from './typeGuards.js';\nimport type { SerializedSmartEnums, AnyEnumLike } from '../types.js';\n\nimport { debug } from './logger.js';\nimport { isSerializedSmartEnumItem, isSmartEnumItem } from './typeGuards.js';\n\ntype PlainObject = Record<string, unknown>;\n\nconst isPlainObject = (x: unknown): x is PlainObject =>\n typeof x === 'object' &&\n x !== null &&\n Object.getPrototypeOf(x) === Object.prototype;\n\n/**\n * Recursively replaces Smart Enum items with self-describing objects\n * `{ __smart_enum_type, value }` for JSON transport or storage.\n *\n * @param input - Object or array that may contain enum items\n * @returns Same structure with enum items replaced by serialized shape\n *\n * @example\n * ```typescript\n * const dto = { id: '1', status: Status.active, color: Color.red };\n * const wire = serializeSmartEnums(dto);\n * // wire: { id: '1', status: { __smart_enum_type: 'Status', value: 'ACTIVE' }, color: { __smart_enum_type: 'Color', value: 'RED' } }\n * ```\n */\n// Overloads:\n// 1) Inferred\nexport function serializeSmartEnums<T>(input: T): SerializedSmartEnums<T>;\n// 2) Return-type only (constrained to objects/arrays)\nexport function serializeSmartEnums<\n S extends Readonly<PlainObject> | readonly unknown[],\n>(input: unknown): S;\n// Implementation\nexport function serializeSmartEnums(input: unknown): unknown {\n const seen = new WeakMap<object, unknown>();\n\n const walk = (v: unknown): unknown => {\n if (isSmartEnumItem(v)) {\n return {\n __smart_enum_type: v.__smart_enum_type,\n value: v.value,\n };\n }\n if (typeof v === 'object' && v !== null && seen.has(v)) {\n return seen.get(v);\n }\n\n if (Array.isArray(v)) {\n const arr: unknown[] = [];\n seen.set(v, arr);\n for (const item of v) {\n arr.push(walk(item));\n }\n return arr;\n }\n if (isPlainObject(v)) {\n const out: PlainObject = {};\n seen.set(v, out);\n for (const [k, val] of Object.entries(v)) {\n out[k] = walk(val);\n }\n return out;\n }\n return v;\n };\n\n return walk(input);\n}\n\n/**\n * Recursively revives serialized enum objects back to Smart Enum items\n * using a registry of enum types. Expects payload to contain\n * `{ __smart_enum_type, value }` where the type exists in the registry.\n *\n * @param input - Serialized payload (e.g. from JSON)\n * @param registry - Map of enum type name to enum object (e.g. `{ Status, Color }`)\n * @returns Payload with serialized enums revived to enum items\n *\n * @example\n * ```typescript\n * const wire = { status: { __smart_enum_type: 'Status', value: 'ACTIVE' } };\n * const revived = reviveSmartEnums(wire, { Status, Color });\n * // revived.status === Status.active\n * ```\n */\nexport function reviveSmartEnums<R>(\n input: unknown,\n registry: Record<string, AnyEnumLike>,\n): R {\n const seen = new WeakMap<object, unknown>();\n\n const walk = (v: unknown): unknown => {\n // Handle self-describing enum objects with __smart_enum_type and value\n if (isSerializedSmartEnumItem(v)) {\n debug(`Found serialized smartEnum: ${v.__smart_enum_type}`);\n const enumInstance = registry[v.__smart_enum_type];\n if (enumInstance) {\n debug(`Found enumInstance in registry: ${v.__smart_enum_type}`);\n // Try to find the enum item by value first\n const enumItem = enumInstance.tryFromValue(v.value);\n if (enumItem) {\n debug(`Revived enumItem using value: ${v.value}`);\n return enumItem;\n }\n // If that fails, try to find by key (convert value to key format)\n const key = v.value.toLowerCase();\n const enumItemFromKey = enumInstance.tryFromKey(key);\n if (enumItemFromKey) {\n debug(`Revived enumItem using key: ${key}`);\n return enumItemFromKey;\n }\n }\n // If no matching enum type in registry, return the original serialized object\n return v;\n }\n\n if (typeof v === 'object' && v !== null && seen.has(v)) {\n return seen.get(v);\n }\n\n if (Array.isArray(v)) {\n const arr: unknown[] = [];\n seen.set(v, arr);\n for (const item of v) arr.push(walk(item));\n return arr;\n }\n if (isPlainObject(v)) {\n const out: PlainObject = {};\n seen.set(v, out);\n for (const [k, val] of Object.entries(v)) {\n out[k] = walk(val);\n }\n return out;\n }\n return v;\n };\n return walk(input) as R;\n}\n\n/**\n * Maps a plain string (for example a column value from a database query) to the\n * corresponding Smart Enum item by calling `tryFromValue` on the given enum.\n *\n * Use this when you already know which enum type a field uses and the stored\n * value is the enum’s wire `value` string (same shape `tryFromValue` expects).\n *\n * @param value - Raw value; only strings are resolved—anything else returns `undefined`\n * @param smartEnum - Smart enum instance (`AnyEnumLike<TItem>`; same shape as registry entries)\n * @param strict - When `true`, throws if the string does not match any member; when `false`, returns `undefined`\n * @returns The matching enum item, or `undefined` if not found (non-string input always yields `undefined`)\n *\n * @example\n * ```typescript\n * const item = reviveEnumField(row.status, UserStatus);\n * const mustMatch = reviveEnumField(row.code, OrderStatus, true);\n * ```\n */\nexport const reviveEnumField = <TItem>(\n value: unknown,\n smartEnum: AnyEnumLike<TItem>,\n strict = false,\n): TItem | undefined => {\n if (typeof value !== 'string') return undefined;\n\n const revived = smartEnum.tryFromValue(value);\n if (revived !== undefined) return revived;\n\n if (strict) {\n throw new Error(`Unknown enum value: ${JSON.stringify(value)}`);\n }\n\n return undefined;\n};\n","import { isSmartEnumItem } from '../utilities/typeGuards.js';\nimport type { DatabaseFormat } from '../types.js';\n\ntype PlainObject = Record<string, unknown>;\n\nconst isPlainObject = (x: unknown): x is PlainObject =>\n typeof x === 'object' &&\n x !== null &&\n Object.getPrototypeOf(x) === Object.prototype;\n\n/**\n * Recursively replaces smart enum items with their `.value` strings for persistence.\n * Inbound revival requires explicit mapping (`reviveRowFromDatabase`, etc.).\n */\nexport const prepareForDatabase = <T>(payload: T): DatabaseFormat<T> => {\n const seen = new WeakMap<object, unknown>();\n\n const walk = (v: unknown): unknown => {\n if (isSmartEnumItem(v)) {\n return v.value;\n }\n\n if (typeof v === 'object' && v !== null && seen.has(v)) {\n return seen.get(v);\n }\n\n if (Array.isArray(v)) {\n const arr: unknown[] = [];\n seen.set(v, arr);\n for (const item of v) {\n arr.push(walk(item));\n }\n return arr;\n }\n if (isPlainObject(v)) {\n const out: PlainObject = {};\n seen.set(v, out);\n for (const [k, val] of Object.entries(v)) {\n out[k] = walk(val);\n }\n return out;\n }\n return v;\n };\n\n return walk(payload) as DatabaseFormat<T>;\n};\n","export class EnumRevivalError extends Error {\n public constructor(\n message: string,\n public readonly path: string,\n public readonly value: unknown,\n ) {\n super(message);\n this.name = 'EnumRevivalError';\n }\n}\n","import type { ReviveRowOptions } from '../types.js';\n\nimport { EnumRevivalError } from './enumRevivalError.js';\n\nexport const reviveRowFromDatabase = <T extends Record<string, unknown>>(\n row: T,\n options: ReviveRowOptions,\n): T => {\n const { fieldEnumMapping, strict = false } = options;\n const out = { ...row } as Record<string, unknown>;\n\n for (const [field, smartEnum] of Object.entries(fieldEnumMapping)) {\n if (!Object.hasOwn(out, field)) {\n continue;\n }\n const raw = out[field];\n\n if (typeof raw === 'string') {\n const revived = smartEnum.tryFromValue(raw);\n if (revived !== undefined) {\n out[field] = revived as unknown;\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive field ${JSON.stringify(field)}: unknown enum value ${JSON.stringify(raw)}`,\n field,\n raw,\n );\n }\n continue;\n }\n\n if (Array.isArray(raw)) {\n const revivedItems: unknown[] = [];\n for (const item of raw) {\n if (typeof item !== 'string') {\n revivedItems.push(item);\n continue;\n }\n const revived = smartEnum.tryFromValue(item);\n if (revived !== undefined) {\n revivedItems.push(revived);\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive field ${JSON.stringify(field)}: unknown enum value ${JSON.stringify(item)} in array`,\n field,\n item,\n );\n } else {\n revivedItems.push(item);\n }\n }\n out[field] = revivedItems;\n continue;\n }\n }\n\n return out as T;\n};\n","import type { RevivePayloadOptions, SmartEnumLike } from '../types.js';\n\nimport { EnumRevivalError } from './enumRevivalError.js';\n\ntype PlainObject = Record<string, unknown>;\n\n/** Plain data objects (including `structuredClone` output where prototype may not be Object.prototype). */\nconst isObjectRecord = (x: unknown): x is PlainObject =>\n typeof x === 'object' && x !== null && !Array.isArray(x);\n\ntype PathSeg = { type: 'prop'; name: string } | { type: 'arrayEach' };\n\nconst parsePath = (pathStr: string): PathSeg[] => {\n const tokens = pathStr.split('.').filter(Boolean);\n const segs: PathSeg[] = [];\n\n for (const token of tokens) {\n if (token.endsWith('[]')) {\n const name = token.slice(0, -2);\n if (name.length === 0) {\n throw new Error(\n `Invalid enum revival path \"${pathStr}\": empty key before []`,\n );\n }\n segs.push({ type: 'prop', name }, { type: 'arrayEach' });\n } else {\n segs.push({ type: 'prop', name: token });\n }\n }\n\n const last = segs.at(-1);\n if (!last || last.type !== 'prop') {\n throw new Error(\n `Invalid enum revival path \"${pathStr}\": must end with a property name (not [])`,\n );\n }\n\n return segs;\n};\n\nconst reviveLeaf = (\n host: PlainObject,\n key: string,\n smartEnum: SmartEnumLike,\n strict: boolean,\n pathLabel: string,\n): void => {\n const raw = host[key];\n\n if (typeof raw === 'string') {\n const revived = smartEnum.tryFromValue(raw);\n if (revived !== undefined) {\n host[key] = revived as unknown;\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": unknown enum value ${JSON.stringify(raw)}`,\n pathLabel,\n raw,\n );\n }\n return;\n }\n\n if (Array.isArray(raw)) {\n const revivedItems: unknown[] = [];\n for (const item of raw) {\n if (typeof item !== 'string') {\n revivedItems.push(item);\n continue;\n }\n const revived = smartEnum.tryFromValue(item);\n if (revived !== undefined) {\n revivedItems.push(revived);\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": unknown enum value ${JSON.stringify(item)} in array`,\n pathLabel,\n item,\n );\n } else {\n revivedItems.push(item);\n }\n }\n host[key] = revivedItems;\n return;\n }\n};\n\nconst walkPath = (\n value: unknown,\n segs: PathSeg[],\n segIndex: number,\n smartEnum: SmartEnumLike,\n strict: boolean,\n pathLabel: string,\n): void => {\n const seg = segs[segIndex];\n if (seg === undefined) {\n return;\n }\n\n const isLast = segIndex === segs.length - 1;\n\n if (isLast) {\n if (seg.type !== 'prop') {\n return;\n }\n if (!isObjectRecord(value)) {\n if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": expected object at parent of \"${seg.name}\"`,\n pathLabel,\n value,\n );\n }\n return;\n }\n reviveLeaf(value, seg.name, smartEnum, strict, pathLabel);\n return;\n }\n\n if (seg.type === 'prop') {\n if (!isObjectRecord(value)) {\n if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": expected object at \"${seg.name}\"`,\n pathLabel,\n value,\n );\n }\n return;\n }\n walkPath(value[seg.name], segs, segIndex + 1, smartEnum, strict, pathLabel);\n return;\n }\n\n if (seg.type === 'arrayEach') {\n if (!Array.isArray(value)) {\n if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": expected array before nested path`,\n pathLabel,\n value,\n );\n }\n return;\n }\n for (const el of value) {\n walkPath(el, segs, segIndex + 1, smartEnum, strict, pathLabel);\n }\n }\n};\n\nexport const revivePayloadFromDatabase = <T>(\n payload: T,\n options: RevivePayloadOptions,\n): T => {\n const { pathEnumMapping, strict = false } = options;\n const root = structuredClone(payload);\n\n for (const [pathStr, smartEnum] of Object.entries(pathEnumMapping)) {\n const segs = parsePath(pathStr);\n walkPath(root as unknown, segs, 0, smartEnum, strict, pathStr);\n }\n\n return root;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,2BAA0C;;;ACanC,IAAM,kBAAkB,OAAO,iBAAiB;AAChD,IAAM,gBAAgB,OAAO,eAAe;AAC5C,IAAM,aAAa,OAAO,YAAY;;;ACOtC,IAAM,kBAAkB,CAC7B,MAMG;AACH,SACE,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,QAAQ,IAAI,GAAG,eAAe,MAAM;AAExE;AAaO,IAAM,cAAc,CAAC,MAAmC;AAC7D,SAAO,CAAC,CAAC,KAAK,OAAO,MAAM,YAAY,QAAQ,IAAI,GAAG,UAAU,MAAM;AACxE;;;AC3CO,IAAM,iBAAiB,CAAC,GAAY,MAAwB;AACjE,MAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG;AAC9C,WAAO;AAAA,EACT;AAEA,SACE,QAAQ,IAAI,GAAG,aAAa,MAAM,QAAQ,IAAI,GAAG,aAAa,KAC9D,EAAE,UAAU,EAAE;AAElB;;;ACZO,IAAM,sBAAsB,CACjC,cAC2B;AAC3B,QAAM,SAAS,CAAwB,OAAU,WAC/C,UAAU,KAAK,UAAQ,KAAK,KAAK,MAAM,MAAM;AAE/C,QAAM,YAAY,CAChB,OACA,QACA,UACG;AACH,UAAM,OAAO,OAAO,OAAO,MAAM;AACjC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,WAAW,KAAK,eAAe,OAAO,MAAM,CAAC,GAAG;AAAA,IAClE;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,WAAW,WAAS,UAAU,SAAS,OAAyB,OAAO;AAAA,IACvE,cAAc,WACZ,QAAQ,OAAO,SAAS,KAAuB,IAAI;AAAA,IAErD,SAAS,SAAO,UAAU,OAAO,KAAqB,KAAK;AAAA,IAC3D,YAAY,SAAQ,MAAM,OAAO,OAAO,GAAmB,IAAI;AAAA,IAE/D,QAAQ;AAAA,IAER,OAAO,MAAM,CAAC,GAAG,SAAS;AAAA,IAC1B,QAAQ,MAAM,UAAU,IAAI,UAAQ,KAAK,KAAK;AAAA,IAC9C,MAAM,MAAM,UAAU,IAAI,UAAQ,KAAK,GAAG;AAAA,EAC5C;AACF;;;AChCA,IAAI;AA2BG,IAAM,2BAA2B,CACtC,YACsB,WAAW,iBAAiB;;;ALHpD,SAAS,eACP,OAC6B;AAC7B,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,OAAO;AAAA,MACZ,MAAM,IAAI,OAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,mBAAmB,CACvB,MACA,UACA,gBACA,gBAC4B;AAC5B,SAAO,eAAe,MAAM,iBAAiB;AAAA,IAC3C,OAAO;AAAA,IACP,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,eAAe;AAAA,IACzC,OAAO;AAAA,IACP,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,sBAAsB;AAAA,IAChD,OAAO;AAAA,IACP,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,qBAAqB;AAAA,IAC/C,OAAO;AAAA,IACP,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,UAAU;AAAA,IACpC,OAAO,MAAM;AACX,YAAM,OAAO,yBAAyB,WAAW;AACjD,UAAI,SAAS,SAAS;AACpB,eAAO,KAAK;AAAA,MACd;AACA,aAAO,EAAE,mBAAmB,UAAU,OAAO,KAAK,MAAM;AAAA,IAC1D;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,cAAc;AAAA,IACxC,OAAO,MAAM,KAAK;AAAA,IAClB,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,UAAU;AAAA,IACpC,OAAO,CAAC,UAA4B,eAAe,MAAM,KAAK;AAAA,IAC9D,YAAY;AAAA,EACd,CAAC;AAED,SAAO,eAAe,MAAM,SAAS;AAAA,IACnC,OAAO,CAAC,aAAsD;AAC5D,YAAM,UAAU,SAAS,KAAK,GAAG;AACjC,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,0BAA0B,KAAK,GAAG,cAAc,QAAQ;AAAA,QAC1D;AAAA,MACF;AACA,aAAO,QAAQ,IAAI;AAAA,IACrB;AAAA,IACA,YAAY;AAAA,EACd,CAAC;AACD,SAAO;AACT;AAEA,IAAM,mBAAmB,CACvB,GACA,eAEA,WAAW;AAAA,EACT,CAAC,KAAK,cAAc;AAClB,QAAI,UAAU,GAAG,IAAI,UAAU,OAAO,CAAC;AACvC,WAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,WAAO,mCAAa,CAAC;AAAA,IACrB,aAAS,kCAAY,CAAC;AAAA,EACxB;AACF;AAEF,SAAS,oBAIP,UACA,OACA,wBACA,aACuC;AACvC,QAAM,yBAAkD;AAAA,IACtD,EAAE,KAAK,SAAS,QAAQ,kCAAa;AAAA,IACrC,EAAE,KAAK,WAAW,QAAQ,iCAAY;AAAA,IACtC,GAAI,0BAA0B,CAAC;AAAA,EACjC;AAIA,QAAM,eAED,CAAC;AAEN,QAAM,iBAAiB,OAAO,qBAAqB;AACnD,MAAI,QAAQ;AAEZ,aAAW,OAAO,OAAO;AACvB,QAAI,OAAO,UAAU,eAAe,KAAK,OAAO,GAAG,GAAG;AACpD,YAAM,WAAW;AACjB,YAAM,QAAQ,MAAM,QAAQ;AAE5B,YAAM,eAAe;AAAA,QACnB;AAAA,QACA,KAAK;AAAA,QACL,GAAG,iBAAiB,UAAU,sBAAsB;AAAA,QACpD,GAAG;AAAA,MACL;AAEA,YAAM,WAAW;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,aAAO,OAAO,QAAQ;AACtB,mBAAa,QAAsB,IAAI;AACvC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,mBAAmB;AAAA,IACvB,OAAO,OAAO,YAAY;AAAA,EAC5B;AAEA,QAAM,aAAa;AAAA,IACjB,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AAEA,SAAO,eAAe,YAAY,YAAY;AAAA,IAC5C,OAAO;AAAA,IACP,YAAY;AAAA,EACd,CAAC;AAED,SAAO,OAAO,UAAU;AAExB,SAAO;AACT;AAkBO,SAAS,YACd,UACA,OAIA;AACA,QAAM,aAAa,eAAe,MAAM,KAAK;AAC7C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;;;AMvDO,IAAM,kBAAkB,CAC7B,OACA,WACA,SAAS,UACa;AACtB,MAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAM,UAAU,UAAU,aAAa,KAAK;AAC5C,MAAI,YAAY,OAAW,QAAO;AAElC,MAAI,QAAQ;AACV,UAAM,IAAI,MAAM,uBAAuB,KAAK,UAAU,KAAK,CAAC,EAAE;AAAA,EAChE;AAEA,SAAO;AACT;;;AC1KA,IAAM,gBAAgB,CAAC,MACrB,OAAO,MAAM,YACb,MAAM,QACN,OAAO,eAAe,CAAC,MAAM,OAAO;AAM/B,IAAM,qBAAqB,CAAI,YAAkC;AACtE,QAAM,OAAO,oBAAI,QAAyB;AAE1C,QAAM,OAAO,CAAC,MAAwB;AACpC,QAAI,gBAAgB,CAAC,GAAG;AACtB,aAAO,EAAE;AAAA,IACX;AAEA,QAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG;AACtD,aAAO,KAAK,IAAI,CAAC;AAAA,IACnB;AAEA,QAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,YAAM,MAAiB,CAAC;AACxB,WAAK,IAAI,GAAG,GAAG;AACf,iBAAW,QAAQ,GAAG;AACpB,YAAI,KAAK,KAAK,IAAI,CAAC;AAAA,MACrB;AACA,aAAO;AAAA,IACT;AACA,QAAI,cAAc,CAAC,GAAG;AACpB,YAAM,MAAmB,CAAC;AAC1B,WAAK,IAAI,GAAG,GAAG;AACf,iBAAW,CAAC,GAAG,GAAG,KAAK,OAAO,QAAQ,CAAC,GAAG;AACxC,YAAI,CAAC,IAAI,KAAK,GAAG;AAAA,MACnB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,OAAO;AACrB;;;AC9CO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACnC,YACL,SACgB,MACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;ACLO,IAAM,wBAAwB,CACnC,KACA,YACM;AACN,QAAM,EAAE,kBAAkB,SAAS,MAAM,IAAI;AAC7C,QAAM,MAAM,EAAE,GAAG,IAAI;AAErB,aAAW,CAAC,OAAO,SAAS,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AACjE,QAAI,CAAC,OAAO,OAAO,KAAK,KAAK,GAAG;AAC9B;AAAA,IACF;AACA,UAAM,MAAM,IAAI,KAAK;AAErB,QAAI,OAAO,QAAQ,UAAU;AAC3B,YAAM,UAAU,UAAU,aAAa,GAAG;AAC1C,UAAI,YAAY,QAAW;AACzB,YAAI,KAAK,IAAI;AAAA,MACf,WAAW,QAAQ;AACjB,cAAM,IAAI;AAAA,UACR,uBAAuB,KAAK,UAAU,KAAK,CAAC,wBAAwB,KAAK,UAAU,GAAG,CAAC;AAAA,UACvF;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,YAAM,eAA0B,CAAC;AACjC,iBAAW,QAAQ,KAAK;AACtB,YAAI,OAAO,SAAS,UAAU;AAC5B,uBAAa,KAAK,IAAI;AACtB;AAAA,QACF;AACA,cAAM,UAAU,UAAU,aAAa,IAAI;AAC3C,YAAI,YAAY,QAAW;AACzB,uBAAa,KAAK,OAAO;AAAA,QAC3B,WAAW,QAAQ;AACjB,gBAAM,IAAI;AAAA,YACR,uBAAuB,KAAK,UAAU,KAAK,CAAC,wBAAwB,KAAK,UAAU,IAAI,CAAC;AAAA,YACxF;AAAA,YACA;AAAA,UACF;AAAA,QACF,OAAO;AACL,uBAAa,KAAK,IAAI;AAAA,QACxB;AAAA,MACF;AACA,UAAI,KAAK,IAAI;AACb;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AClDA,IAAM,iBAAiB,CAAC,MACtB,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAIzD,IAAM,YAAY,CAAC,YAA+B;AAChD,QAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAChD,QAAM,OAAkB,CAAC;AAEzB,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,IAAI,GAAG;AACxB,YAAM,OAAO,MAAM,MAAM,GAAG,EAAE;AAC9B,UAAI,KAAK,WAAW,GAAG;AACrB,cAAM,IAAI;AAAA,UACR,8BAA8B,OAAO;AAAA,QACvC;AAAA,MACF;AACA,WAAK,KAAK,EAAE,MAAM,QAAQ,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAAA,IACzD,OAAO;AACL,WAAK,KAAK,EAAE,MAAM,QAAQ,MAAM,MAAM,CAAC;AAAA,IACzC;AAAA,EACF;AAEA,QAAM,OAAO,KAAK,GAAG,EAAE;AACvB,MAAI,CAAC,QAAQ,KAAK,SAAS,QAAQ;AACjC,UAAM,IAAI;AAAA,MACR,8BAA8B,OAAO;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAM,aAAa,CACjB,MACA,KACA,WACA,QACA,cACS;AACT,QAAM,MAAM,KAAK,GAAG;AAEpB,MAAI,OAAO,QAAQ,UAAU;AAC3B,UAAM,UAAU,UAAU,aAAa,GAAG;AAC1C,QAAI,YAAY,QAAW;AACzB,WAAK,GAAG,IAAI;AAAA,IACd,WAAW,QAAQ;AACjB,YAAM,IAAI;AAAA,QACR,uBAAuB,SAAS,yBAAyB,KAAK,UAAU,GAAG,CAAC;AAAA,QAC5E;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,UAAM,eAA0B,CAAC;AACjC,eAAW,QAAQ,KAAK;AACtB,UAAI,OAAO,SAAS,UAAU;AAC5B,qBAAa,KAAK,IAAI;AACtB;AAAA,MACF;AACA,YAAM,UAAU,UAAU,aAAa,IAAI;AAC3C,UAAI,YAAY,QAAW;AACzB,qBAAa,KAAK,OAAO;AAAA,MAC3B,WAAW,QAAQ;AACjB,cAAM,IAAI;AAAA,UACR,uBAAuB,SAAS,yBAAyB,KAAK,UAAU,IAAI,CAAC;AAAA,UAC7E;AAAA,UACA;AAAA,QACF;AAAA,MACF,OAAO;AACL,qBAAa,KAAK,IAAI;AAAA,MACxB;AAAA,IACF;AACA,SAAK,GAAG,IAAI;AACZ;AAAA,EACF;AACF;AAEA,IAAM,WAAW,CACf,OACA,MACA,UACA,WACA,QACA,cACS;AACT,QAAM,MAAM,KAAK,QAAQ;AACzB,MAAI,QAAQ,QAAW;AACrB;AAAA,EACF;AAEA,QAAM,SAAS,aAAa,KAAK,SAAS;AAE1C,MAAI,QAAQ;AACV,QAAI,IAAI,SAAS,QAAQ;AACvB;AAAA,IACF;AACA,QAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,UAAI,QAAQ;AACV,cAAM,IAAI;AAAA,UACR,uBAAuB,SAAS,oCAAoC,IAAI,IAAI;AAAA,UAC5E;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AACA,eAAW,OAAO,IAAI,MAAM,WAAW,QAAQ,SAAS;AACxD;AAAA,EACF;AAEA,MAAI,IAAI,SAAS,QAAQ;AACvB,QAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,UAAI,QAAQ;AACV,cAAM,IAAI;AAAA,UACR,uBAAuB,SAAS,0BAA0B,IAAI,IAAI;AAAA,UAClE;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AACA,aAAS,MAAM,IAAI,IAAI,GAAG,MAAM,WAAW,GAAG,WAAW,QAAQ,SAAS;AAC1E;AAAA,EACF;AAEA,MAAI,IAAI,SAAS,aAAa;AAC5B,QAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,UAAI,QAAQ;AACV,cAAM,IAAI;AAAA,UACR,uBAAuB,SAAS;AAAA,UAChC;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AACA,eAAW,MAAM,OAAO;AACtB,eAAS,IAAI,MAAM,WAAW,GAAG,WAAW,QAAQ,SAAS;AAAA,IAC/D;AAAA,EACF;AACF;AAEO,IAAM,4BAA4B,CACvC,SACA,YACM;AACN,QAAM,EAAE,iBAAiB,SAAS,MAAM,IAAI;AAC5C,QAAM,OAAO,gBAAgB,OAAO;AAEpC,aAAW,CAAC,SAAS,SAAS,KAAK,OAAO,QAAQ,eAAe,GAAG;AAClE,UAAM,OAAO,UAAU,OAAO;AAC9B,aAAS,MAAiB,MAAM,GAAG,WAAW,QAAQ,OAAO;AAAA,EAC/D;AAEA,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/database.ts","../src/enumerations.ts","../src/utilities/typeGuards.ts","../src/utilities/enumItemsEqual.ts","../src/extensionMethods.ts","../src/utilities/serializationMode.ts","../src/utilities/transformation.ts","../src/db/prepareForDatabase.ts","../src/db/enumRevivalError.ts","../src/db/reviveRowFromDatabase.ts","../src/db/revivePayloadFromDatabase.ts"],"sourcesContent":["/**\n * Smart Enums — database persistence helpers (`src/db`).\n *\n * Transport wire revival (`initializeSmartEnumMappings`, `reviveAfterTransport`)\n * is exported from `@reharik/smart-enum/transport` and `@reharik/smart-enum` root.\n *\n * @example\n * ```typescript\n * import {\n * enumeration,\n * prepareForDatabase,\n * reviveEnumField,\n * reviveRowFromDatabase,\n * } from '@reharik/smart-enum/database';\n * ```\n */\n\nexport { enumeration } from './enumerations.js';\nexport { isSmartEnumItem, isSmartEnum } from './utilities/typeGuards.js';\nexport { reviveEnumField } from './utilities/transformation.js';\nexport {\n prepareForDatabase,\n reviveRowFromDatabase,\n revivePayloadFromDatabase,\n EnumRevivalError,\n} from './db/index.js';\nexport type { Logger } from './utilities/logger.js';\nexport type {\n Enumeration,\n AnyEnumLike,\n DatabaseFormat,\n SmartApiHelperConfig,\n LogLevel,\n SmartEnumMappingsConfig,\n EnumLikeBase,\n SmartEnumLike,\n FieldEnumMapping,\n ReviveRowOptions,\n PathEnumMapping,\n RevivePayloadOptions,\n StandardEnumItemBase,\n StandardEnumItem,\n} from './types.js';\n","import { capitalCase, constantCase } from 'case-anything';\n\nimport { addExtensionMethods } from './extensionMethods.js';\nimport {\n SerializationMode,\n type EnumFromNormalizedObject,\n type EnumItemFromNormalizedObject,\n type EnumMemberUnionFromNormalizedObject,\n type EnumerationProps,\n type FinalizableEnumItem,\n type FinalizedEnumFields,\n type NormalizedInputType,\n type ObjectEnumInput,\n type PropertyAutoFormatter,\n type StandardEnumItem,\n} from './types.js';\nimport { enumItemsEqual } from './utilities/enumItemsEqual.js';\nimport { resolveSerializationMode } from './utilities/serializationMode.js';\n\nexport type EnumItem<TEnum> = {\n [K in keyof TEnum]: TEnum[K] extends { __smart_enum_brand: true }\n ? TEnum[K]\n : never;\n}[keyof TEnum];\n\n/**\n * Creation-time name-uniqueness guard.\n *\n * Enum names are the wire/identity key: equality keys on `__smart_enum_type`\n * (see {@link enumItemsEqual}) and revival looks enums up by name (see\n * `reviveSmartEnums`). Two *different* enums sharing a name would make both\n * ambiguous, so we reject that collision here — a name may only be reused if the\n * new definition has the *same* members (that is harmless: members compare equal\n * across instances under the string-based identity).\n *\n * The signature is the sorted set of `key=value` pairs; extras/formatters/\n * `serializeAs` don't affect wire identity and are intentionally ignored.\n *\n * Limitation: this registry is module-scoped, so it only catches collisions\n * within a single library instance — duplicate copies of `@reharik/smart-enum`\n * each keep their own registry. That is acceptable: it catches the likely\n * accidental case (defining conflicting enums in one app) and documents the\n * invariant the string-based identity relies on.\n */\nconst registeredEnumSignatures = new Map<string, string>();\n\nconst registerEnumName = (\n enumType: string,\n items: readonly { key: string; value: string }[],\n): void => {\n const signature = items\n .map(item => `${item.key}=${item.value}`)\n .sort()\n .join('|');\n\n const existing = registeredEnumSignatures.get(enumType);\n if (existing !== undefined && existing !== signature) {\n throw new Error(\n `Enum name '${enumType}' is already defined with different members; ` +\n `enum names must be unique because they are the wire/identity key ` +\n `(equality and revival key on __smart_enum_type + value).`,\n );\n }\n registeredEnumSignatures.set(enumType, signature);\n};\n\nfunction normalizeInput<TInput extends readonly string[] | ObjectEnumInput>(\n input: TInput,\n): NormalizedInputType<TInput> {\n if (Array.isArray(input)) {\n return Object.fromEntries(\n input.map(k => [k, {}]),\n ) as NormalizedInputType<TInput>;\n }\n\n return input as NormalizedInputType<TInput>;\n}\n\nconst finalizeEnumItem = <T extends { value: string; key: string }>(\n item: T,\n enumType: string,\n serializeAs: SerializationMode | undefined,\n): T & FinalizedEnumFields => {\n // `__smart_enum_brand` is the package-stable detection marker read by\n // `isSmartEnumItem`; combined with the string `__smart_enum_type` + `value`\n // below it fully identifies an item across enum instances and package copies.\n Object.defineProperty(item, '__smart_enum_brand', {\n value: true,\n enumerable: false,\n });\n\n Object.defineProperty(item, '__smart_enum_type', {\n value: enumType,\n enumerable: false,\n });\n\n Object.defineProperty(item, 'toJSON', {\n value: () => {\n const mode = resolveSerializationMode(serializeAs);\n if (mode === 'value') {\n return item.value;\n }\n return { __smart_enum_type: enumType, value: item.value };\n },\n enumerable: false,\n });\n\n Object.defineProperty(item, 'toPostgres', {\n value: () => item.value,\n enumerable: false,\n });\n\n Object.defineProperty(item, 'equals', {\n value: (other: StandardEnumItem) => enumItemsEqual(item, other),\n enumerable: false,\n });\n\n Object.defineProperty(item, 'match', {\n value: (handlers: Record<string, (i: unknown) => unknown>) => {\n const handler = handlers[item.key];\n if (!handler) {\n throw new Error(\n `match: no handler for '${item.key}' on enum '${enumType}'`,\n );\n }\n return handler(item);\n },\n enumerable: false,\n });\n return item as T & FinalizedEnumFields;\n};\n\nconst formatProperties = (\n k: string,\n formatters: PropertyAutoFormatter[],\n): { value: string; display: string } & Record<string, string> =>\n formatters.reduce(\n (acc, formatter) => {\n acc[formatter.key] = formatter.format(k);\n return acc;\n },\n {\n value: constantCase(k),\n display: capitalCase(k),\n } as { value: string; display: string } & Record<string, string>,\n );\n\nfunction buildEnumFromObject<\n TName extends string,\n TObj extends ObjectEnumInput,\n>(\n enumType: TName,\n input: TObj,\n propertyAutoFormatters?: PropertyAutoFormatter[],\n serializeAs?: SerializationMode,\n): EnumFromNormalizedObject<TObj, TName> {\n const formattersWithDefaults: PropertyAutoFormatter[] = [\n { key: 'value', format: constantCase },\n { key: 'display', format: capitalCase },\n ...(propertyAutoFormatters ?? []),\n ];\n\n type TItem = EnumMemberUnionFromNormalizedObject<TObj, TName>;\n\n const rawEnumItems: Partial<{\n [K in keyof TObj]: EnumItemFromNormalizedObject<TObj, K, TName>;\n }> = {};\n\n let index = 0;\n\n for (const key in input) {\n if (Object.prototype.hasOwnProperty.call(input, key)) {\n const typedKey = key;\n const value = input[typedKey];\n\n const enumItemBase = {\n index,\n key: typedKey,\n ...formatProperties(typedKey, formattersWithDefaults),\n ...value,\n } as FinalizableEnumItem & TObj[typeof typedKey];\n\n const enumItem = finalizeEnumItem(\n enumItemBase,\n enumType,\n serializeAs,\n ) as unknown as TItem;\n\n Object.freeze(enumItem);\n rawEnumItems[typedKey as keyof TObj] = enumItem;\n index++;\n }\n }\n\n registerEnumName(\n enumType,\n Object.values(rawEnumItems) as FinalizableEnumItem[],\n );\n\n const extensionMethods = addExtensionMethods<TItem>(\n Object.values(rawEnumItems) as TItem[],\n );\n\n const enumObject = {\n ...rawEnumItems,\n ...extensionMethods,\n } as EnumFromNormalizedObject<TObj, TName>;\n\n // `__smart_enum` is the package-stable marker read by `isSmartEnum`\n // (replaces the former module-level Symbol so detection survives across copies).\n Object.defineProperty(enumObject, '__smart_enum', {\n value: true,\n enumerable: false,\n });\n\n Object.freeze(enumObject);\n\n return enumObject;\n}\n\nexport function enumeration<\n const TArr extends readonly string[],\n const TName extends string = string,\n>(\n enumType: TName,\n props: EnumerationProps<TArr>,\n): EnumFromNormalizedObject<NormalizedInputType<TArr>, TName>;\n\nexport function enumeration<\n const TObj extends ObjectEnumInput,\n const TName extends string = string,\n>(\n enumType: TName,\n props: EnumerationProps<TObj>,\n): EnumFromNormalizedObject<NormalizedInputType<TObj>, TName>;\n\nexport function enumeration<const TName extends string = string>(\n enumType: TName,\n props: EnumerationProps<readonly string[] | ObjectEnumInput>,\n): EnumFromNormalizedObject<\n NormalizedInputType<readonly string[] | ObjectEnumInput>,\n TName\n> {\n const normalized = normalizeInput(props.input);\n return buildEnumFromObject(\n enumType,\n normalized,\n props.propertyAutoFormatters,\n props.serializeAs,\n );\n}\n","import { SmartEnumItemSerialized, SmartEnumLike } from '../types.js';\n\n/**\n * Runtime type guard to detect Smart Enum items.\n *\n * Detection is **structural** and package-stable: it keys on the string\n * properties `__smart_enum_brand === true`, string `__smart_enum_type` and\n * string `value`. It does not read any Symbol, so it recognizes items created\n * by a *different* copy of `@reharik/smart-enum` (duplicate-package resistant).\n *\n * Because detection is structural, a self-describing wire object that carries\n * the brand — `{ __smart_enum_brand: true, __smart_enum_type, value }` — also\n * passes. That is intentional: it lets `equals`/`has` treat a revival-boundary\n * object as the member it represents. A plain serialized shape *without* the\n * brand (`{ __smart_enum_type, value }`, as emitted by `serializeSmartEnums`)\n * is still rejected here; use {@link isSerializedSmartEnumItem} for that.\n *\n * @example\n * ```typescript\n * import { Status } from './status';\n * const item = Status.active;\n * isSmartEnumItem(item); // true\n * isSmartEnumItem({ key: 'active', value: 'ACTIVE' }); // false (no brand)\n * if (isSmartEnumItem(x)) {\n * console.log(x.value, x.__smart_enum_type); // narrowed to enum item\n * }\n * ```\n */\nexport const isSmartEnumItem = (\n x: unknown,\n): x is {\n key: string;\n value: string;\n index?: number;\n __smart_enum_type: string;\n} => {\n return (\n !!x &&\n typeof x === 'object' &&\n Reflect.get(x, '__smart_enum_brand') === true &&\n typeof Reflect.get(x, '__smart_enum_type') === 'string' &&\n typeof Reflect.get(x, 'value') === 'string'\n );\n};\n\n/**\n * Runtime type guard to detect a full Smart Enum object.\n *\n * Detection is **structural** and package-stable: it keys on the string marker\n * property `__smart_enum === true` that `enumeration()` stamps on every enum\n * object. It does not read any Symbol, so it recognizes enum objects created by\n * a *different* copy of `@reharik/smart-enum` (duplicate-package resistant).\n *\n * @example\n * ```typescript\n * import { MyEnum } from './blah';\n * isSmartEnum(MyEnum) === true; // true\n * isSmartEnum(MyEnum.one) === false; // false (this is an item, not the enum)\n * ```\n */\nexport const isSmartEnum = (x: unknown): x is SmartEnumLike => {\n return (\n !!x && typeof x === 'object' && Reflect.get(x, '__smart_enum') === true\n );\n};\n\n/**\n * Runtime type guard to detect a serialized Smart Enum item created by this library.\n * Returns true if the value has `__smart_enum_type` and `value` (wire/database shape).\n *\n * @example\n * ```typescript\n * const wire = { __smart_enum_type: 'Status', value: 'ACTIVE' };\n * isSerializedSmartEnumItem(wire); // true\n * isSerializedSmartEnumItem(Status.active); // false (live enum item)\n * if (isSerializedSmartEnumItem(x)) {\n * reviveItem(x.__smart_enum_type, x.value); // narrowed to SmartEnumItemSerialized\n * }\n * ```\n */\nexport const isSerializedSmartEnumItem = (\n x: unknown,\n): x is SmartEnumItemSerialized => {\n return (\n !!x &&\n typeof x === 'object' &&\n Reflect.has(x, '__smart_enum_type') &&\n Reflect.has(x, 'value')\n );\n};\n","import { isSmartEnumItem } from './typeGuards.js';\n\n/**\n * Value-based equality for smart enum items.\n *\n * Compares only the package-stable string identity — `__smart_enum_type` plus\n * `value` — so it holds across separate `enumeration()` calls of the same\n * logical enum and across duplicate copies of `@reharik/smart-enum` (it does\n * not depend on any per-instance or module-level Symbol). This makes it a safe\n * replacement for `===`, which fails in both of those situations.\n */\nexport const enumItemsEqual = (a: unknown, b: unknown): boolean => {\n if (!isSmartEnumItem(a) || !isSmartEnumItem(b)) return false;\n return a.__smart_enum_type === b.__smart_enum_type && a.value === b.value;\n};\n","import type { CoreEnumMethods, StandardEnumItem } from './types.js';\nimport { enumItemsEqual } from './utilities/enumItemsEqual.js';\nexport const addExtensionMethods = <TItem extends StandardEnumItem>(\n enumItems: readonly TItem[],\n): CoreEnumMethods<TItem> => {\n const findBy = <K extends keyof TItem>(field: K, target: TItem[K]) =>\n enumItems.find(item => item[field] === target);\n\n const requireBy = <K extends keyof TItem>(\n field: K,\n target: TItem[K],\n label: string,\n ) => {\n const item = findBy(field, target);\n if (!item) {\n throw new Error(`No enum ${label} found for '${String(target)}'`);\n }\n return item;\n };\n\n return {\n fromValue: value => requireBy('value', value as TItem['value'], 'value'),\n tryFromValue: value =>\n value ? findBy('value', value as TItem['value']) : undefined,\n\n fromKey: key => requireBy('key', key as TItem['key'], 'key'),\n tryFromKey: key => (key ? findBy('key', key as TItem['key']) : undefined),\n\n equals: enumItemsEqual,\n\n has: (x: unknown): x is TItem =>\n enumItems.some(item => enumItemsEqual(item, x)),\n\n items: () => [...enumItems],\n values: () => enumItems.map(item => item.value),\n keys: () => enumItems.map(item => item.key),\n };\n};\n","import { SerializationMode } from '../types.js';\n\nlet globalDefault: SerializationMode | undefined;\n\n/**\n * Set the global default serialization mode for all smart-enum items\n * that don't have a per-enum serializeAs option.\n *\n * Call once at app startup, before any JSON.stringify happens on enum items.\n *\n * @example\n * setDefaultSerializationMode('value');\n */\nexport const setDefaultSerializationMode = (mode: SerializationMode): void => {\n globalDefault = mode;\n};\n\n/**\n * Reset the global default to its initial unset state.\n * Primarily useful for tests.\n */\nexport const resetDefaultSerializationMode = (): void => {\n globalDefault = undefined;\n};\n\n/**\n * Resolve the effective serialization mode for an enum item.\n * Per-enum option wins, then global, then 'wrapped'.\n */\nexport const resolveSerializationMode = (\n perEnum: SerializationMode | undefined,\n): SerializationMode => perEnum ?? globalDefault ?? 'wrapped';\n","// serializeSmartEnums.ts\nexport { isSmartEnumItem, isSmartEnum } from './typeGuards.js';\nimport type { SerializedSmartEnums, AnyEnumLike } from '../types.js';\n\nimport { debug } from './logger.js';\nimport { isSerializedSmartEnumItem, isSmartEnumItem } from './typeGuards.js';\n\ntype PlainObject = Record<string, unknown>;\n\nconst isPlainObject = (x: unknown): x is PlainObject =>\n typeof x === 'object' &&\n x !== null &&\n Object.getPrototypeOf(x) === Object.prototype;\n\n/**\n * Recursively replaces Smart Enum items with self-describing objects\n * `{ __smart_enum_type, value }` for JSON transport or storage.\n *\n * @param input - Object or array that may contain enum items\n * @returns Same structure with enum items replaced by serialized shape\n *\n * @example\n * ```typescript\n * const dto = { id: '1', status: Status.active, color: Color.red };\n * const wire = serializeSmartEnums(dto);\n * // wire: { id: '1', status: { __smart_enum_type: 'Status', value: 'ACTIVE' }, color: { __smart_enum_type: 'Color', value: 'RED' } }\n * ```\n */\n// Overloads:\n// 1) Inferred\nexport function serializeSmartEnums<T>(input: T): SerializedSmartEnums<T>;\n// 2) Return-type only (constrained to objects/arrays)\nexport function serializeSmartEnums<\n S extends Readonly<PlainObject> | readonly unknown[],\n>(input: unknown): S;\n// Implementation\nexport function serializeSmartEnums(input: unknown): unknown {\n const seen = new WeakMap<object, unknown>();\n\n const walk = (v: unknown): unknown => {\n if (isSmartEnumItem(v)) {\n return {\n __smart_enum_type: v.__smart_enum_type,\n value: v.value,\n };\n }\n if (typeof v === 'object' && v !== null && seen.has(v)) {\n return seen.get(v);\n }\n\n if (Array.isArray(v)) {\n const arr: unknown[] = [];\n seen.set(v, arr);\n for (const item of v) {\n arr.push(walk(item));\n }\n return arr;\n }\n if (isPlainObject(v)) {\n const out: PlainObject = {};\n seen.set(v, out);\n for (const [k, val] of Object.entries(v)) {\n out[k] = walk(val);\n }\n return out;\n }\n return v;\n };\n\n return walk(input);\n}\n\n/**\n * Recursively revives serialized enum objects back to Smart Enum items\n * using a registry of enum types. Expects payload to contain\n * `{ __smart_enum_type, value }` where the type exists in the registry.\n *\n * @param input - Serialized payload (e.g. from JSON)\n * @param registry - Map of enum type name to enum object (e.g. `{ Status, Color }`)\n * @returns Payload with serialized enums revived to enum items\n *\n * @example\n * ```typescript\n * const wire = { status: { __smart_enum_type: 'Status', value: 'ACTIVE' } };\n * const revived = reviveSmartEnums(wire, { Status, Color });\n * // revived.status === Status.active\n * ```\n */\nexport function reviveSmartEnums<R>(\n input: unknown,\n registry: Record<string, AnyEnumLike>,\n): R {\n const seen = new WeakMap<object, unknown>();\n\n const walk = (v: unknown): unknown => {\n // Handle self-describing enum objects with __smart_enum_type and value\n if (isSerializedSmartEnumItem(v)) {\n debug(`Found serialized smartEnum: ${v.__smart_enum_type}`);\n const enumInstance = registry[v.__smart_enum_type];\n if (enumInstance) {\n debug(`Found enumInstance in registry: ${v.__smart_enum_type}`);\n // Try to find the enum item by value first\n const enumItem = enumInstance.tryFromValue(v.value);\n if (enumItem) {\n debug(`Revived enumItem using value: ${v.value}`);\n return enumItem;\n }\n // If that fails, try to find by key (convert value to key format)\n const key = v.value.toLowerCase();\n const enumItemFromKey = enumInstance.tryFromKey(key);\n if (enumItemFromKey) {\n debug(`Revived enumItem using key: ${key}`);\n return enumItemFromKey;\n }\n }\n // If no matching enum type in registry, return the original serialized object\n return v;\n }\n\n if (typeof v === 'object' && v !== null && seen.has(v)) {\n return seen.get(v);\n }\n\n if (Array.isArray(v)) {\n const arr: unknown[] = [];\n seen.set(v, arr);\n for (const item of v) arr.push(walk(item));\n return arr;\n }\n if (isPlainObject(v)) {\n const out: PlainObject = {};\n seen.set(v, out);\n for (const [k, val] of Object.entries(v)) {\n out[k] = walk(val);\n }\n return out;\n }\n return v;\n };\n return walk(input) as R;\n}\n\n/**\n * Maps a plain string (for example a column value from a database query) to the\n * corresponding Smart Enum item by calling `tryFromValue` on the given enum.\n *\n * Use this when you already know which enum type a field uses and the stored\n * value is the enum’s wire `value` string (same shape `tryFromValue` expects).\n *\n * @param value - Raw value; only strings are resolved—anything else returns `undefined`\n * @param smartEnum - Smart enum instance (`AnyEnumLike<TItem>`; same shape as registry entries)\n * @param strict - When `true`, throws if the string does not match any member; when `false`, returns `undefined`\n * @returns The matching enum item, or `undefined` if not found (non-string input always yields `undefined`)\n *\n * @example\n * ```typescript\n * const item = reviveEnumField(row.status, UserStatus);\n * const mustMatch = reviveEnumField(row.code, OrderStatus, true);\n * ```\n */\nexport const reviveEnumField = <TItem>(\n value: unknown,\n smartEnum: AnyEnumLike<TItem>,\n strict = false,\n): TItem | undefined => {\n if (typeof value !== 'string') return undefined;\n\n const revived = smartEnum.tryFromValue(value);\n if (revived !== undefined) return revived;\n\n if (strict) {\n throw new Error(`Unknown enum value: ${JSON.stringify(value)}`);\n }\n\n return undefined;\n};\n","import { isSmartEnumItem } from '../utilities/typeGuards.js';\nimport type { DatabaseFormat } from '../types.js';\n\ntype PlainObject = Record<string, unknown>;\n\nconst isPlainObject = (x: unknown): x is PlainObject =>\n typeof x === 'object' &&\n x !== null &&\n Object.getPrototypeOf(x) === Object.prototype;\n\n/**\n * Recursively replaces smart enum items with their `.value` strings for persistence.\n * Inbound revival requires explicit mapping (`reviveRowFromDatabase`, etc.).\n */\nexport const prepareForDatabase = <T>(payload: T): DatabaseFormat<T> => {\n const seen = new WeakMap<object, unknown>();\n\n const walk = (v: unknown): unknown => {\n if (isSmartEnumItem(v)) {\n return v.value;\n }\n\n if (typeof v === 'object' && v !== null && seen.has(v)) {\n return seen.get(v);\n }\n\n if (Array.isArray(v)) {\n const arr: unknown[] = [];\n seen.set(v, arr);\n for (const item of v) {\n arr.push(walk(item));\n }\n return arr;\n }\n if (isPlainObject(v)) {\n const out: PlainObject = {};\n seen.set(v, out);\n for (const [k, val] of Object.entries(v)) {\n out[k] = walk(val);\n }\n return out;\n }\n return v;\n };\n\n return walk(payload) as DatabaseFormat<T>;\n};\n","export class EnumRevivalError extends Error {\n public constructor(\n message: string,\n public readonly path: string,\n public readonly value: unknown,\n ) {\n super(message);\n this.name = 'EnumRevivalError';\n }\n}\n","import type { ReviveRowOptions } from '../types.js';\n\nimport { EnumRevivalError } from './enumRevivalError.js';\n\nexport const reviveRowFromDatabase = <T extends Record<string, unknown>>(\n row: T,\n options: ReviveRowOptions,\n): T => {\n const { fieldEnumMapping, strict = false } = options;\n const out = { ...row } as Record<string, unknown>;\n\n for (const [field, smartEnum] of Object.entries(fieldEnumMapping)) {\n if (!Object.hasOwn(out, field)) {\n continue;\n }\n const raw = out[field];\n\n if (typeof raw === 'string') {\n const revived = smartEnum.tryFromValue(raw);\n if (revived !== undefined) {\n out[field] = revived as unknown;\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive field ${JSON.stringify(field)}: unknown enum value ${JSON.stringify(raw)}`,\n field,\n raw,\n );\n }\n continue;\n }\n\n if (Array.isArray(raw)) {\n const revivedItems: unknown[] = [];\n for (const item of raw) {\n if (typeof item !== 'string') {\n revivedItems.push(item);\n continue;\n }\n const revived = smartEnum.tryFromValue(item);\n if (revived !== undefined) {\n revivedItems.push(revived);\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive field ${JSON.stringify(field)}: unknown enum value ${JSON.stringify(item)} in array`,\n field,\n item,\n );\n } else {\n revivedItems.push(item);\n }\n }\n out[field] = revivedItems;\n continue;\n }\n }\n\n return out as T;\n};\n","import type { RevivePayloadOptions, SmartEnumLike } from '../types.js';\n\nimport { EnumRevivalError } from './enumRevivalError.js';\n\ntype PlainObject = Record<string, unknown>;\n\n/** Plain data objects (including `structuredClone` output where prototype may not be Object.prototype). */\nconst isObjectRecord = (x: unknown): x is PlainObject =>\n typeof x === 'object' && x !== null && !Array.isArray(x);\n\ntype PathSeg = { type: 'prop'; name: string } | { type: 'arrayEach' };\n\nconst parsePath = (pathStr: string): PathSeg[] => {\n const tokens = pathStr.split('.').filter(Boolean);\n const segs: PathSeg[] = [];\n\n for (const token of tokens) {\n if (token.endsWith('[]')) {\n const name = token.slice(0, -2);\n if (name.length === 0) {\n throw new Error(\n `Invalid enum revival path \"${pathStr}\": empty key before []`,\n );\n }\n segs.push({ type: 'prop', name }, { type: 'arrayEach' });\n } else {\n segs.push({ type: 'prop', name: token });\n }\n }\n\n const last = segs.at(-1);\n if (!last || last.type !== 'prop') {\n throw new Error(\n `Invalid enum revival path \"${pathStr}\": must end with a property name (not [])`,\n );\n }\n\n return segs;\n};\n\nconst reviveLeaf = (\n host: PlainObject,\n key: string,\n smartEnum: SmartEnumLike,\n strict: boolean,\n pathLabel: string,\n): void => {\n const raw = host[key];\n\n if (typeof raw === 'string') {\n const revived = smartEnum.tryFromValue(raw);\n if (revived !== undefined) {\n host[key] = revived as unknown;\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": unknown enum value ${JSON.stringify(raw)}`,\n pathLabel,\n raw,\n );\n }\n return;\n }\n\n if (Array.isArray(raw)) {\n const revivedItems: unknown[] = [];\n for (const item of raw) {\n if (typeof item !== 'string') {\n revivedItems.push(item);\n continue;\n }\n const revived = smartEnum.tryFromValue(item);\n if (revived !== undefined) {\n revivedItems.push(revived);\n } else if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": unknown enum value ${JSON.stringify(item)} in array`,\n pathLabel,\n item,\n );\n } else {\n revivedItems.push(item);\n }\n }\n host[key] = revivedItems;\n return;\n }\n};\n\nconst walkPath = (\n value: unknown,\n segs: PathSeg[],\n segIndex: number,\n smartEnum: SmartEnumLike,\n strict: boolean,\n pathLabel: string,\n): void => {\n const seg = segs[segIndex];\n if (seg === undefined) {\n return;\n }\n\n const isLast = segIndex === segs.length - 1;\n\n if (isLast) {\n if (seg.type !== 'prop') {\n return;\n }\n if (!isObjectRecord(value)) {\n if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": expected object at parent of \"${seg.name}\"`,\n pathLabel,\n value,\n );\n }\n return;\n }\n reviveLeaf(value, seg.name, smartEnum, strict, pathLabel);\n return;\n }\n\n if (seg.type === 'prop') {\n if (!isObjectRecord(value)) {\n if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": expected object at \"${seg.name}\"`,\n pathLabel,\n value,\n );\n }\n return;\n }\n walkPath(value[seg.name], segs, segIndex + 1, smartEnum, strict, pathLabel);\n return;\n }\n\n if (seg.type === 'arrayEach') {\n if (!Array.isArray(value)) {\n if (strict) {\n throw new EnumRevivalError(\n `Cannot revive path \"${pathLabel}\": expected array before nested path`,\n pathLabel,\n value,\n );\n }\n return;\n }\n for (const el of value) {\n walkPath(el, segs, segIndex + 1, smartEnum, strict, pathLabel);\n }\n }\n};\n\nexport const revivePayloadFromDatabase = <T>(\n payload: T,\n options: RevivePayloadOptions,\n): T => {\n const { pathEnumMapping, strict = false } = options;\n const root = structuredClone(payload);\n\n for (const [pathStr, smartEnum] of Object.entries(pathEnumMapping)) {\n const segs = parsePath(pathStr);\n walkPath(root as unknown, segs, 0, smartEnum, strict, pathStr);\n }\n\n return root;\n};\n"],"mappings":"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","names":[]}
|
package/dist/database.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DatabaseFormat,
|
|
2
|
-
export { A as AnyEnumLike,
|
|
1
|
+
import { D as DatabaseFormat, k as ReviveRowOptions, j as RevivePayloadOptions } from './transformation-CuTsvU5q.cjs';
|
|
2
|
+
export { A as AnyEnumLike, d as EnumLikeBase, E as Enumeration, F as FieldEnumMapping, g as LogLevel, L as Logger, P as PathEnumMapping, m as SmartApiHelperConfig, o as SmartEnumLike, p as SmartEnumMappingsConfig, v as StandardEnumItem, w as StandardEnumItemBase, e as enumeration, a as isSmartEnum, i as isSmartEnumItem, b as reviveEnumField } from './transformation-CuTsvU5q.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Recursively replaces smart enum items with their `.value` strings for persistence.
|
package/dist/database.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DatabaseFormat,
|
|
2
|
-
export { A as AnyEnumLike,
|
|
1
|
+
import { D as DatabaseFormat, k as ReviveRowOptions, j as RevivePayloadOptions } from './transformation-CuTsvU5q.js';
|
|
2
|
+
export { A as AnyEnumLike, d as EnumLikeBase, E as Enumeration, F as FieldEnumMapping, g as LogLevel, L as Logger, P as PathEnumMapping, m as SmartApiHelperConfig, o as SmartEnumLike, p as SmartEnumMappingsConfig, v as StandardEnumItem, w as StandardEnumItemBase, e as enumeration, a as isSmartEnum, i as isSmartEnumItem, b as reviveEnumField } from './transformation-CuTsvU5q.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Recursively replaces smart enum items with their `.value` strings for persistence.
|
package/dist/database.js
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
// src/enumerations.ts
|
|
2
2
|
import { capitalCase, constantCase } from "case-anything";
|
|
3
3
|
|
|
4
|
-
// src/types.ts
|
|
5
|
-
var SMART_ENUM_ITEM = Symbol("smart-enum-item");
|
|
6
|
-
var SMART_ENUM_ID = Symbol("smart-enum-id");
|
|
7
|
-
var SMART_ENUM = Symbol("smart-enum");
|
|
8
|
-
|
|
9
4
|
// src/utilities/typeGuards.ts
|
|
10
5
|
var isSmartEnumItem = (x) => {
|
|
11
|
-
return !!x && typeof x === "object" && Reflect.get(x,
|
|
6
|
+
return !!x && typeof x === "object" && Reflect.get(x, "__smart_enum_brand") === true && typeof Reflect.get(x, "__smart_enum_type") === "string" && typeof Reflect.get(x, "value") === "string";
|
|
12
7
|
};
|
|
13
8
|
var isSmartEnum = (x) => {
|
|
14
|
-
return !!x && typeof x === "object" && Reflect.get(x,
|
|
9
|
+
return !!x && typeof x === "object" && Reflect.get(x, "__smart_enum") === true;
|
|
15
10
|
};
|
|
16
11
|
|
|
17
12
|
// src/utilities/enumItemsEqual.ts
|
|
18
13
|
var enumItemsEqual = (a, b) => {
|
|
19
|
-
if (!isSmartEnumItem(a) || !isSmartEnumItem(b))
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
return Reflect.get(a, SMART_ENUM_ID) === Reflect.get(b, SMART_ENUM_ID) && a.value === b.value;
|
|
14
|
+
if (!isSmartEnumItem(a) || !isSmartEnumItem(b)) return false;
|
|
15
|
+
return a.__smart_enum_type === b.__smart_enum_type && a.value === b.value;
|
|
23
16
|
};
|
|
24
17
|
|
|
25
18
|
// src/extensionMethods.ts
|
|
@@ -38,6 +31,7 @@ var addExtensionMethods = (enumItems) => {
|
|
|
38
31
|
fromKey: (key) => requireBy("key", key, "key"),
|
|
39
32
|
tryFromKey: (key) => key ? findBy("key", key) : void 0,
|
|
40
33
|
equals: enumItemsEqual,
|
|
34
|
+
has: (x) => enumItems.some((item) => enumItemsEqual(item, x)),
|
|
41
35
|
items: () => [...enumItems],
|
|
42
36
|
values: () => enumItems.map((item) => item.value),
|
|
43
37
|
keys: () => enumItems.map((item) => item.key)
|
|
@@ -49,6 +43,17 @@ var globalDefault;
|
|
|
49
43
|
var resolveSerializationMode = (perEnum) => perEnum ?? globalDefault ?? "wrapped";
|
|
50
44
|
|
|
51
45
|
// src/enumerations.ts
|
|
46
|
+
var registeredEnumSignatures = /* @__PURE__ */ new Map();
|
|
47
|
+
var registerEnumName = (enumType, items) => {
|
|
48
|
+
const signature = items.map((item) => `${item.key}=${item.value}`).sort().join("|");
|
|
49
|
+
const existing = registeredEnumSignatures.get(enumType);
|
|
50
|
+
if (existing !== void 0 && existing !== signature) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Enum name '${enumType}' is already defined with different members; enum names must be unique because they are the wire/identity key (equality and revival key on __smart_enum_type + value).`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
registeredEnumSignatures.set(enumType, signature);
|
|
56
|
+
};
|
|
52
57
|
function normalizeInput(input) {
|
|
53
58
|
if (Array.isArray(input)) {
|
|
54
59
|
return Object.fromEntries(
|
|
@@ -57,15 +62,7 @@ function normalizeInput(input) {
|
|
|
57
62
|
}
|
|
58
63
|
return input;
|
|
59
64
|
}
|
|
60
|
-
var finalizeEnumItem = (item, enumType,
|
|
61
|
-
Object.defineProperty(item, SMART_ENUM_ITEM, {
|
|
62
|
-
value: true,
|
|
63
|
-
enumerable: false
|
|
64
|
-
});
|
|
65
|
-
Object.defineProperty(item, SMART_ENUM_ID, {
|
|
66
|
-
value: enumInstanceId,
|
|
67
|
-
enumerable: false
|
|
68
|
-
});
|
|
65
|
+
var finalizeEnumItem = (item, enumType, serializeAs) => {
|
|
69
66
|
Object.defineProperty(item, "__smart_enum_brand", {
|
|
70
67
|
value: true,
|
|
71
68
|
enumerable: false
|
|
@@ -123,7 +120,6 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
123
120
|
...propertyAutoFormatters ?? []
|
|
124
121
|
];
|
|
125
122
|
const rawEnumItems = {};
|
|
126
|
-
const enumInstanceId = Symbol("smart-enum-instance");
|
|
127
123
|
let index = 0;
|
|
128
124
|
for (const key in input) {
|
|
129
125
|
if (Object.prototype.hasOwnProperty.call(input, key)) {
|
|
@@ -138,7 +134,6 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
138
134
|
const enumItem = finalizeEnumItem(
|
|
139
135
|
enumItemBase,
|
|
140
136
|
enumType,
|
|
141
|
-
enumInstanceId,
|
|
142
137
|
serializeAs
|
|
143
138
|
);
|
|
144
139
|
Object.freeze(enumItem);
|
|
@@ -146,6 +141,10 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
146
141
|
index++;
|
|
147
142
|
}
|
|
148
143
|
}
|
|
144
|
+
registerEnumName(
|
|
145
|
+
enumType,
|
|
146
|
+
Object.values(rawEnumItems)
|
|
147
|
+
);
|
|
149
148
|
const extensionMethods = addExtensionMethods(
|
|
150
149
|
Object.values(rawEnumItems)
|
|
151
150
|
);
|
|
@@ -153,7 +152,7 @@ function buildEnumFromObject(enumType, input, propertyAutoFormatters, serializeA
|
|
|
153
152
|
...rawEnumItems,
|
|
154
153
|
...extensionMethods
|
|
155
154
|
};
|
|
156
|
-
Object.defineProperty(enumObject,
|
|
155
|
+
Object.defineProperty(enumObject, "__smart_enum", {
|
|
157
156
|
value: true,
|
|
158
157
|
enumerable: false
|
|
159
158
|
});
|