enum-plus
Version:
A drop-in replacement for native enum. Like native enum but much better!
170 lines (164 loc) • 5.08 kB
JavaScript
import { EnumItemClass } from "./enum-item";
import { EnumItemsArray } from "./enum-values";
import { ENUM_COLLECTION, ITEMS, KEYS, VALUES } from "./utils";
/**
* **EN:** Enum collection extension base class, used to extend the Enums
*
* **CN:** 枚举集合扩展基类,用于扩展枚举
*/
// @ts-expect-error: because of typing extend in tests
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class EnumExtensionClass {}
/**
* **EN:** Enum collection
*
* **CN:** 枚举项集合
*/
export class EnumCollectionClass extends EnumExtensionClass {
items;
keys;
/**
* **EN:** A boolean value indicates that this is an enum collection instance.
*
* **CN:** 布尔值,表示这是一个枚举集合实例
*/
[ENUM_COLLECTION] = true;
constructor(init = {}, options) {
super();
// exclude number keys with a "reverse mapping" value, it means those "reverse mapping" keys of number enums
const keys = Object.keys(init).filter(k => !(/^-?\d+$/.test(k) && k === `${init[init[k]] ?? ''}`));
const parsed = keys.map(key => parseEnumItem(init[key], key));
keys.forEach((key, index) => {
const {
value
} = parsed[index];
// @ts-expect-error: because of dynamically define property
this[key] = value;
});
Object.freeze(keys);
// @ts-expect-error: because use KEYS to avoid naming conflicts in case of 'keys' field name is taken
this[Object.keys(init).some(k => k === 'keys') ? KEYS : 'keys'] = keys;
// Build enum item data
const items = new EnumItemsArray(init, options, ...keys.map((key, index) => {
const {
value,
label
} = parsed[index];
return new EnumItemClass(key, value, label, init[key], options).readonly();
}));
// @ts-expect-error: because use ITEMS to avoid naming conflicts in case of 'items' field name is taken
this[Object.keys(init).some(k => k === 'items') ? ITEMS : 'items'] = items;
// @ts-expect-error: because use VALUES to avoid naming conflicts in case of 'values' field name is taken
this[Object.keys(init).some(k => k === 'values') ? VALUES : 'values'] = items;
// Override the `instanceof` operator rule
// @ts-expect-error: because override the instanceof operator
this[Symbol.hasInstance] = instance => {
// intentionally use == to support both number and string format value
return this.items.some(
// eslint-disable-next-line eqeqeq
i => instance == i.value || instance === i.key);
};
Object.freeze(this);
Object.freeze(this.items);
Object.freeze(this.keys);
}
key(value) {
return this.items.key(value);
}
label(keyOrValue) {
return this.items.label(keyOrValue);
}
has(keyOrValue) {
return this.items.has(keyOrValue);
}
toSelect(config) {
return this.items.toSelect(config);
}
/** @deprecated use `toSelect` instead */
options(config) {
return this.items.options(config);
}
toMenu() {
return this.items.toMenu();
}
/** @deprecated use `toMenu` instead */
menus() {
return this.items.menus();
}
toFilter() {
return this.items.toFilter();
}
/** @deprecated use `toFilter` instead */
filters() {
return this.items.filters();
}
toValueMap() {
return this.items.toValueMap();
}
/** @deprecated use `toValueMap` instead */
valuesEnum() {
return this.items.valuesEnum();
}
// eslint-disable-next-line @typescript-eslint/ban-types
raw(value) {
if (value != null) {
return this.items.raw(value);
} else {
return this.items.raw();
}
}
get valueType() {
return this.items.valueType;
}
get keyType() {
return this.items.keyType;
}
get rawType() {
return this.items.rawType;
}
}
function parseEnumItem(init, key) {
let value;
let label;
if (init != null) {
if (typeof init === 'number' || typeof init === 'string' || typeof init === 'symbol') {
value = init;
label = key;
} else if (typeof init === 'object') {
// Initialize using object
if (Object.prototype.toString.call(init) === '[object Object]') {
if ('value' in init && Object.keys(init).some(k => k === 'value')) {
// type of {value, label}
value = init.value ?? key;
if ('label' in init && Object.keys(init).some(k => k === 'label')) {
label = init.label;
} else {
label = key;
}
} else if ('label' in init && Object.keys(init).some(k => k === 'label')) {
// typeof {label}
value = key;
label = init.label ?? key;
} else {
// {} empty object
value = key;
label = key;
}
} else {
// Probably Date, RegExp and other primitive types
value = init;
label = key;
}
} else {
throw new Error(`Invalid enum item: ${JSON.stringify(init)}`);
}
} else {
value = key;
label = key;
}
return {
value,
label
};
}
//# sourceMappingURL=enum-collection.js.map