UNPKG

@etsoo/shared

Version:

TypeScript shared utilities and functions

549 lines (548 loc) 17.8 kB
"use strict"; /** * Generic object type * Narrow case, uses StringRecord * Before was wrong with {}, from 4.8 unknown = {} | null | undefined */ Object.defineProperty(exports, "__esModule", { value: true }); exports.DataTypes = void 0; BigInt.prototype.toJSON = function () { return this.toString() + "n"; }; /** * Interface data types */ var DataTypes; (function (DataTypes) { /** * Basic type and basic type array names array */ DataTypes.BasicArray = [ "number", "number[]", "bigint", "bigint[]", "date", "date[]", "boolean", "boolean[]", "string", "string[]", "unknown[]" ]; /** * Simple type enum */ let SimpleEnum; (function (SimpleEnum) { SimpleEnum[SimpleEnum["Number"] = 1] = "Number"; SimpleEnum[SimpleEnum["Bigint"] = 2] = "Bigint"; SimpleEnum[SimpleEnum["Date"] = 3] = "Date"; SimpleEnum[SimpleEnum["Boolean"] = 4] = "Boolean"; SimpleEnum[SimpleEnum["String"] = 5] = "String"; SimpleEnum[SimpleEnum["Array"] = 9] = "Array"; })(SimpleEnum = DataTypes.SimpleEnum || (DataTypes.SimpleEnum = {})); /** * Extended type enum */ let ExtendedEnum; (function (ExtendedEnum) { ExtendedEnum[ExtendedEnum["Unkwown"] = 0] = "Unkwown"; ExtendedEnum[ExtendedEnum["Int"] = 10] = "Int"; ExtendedEnum[ExtendedEnum["Money"] = 11] = "Money"; ExtendedEnum[ExtendedEnum["IntMoney"] = 12] = "IntMoney"; ExtendedEnum[ExtendedEnum["DateTime"] = 13] = "DateTime"; ExtendedEnum[ExtendedEnum["Email"] = 21] = "Email"; ExtendedEnum[ExtendedEnum["Phone"] = 22] = "Phone"; ExtendedEnum[ExtendedEnum["URL"] = 23] = "URL"; ExtendedEnum[ExtendedEnum["Logo"] = 24] = "Logo"; })(ExtendedEnum = DataTypes.ExtendedEnum || (DataTypes.ExtendedEnum = {})); /** * Combined type enum */ DataTypes.CombinedEnum = { ...SimpleEnum, ...ExtendedEnum }; /** * Horizontal align enum */ let HAlignEnum; (function (HAlignEnum) { HAlignEnum[HAlignEnum["Left"] = 1] = "Left"; HAlignEnum[HAlignEnum["Center"] = 2] = "Center"; HAlignEnum[HAlignEnum["Right"] = 3] = "Right"; })(HAlignEnum = DataTypes.HAlignEnum || (DataTypes.HAlignEnum = {})); /** * Vertical align enum */ let VAlignEnum; (function (VAlignEnum) { VAlignEnum[VAlignEnum["Top"] = 1] = "Top"; VAlignEnum[VAlignEnum["Center"] = 2] = "Center"; VAlignEnum[VAlignEnum["Bottom"] = 3] = "Bottom"; })(VAlignEnum = DataTypes.VAlignEnum || (DataTypes.VAlignEnum = {})); /** * Placement enum */ let PlacementEnum; (function (PlacementEnum) { PlacementEnum[PlacementEnum["TopLeft"] = 0] = "TopLeft"; PlacementEnum[PlacementEnum["TopCenter"] = 1] = "TopCenter"; PlacementEnum[PlacementEnum["TopRight"] = 2] = "TopRight"; PlacementEnum[PlacementEnum["MiddleLeft"] = 3] = "MiddleLeft"; PlacementEnum[PlacementEnum["Center"] = 4] = "Center"; PlacementEnum[PlacementEnum["MiddleRight"] = 5] = "MiddleRight"; PlacementEnum[PlacementEnum["BottomLeft"] = 6] = "BottomLeft"; PlacementEnum[PlacementEnum["BottomCenter"] = 7] = "BottomCenter"; PlacementEnum[PlacementEnum["BottomRight"] = 8] = "BottomRight"; PlacementEnum[PlacementEnum["Unknown"] = 9] = "Unknown"; // Reserved for modal, only one instance held at the same time })(PlacementEnum = DataTypes.PlacementEnum || (DataTypes.PlacementEnum = {})); /** * Tristate enum * 三态枚举 */ let TristateEnum; (function (TristateEnum) { /** * False * 假 */ TristateEnum[TristateEnum["False"] = 0] = "False"; /** * True * 真 */ TristateEnum[TristateEnum["True"] = 1] = "True"; /** * Unsure * 无法判断 */ TristateEnum[TristateEnum["Unsure"] = 9] = "Unsure"; })(TristateEnum = DataTypes.TristateEnum || (DataTypes.TristateEnum = {})); /** * Convert value to target type * @param input Input value * @param target Target type * @returns Converted value */ function convert(input, target) { // null or undefined if (input == null) return undefined; // Array if (Array.isArray(target)) { // Element item const elementItem = target.length > 0 ? target[0] : input; const elementType = getBasicNameByValue(elementItem, true); if (elementType == null) return input; return convertByType(input, elementType); } // Target type const targetType = getBasicNameByValue(target, false); if (targetType == null) { if (typeof input === typeof target) return input; return undefined; } return convertByType(input, targetType); } DataTypes.convert = convert; /** * Convert by type name like 'string' * @param input Input value * @param targetType Target type * @returns Converted value */ function convertByType(input, targetType) { // null or undefined // And avoid empty string to mass up in different type if (input == null || (typeof input === "string" && input.trim() === "")) return undefined; // Array if (targetType.endsWith("[]")) { // Input array const inputArray = Array.isArray(input) ? input : typeof input === "string" ? input.split(/,\s*/g) // Support comma separated array : [input]; // Element type const elementType = (targetType.slice(0, targetType.length - 2)); // Convert type return (inputArray .map((item) => convertByType(item, elementType)) .filter((item) => item != null) // Remove undefined item ); } // Same type if (typeof input === targetType) return input; // Date if (targetType === "date") { if (input instanceof Date) return input; if (typeof input === "string" || typeof input === "number") { const date = new Date(input); return date == null ? undefined : date; } return undefined; } // Bigint if (targetType === "bigint") { if (typeof input === "string" || typeof input === "number" || typeof input === "boolean") return BigInt(input); return undefined; } // Boolean if (targetType === "boolean") { if (typeof input === "string" || typeof input === "number") { // Here are different with official definition // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean if (input === "0" || input === "false") return false; return Boolean(input); } return undefined; } // Number if (targetType === "number") { const number = Number(input); return isNaN(number) ? undefined : number; } // String if (targetType === "string") { return String(input); } // Default return undefined; } DataTypes.convertByType = convertByType; /** * Convert value to target enum type * @param input Input value * @param enumType Target enum type * @returns Converted type */ function convertSimple(input, enumType) { const type = getBasicName(enumType); const value = convertByType(input, type); if (value == null) return undefined; if (typeof value === "number") { if (enumType === DataTypes.CombinedEnum.Int || enumType === DataTypes.CombinedEnum.IntMoney) return Math.round(value); if (enumType === DataTypes.CombinedEnum.Money) return Math.round(10000 * value) / 10000; } return value; } DataTypes.convertSimple = convertSimple; /** * Get basic type name from Enum type * @param enumType Enum type * @returns Basic type name result */ function getBasicName(enumType) { switch (enumType) { case DataTypes.CombinedEnum.Array: return "unknown[]"; case DataTypes.CombinedEnum.Bigint: return "bigint"; case DataTypes.CombinedEnum.Boolean: return "boolean"; case DataTypes.CombinedEnum.Date: case DataTypes.CombinedEnum.DateTime: return "date"; case DataTypes.CombinedEnum.Number: case DataTypes.CombinedEnum.Int: case DataTypes.CombinedEnum.IntMoney: case DataTypes.CombinedEnum.Money: return "number"; default: return "string"; } } DataTypes.getBasicName = getBasicName; /** * Get value's basic type name * @param value Input value * @param isArray Is array * @returns Value's basic type name */ function getBasicNameByValue(value, isArray = false) { // null or undefined if (value == null) return undefined; // Date if (value instanceof Date) { return isArray ? "date[]" : "date"; } // No array // Other cases const valueType = typeof value; const typeName = isArray ? valueType + "[]" : valueType; if (!isBasicName(typeName)) return undefined; return typeName; } DataTypes.getBasicNameByValue = getBasicNameByValue; /* enum Gender { Male = "M", Female = "F" } */ /** * Get enum item from key * getEnumByKey(Gender, "Male") === Gender.Male * @param enumItem Enum * @param key Key * @returns Enum item */ function getEnumByKey(enumItem, key) { if (key in enumItem) return enumItem[key]; return undefined; } DataTypes.getEnumByKey = getEnumByKey; /** * Get enum item from value * getEnumByKey(Gender, "M") === Gender.Male * @param enumItem Enum * @param value Key * @returns Enum item or undefined */ function getEnumByValue(enumItem, value) { if (typeof value === "number") { if (value in enumItem) return value; } else { const keys = Object.keys(enumItem); for (const key of keys) { const kv = enumItem[key]; if (kv === value) return kv; } } return undefined; } DataTypes.getEnumByValue = getEnumByValue; /** * Get enum string literal type value * getEnumKey(Gender, "F") === "Female" * @param enumItem Enum item * @param value Value * @returns Result */ function getEnumKey(enumItem, value) { if (typeof value === "number") { if (value in enumItem) return enumItem[value].toString(); } else { const keys = Object.keys(enumItem); for (const key of keys) { if (enumItem[key] === value) return key; } } return undefined; } DataTypes.getEnumKey = getEnumKey; /** * Get Enum keys * @param input Input Enum * @returns Keys */ function getEnumKeys(input) { return Object.keys(input) .filter((key) => !/^\d+$/.test(key)) .map((item) => item); } DataTypes.getEnumKeys = getEnumKeys; /** * Get ListType2 item label * @param item Item * @returns Result */ function getListItemLabel(item) { return "label" in item ? item.label : "name" in item ? item.name : item.title; } DataTypes.getListItemLabel = getListItemLabel; /** * Get object item label * @param item Item * @returns Result */ function getObjectItemLabel(item) { return "label" in item ? `${item.label}` : "name" in item ? `${item.name}` : "title" in item ? `${item.title}` : `${item}`; } DataTypes.getObjectItemLabel = getObjectItemLabel; /** * Get object field value * @param data Data * @param key Property name * @returns Value */ function getValue(data, key) { if (data != null && typeof key === "string" && key in data) { return Reflect.get(data, key); } return undefined; } DataTypes.getValue = getValue; /** * Get object id field value * @param data Data * @param key Property name * @returns Id value */ function getIdValue(data, key) { return data[key]; } DataTypes.getIdValue = getIdValue; /** * Get object id field value 1 * @param data Data * @param key Property name * @returns Id value */ function getIdValue1(data, key) { const value = getValue(data, key); if (value == null) return undefined; if (typeof value === "number") return value; return `${value}`; } DataTypes.getIdValue1 = getIdValue1; /** * Get object string field value * @param data Data * @param key Property name * @returns String value */ function getStringValue(data, key) { const value = getValue(data, key); if (value == null) return undefined; if (typeof value === "string") return value; return `${value}`; } DataTypes.getStringValue = getStringValue; /** * Check the type is a basic type or not (type guard) * @param name Type name * @returns Is basic type */ function isBasicName(name) { return DataTypes.BasicArray.includes(name); } DataTypes.isBasicName = isBasicName; /** * Is the target a simple object (Type guard) * @param input Test data * @param includeArray Include array as simple type * @returns Result */ function isSimpleObject(input, includeArray = true) { return (typeof input === "object" && input != null && Object.values(input).every((value) => isSimpleType(value, includeArray))); } DataTypes.isSimpleObject = isSimpleObject; /** * Is the input value simple type, include null and undefined * @param input Input value * @param includeArray Is array included, first non null element shoud also be basic type */ function isSimpleType(input, includeArray = true) { // null & undefined if (input == null) return true; // Date if (input instanceof Date) return true; // Array if (Array.isArray(input)) { if (includeArray) { return isSimpleType(input.find((item) => item != null)); } else { // No array needed return false; } } // Other cases const type = typeof input; if (type === "function" || type === "object" || type === "symbol") return false; return true; } DataTypes.isSimpleType = isSimpleType; /** * JSON.stringify replacer with full path * https://stackoverflow.com/questions/61681176/json-stringify-replacer-how-to-get-full-path */ function jsonReplacer(replacer) { const m = new Map(); return function (key, value) { const path = m.get(this) + (Array.isArray(this) ? `[${key}]` : "." + key); if (value === Object(value)) m.set(value, path); return replacer.call(this, key, value, path.replace(/undefined\.\.?/, "")); }; } DataTypes.jsonReplacer = jsonReplacer; /** * JSON.stringify receiver for bigint * @param args Keys or paths to convert to bigint * @returns JSON receiver function */ function jsonBigintReceiver(...args) { return jsonReplacer(function (key, value, path) { if ((args.includes(key) || args.includes(path)) && typeof value === "string") { if (value.endsWith("n")) return BigInt(value.slice(0, -1)); else return BigInt(value); } return value; }); } DataTypes.jsonBigintReceiver = jsonBigintReceiver; /** * JSON serialize with options * @param obj Object to serialize * @param options Options to ignore null or empty values * @returns Result */ function jsonSerialize(obj, options) { const { ignoreNull = true, ignoreEmpty = false } = options ?? {}; return JSON.stringify(obj, (_key, value) => { if (ignoreNull && value == null) return undefined; if (ignoreEmpty && value === "") return undefined; return value; }); } DataTypes.jsonSerialize = jsonSerialize; })(DataTypes || (exports.DataTypes = DataTypes = {}));