UNPKG

@cc-heart/utils

Version:

🔧 javascript common tools collection

964 lines (952 loc) 31.4 kB
const _toString = Object.prototype.toString; /** * Checks if the given value is an object. * * @param val - The value to be checked. * @returns Returns true if the value is an object, otherwise false. */ function isObject(val) { return _toString.call(val) === '[object Object]'; } /** * Checks if the given value is an symbol. * * @param val - The value to be checked. * @returns Returns true if the value is an object, otherwise false. */ function isSymbol(val) { return typeof val === 'symbol'; } /** * Checks if the given value is a function. * * @param val - The value to be checked. * @returns Returns true if the value is a function, false otherwise. */ function isFn(val) { return typeof val === 'function'; } /** * Checks if the given value is a string. * * @param val - The value to be checked. * @returns Returns true if the value is a string, false otherwise. */ function isStr(val) { return typeof val === 'string'; } /** * Checks if the provided value is a boolean. * * @param val - The value to check. * @returns Returns true if the value is a boolean, false otherwise. */ function isBool(val) { return typeof val === 'boolean'; } /** * Checks if a value is undefined. * * @param val - The value to check. * @returns Returns true if the value is undefined, otherwise false. */ function isUndef(val) { return typeof val === 'undefined'; } /** * Checks if the given value is null. * * @param val - The value to check. * @returns Returns true if the value is null, false otherwise. */ function isNull(val) { return val === null; } const isNil = isNull; /** * Determines whether a value is a primitive. * * @param val - The value to check. * @returns Returns `true` if the value is a primitive, `false` otherwise. */ function isPrimitive(val) { return typeof val !== 'object' || val === null; } /** * Checks if a value is falsy. * * @param val - The value to check. * @returns Returns true if the value is falsy, otherwise false. */ function isFalsy(val) { return !val; } /** * Checks if the given value is a number. * * @param val - The value to be checked. * @returns Returns true if the value is a number, false otherwise. */ function isNumber(val) { return typeof val === 'number'; } /** * determines if it is a valid value other than NaN * @param val * @returns */ function isEffectiveNumber(val) { if (!isNumber(val)) return false; return !isNaN(val); } /** * Checks if a value is a Promise. * * @param val - The value to check. * @returns Returns `true` if the value is a Promise, else `false`. */ function isPromise(val) { return (typeof val === 'object' && !isNull(val) && (_toString.call(val) === '[object Promise]' || isFn(Reflect.get(val, 'then')))); } /** * Checks if the given object has its own property. * * @param obj - The object to check. * @param prop - The property to check. * @returns Returns true if the object has its own property, otherwise false. */ function hasOwn(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } /** * An array is considered valid if it is an array and its length is greater than or equal to 0. * * @param arr - The array to be checked. * @returns Returns true if the array is valid, false otherwise. */ function isValidArray(arr) { return Array.isArray(arr) && arr.length > 0; } /** * Checks if a given value is a valid PropertyKey. * A PropertyKey is a string, number, or symbol that can be used as a property name. * * @param val - The value to check. * @returns True if the value is a PropertyKey, false otherwise. */ function isPropertyKey(val) { return isStr(val) || isNumber(val) || isSymbol(val); } /** * Checks if a given date is valid. * * @param date - The date to check. * @returns True if the date is valid, false otherwise. */ function isValidDate(date) { return date.toString() !== 'Invalid Date'; } const createDateWithoutTimezoneOffset = (...rest) => { const date = new Date(...rest); date.setMinutes(date.getMinutes() - date.getTimezoneOffset()); return date; }; /** * Returns the current time in ISO string format. * @returns The current time in ISO string format. */ function getCurrentTimeISOString() { return createDateWithoutTimezoneOffset().toISOString(); } function formatDateString(date, maxLength) { return String(date).padStart(maxLength, '0'); } function formatDate(date, formatter = 'YYYY-MM-DD hh:mm:ss', utc = false) { const year = formatDateString(date[utc ? 'getUTCFullYear' : 'getFullYear'](), 4); const month = formatDateString(date[utc ? 'getUTCMonth' : 'getMonth']() + 1, 2); const day = formatDateString(date[utc ? 'getUTCDate' : 'getDate'](), 2); const hours = formatDateString(date[utc ? 'getUTCHours' : 'getHours'](), 2); const minutes = formatDateString(date[utc ? 'getUTCMinutes' : 'getMinutes'](), 2); const seconds = formatDateString(date[utc ? 'getUTCMinutes' : 'getSeconds'](), 2); return formatter .replace('YYYY', year) .replace('MM', month) .replace('DD', day) .replace('hh', hours) .replace('mm', minutes) .replace('ss', seconds); } /** * Formats a date based on a given timestamp. * * @param timeStamp - The timestamp to be formatted, in milliseconds. * @param formatter - Optional. A specific format string to format the date. Defaults to 'YYYY-MM-DD HH:mm:ss'. * * @returns The formatted date string. * * @throws {Error} Throws an error if the timestamp is invalid or out of range. * * @example * const timestamp = new Date().getTime(); * const formattedDate = formatDateByTimeStamp(timestamp); * console.log(formattedDate); */ function formatDateByTimeStamp(timeStamp, formatter) { const date = new Date(timeStamp); if (timeStamp < 0 || !isValidDate(date)) { console.warn('invalid timeStamp'); return 'Invalid Date'; } return formatDate(date, formatter); } /** * Formats a date string into a specified date time format * * @param dateString - A string representing the date. * @param formatter - Optional. A specific format string to format the date. Defaults to 'YYYY-MM-DD HH:mm:ss'. * * @returns The formatted date string. * * @throws {Error} Throws an error if the date string is invalid or cannot be parsed into a Date object. * * @example * const dateString = '2024-02-19T10:30:00Z'; * const formattedDateTime = formatDateTimeByString(dateString, 'MMMM D, YYYY, h:mm A'); * console.log(formattedDateTime); */ function formatDateTimeByString(dateString, formatter) { const date = new Date(dateString); if (!isValidDate(date)) { console.warn('invalid date string'); return date.toString(); } return formatDate(date, formatter); } /** * Formats a date based on an array of numbers, with optional formatting string * * This function expects an array containing year, month, day, hour, minute, and second values. If the array is invalid or does not contain the necessary values, it logs a warning and returns 'Invalid Date'. * The function uses the slice method to create a new array containing only the first six elements, and decrements the month value by 1 to convert it from a 1-based index to a 0-based index used by the Date object. * It then creates a new Date object using the elements of the new array. If the date is invalid, it logs a warning and returns the date as a string. * Finally, the function formats the date according to an optional formatting string and returns the formatted date string. * * @param array - The array representing the date. This array should contain year, month, day, hour, minute, and second values. * @param formatter - Optional. A specific format string to format the date. Defaults to 'YYYY-MM-DD HH:mm:ss'. * * @returns The formatted date string. * * @throws {Error} Throws an error if the array is invalid or does not contain the necessary values. * * @example * const dateArray = [2024, 2, 19, 10, 30, 0]; * const formattedDate = formatDateByArray(dateArray, 'MMMM D, YYYY, h:mm A'); * console.log(formattedDate); */ function formatDateByArray(array, formatter) { if (!Array.isArray(array) || array.length < 2) { console.warn('invalid date array'); return 'Invalid Date'; } const newDateArray = array.slice(0, 6); newDateArray[1] = newDateArray[1] - 1; const date = new Date(...newDateArray); if (!isValidDate(date)) { console.warn(`Invalid date generated from array: ${newDateArray}`); return date.toString(); } return formatDate(date, formatter); } /** * DefineDebounceFn is a function that creates a debounced function. * @param fn - The function to be debounced. * @param delay - The delay in milliseconds to wait before the debounced function is called. Default is 500ms. * @param immediate - Whether the debounced function should be called immediately before the delay. Default is false. * @returns - The debounce function. */ const defineDebounceFn = function (fn, delay = 500, immediate = false) { let timer = null; const debounced = function (...args) { if (timer) clearTimeout(timer); if (immediate && !timer) { immediate = false; debounced._result = fn.apply(this, args); } else { timer = setTimeout(() => { debounced._result = fn.apply(this, args); timer = null; }, delay); } }; return debounced; }; /** * Creates a function that can only be called once. * * @param fn - The function to be called once. * @returns - A new function that can only be called once. */ function defineOnceFn(fn) { let __once = false; let __cache; if (!(fn instanceof Function)) { throw new Error('first params must be a function'); } return function (...args) { if (!__once) { __once = true; __cache = fn.apply(this, args); } return __cache; }; } /** * defineThrottleFn is a function that creates a throttled function. * @param - The function to be throttled. * @param - The delay in milliseconds to wait before the throttled function is called. Default is 500ms. * @returns - The throttled function. */ function defineThrottleFn(fn, delay = 500) { let startTimer = null; let timer = null; delay = Math.max(delay, 0); const throttle = function (...args) { const curTimer = Date.now(); const remainingTime = startTimer === null ? 0 : delay + startTimer - curTimer; clearTimeout(timer); if (remainingTime <= 0 || delay === 0) { throttle._result = fn.apply(this, args); startTimer = Date.now(); } else { timer = setTimeout(() => { throttle._result = fn.apply(this, args); }, remainingTime); } }; return throttle; } /** * defineSinglePromiseFn ensures that the provided function can only be called once at a time. * If the function is invoked while it's still executing, it returns the same promise, avoiding multiple calls. * * @param fn - The function to be wrapped, which returns a promise. * @returns A function that ensures the provided function is only executed once and returns a promise. */ function defineSinglePromiseFn(fn) { let ret = null; return function () { if (ret === null) { ret = Promise.resolve(fn()).finally(() => { ret = null; }); } return ret; }; } /** * Generates a random integer between min (inclusive) and max (inclusive). * * @param min - The minimum value (inclusive). * @param max - The maximum value (inclusive). * @returns A random integer between min and max. */ function random(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } /** * This function does nothing. * * @returns No return value. */ const noop = () => { /** */ }; /** * Sleeps for a given delay. * * @param delay - The delay, in milliseconds. * @return A promise that resolves after the delay. */ const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)); /** * Capitalizes the first letter of a string. * * @param target - The string to be capitalized. * @returns - The capitalized string. */ const capitalize = (target) => (target.charAt(0).toUpperCase() + target.slice(1)); /** * Returns a new string with the first character converted to lowercase. * * @param target - The string to be unCapitalized. * @returns - The unCapitalized string. */ const unCapitalize = (target) => (target.charAt(0).toLowerCase() + target.slice(1)); /** * @description Add the number of cuts based on the original split and return all subsets after the cut * @param str need to split of primitive string * @param splitStr split params * @param num split limit * @returns a new split array, length is num + 1 */ function mulSplit(str, splitStr, num = -1) { const splitList = str.split(splitStr, num); if (num === -1) return splitList; const originStr = splitList.join(splitStr); if (originStr === str) return splitList; const endStr = str.slice(originStr.length + 1); splitList.push(endStr); return splitList; } /** * Converts an underline-separated string to camel case. * e.g. underlineToHump('hello_word') => 'helloWord' * * @param target - The underline-separated string to convert. * @returns The camel case version of the input string. */ function underlineToHump(target) { let isStartUnderline = true; let prefixStr = null; let str = ''; for (let i = 0; i < target.length; i++) { if (target[i] === '_' && /[a-z]/.test(target[i + 1]) && !isStartUnderline && prefixStr !== '_') { i++; str += target[i].toUpperCase(); continue; } prefixStr = target[i]; if (isStartUnderline && target[i] !== '_') { isStartUnderline = false; } str += target[i]; } return str; } function parseKey(obj, key, value) { const isArrayKey = key.includes('[') && key.includes(']'); if (isArrayKey) { const keys = key.split(/[[\]]/).filter(Boolean); let currentObj = obj; for (let i = 0; i < keys.length; i++) { let currentKey = keys[i]; if (currentKey.startsWith('.')) currentKey = currentKey.split('.')[1]; if (i === keys.length - 1) { if (Array.isArray(currentObj)) { currentObj.push(value); } else { currentObj[currentKey] = value; } } else { if (!currentObj[currentKey]) { currentObj[currentKey] = keys[i + 1].match(/^\d+$/) ? [] : {}; } currentObj = currentObj[currentKey]; } } } else { let nestedObj = obj; const keyParts = key.split('.'); for (let i = 0; i < keyParts.length - 1; i++) { const currentKey = keyParts[i]; if (!nestedObj[currentKey]) { nestedObj[currentKey] = {}; } nestedObj = nestedObj[currentKey]; } nestedObj[keyParts[keyParts.length - 1]] = value; } } /** * Converts a query string to an object. * * @example `queryStringToObject('foo=1&bar=2&baz=3')` * @example `queryStringToObject('foo=&bar=2&baz=3')` * @example `queryStringToObject('foo[0]=1&foo[1]=2&baz=3')` * @template T - The type of the URL string. * @template U - The type of the object to return. * @param {T} url - The URL string to convert. * @returns {U} The object representation of the query string in `url`. */ function queryStringToObject(url) { const result = {}; if (url) { url.split('&').forEach((item) => { const [rawKey, value] = item.split('='); const key = decodeURIComponent(rawKey); parseKey(result, key, decodeURIComponent(value)); }); } return result; } /** * Converts an object to a query string. * * @param data - The object to convert. * @returns The query string representation of `data`. */ function objectToQueryString(data) { const res = []; for (const key in data) { if (hasOwn(data, key)) { if (Array.isArray(data[key])) { res.push(arrayToQueryString(data[key], key)); } else { res.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`); } } } return res.join('&'); } /** * convert params routes to regular expressions * * @param path a params paths * @returns null or An array contains the RegExp that matches the params and the path for each params parameter */ function convertParamsRouterToRegExp(path) { const matcher = path.match(/:(.*?)(?:\/|$)/g); if (matcher === null) return null; const reg = new RegExp(path.replace(/:(.*?)(\/|$)/g, '.*?$2')); return [reg, matcher.map((val) => val.replace(/:(.*?)(\/|$)/g, '$1'))]; } /** * Returns the last portion of a path, similar to the Unix basename command. * Trims the query string if it exists. * Optionally, removes a suffix from the result. * * @param path - The path to get the basename from. * @param [suffix] - An optional suffix to remove from the basename. * @returns The basename of the path. */ function basename(path, suffix) { const separator = '/'; const index = path.lastIndexOf(separator); let str = path.slice(index + 1); if (str) { const querySeparator = str.lastIndexOf('?'); if (querySeparator !== -1) { str = str.slice(0, querySeparator); } } if (suffix) { return str.replace(new RegExp(suffix + '$'), ''); } return str; } /** * Convert a multi-dimensional array to a query string. * @param array The multi-dimensional array to convert. * @param field The field name to use in the query string. * @returns The generated query string. */ function arrayToQueryString(array, field) { let queryString = ''; function buildQueryString(arr, prefix) { arr.forEach((element, index) => { if (Array.isArray(element)) { buildQueryString(element, `${prefix}${encodeURIComponent(`[${index}]`)}`); } else if (isObject(element)) { for (const key in element) { if (hasOwn(element, key)) { queryString += `${prefix}${encodeURIComponent(`[${index}]`)}.${encodeURIComponent(key)}=${encodeURIComponent(String(Reflect.get(element, key)))}&`; } } } else { queryString += `${prefix}${encodeURIComponent(`[${index}]`)}=${encodeURIComponent(String(element))}&`; } }); } buildQueryString(array, field); // Remove the trailing '&' if present queryString = queryString.slice(0, -1); return queryString; } async function executeConcurrency(tasks, maxConcurrency) { if (isUndef(maxConcurrency)) { console.warn('maxConcurrency is undefined'); return null; } const ret = []; const excluding = []; for (let i = 0; i < tasks.length; i++) { const res = tasks[i](); ret.push(res); if (maxConcurrency < tasks.length) { const p = res.then(() => excluding.splice(excluding.indexOf(p), 1)); excluding.push(p); if (excluding.length >= maxConcurrency) { await Promise.race(excluding); } } } return Promise.all(ret); } /** * Invokes a queue. * @param {Array.<function(...any): any>} taskArray - An array of tasks to be executed. * @returns {Promise<void>} - A promise that resolves when all tasks are completed. */ function executeQueue(taskArray) { const taskQueue = taskArray.slice(); let index = 0; return new Promise((resolve) => { const loopFunc = () => { if (index >= taskQueue.length) { resolve(); return; } const fn = taskQueue[index++]; fn && Promise.resolve(fn?.()).finally(() => { loopFunc(); }); }; loopFunc(); }); } const definePrams = (params, index) => { if (index === 0 && Array.isArray(params)) { return params; } return [params]; }; /** * Takes a series of functions and returns a new function that runs these functions in sequence. * If a function returns a Promise, the next function is called with the resolved value. * * @param fns - The functions to pipe. * @returns A new function that takes any number of arguments and pipes them through `fns`. */ function pipe(...fns) { return (...args) => { if (fns.length === 0) return args[0]; return fns.reduce((arg, fn, index) => { if (isPromise(arg)) { return arg.then((res) => { return fn(...definePrams(res, index)); }); } return fn(...definePrams(arg, index)); }, args); }; } /** * Takes a series of functions and returns a new function that runs these functions in reverse sequence. * If a function returns a Promise, the next function is called with the resolved value. * * @param fns - The functions to compose. * @returns A new function that takes any number of arguments and composes them through `fns`. */ function compose(...fns) { return pipe(...fns.reverse()); } /** * Executes a given function repeatedly at a specified interval using setTimeout and clearTimeout. * * @param func - The function to be executed. * @param delay - The interval (in milliseconds) at which the function should be executed. * @returns A function that, when called, clears the interval and stops the execution of the given function. */ function setintervalByTimeout(func, delay) { let timer = null; let cancelTimer = null; const fn = function () { timer = setTimeout(async () => { const res = func(); if (isPromise(res)) { await res; if (cancelTimer && cancelTimer === timer) { return; } } fn(); }, delay); }; const clearInterval = () => { if (timer) { clearTimeout(timer); cancelTimer = timer; } }; fn(); return clearInterval; } const setIntervalByTimeout = setintervalByTimeout; const HTTP_STATUS = { CONTINUE: 100, SWITCHING_PROTOCOLS: 101, PROCESSING: 102, EARLYHINTS: 103, OK: 200, CREATED: 201, ACCEPTED: 202, NON_AUTHORITATIVE_INFORMATION: 203, NO_CONTENT: 204, RESET_CONTENT: 205, PARTIAL_CONTENT: 206, AMBIGUOUS: 300, MOVED_PERMANENTLY: 301, FOUND: 302, SEE_OTHER: 303, NOT_MODIFIED: 304, TEMPORARY_REDIRECT: 307, PERMANENT_REDIRECT: 308, BAD_REQUEST: 400, UNAUTHORIZED: 401, PAYMENT_REQUIRED: 402, FORBIDDEN: 403, NOT_FOUND: 404, METHOD_NOT_ALLOWED: 405, NOT_ACCEPTABLE: 406, PROXY_AUTHENTICATION_REQUIRED: 407, REQUEST_TIMEOUT: 408, CONFLICT: 409, GONE: 410, LENGTH_REQUIRED: 411, PRECONDITION_FAILED: 412, PAYLOAD_TOO_LARGE: 413, URI_TOO_LONG: 414, UNSUPPORTED_MEDIA_TYPE: 415, REQUESTED_RANGE_NOT_SATISFIABLE: 416, EXPECTATION_FAILED: 417, I_AM_A_TEAPOT: 418, MISDIRECTED: 421, UNPROCESSABLE_ENTITY: 422, FAILED_DEPENDENCY: 424, PRECONDITION_REQUIRED: 428, TOO_MANY_REQUESTS: 429, INTERNAL_SERVER_ERROR: 500, NOT_IMPLEMENTED: 501, BAD_GATEWAY: 502, SERVICE_UNAVAILABLE: 503, GATEWAY_TIMEOUT: 504, HTTP_VERSION_NOT_SUPPORTED: 505 }; const REQUEST_METHOD = { GET: 'GET', POST: 'POST', PUT: 'PUT', DELETE: 'DELETE', PATCH: 'PATCH', ALL: 'ALL', OPTIONS: 'OPTIONS', HEAD: 'HEAD', SEARCH: 'SEARCH' }; const MIME_TYPES = { TXT: 'text/plain', HTML: 'text/html', HTM: 'text/html', CSS: 'text/css', CSV: 'text/csv', XML: 'application/xml', JSON: 'application/json', JAVASCRIPT: 'application/javascript', PNG: 'image/png', JPG: 'image/jpeg', JPEG: 'image/jpeg', GIF: 'image/gif', BMP: 'image/bmp', WEBP: 'image/webp', SVG: 'image/svg+xml', ICO: 'image/vnd.microsoft.icon', MP3: 'audio/mpeg', WAV: 'audio/wav', OGG: 'audio/ogg', M4A: 'audio/mp4', FLAC: 'audio/flac', MP4: 'video/mp4', AVI: 'video/x-msvideo', MOV: 'video/quicktime', WMV: 'video/x-ms-wmv', FLV: 'video/x-flv', WEBM: 'video/webm', MKV: 'video/x-matroska', ZIP: 'application/zip', RAR: 'application/vnd.rar', '7Z': 'application/x-7z-compressed', TAR: 'application/x-tar', GZ: 'application/gzip', BZ2: 'application/x-bzip2', PDF: 'application/pdf', DOC: 'application/msword', DOT: 'application/msword', DOCX: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', DOTX: 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', XLS: 'application/vnd.ms-excel', XLT: 'application/vnd.ms-excel', XLSX: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', XLSM: 'application/vnd.ms-excel.sheet.macroEnabled.12', PPT: 'application/vnd.ms-powerpoint', POT: 'application/vnd.ms-powerpoint', PPTX: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', POTX: 'application/vnd.openxmlformats-officedocument.presentationml.template', PPSX: 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', EXE: 'application/vnd.microsoft.portable-executable', DLL: 'application/vnd.microsoft.portable-executable', MSI: 'application/x-msdownload', BAT: 'application/x-msdownload', WOFF: 'font/woff', WOFF2: 'font/woff2', TTF: 'font/ttf', OTF: 'font/otf', EOT: 'application/vnd.ms-fontobject', JSONLD: 'application/ld+json', MAP: 'application/json', WASM: 'application/wasm', TS: 'video/mp2t', MPD: 'application/dash+xml', M3U8: 'application/vnd.apple.mpegurl', TORRENT: 'application/x-bittorrent', SWF: 'application/x-shockwave-flash', EPUB: 'application/epub+zip', APK: 'application/vnd.android.package-archive', DMG: 'application/x-apple-diskimage', EML: 'message/rfc822', MSG: 'application/vnd.ms-outlook', DWG: 'application/acad', DXF: 'application/vnd.dxf', OBJ: 'application/octet-stream', STL: 'application/sla', PY: 'text/x-python', JAVA: 'text/x-java-source', C: 'text/x-csrc', CPP: 'text/x-c++src', CS: 'text/plain', RB: 'application/x-ruby', GO: 'text/plain', PHP: 'application/x-httpd-php', SWIFT: 'text/x-swift', KT: 'text/plain', RTF: 'application/rtf', ALZ: 'application/x-alz', '7ZIP': 'application/x-7z-compressed' }; const LOG_LEVELS = { START: -2, SUCCESS: -1, ERROR: 0, WARN: 1, INFO: 2, DEBUG: 3, TRACE: 4 }; const ANSI_COLORS = { [LOG_LEVELS.START]: '\x1b[32m', // green [LOG_LEVELS.SUCCESS]: '\x1b[32m', // green [LOG_LEVELS.ERROR]: '\x1b[31m', // red [LOG_LEVELS.WARN]: '\x1b[33m', // yellow [LOG_LEVELS.INFO]: '\x1b[32m', // green [LOG_LEVELS.DEBUG]: '\x1b[34m', // blue [LOG_LEVELS.TRACE]: '\x1b[35m' // purple }; const LOG_LEVEL_NAMES = { [LOG_LEVELS.START]: 'success', [LOG_LEVELS.SUCCESS]: 'success', [LOG_LEVELS.ERROR]: 'error', [LOG_LEVELS.WARN]: 'warn', [LOG_LEVELS.INFO]: 'info', [LOG_LEVELS.DEBUG]: 'debug', [LOG_LEVELS.TRACE]: 'trace' }; function isUnicodeSupported() { // @ts-expect-error: expect error return typeof window === 'undefined'; } const unicode = isUnicodeSupported(); const s = (c, fallback) => (unicode ? c : fallback); const TYPE_ICONS = { error: s('✖', '×'), warn: s('⚠', '‼'), info: s('ℹ', 'i'), debug: s('⚙', 'D'), trace: s('→', '→'), start: s('◐', 'o'), success: s('✔', '√'), log: '' }; class Logger { level; constructor(level = LOG_LEVELS.TRACE) { this.level = level; } setLevel(level) { this.level = level; } log(level, ...message) { if (level > this.level) { return; } const color = ANSI_COLORS[level] || ANSI_COLORS[LOG_LEVELS.INFO]; const levelName = LOG_LEVEL_NAMES[level]; const icon = Reflect.get(TYPE_ICONS, levelName) || ''; const timestamp = new Date().toLocaleString(); const logMethod = level === LOG_LEVELS.ERROR ? 'error' : 'log'; console[logMethod](`${color}${icon}\x1b[0m [${levelName}] (${timestamp}) :`, ...message); } error(...message) { this.log(LOG_LEVELS.ERROR, ...message); } warn(...message) { this.log(LOG_LEVELS.WARN, ...message); } info(...message) { this.log(LOG_LEVELS.INFO, ...message); } debug(...message) { this.log(LOG_LEVELS.DEBUG, ...message); } trace(...message) { this.log(LOG_LEVELS.TRACE, ...message); } start(...message) { this.log(LOG_LEVELS.START, ...message); } success(...message) { this.log(LOG_LEVELS.SUCCESS, ...message); } } /** * Formats an error object into a string representation. * @param error - The error to format. It can be an `Error` instance, a string, or another object. * @param [defaultErrorString=''] - The default error message if the error cannot be formatted. * @param [opts={}] - Additional options. * @param [opts.errorLimit=8] - The maximum number of stack trace lines to include. * @returns The formatted error message. */ function formatErrorToString(error, defaultErrorString = '', opts = { errorLimit: 8 }) { if (error instanceof Error) { Error.captureStackTrace(error, formatErrorToString); const stackLines = error.stack?.split('\n').slice(0, opts.errorLimit) || []; return stackLines.join('\n'); } if (isStr(error)) return error; if (isObject(error) && 'toString' in error && isFn(error.toString)) return error.toString(); return defaultErrorString; } export { HTTP_STATUS, Logger, MIME_TYPES, REQUEST_METHOD, _toString, arrayToQueryString, basename, capitalize, compose, convertParamsRouterToRegExp, defineDebounceFn, defineOnceFn, defineSinglePromiseFn, defineThrottleFn, executeConcurrency, executeQueue, formatDateByArray, formatDateByTimeStamp, formatDateTimeByString, formatErrorToString, getCurrentTimeISOString, hasOwn, isBool, isEffectiveNumber, isFalsy, isFn, isNil, isNull, isNumber, isObject, isPrimitive, isPromise, isPropertyKey, isStr, isSymbol, isUndef, isValidArray, isValidDate, mulSplit, noop, objectToQueryString, parseKey, pipe, queryStringToObject, random, setIntervalByTimeout, setintervalByTimeout, sleep, unCapitalize, underlineToHump };