UNPKG

enum-plus

Version:

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

270 lines 10.6 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 {EnumItemClass<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, P> | undefined} options Enum item options */ constructor(raw, options) { super(); // Do not use class field here, because don't want print this field in Node.js Object.defineProperty(this, '__raw__', { value: raw, enumerable: false, writable: false, configurable: false, }); // 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[utils_1.KEYS] = keys; Object.freeze(keys); const items = []; const meta = {}; this.meta = meta; const named = {}; this.named = named; 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 (metaKey !== 'key' && metaKey !== 'value' && metaKey !== 'label') { if (meta[metaKey] == null) { meta[metaKey] = []; } // eslint-disable-next-line @typescript-eslint/no-explicit-any const metaValue = itemRaw[metaKey]; if (metaValue != null) { meta[metaKey].push(metaValue); } } }); } }); // Freeze meta arrays Object.keys(meta).forEach((k) => { Object.freeze(meta[k]); }); // Generate values array const values = parsed.map((item) => item.value); this[utils_1.VALUES] = values; Object.freeze(values); // Generate labels array Object.defineProperty(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, configurable: false, }); this._runtimeError = undefined; Object.defineProperty(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}`; }, writable: false, enumerable: false, configurable: false, }); } [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; } 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