UNPKG

enum-plus

Version:

A drop-in replacement for native enum. Like native enum but much better!

297 lines 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EnumItemsArray = void 0; exports.parseKeys = parseKeys; const enum_item_1 = require("./enum-item"); const utils_1 = require("./utils"); /** * Enum items array, mostly are simple wrappers for EnumCollectionClass * * @template T Type of the initialization data of the enum collection * * @class EnumItemsArray * * @extends {EnumItemInterface<T, K, V>[]} * * @implements {IEnumItems<T, K, V>} */ class EnumItemsArray extends Array { /** * - **EN:** A boolean value indicates that this is an enum items array. * - **CN:** 布尔值,表示这是一个枚举项数组 */ // Do not use readonly field here, because don't want print this field in Node.js // eslint-disable-next-line @typescript-eslint/class-literal-property-style get [utils_1.IS_ENUM_ITEMS]() { return true; } /** * Instantiate an enum items array * * @memberof EnumItemsArray * * @param {T} raw Original initialization data object * @param {EnumItemOptions<T[K], K, V, LP> | undefined} options Enum item options */ constructor(raw, options) { super(); const define = Object.defineProperty; const freeze = Object.freeze; // Generate keys array // exclude number keys with a "reverse mapping" value, it means those "reverse mapping" keys of number enums const keys = parseKeys(raw); const parsed = keys.map((key) => parseEnumItem(raw[key], key)); // this[KEYS] = keys; define(this, utils_1.KEYS, { value: keys }); freeze(keys); const items = []; const named = {}; this.named = named; const meta = {}; this.meta = meta; keys.forEach((key, index) => { const { value, label } = parsed[index]; const item = new enum_item_1.EnumItemClass(key, value, label, raw[key], options); items.push(item); this.push(item); named[key] = item; // Collect custom meta fields const itemRaw = raw[key]; if (itemRaw && typeof itemRaw === 'object') { Object.keys(itemRaw).forEach((k) => { const metaKey = k; if (!['value', 'label'].includes(k)) { if (meta[metaKey] == null) { meta[metaKey] = []; } const metaValue = item[k]; if (metaValue != null) { meta[metaKey].push(metaValue); } } }); } }); const autoLocalizeMeta = options === null || options === void 0 ? void 0 : options.autoLocalizeMeta; // Freeze meta arrays Object.keys(meta).forEach((k) => { const autoLocalize = autoLocalizeMeta && (autoLocalizeMeta === true || autoLocalizeMeta.includes(k)); if (autoLocalize) { const descriptor = { get: function get() { return ( // @ts-expect-error: because we attach items array to the getter function Array.from(this._items) // @ts-expect-error: because we attach items array to the getter function .map((item) => item[get._key]) .filter((v) => v != null)); }, enumerable: true, configurable: false, }; // @ts-expect-error: because we attach items array to the getter function descriptor.get._key = k; define(meta, k, descriptor); } else { freeze(meta[k]); } }); if (autoLocalizeMeta) { define(meta, '_items', { value: this }); } // Generate values array const values = parsed.map((item) => item.value); // Do not use class field here, because don't want print this field in Node.js define(this, utils_1.VALUES, { value: values }); Object.freeze(values); // Generate labels array define(this, 'labels', { get: function () { // Cannot save to static array because labels may be localized contents // Should not use `items` in the closure because the getter function cannot be fully serialized return Array.from(this).map((item) => item.label); }, enumerable: true, }); // Do not use class field here, because don't want print this field in Node.js define(this, '__raw__', { value: raw }); this._runtimeError = undefined; define(this, '_runtimeError', { value: function (name) { return `The ${name} property of the enumeration is only allowed to be used to declare the ts type, and cannot be accessed at runtime! Please use the typeof operator in the ts type, for example: typeof Week.${name}`; }, enumerable: false, }); freeze(EnumItemsArray.prototype); // Do not freeze in constructor. See the enum-collection. // freeze(this); } [Symbol.hasInstance](instance) { // intentionally use == to support both number and string format value return this.some( // eslint-disable-next-line eqeqeq (i) => instance == i.value || instance === i.key); } label(keyOrValue) { var _a, _b; // Find by value, then try key // eslint-disable-next-line @typescript-eslint/no-explicit-any return (_b = ((_a = this.find((i) => i.value === keyOrValue)) !== null && _a !== void 0 ? _a : this.find((i) => i.key === keyOrValue))) === null || _b === void 0 ? void 0 : _b.label; } item(keyOrValue) { var _a; // eslint-disable-next-line @typescript-eslint/no-explicit-any return ((_a = this.find((i) => i.value === keyOrValue)) !== null && _a !== void 0 ? _a : this.find((i) => i.key === keyOrValue)); } key(value) { var _a; // eslint-disable-next-line @typescript-eslint/no-explicit-any return (_a = this.find((i) => i.value === value)) === null || _a === void 0 ? void 0 : _a.key; } raw(keyOrValue) { if (keyOrValue == null) { // Return the original initialization object return this.__raw__; } else { // Find by key if (Object.keys(this.__raw__).some((k) => k === keyOrValue)) { return this.__raw__[keyOrValue]; } // Find by value const itemByValue = this.find((i) => i.value === keyOrValue); if (itemByValue) { return itemByValue.raw; } return undefined; } } has(keyOrValue) { return this.some((i) => i.value === keyOrValue || i.key === keyOrValue); } findBy(field, value) { return this.find((item) => { var _a, _b; if (field === 'key' || field === 'value') { return item[field] === value; } else if (field === 'label') { // eslint-disable-next-line @typescript-eslint/no-explicit-any return ((_a = item.raw) === null || _a === void 0 ? void 0 : _a.label) === value || item.label === value; } else { // For other fields, use the raw object to find // eslint-disable-next-line @typescript-eslint/no-explicit-any return ((_b = item.raw) === null || _b === void 0 ? void 0 : _b[field]) === value; } // eslint-disable-next-line @typescript-eslint/no-explicit-any }); } toList(config) { const { valueField = 'value', labelField = 'label', extra } = config !== null && config !== void 0 ? config : {}; return Array.from(this).map((item) => { const valueFieldName = typeof valueField === 'function' ? valueField(item) : valueField; const labelFieldName = typeof labelField === 'function' ? labelField(item) : labelField; const extraData = extra ? extra(item) : {}; const listItem = Object.assign({ [valueFieldName]: item.value, [labelFieldName]: item.label }, extraData); return listItem; }); } toMap(config) { if (!config) { return this.reduce((prev, cur) => { prev[cur.value] = cur.label; return prev; }, // eslint-disable-next-line @typescript-eslint/no-explicit-any {}); } const { keySelector = 'value', valueSelector = 'label' } = config; return this.reduce((prev, cur) => { let key; if (typeof keySelector === 'function') { key = keySelector(cur); } else { key = cur[keySelector]; } // eslint-disable-next-line @typescript-eslint/no-explicit-any let value; if (typeof valueSelector === 'function') { value = valueSelector(cur); } else { value = cur[valueSelector]; } prev[key] = value; return prev; }, {}); } /** Stub method, only for typing usages, not for runtime calling */ get valueType() { throw new Error(this._runtimeError('valueType')); } /** Stub method, only for typing usages, not for runtime calling */ get keyType() { throw new Error(this._runtimeError('keyType')); } /** Stub method, only for typing usages, not for runtime calling */ get rawType() { throw new Error(this._runtimeError('rawType')); } } exports.EnumItemsArray = EnumItemsArray; function parseKeys(raw) { return Object.keys(raw).filter((k) => { var _a; return !(/^-?\d+$/.test(k) && k === `${(_a = raw[raw[k]]) !== null && _a !== void 0 ? _a : ''}`); }); } function parseEnumItem(init, key) { var _a, _b; 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 = ((_a = init.value) !== null && _a !== void 0 ? _a : 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 = (_b = init.label) !== null && _b !== void 0 ? _b : 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-items.js.map