Skip to content

Commit 2a5c05a

Browse files
committed
feat: enhance enum handling with functional labels
1 parent 4887283 commit 2a5c05a

File tree

15 files changed

+459
-118
lines changed

15 files changed

+459
-118
lines changed

.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
module.exports = {
22
extends: ['./node_modules/@tiny-codes/code-style-all-in-one/eslint/config/typescript'],
3+
parserOptions: {
4+
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
5+
},
36
settings: {
47
'import/resolver': {
58
typescript: true,

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
# enum-plus Changelog
44

5+
## 3.1.5
6+
7+
2025-11-20
8+
9+
### Features
10+
11+
- ✨ Enhance enum creation to support function labels and enum name.
12+
13+
### Bug Fixes
14+
15+
- 🐞 Fix the issue where `enum.meta` is always empty in `meta-only` mode.
16+
517
## 3.1.4
618

719
2025-11-19

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "enum-plus",
3-
"version": "3.1.4",
3+
"version": "3.1.5",
44
"description": "A drop-in replacement for native enum. Like native enum but much better!",
55
"keywords": [
66
"enum",
@@ -190,7 +190,7 @@
190190
"father": "^4.6.3",
191191
"glob": "^11.1.0",
192192
"jest": "^29.7.0",
193-
"jsoneo": "^1.0.2",
193+
"jsoneo": "^1.0.3",
194194
"npm-run-all2": "^8.0.4",
195195
"playwright": "^1.55.0",
196196
"rollup": "^4.50.0",

src/enum-collection.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ export class EnumCollectionClass<
127127
* set.
128128
*/
129129
get name(): string | undefined {
130+
if (typeof this.__options__?.name === 'function') {
131+
return this.__options__.name(undefined!);
132+
}
130133
const localize = this.__options__?.localize ?? localizer.localize;
131134
if (typeof localize === 'function') {
132135
return localize(this.__options__?.name);

src/enum-item.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import { internalConfig, localizer } from './global-config';
2-
import type { EnumItemInit, EnumKey, EnumValue, LocalizeInterface, ValueTypeFromSingleInit } from './types';
2+
import type {
3+
EnumItemInit,
4+
EnumItemLabel,
5+
EnumKey,
6+
EnumValue,
7+
LocalizeInterface,
8+
ValueTypeFromSingleInit,
9+
} from './types';
310
import { IS_ENUM_ITEM } from './utils';
411

512
/**
@@ -20,7 +27,7 @@ export class EnumItemClass<
2027
const P = any,
2128
> {
2229
private _options: EnumItemOptions<T, K, V, P> | undefined;
23-
private _label: string | undefined;
30+
private _label: EnumItemLabel | undefined;
2431
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2532
private _localize: (content: string | undefined) => any;
2633

@@ -34,10 +41,10 @@ export class EnumItemClass<
3441
* @param raw The original initialization object | 原始初始化对象
3542
* @param options Optional settings for the enum item | 枚举项的可选设置
3643
*/
37-
constructor(key: K, value: V, label: string, raw: T, options?: EnumItemOptions<T, K, V, P>) {
44+
constructor(key: K, value: V, label: EnumItemLabel, raw: T, options?: EnumItemOptions<T, K, V, P>) {
3845
this.key = key;
3946
this.value = value;
40-
this.label = label;
47+
this.label = label as string;
4148
this.raw = raw;
4249

4350
// Should use _label instead of label closure, to make sure it can be serialized correctly
@@ -62,6 +69,10 @@ export class EnumItemClass<
6269
const labelPrefix = this._options?.labelPrefix;
6370
const autoLabel = this._options?.autoLabel ?? internalConfig.autoLabel;
6471
let localeKey = this._label;
72+
if (typeof localeKey === 'function') {
73+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
74+
return localeKey(this as any);
75+
}
6576
if (autoLabel && labelPrefix != null) {
6677
if (typeof autoLabel === 'function') {
6778
localeKey = autoLabel({

src/enum-items.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { EnumItemClass } from './enum-item';
33
import type {
44
EnumInit,
55
EnumItemInit,
6+
EnumItemLabel,
67
EnumKey,
78
EnumValue,
89
ExactEqual,
@@ -107,7 +108,7 @@ export class EnumItemsArray<
107108
Object.keys(itemRaw).forEach((k) => {
108109
const metaKey = k as Exclude<keyof T[keyof T], 'key' | 'value' | 'label'>;
109110
if (metaKey !== 'key' && metaKey !== 'value' && metaKey !== 'label') {
110-
if (!meta[metaKey]) {
111+
if (meta[metaKey] == null) {
111112
meta[metaKey] = [];
112113
}
113114
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -865,42 +866,42 @@ function parseEnumItem<
865866
V extends EnumValue,
866867
>(init: T, key: K): StandardEnumItemInit<V> {
867868
let value: V;
868-
let label: string;
869+
let label: EnumItemLabel;
869870
if (init != null) {
870871
if (typeof init === 'number' || typeof init === 'string' || typeof init === 'symbol') {
871872
value = init as V;
872-
label = key as string;
873+
label = key as EnumItemLabel;
873874
} else if (typeof init === 'object') {
874875
// Initialize using object
875876
if (Object.prototype.toString.call(init) === '[object Object]') {
876877
if ('value' in init && Object.keys(init).some((k) => k === 'value')) {
877878
// type of {value, label}
878879
value = (init.value ?? key) as V;
879880
if ('label' in init && Object.keys(init).some((k) => k === 'label')) {
880-
label = init.label as string;
881+
label = init.label!;
881882
} else {
882-
label = key as string;
883+
label = key as EnumItemLabel;
883884
}
884885
} else if ('label' in init && Object.keys(init).some((k) => k === 'label')) {
885886
// typeof {label}
886887
value = key as unknown as V;
887-
label = init.label ?? (key as string);
888+
label = init.label ?? (key as EnumItemLabel);
888889
} else {
889890
// {} empty object
890891
value = key as unknown as V;
891-
label = key as string;
892+
label = key as EnumItemLabel;
892893
}
893894
} else {
894895
// Probably Date, RegExp and other primitive types
895896
value = init as V;
896-
label = key as string;
897+
label = key as EnumItemLabel;
897898
}
898899
} else {
899900
throw new Error(`Invalid enum item: ${JSON.stringify(init)}`);
900901
}
901902
} else {
902903
value = key as unknown as V;
903-
label = key as string;
904+
label = key as EnumItemLabel;
904905
}
905906
return { value, label };
906907
}

src/extension.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ declare module 'enum-plus/extension' {
2424
*
2525
* **CN:** 枚举本地化文本的Key值,可以用来增强编辑器的智能提示
2626
*/
27-
LocaleKeys: NonNullable<string>;
27+
LocaleKeys: // eslint-disable-next-line @typescript-eslint/ban-types
28+
| (string & {})
29+
| ((
30+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
31+
item: import('./enum-item').EnumItemClass<import('./types').StandardEnumItemInit<import('./types').EnumValue>>
32+
) => string | undefined);
2833
}
2934
}

src/localize-interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { EnumLocaleExtends } from 'enum-plus/extension';
22

33
export type LocalizeInterface = (
4-
localeKey: EnumLocaleExtends['LocaleKeys'] | undefined
4+
localeKey: Exclude<EnumLocaleExtends['LocaleKeys'], (...args: any[]) => string | undefined> | undefined
55
// eslint-disable-next-line @typescript-eslint/no-explicit-any
66
) => any;

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,6 @@ export const IS_ENUM_ITEMS = Symbol.for('[IsEnumItems]');
7474
* English, does not provide actual localization functions
7575
* - **CN:** 默认的全局本地化函数,仅用于将内置资源解析为英文,并不提供实际的本地化功能
7676
*/
77-
export const defaultLocalize: LocalizeInterface = (content) => {
77+
export const defaultLocalize: LocalizeInterface = (content): string | undefined => {
7878
return content;
7979
};

0 commit comments

Comments
 (0)