@cloudcome/utils-core 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.cjs.map +1 -1
- package/dist/array.mjs.map +1 -1
- package/dist/async.cjs +1 -0
- package/dist/async.cjs.map +1 -1
- package/dist/async.mjs +1 -0
- package/dist/async.mjs.map +1 -1
- package/dist/base64.cjs.map +1 -1
- package/dist/base64.mjs.map +1 -1
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.mjs.map +1 -1
- package/dist/color.cjs.map +1 -1
- package/dist/color.mjs.map +1 -1
- package/dist/crypto.cjs.map +1 -1
- package/dist/crypto.mjs.map +1 -1
- package/dist/date.cjs.map +1 -1
- package/dist/date.mjs.map +1 -1
- package/dist/dict.cjs.map +1 -1
- package/dist/dict.mjs.map +1 -1
- package/dist/easing.cjs.map +1 -1
- package/dist/easing.mjs.map +1 -1
- package/dist/emitter.cjs.map +1 -1
- package/dist/emitter.mjs.map +1 -1
- package/dist/env.cjs.map +1 -1
- package/dist/env.mjs.map +1 -1
- package/dist/error.cjs.map +1 -1
- package/dist/error.mjs.map +1 -1
- package/dist/function.cjs.map +1 -1
- package/dist/function.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/object.cjs.map +1 -1
- package/dist/object.mjs.map +1 -1
- package/dist/path.cjs.map +1 -1
- package/dist/path.mjs.map +1 -1
- package/dist/promise.cjs.map +1 -1
- package/dist/promise.mjs.map +1 -1
- package/dist/qs.cjs.map +1 -1
- package/dist/qs.mjs.map +1 -1
- package/dist/regexp.cjs.map +1 -1
- package/dist/regexp.mjs.map +1 -1
- package/dist/string2.cjs.map +1 -1
- package/dist/string2.mjs.map +1 -1
- package/dist/time.cjs.map +1 -1
- package/dist/time.mjs.map +1 -1
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.mjs.map +1 -1
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.mjs.map +1 -1
- package/dist/try.cjs.map +1 -1
- package/dist/try.mjs.map +1 -1
- package/dist/type.cjs.map +1 -1
- package/dist/type.mjs.map +1 -1
- package/dist/unique.cjs.map +1 -1
- package/dist/unique.mjs.map +1 -1
- package/dist/url.cjs.map +1 -1
- package/dist/url.mjs.map +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +1 -9
- package/dist/exception.cjs +0 -40
- package/dist/exception.cjs.map +0 -1
- package/dist/exception.d.ts +0 -31
- package/dist/exception.mjs +0 -39
- package/dist/exception.mjs.map +0 -1
package/dist/string2.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"string2.mjs","names":[],"sources":["../src/number.ts","../src/string.ts"],"sourcesContent":["import { objectDefaults } from './object';\nimport { STRING_DICT } from './string';\nimport { isNumber } from './type';\n\nexport type NumberFixedOptions = {\n /**\n * 保留的小数位数\n * @default 0\n */\n decimals?: number;\n\n /**\n * 舍入方法,0 为四舍五入,1 为向上取整,-1 为向下取整\n * @default 0\n */\n round?: 0 | 1 | -1;\n};\n\n/**\n * 对数字进行精确小数位数处理并按规则舍入\n * @param number 需要处理的原始数值\n * @param options 可选配置参数\n * @returns 处理后的数值(number类型)\n * @example\n * // 四舍五入示例\n * numberFixed(3.1415, { decimals: 2 }); // 3.14\n * // 向上取整示例\n * numberFixed(3.1415, { decimals: 2, round: 1 }); // 3.15\n * // 向下取整示例\n * numberFixed(3.9999, { decimals: 1, round: -1 }); // 3.9\n */\nexport function numberFixed(number: number, options?: NumberFixedOptions) {\n const { decimals = 0, round = 0 } = options || {};\n const scale = 10 ** decimals;\n\n if (round === 1) {\n return Math.ceil(number * scale) / scale;\n }\n\n if (round === -1) {\n return Math.floor(number * scale) / scale;\n }\n\n return Math.round(number * scale) / scale;\n}\n\n/**\n * 生成指定范围内的随机数\n * @param {number | string} min - 随机数的最小值(包含,支持小数、字符串)\n * @param {number | string} max - 随机数的最大值(包含,支持小数、字符串)\n * @returns {number} - 生成的随机数\n * @example\n * // 生成 1 到 10 之间的随机整数\n * randomNumber(1, 10); // 可能返回 7\n *\n * // 生成 0.1 到 2 之间的一位随机小数\n * randomNumber(0.1, 2); // 可能返回 0.7\n *\n * // 生成 0.10 到 2 之间的两位随机小数\n * randomNumber(\"0.10\", 2); // 可能返回 0.75\n */\nexport function randomNumber(min: number | string, max: number | string): number {\n const minDecimals = numberDecimals(min);\n const maxDecimals = numberDecimals(max);\n const decimals = Math.max(minDecimals, maxDecimals);\n const scale = 10 ** decimals;\n\n const minNum = Number(min);\n const maxNum = Number(max);\n const [minFinal, maxFinal] = minNum > maxNum ? [maxNum, minNum] : [minNum, maxNum];\n\n const scaledMin = minFinal * scale;\n const scaledMax = maxFinal * scale;\n\n return Math.floor(Math.random() * (scaledMax - scaledMin + 1) + scaledMin) / scale;\n}\n\n/**\n * 数字缩写选项\n */\nexport type NumberAbbrOptions = {\n /**\n * 进制基数,用于计算单位进阶(如 1000 表示千进制)\n * @default 1000\n */\n base?: number;\n\n /**\n * 数值保留的小数位数\n * @default 0\n */\n decimals?: number;\n};\n\n/**\n * 将数字转换为带单位缩写的字符串表示\n *\n * @param {number} number - 需要转换的原始数值\n * @param {Array<string>} units - 单位数组,按从小到大顺序排列(如['B','KB','MB']),不能为空\n * @param {NumberAbbrOptions} [options] - 可选配置参数\n * @returns {string} - 转换后的带单位字符串(如\"1.2KB\")\n * @example\n * // 基础用法\n * numberAbbr(1500, ['', 'K', 'M'], { base: 1000 }); // \"1.5K\"\n * @example\n * // 自定义小数位\n * numberAbbr(123456, ['B','KB','MB'], { decimals: 1 }); // \"0.1MB\"\n * @example\n * // 处理不足基数的情况\n * numberAbbr(500, ['B','KB']); // \"500B\"\n */\nexport function numberAbbr(number: number, units: Array<string>, options?: NumberAbbrOptions): string {\n const { base = 1000, decimals = 0 } = options || {};\n const { length } = units;\n\n if (length === 0) throw new Error('数字单位组不能为空');\n\n let numberFinal = number;\n let step = 0;\n\n while (numberFinal >= base && step < length - 1) {\n numberFinal = numberFinal / base;\n step++;\n }\n\n const value = numberFixed(numberFinal, { decimals: decimals, round: -1 });\n const unit = units[step];\n\n return `${value}${unit}`;\n}\n\n/**\n * 将文件大小转换为带单位缩写的字符串表示\n *\n * @param {number} number - 需要转换的文件大小数值\n * @param {number} [decimals=0] - 数值保留的小数位数\n * @returns {string} - 转换后的带单位字符串(如\"1.2KB\")\n * @example\n * // 基础用法\n * fileSizeAbbr(1024); // \"1KB\"\n * @example\n * // 自定义小数位\n * fileSizeAbbr(123456, 1); // \"0.1MB\"\n */\nexport function fileSizeAbbr(number: number, decimals = 0) {\n return numberAbbr(number, ['B', 'KB', 'MB', 'GB', 'TB'], {\n base: 1024,\n decimals: decimals,\n });\n}\n\n/**\n * 将十进制数转换为指定进制的字符串表示\n *\n * @param {number | bigint} decimal - 需要转换的十进制数,可以是任意长度的数字或大整数\n * @param {string} [dict] - 用于表示进制的字符字典,默认为数字、小写字母和大写字母的组合(62 进制)\n * @returns {string} - 转换后的指定进制字符串\n * @throws {Error} - 如果字符字典的长度小于 2,将抛出错误\n * @example\n * // 默认 62 进制\n * numberConvert(123456789); // \"8M0kX\"\n * @example\n * // 自定义 16 进制\n * numberConvert(255, '0123456789ABCDEF'); // \"FF\"\n * @example\n * // 处理大整数\n * numberConvert(9007199254740991n); // \"2gosa7pa2GV\"\n */\nexport function numberConvert(decimal: number | bigint, dict?: string): string {\n const dictFinal = dict || STRING_DICT;\n\n if (dictFinal.length < 2) throw new Error('进制转换字典长度不能小于 2');\n\n let bigInt = BigInt(decimal);\n const symbol = bigInt < 0n ? '-' : '';\n bigInt = bigInt < 0n ? -bigInt : bigInt;\n const result: Array<string> = [];\n const { length } = dictFinal;\n const bigLength = BigInt(length);\n const calculate = (): void => {\n const y = Number(bigInt % bigLength);\n\n bigInt = bigInt / bigLength;\n result.unshift(dictFinal[y]);\n\n if (bigInt > 0) {\n calculate();\n }\n };\n\n calculate();\n\n return symbol + result.join('');\n}\n\n/**\n * 数字格式化配置选项\n */\nexport type NumberFormatOptions = {\n /**\n * 分隔符字符,用于数字分隔\n * @default ','\n * @example 使用 '_' 分隔符时,123456 会格式化为 '123_456'\n */\n separator?: string;\n\n /**\n * 分隔步长,即每隔多少位添加分隔符\n * @default 3\n * @example 步长为 2 时,123456 会格式化为 '12,34,56'\n */\n step?: number;\n};\n\n/**\n * 数字格式化\n * @param [number] {number} 数字\n * @param options {NumberFormatOptions} 格式化配置\n * @returns {string} 分割后的字符串\n * @example\n * // 使用默认分隔符和步长\n * numberFormat(123456.789); // => \"123,456.789\"\n * // 自定义分隔符\n * numberFormat(123456.789, '_'); // => \"123_456.789\"\n * // 自定义步长\n * numberFormat(123456.789, 2); // => \"12,34,56.789\"\n * // 使用对象配置\n * numberFormat(123456.789, { separator: '.', step: 4 }); // => \"12.3456.789\"\n */\nexport function numberFormat(number: number | string, options: NumberFormatOptions): string;\nexport function numberFormat(number: number | string, separator: string): string;\nexport function numberFormat(number: number | string, step: number): string;\nexport function numberFormat(number: number | string): string;\nexport function numberFormat(number: number | string, options?: NumberFormatOptions | string | number) {\n let optionsFinal: Required<NumberFormatOptions> = {\n separator: ',',\n step: 3,\n };\n\n if (typeof options === 'string') {\n optionsFinal.separator = options;\n } else if (typeof options === 'number') {\n optionsFinal.step = options;\n } else {\n optionsFinal = objectDefaults(options || {}, optionsFinal) as Required<NumberFormatOptions>;\n }\n\n const { separator, step } = optionsFinal;\n const arr = String(number).split('.');\n const re = new RegExp(`(\\\\d)(?=(\\\\d{${step}})+(?!\\\\d))`, 'g');\n const p1 = arr[0].replace(re, `$1${separator}`);\n\n return p1 + (arr[1] ? `.${arr[1]}` : '');\n}\n\n/**\n * 将数字限制在指定范围内。\n *\n * @param min - 最小值。\n * @param number - 要限制的数字。\n * @param max - 最大值。\n * @returns 限制后的数字。\n */\nexport function numberClamp(min: number, number: number, max: number) {\n return Math.min(Math.max(number, min), max);\n}\n\n/**\n * 为数字添加单位\n * @param number - 需要处理的数字,可以是数字类型或字符串类型\n * @param unit - 要添加的单位,默认为空字符串\n * @returns 如果输入是数字或纯数字字符串,则返回带单位的字符串;否则返回原值\n */\nexport function numberUnit(number: string | number, unit = '') {\n if (isNumber(number)) return `${number}${unit}`;\n if (/^-?[\\d.]+$/.test(number)) return `${number}${unit}`;\n return number;\n}\n\n/**\n * 获取数字的小数位数\n * @param num - 需要计算小数位数的数字或数字字符串\n * @returns 返回数字的小数位数,如果是整数则返回0\n * @example\n * // 基本用法\n * numberDecimals(3.1415); // 4\n * numberDecimals(\"3.1415\"); // 4\n * numberDecimals(100); // 0\n * numberDecimals(\"100\"); // 0\n * // 科学计数法\n * numberDecimals(\"1.23e-4\"); // 6\n */\nexport function numberDecimals(num: number | string) {\n const numStr = String(num);\n const matches = numStr.match(/(?:\\.(\\d+))?(?:e-(\\d+))?$/i);\n if (!matches) return 0;\n return (matches[1] || '').length + Number.parseInt(matches[2] || '0', 10);\n}\n","import { randomNumber } from './number';\nimport { isFunction, isNullish, isObject, isUndefined } from './type';\n\n/** 阿拉伯数字字符集合 */\nexport const STRING_ARABIC_NUMERALS = '0123456789';\n/** 十六进制字符集合 */\nexport const STRING_HEXADECIMALS = '0123456789abcdef';\n/** 小写字母字符集合 */\nexport const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';\n/** 大写字母字符集合 */\nexport const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n/** 随机字符串字典,包含数字、大写字母和小写字母 */\nexport const STRING_DICT = `${STRING_ARABIC_NUMERALS + STRING_UPPERCASE_ALPHA + STRING_LOWERCASE_ALPHA}`;\n\n/**\n * 将字符串转换为驼峰格式\n * @param {string} string - 要转换的字符串\n * @param {boolean} [bigger] - 是否大写第一个字母,默认为 false\n * @returns {string} - 转换后的驼峰格式字符串\n */\nexport function stringCamelCase(string: string, bigger?: boolean): string {\n const string2 = string.replace(/[\\s_-](.)/g, (_, char) => (char as string).toUpperCase());\n return bigger ? string2.slice(0, 1).toUpperCase() + string2.slice(1) : string2;\n}\n\n/**\n * 将字符串转换为连字格式\n * @param {string} string - 要转换的字符串\n * @param {string} [separator] - 分隔符,默认是 \"-\"(短横线)\n * @returns {string} - 转换后的连字格式字符串\n */\nexport function stringKebabCase(string: string, separator = '-'): string {\n return string.replace(/[A-Z]/g, (origin) => `${separator}${origin.toLowerCase()}`);\n}\n\n/**\n * 生成随机字符串\n * @param {number} length - 生成的随机字符串长度\n * @param {string} [dict] - 用于生成随机字符串的字符字典,默认为数字、小写字母和大写字母的组合\n * @returns {string} - 生成的随机字符串\n * @example\n * randomString(10); // 生成一个长度为 10 的随机字符串\n * randomString(8, 'ABCDEF'); // 生成一个长度为 8 的随机字符串,仅包含字符 'ABCDEF'\n */\nexport function randomString(length: number, dict?: string): string {\n const dictFinal = dict || STRING_DICT;\n const dictLength = dictFinal.length;\n\n let result = '';\n\n for (let i = 0; i < length; i++) {\n result += dictFinal.charAt(randomNumber(0, dictLength - 1));\n }\n\n return result;\n}\n\n/**\n * 简单的模板引擎,类似于 Python 的 `.format()` 方法\n * 支持通过索引或对象/名称的方式传递变量\n * 当使用对象/名称方式时,可以传递一个回退值作为第三个参数\n *\n * @category 字符串\n * @example\n * ```\n * // 索引方式\n * const result = stringFormat(\n * '你好 {0}!我的名字是 {1}。',\n * '张三',\n * '李四'\n * ); // 你好 张三!我的名字是 李四。\n * ```\n *\n * @example\n * ```\n * // 对象方式\n * const result = stringFormat(\n * '{greet}!我的名字是 {name}。',\n * { greet: '你好', name: '王五' }\n * ); // 你好!我的名字是 王五。\n * ```\n *\n * @example\n * ```\n * // 带回退值的对象方式\n * const result = stringFormat(\n * '{greet}!我的名字是 {name}。',\n * { greet: '你好' }, // name 未传递,因此会使用回退值\n * '未知'\n * ); // 你好!我的名字是 未知。\n * ```\n */\nexport function stringFormat(\n str: string,\n object: Record<string | number, unknown>,\n fallback?: string | ((key: string) => string),\n): string;\nexport function stringFormat(str: string, ...args: (string | number | bigint | undefined | null)[]): string;\nexport function stringFormat(str: string, ...args: unknown[]): string {\n const [firstArg, fallback] = args;\n\n if (isObject(firstArg) || isUndefined(firstArg)) {\n const vars = firstArg || {};\n return str.replace(/\\{(\\w+)\\}/g, (_, key) => vars[key] ?? (isFunction(fallback) ? fallback(key) : fallback) ?? key);\n }\n\n return str.replace(/\\{(\\d+)\\}/g, (_, key) => {\n const index = Number(key);\n if (Number.isNaN(index)) return key;\n return args[index];\n });\n}\n\n/**\n * 生成符合 [RFC 4122](https://www.ietf.org/rfc/rfc4122.txt) 版本 4 的 UUID 字符串\n * @returns {string} - 生成的 UUID 字符串\n * @example\n * const uuid = randomUUID4();\n * console.log(uuid); // 输出类似 '123e4567-e89b-12d3-a456-426614174000' 的 UUID 字符串\n */\nexport function randomUUID4(): string {\n const template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';\n let result = '';\n\n for (let i = 0; i < template.length; i++) {\n const t = template[i];\n\n if (t === '-' || t === '4') {\n result += t;\n continue;\n }\n\n if (t === 'y') {\n result += randomString(1, '89ab');\n continue;\n }\n\n result += randomString(1, STRING_HEXADECIMALS);\n }\n\n return result;\n}\n\n/**\n * 将值转换为字符串,若值为 null 或 undefined 则返回空字符串\n * @param {unknown} value - 需要转换的值\n * @returns {string} 转换后的字符串结果\n */\nexport function stringify(value: unknown) {\n return isNullish(value) ? '' : String(value);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA+BA,SAAgB,YAAY,QAAgB,SAA8B;CACxE,MAAM,EAAE,WAAW,GAAG,QAAQ,MAAM,WAAW,EAAE;CACjD,MAAM,QAAQ,MAAM;CAEpB,IAAI,UAAU,GACZ,OAAO,KAAK,KAAK,SAAS,MAAM,GAAG;CAGrC,IAAI,UAAU,IACZ,OAAO,KAAK,MAAM,SAAS,MAAM,GAAG;CAGtC,OAAO,KAAK,MAAM,SAAS,MAAM,GAAG;;;;;;;;;;;;;;;;;AAkBtC,SAAgB,aAAa,KAAsB,KAA8B;CAC/E,MAAM,cAAc,eAAe,IAAI;CACvC,MAAM,cAAc,eAAe,IAAI;CAEvC,MAAM,QAAQ,MADG,KAAK,IAAI,aAAa,YACnB;CAEpB,MAAM,SAAS,OAAO,IAAI;CAC1B,MAAM,SAAS,OAAO,IAAI;CAC1B,MAAM,CAAC,UAAU,YAAY,SAAS,SAAS,CAAC,QAAQ,OAAO,GAAG,CAAC,QAAQ,OAAO;CAElF,MAAM,YAAY,WAAW;CAC7B,MAAM,YAAY,WAAW;CAE7B,OAAO,KAAK,MAAM,KAAK,QAAQ,IAAI,YAAY,YAAY,KAAK,UAAU,GAAG;;;;;;;;;;;;;;;;;;;AAqC/E,SAAgB,WAAW,QAAgB,OAAsB,SAAqC;CACpG,MAAM,EAAE,OAAO,KAAM,WAAW,MAAM,WAAW,EAAE;CACnD,MAAM,EAAE,WAAW;CAEnB,IAAI,WAAW,GAAG,MAAM,IAAI,MAAM,YAAY;CAE9C,IAAI,cAAc;CAClB,IAAI,OAAO;CAEX,OAAO,eAAe,QAAQ,OAAO,SAAS,GAAG;EAC/C,cAAc,cAAc;EAC5B;;CAMF,OAAO,GAHO,YAAY,aAAa;EAAY;EAAU,OAAO;EAAI,CAG9D,GAFG,MAAM;;;;;;;;;;;;;;;AAkBrB,SAAgB,aAAa,QAAgB,WAAW,GAAG;CACzD,OAAO,WAAW,QAAQ;EAAC;EAAK;EAAM;EAAM;EAAM;EAAK,EAAE;EACvD,MAAM;EACI;EACX,CAAC;;;;;;;;;;;;;;;;;;;AAoBJ,SAAgB,cAAc,SAA0B,MAAuB;CAC7E,MAAM,YAAY,QAAQ;CAE1B,IAAI,UAAU,SAAS,GAAG,MAAM,IAAI,MAAM,iBAAiB;CAE3D,IAAI,SAAS,OAAO,QAAQ;CAC5B,MAAM,SAAS,SAAS,KAAK,MAAM;CACnC,SAAS,SAAS,KAAK,CAAC,SAAS;CACjC,MAAM,SAAwB,EAAE;CAChC,MAAM,EAAE,WAAW;CACnB,MAAM,YAAY,OAAO,OAAO;CAChC,MAAM,kBAAwB;EAC5B,MAAM,IAAI,OAAO,SAAS,UAAU;EAEpC,SAAS,SAAS;EAClB,OAAO,QAAQ,UAAU,GAAG;EAE5B,IAAI,SAAS,GACX,WAAW;;CAIf,WAAW;CAEX,OAAO,SAAS,OAAO,KAAK,GAAG;;AAyCjC,SAAgB,aAAa,QAAyB,SAAiD;CACrG,IAAI,eAA8C;EAChD,WAAW;EACX,MAAM;EACP;CAED,IAAI,OAAO,YAAY,UACrB,aAAa,YAAY;MACpB,IAAI,OAAO,YAAY,UAC5B,aAAa,OAAO;MAEpB,eAAe,eAAe,WAAW,EAAE,EAAE,aAAa;CAG5D,MAAM,EAAE,WAAW,SAAS;CAC5B,MAAM,MAAM,OAAO,OAAO,CAAC,MAAM,IAAI;CACrC,MAAM,KAAK,IAAI,OAAO,gBAAgB,KAAK,cAAc,IAAI;CAG7D,OAFW,IAAI,GAAG,QAAQ,IAAI,KAAK,YAE5B,IAAM,IAAI,KAAK,IAAI,IAAI,OAAO;;;;;;;;;;AAWvC,SAAgB,YAAY,KAAa,QAAgB,KAAa;CACpE,OAAO,KAAK,IAAI,KAAK,IAAI,QAAQ,IAAI,EAAE,IAAI;;;;;;;;AAS7C,SAAgB,WAAW,QAAyB,OAAO,IAAI;CAC7D,IAAI,SAAS,OAAO,EAAE,OAAO,GAAG,SAAS;CACzC,IAAI,aAAa,KAAK,OAAO,EAAE,OAAO,GAAG,SAAS;CAClD,OAAO;;;;;;;;;;;;;;;AAgBT,SAAgB,eAAe,KAAsB;CAEnD,MAAM,UADS,OAAO,IACN,CAAO,MAAM,6BAA6B;CAC1D,IAAI,CAAC,SAAS,OAAO;CACrB,QAAQ,QAAQ,MAAM,IAAI,SAAS,OAAO,SAAS,QAAQ,MAAM,KAAK,GAAG;;;;;ACpS3E,IAAa,yBAAyB;;AAEtC,IAAa,sBAAsB;;AAEnC,IAAa,yBAAyB;;AAEtC,IAAa,yBAAyB;;AAEtC,IAAa,cAAc,GAAG,yBAAyB,yBAAyB;;;;;;;AAQhF,SAAgB,gBAAgB,QAAgB,QAA0B;CACxE,MAAM,UAAU,OAAO,QAAQ,eAAe,GAAG,SAAU,KAAgB,aAAa,CAAC;CACzF,OAAO,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,aAAa,GAAG,QAAQ,MAAM,EAAE,GAAG;;;;;;;;AASzE,SAAgB,gBAAgB,QAAgB,YAAY,KAAa;CACvE,OAAO,OAAO,QAAQ,WAAW,WAAW,GAAG,YAAY,OAAO,aAAa,GAAG;;;;;;;;;;;AAYpF,SAAgB,aAAa,QAAgB,MAAuB;CAClE,MAAM,YAAY,QAAQ;CAC1B,MAAM,aAAa,UAAU;CAE7B,IAAI,SAAS;CAEb,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAC1B,UAAU,UAAU,OAAO,aAAa,GAAG,aAAa,EAAE,CAAC;CAG7D,OAAO;;AA4CT,SAAgB,aAAa,KAAa,GAAG,MAAyB;CACpE,MAAM,CAAC,UAAU,YAAY;CAE7B,IAAI,SAAS,SAAS,IAAI,YAAY,SAAS,EAAE;EAC/C,MAAM,OAAO,YAAY,EAAE;EAC3B,OAAO,IAAI,QAAQ,eAAe,GAAG,QAAQ,KAAK,SAAS,WAAW,SAAS,GAAG,SAAS,IAAI,GAAG,aAAa,IAAI;;CAGrH,OAAO,IAAI,QAAQ,eAAe,GAAG,QAAQ;EAC3C,MAAM,QAAQ,OAAO,IAAI;EACzB,IAAI,OAAO,MAAM,MAAM,EAAE,OAAO;EAChC,OAAO,KAAK;GACZ;;;;;;;;;AAUJ,SAAgB,cAAsB;CACpC,MAAM,WAAW;CACjB,IAAI,SAAS;CAEb,KAAK,IAAI,IAAI,GAAG,IAAI,IAAiB,KAAK;EACxC,MAAM,IAAI,SAAS;EAEnB,IAAI,MAAM,OAAO,MAAM,KAAK;GAC1B,UAAU;GACV;;EAGF,IAAI,MAAM,KAAK;GACb,UAAU,aAAa,GAAG,OAAO;GACjC;;EAGF,UAAU,aAAa,GAAG,oBAAoB;;CAGhD,OAAO;;;;;;;AAQT,SAAgB,UAAU,OAAgB;CACxC,OAAO,UAAU,MAAM,GAAG,KAAK,OAAO,MAAM"}
|
|
1
|
+
{"version":3,"file":"string2.mjs","names":[],"sources":["../src/number.ts","../src/string.ts"],"sourcesContent":["import { objectDefaults } from './object';\nimport { STRING_DICT } from './string';\nimport { isNumber } from './type';\n\nexport type NumberFixedOptions = {\n /**\n * 保留的小数位数\n * @default 0\n */\n decimals?: number;\n\n /**\n * 舍入方法,0 为四舍五入,1 为向上取整,-1 为向下取整\n * @default 0\n */\n round?: 0 | 1 | -1;\n};\n\n/**\n * 对数字进行精确小数位数处理并按规则舍入\n * @param number 需要处理的原始数值\n * @param options 可选配置参数\n * @returns 处理后的数值(number类型)\n * @example\n * // 四舍五入示例\n * numberFixed(3.1415, { decimals: 2 }); // 3.14\n * // 向上取整示例\n * numberFixed(3.1415, { decimals: 2, round: 1 }); // 3.15\n * // 向下取整示例\n * numberFixed(3.9999, { decimals: 1, round: -1 }); // 3.9\n */\nexport function numberFixed(number: number, options?: NumberFixedOptions) {\n const { decimals = 0, round = 0 } = options || {};\n const scale = 10 ** decimals;\n\n if (round === 1) {\n return Math.ceil(number * scale) / scale;\n }\n\n if (round === -1) {\n return Math.floor(number * scale) / scale;\n }\n\n return Math.round(number * scale) / scale;\n}\n\n/**\n * 生成指定范围内的随机数\n * @param {number | string} min - 随机数的最小值(包含,支持小数、字符串)\n * @param {number | string} max - 随机数的最大值(包含,支持小数、字符串)\n * @returns {number} - 生成的随机数\n * @example\n * // 生成 1 到 10 之间的随机整数\n * randomNumber(1, 10); // 可能返回 7\n *\n * // 生成 0.1 到 2 之间的一位随机小数\n * randomNumber(0.1, 2); // 可能返回 0.7\n *\n * // 生成 0.10 到 2 之间的两位随机小数\n * randomNumber(\"0.10\", 2); // 可能返回 0.75\n */\nexport function randomNumber(min: number | string, max: number | string): number {\n const minDecimals = numberDecimals(min);\n const maxDecimals = numberDecimals(max);\n const decimals = Math.max(minDecimals, maxDecimals);\n const scale = 10 ** decimals;\n\n const minNum = Number(min);\n const maxNum = Number(max);\n const [minFinal, maxFinal] = minNum > maxNum ? [maxNum, minNum] : [minNum, maxNum];\n\n const scaledMin = minFinal * scale;\n const scaledMax = maxFinal * scale;\n\n return Math.floor(Math.random() * (scaledMax - scaledMin + 1) + scaledMin) / scale;\n}\n\n/**\n * 数字缩写选项\n */\nexport type NumberAbbrOptions = {\n /**\n * 进制基数,用于计算单位进阶(如 1000 表示千进制)\n * @default 1000\n */\n base?: number;\n\n /**\n * 数值保留的小数位数\n * @default 0\n */\n decimals?: number;\n};\n\n/**\n * 将数字转换为带单位缩写的字符串表示\n *\n * @param {number} number - 需要转换的原始数值\n * @param {Array<string>} units - 单位数组,按从小到大顺序排列(如['B','KB','MB']),不能为空\n * @param {NumberAbbrOptions} [options] - 可选配置参数\n * @returns {string} - 转换后的带单位字符串(如\"1.2KB\")\n * @example\n * // 基础用法\n * numberAbbr(1500, ['', 'K', 'M'], { base: 1000 }); // \"1.5K\"\n * @example\n * // 自定义小数位\n * numberAbbr(123456, ['B','KB','MB'], { decimals: 1 }); // \"0.1MB\"\n * @example\n * // 处理不足基数的情况\n * numberAbbr(500, ['B','KB']); // \"500B\"\n */\nexport function numberAbbr(number: number, units: Array<string>, options?: NumberAbbrOptions): string {\n const { base = 1000, decimals = 0 } = options || {};\n const { length } = units;\n\n if (length === 0) throw new Error('数字单位组不能为空');\n\n let numberFinal = number;\n let step = 0;\n\n while (numberFinal >= base && step < length - 1) {\n numberFinal = numberFinal / base;\n step++;\n }\n\n const value = numberFixed(numberFinal, { decimals: decimals, round: -1 });\n const unit = units[step];\n\n return `${value}${unit}`;\n}\n\n/**\n * 将文件大小转换为带单位缩写的字符串表示\n *\n * @param {number} number - 需要转换的文件大小数值\n * @param {number} [decimals=0] - 数值保留的小数位数\n * @returns {string} - 转换后的带单位字符串(如\"1.2KB\")\n * @example\n * // 基础用法\n * fileSizeAbbr(1024); // \"1KB\"\n * @example\n * // 自定义小数位\n * fileSizeAbbr(123456, 1); // \"0.1MB\"\n */\nexport function fileSizeAbbr(number: number, decimals = 0) {\n return numberAbbr(number, ['B', 'KB', 'MB', 'GB', 'TB'], {\n base: 1024,\n decimals: decimals,\n });\n}\n\n/**\n * 将十进制数转换为指定进制的字符串表示\n *\n * @param {number | bigint} decimal - 需要转换的十进制数,可以是任意长度的数字或大整数\n * @param {string} [dict] - 用于表示进制的字符字典,默认为数字、小写字母和大写字母的组合(62 进制)\n * @returns {string} - 转换后的指定进制字符串\n * @throws {Error} - 如果字符字典的长度小于 2,将抛出错误\n * @example\n * // 默认 62 进制\n * numberConvert(123456789); // \"8M0kX\"\n * @example\n * // 自定义 16 进制\n * numberConvert(255, '0123456789ABCDEF'); // \"FF\"\n * @example\n * // 处理大整数\n * numberConvert(9007199254740991n); // \"2gosa7pa2GV\"\n */\nexport function numberConvert(decimal: number | bigint, dict?: string): string {\n const dictFinal = dict || STRING_DICT;\n\n if (dictFinal.length < 2) throw new Error('进制转换字典长度不能小于 2');\n\n let bigInt = BigInt(decimal);\n const symbol = bigInt < 0n ? '-' : '';\n bigInt = bigInt < 0n ? -bigInt : bigInt;\n const result: Array<string> = [];\n const { length } = dictFinal;\n const bigLength = BigInt(length);\n const calculate = (): void => {\n const y = Number(bigInt % bigLength);\n\n bigInt = bigInt / bigLength;\n result.unshift(dictFinal[y]);\n\n if (bigInt > 0) {\n calculate();\n }\n };\n\n calculate();\n\n return symbol + result.join('');\n}\n\n/**\n * 数字格式化配置选项\n */\nexport type NumberFormatOptions = {\n /**\n * 分隔符字符,用于数字分隔\n * @default ','\n * @example 使用 '_' 分隔符时,123456 会格式化为 '123_456'\n */\n separator?: string;\n\n /**\n * 分隔步长,即每隔多少位添加分隔符\n * @default 3\n * @example 步长为 2 时,123456 会格式化为 '12,34,56'\n */\n step?: number;\n};\n\n/**\n * 数字格式化\n * @param [number] {number} 数字\n * @param options {NumberFormatOptions} 格式化配置\n * @returns {string} 分割后的字符串\n * @example\n * // 使用默认分隔符和步长\n * numberFormat(123456.789); // => \"123,456.789\"\n * // 自定义分隔符\n * numberFormat(123456.789, '_'); // => \"123_456.789\"\n * // 自定义步长\n * numberFormat(123456.789, 2); // => \"12,34,56.789\"\n * // 使用对象配置\n * numberFormat(123456.789, { separator: '.', step: 4 }); // => \"12.3456.789\"\n */\nexport function numberFormat(number: number | string, options: NumberFormatOptions): string;\nexport function numberFormat(number: number | string, separator: string): string;\nexport function numberFormat(number: number | string, step: number): string;\nexport function numberFormat(number: number | string): string;\nexport function numberFormat(number: number | string, options?: NumberFormatOptions | string | number) {\n let optionsFinal: Required<NumberFormatOptions> = {\n separator: ',',\n step: 3,\n };\n\n if (typeof options === 'string') {\n optionsFinal.separator = options;\n } else if (typeof options === 'number') {\n optionsFinal.step = options;\n } else {\n optionsFinal = objectDefaults(options || {}, optionsFinal) as Required<NumberFormatOptions>;\n }\n\n const { separator, step } = optionsFinal;\n const arr = String(number).split('.');\n const re = new RegExp(`(\\\\d)(?=(\\\\d{${step}})+(?!\\\\d))`, 'g');\n const p1 = arr[0].replace(re, `$1${separator}`);\n\n return p1 + (arr[1] ? `.${arr[1]}` : '');\n}\n\n/**\n * 将数字限制在指定范围内。\n *\n * @param min - 最小值。\n * @param number - 要限制的数字。\n * @param max - 最大值。\n * @returns 限制后的数字。\n */\nexport function numberClamp(min: number, number: number, max: number) {\n return Math.min(Math.max(number, min), max);\n}\n\n/**\n * 为数字添加单位\n * @param number - 需要处理的数字,可以是数字类型或字符串类型\n * @param unit - 要添加的单位,默认为空字符串\n * @returns 如果输入是数字或纯数字字符串,则返回带单位的字符串;否则返回原值\n */\nexport function numberUnit(number: string | number, unit = '') {\n if (isNumber(number)) return `${number}${unit}`;\n if (/^-?[\\d.]+$/.test(number)) return `${number}${unit}`;\n return number;\n}\n\n/**\n * 获取数字的小数位数\n * @param num - 需要计算小数位数的数字或数字字符串\n * @returns 返回数字的小数位数,如果是整数则返回0\n * @example\n * // 基本用法\n * numberDecimals(3.1415); // 4\n * numberDecimals(\"3.1415\"); // 4\n * numberDecimals(100); // 0\n * numberDecimals(\"100\"); // 0\n * // 科学计数法\n * numberDecimals(\"1.23e-4\"); // 6\n */\nexport function numberDecimals(num: number | string) {\n const numStr = String(num);\n const matches = numStr.match(/(?:\\.(\\d+))?(?:e-(\\d+))?$/i);\n if (!matches) return 0;\n return (matches[1] || '').length + Number.parseInt(matches[2] || '0', 10);\n}\n","import { randomNumber } from './number';\nimport { isFunction, isNullish, isObject, isUndefined } from './type';\n\n/** 阿拉伯数字字符集合 */\nexport const STRING_ARABIC_NUMERALS = '0123456789';\n/** 十六进制字符集合 */\nexport const STRING_HEXADECIMALS = '0123456789abcdef';\n/** 小写字母字符集合 */\nexport const STRING_LOWERCASE_ALPHA = 'abcdefghijklmnopqrstuvwxyz';\n/** 大写字母字符集合 */\nexport const STRING_UPPERCASE_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';\n/** 随机字符串字典,包含数字、大写字母和小写字母 */\nexport const STRING_DICT = `${STRING_ARABIC_NUMERALS + STRING_UPPERCASE_ALPHA + STRING_LOWERCASE_ALPHA}`;\n\n/**\n * 将字符串转换为驼峰格式\n * @param {string} string - 要转换的字符串\n * @param {boolean} [bigger] - 是否大写第一个字母,默认为 false\n * @returns {string} - 转换后的驼峰格式字符串\n */\nexport function stringCamelCase(string: string, bigger?: boolean): string {\n const string2 = string.replace(/[\\s_-](.)/g, (_, char) => (char as string).toUpperCase());\n return bigger ? string2.slice(0, 1).toUpperCase() + string2.slice(1) : string2;\n}\n\n/**\n * 将字符串转换为连字格式\n * @param {string} string - 要转换的字符串\n * @param {string} [separator] - 分隔符,默认是 \"-\"(短横线)\n * @returns {string} - 转换后的连字格式字符串\n */\nexport function stringKebabCase(string: string, separator = '-'): string {\n return string.replace(/[A-Z]/g, (origin) => `${separator}${origin.toLowerCase()}`);\n}\n\n/**\n * 生成随机字符串\n * @param {number} length - 生成的随机字符串长度\n * @param {string} [dict] - 用于生成随机字符串的字符字典,默认为数字、小写字母和大写字母的组合\n * @returns {string} - 生成的随机字符串\n * @example\n * randomString(10); // 生成一个长度为 10 的随机字符串\n * randomString(8, 'ABCDEF'); // 生成一个长度为 8 的随机字符串,仅包含字符 'ABCDEF'\n */\nexport function randomString(length: number, dict?: string): string {\n const dictFinal = dict || STRING_DICT;\n const dictLength = dictFinal.length;\n\n let result = '';\n\n for (let i = 0; i < length; i++) {\n result += dictFinal.charAt(randomNumber(0, dictLength - 1));\n }\n\n return result;\n}\n\n/**\n * 简单的模板引擎,类似于 Python 的 `.format()` 方法\n * 支持通过索引或对象/名称的方式传递变量\n * 当使用对象/名称方式时,可以传递一个回退值作为第三个参数\n *\n * @category 字符串\n * @example\n * ```\n * // 索引方式\n * const result = stringFormat(\n * '你好 {0}!我的名字是 {1}。',\n * '张三',\n * '李四'\n * ); // 你好 张三!我的名字是 李四。\n * ```\n *\n * @example\n * ```\n * // 对象方式\n * const result = stringFormat(\n * '{greet}!我的名字是 {name}。',\n * { greet: '你好', name: '王五' }\n * ); // 你好!我的名字是 王五。\n * ```\n *\n * @example\n * ```\n * // 带回退值的对象方式\n * const result = stringFormat(\n * '{greet}!我的名字是 {name}。',\n * { greet: '你好' }, // name 未传递,因此会使用回退值\n * '未知'\n * ); // 你好!我的名字是 未知。\n * ```\n */\nexport function stringFormat(\n str: string,\n object: Record<string | number, unknown>,\n fallback?: string | ((key: string) => string),\n): string;\nexport function stringFormat(str: string, ...args: (string | number | bigint | undefined | null)[]): string;\nexport function stringFormat(str: string, ...args: unknown[]): string {\n const [firstArg, fallback] = args;\n\n if (isObject(firstArg) || isUndefined(firstArg)) {\n const vars = firstArg || {};\n return str.replace(/\\{(\\w+)\\}/g, (_, key) => vars[key] ?? (isFunction(fallback) ? fallback(key) : fallback) ?? key);\n }\n\n return str.replace(/\\{(\\d+)\\}/g, (_, key) => {\n const index = Number(key);\n if (Number.isNaN(index)) return key;\n return args[index];\n });\n}\n\n/**\n * 生成符合 [RFC 4122](https://www.ietf.org/rfc/rfc4122.txt) 版本 4 的 UUID 字符串\n * @returns {string} - 生成的 UUID 字符串\n * @example\n * const uuid = randomUUID4();\n * console.log(uuid); // 输出类似 '123e4567-e89b-12d3-a456-426614174000' 的 UUID 字符串\n */\nexport function randomUUID4(): string {\n const template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';\n let result = '';\n\n for (let i = 0; i < template.length; i++) {\n const t = template[i];\n\n if (t === '-' || t === '4') {\n result += t;\n continue;\n }\n\n if (t === 'y') {\n result += randomString(1, '89ab');\n continue;\n }\n\n result += randomString(1, STRING_HEXADECIMALS);\n }\n\n return result;\n}\n\n/**\n * 将值转换为字符串,若值为 null 或 undefined 则返回空字符串\n * @param {unknown} value - 需要转换的值\n * @returns {string} 转换后的字符串结果\n */\nexport function stringify(value: unknown) {\n return isNullish(value) ? '' : String(value);\n}\n"],"mappings":"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"}
|
package/dist/time.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.cjs","names":[],"sources":["../src/time/from.ts","../src/time/to.ts"],"sourcesContent":["// @rer https://day.js.org/docs/en/durations/creating\n\nimport { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_MONTH_MS, DATE_SECOND_MS, DATE_YEAR_MS } from '@/date';\nimport { isString } from '@/type';\nimport type { TimeDuration } from './to';\n\n/**\n * 时间转换规则数组\n * @type {Array<[RegExp, (match: RegExpMatchArray) => number]>}\n * @property {RegExp} 0 - 匹配时间单位正则表达式\n * @property {function} 1 - 将匹配结果转换为毫秒数的函数\n */\nconst rules: [key: keyof TimeDuration, time: number][] = [\n ['years', DATE_YEAR_MS],\n ['months', DATE_MONTH_MS],\n ['days', DATE_DAY_MS],\n ['hours', DATE_HOUR_MS],\n ['minutes', DATE_MINUTE_MS],\n ['seconds', DATE_SECOND_MS],\n];\n\n/**\n * 将时间持续时间字符串或对象转换为毫秒数\n *\n * @param duration - 可以是时间持续时间字符串(如 '1d2h')或 TimeDuration 对象\n * @returns 计算得到的总毫秒数\n */\nexport function timeFrom(duration: string | TimeDuration) {\n const td = isString(duration) ? timeParse(duration) : duration;\n return rules.reduce((acc, [key, time]) => acc + (td[key] || 0) * time, 0);\n}\n\nconst durationMatchRules: [RegExp, key: keyof TimeDuration][] = [\n [/(\\d+)y/i, 'years'],\n [/(\\d+)M/, 'months'],\n [/(\\d+)d/i, 'days'],\n [/(\\d+)h/i, 'hours'],\n [/(\\d+)m/, 'minutes'],\n [/(\\d+)s/, 'seconds'],\n];\n\n/**\n * 将时长字符串解析为时间对象\n * @param duration - 时长字符串(例如 \"1h30m\")\n * @returns 包含解析后时间单位的对象(小时、分钟等)\n */\nexport function timeParse(duration: string) {\n const result = {} as TimeDuration;\n\n for (const [regex, key] of durationMatchRules) {\n const match = duration.match(regex);\n if (match) result[key] = Number(match[1]);\n else result[key] = 0;\n }\n\n return result;\n}\n","import { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_SECOND_MS } from '../date';\n\nexport type TimeDuration = {\n years: number;\n months: number;\n /** 天数 */\n days: number;\n /** 小时数 */\n hours: number;\n /** 分钟数 */\n minutes: number;\n /** 秒数 */\n seconds: number;\n /** 毫秒数 */\n milliseconds: number;\n};\n\ntype _TTimeParsePoint = 'D' | 'h' | 'm' | 's' | 'S';\n\n/**\n * 解析时间毫秒数为绝对时间对象\n * @param timeMs 时间毫秒数\n * @param maxPoint 最大时间单位(决定分解的起始单位)\n * @returns 包含时间单位分解结果的对象\n * @example\n * ```typescript\n * // 默认以天为最大单位分解\n * timeInDay(123456789);\n * // { days: 1, hours: 10, minutes: 17, seconds: 36, milliseconds: 789 }\n *\n * // 指定最大单位为分钟,分解到分钟及以下单位\n * timeInMinute(123456789);\n * // { days: 0, hours: 0, minutes: 2057, seconds: 36, milliseconds: 789 }\n * ```\n */\nfunction _timeAbsolute(timeMs: number, maxPoint: _TTimeParsePoint): TimeDuration {\n const minPoint: _TTimeParsePoint = 'S';\n\n const defines: [point: _TTimeParsePoint, key: keyof TimeDuration, base: number][] = [\n ['D', 'days', DATE_DAY_MS],\n ['h', 'hours', DATE_HOUR_MS],\n ['m', 'minutes', DATE_MINUTE_MS],\n ['s', 'seconds', DATE_SECOND_MS],\n ['S', 'milliseconds', 1],\n ] as const;\n\n const minIndex = defines.findIndex((item) => item[0] === maxPoint);\n const maxIndex = defines.findIndex((item) => item[0] === minPoint);\n\n let timeMsFinal = timeMs;\n const dao: TimeDuration = {\n years: 0,\n months: 0,\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n milliseconds: 0,\n };\n\n for (let i = minIndex; i <= maxIndex; i++) {\n const mode = defines[i];\n const base = mode[2];\n const value = Math.floor(timeMsFinal / base);\n timeMsFinal = timeMsFinal - value * base;\n dao[mode[1]] = value;\n }\n\n return dao;\n}\n\n/**\n * 将时间毫秒数解析为以天为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含天/小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToDays(timeMs: number) {\n return _timeAbsolute(timeMs, 'D');\n}\n\n/**\n * 将时间毫秒数解析为以小时为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToHours(timeMs: number) {\n return _timeAbsolute(timeMs, 'h');\n}\n\n/**\n * 将时间毫秒数解析为以分钟为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含分钟/秒/毫秒分解结果的对象\n */\nexport function timeToMinutes(timeMs: number) {\n return _timeAbsolute(timeMs, 'm');\n}\n\n/**\n * 将时间毫秒数解析为以秒为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含秒/毫秒分解结果的对象\n */\nexport function timeToSeconds(timeMs: number) {\n return _timeAbsolute(timeMs, 's');\n}\n"],"mappings":";;;;;;;;;;AAYA,IAAM,QAAmD;CACvD,CAAC,SAAS,aAAA,
|
|
1
|
+
{"version":3,"file":"time.cjs","names":[],"sources":["../src/time/from.ts","../src/time/to.ts"],"sourcesContent":["// @rer https://day.js.org/docs/en/durations/creating\n\nimport { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_MONTH_MS, DATE_SECOND_MS, DATE_YEAR_MS } from '@/date';\nimport { isString } from '@/type';\nimport type { TimeDuration } from './to';\n\n/**\n * 时间转换规则数组\n * @type {Array<[RegExp, (match: RegExpMatchArray) => number]>}\n * @property {RegExp} 0 - 匹配时间单位正则表达式\n * @property {function} 1 - 将匹配结果转换为毫秒数的函数\n */\nconst rules: [key: keyof TimeDuration, time: number][] = [\n ['years', DATE_YEAR_MS],\n ['months', DATE_MONTH_MS],\n ['days', DATE_DAY_MS],\n ['hours', DATE_HOUR_MS],\n ['minutes', DATE_MINUTE_MS],\n ['seconds', DATE_SECOND_MS],\n];\n\n/**\n * 将时间持续时间字符串或对象转换为毫秒数\n *\n * @param duration - 可以是时间持续时间字符串(如 '1d2h')或 TimeDuration 对象\n * @returns 计算得到的总毫秒数\n */\nexport function timeFrom(duration: string | TimeDuration) {\n const td = isString(duration) ? timeParse(duration) : duration;\n return rules.reduce((acc, [key, time]) => acc + (td[key] || 0) * time, 0);\n}\n\nconst durationMatchRules: [RegExp, key: keyof TimeDuration][] = [\n [/(\\d+)y/i, 'years'],\n [/(\\d+)M/, 'months'],\n [/(\\d+)d/i, 'days'],\n [/(\\d+)h/i, 'hours'],\n [/(\\d+)m/, 'minutes'],\n [/(\\d+)s/, 'seconds'],\n];\n\n/**\n * 将时长字符串解析为时间对象\n * @param duration - 时长字符串(例如 \"1h30m\")\n * @returns 包含解析后时间单位的对象(小时、分钟等)\n */\nexport function timeParse(duration: string) {\n const result = {} as TimeDuration;\n\n for (const [regex, key] of durationMatchRules) {\n const match = duration.match(regex);\n if (match) result[key] = Number(match[1]);\n else result[key] = 0;\n }\n\n return result;\n}\n","import { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_SECOND_MS } from '../date';\n\nexport type TimeDuration = {\n years: number;\n months: number;\n /** 天数 */\n days: number;\n /** 小时数 */\n hours: number;\n /** 分钟数 */\n minutes: number;\n /** 秒数 */\n seconds: number;\n /** 毫秒数 */\n milliseconds: number;\n};\n\ntype _TTimeParsePoint = 'D' | 'h' | 'm' | 's' | 'S';\n\n/**\n * 解析时间毫秒数为绝对时间对象\n * @param timeMs 时间毫秒数\n * @param maxPoint 最大时间单位(决定分解的起始单位)\n * @returns 包含时间单位分解结果的对象\n * @example\n * ```typescript\n * // 默认以天为最大单位分解\n * timeInDay(123456789);\n * // { days: 1, hours: 10, minutes: 17, seconds: 36, milliseconds: 789 }\n *\n * // 指定最大单位为分钟,分解到分钟及以下单位\n * timeInMinute(123456789);\n * // { days: 0, hours: 0, minutes: 2057, seconds: 36, milliseconds: 789 }\n * ```\n */\nfunction _timeAbsolute(timeMs: number, maxPoint: _TTimeParsePoint): TimeDuration {\n const minPoint: _TTimeParsePoint = 'S';\n\n const defines: [point: _TTimeParsePoint, key: keyof TimeDuration, base: number][] = [\n ['D', 'days', DATE_DAY_MS],\n ['h', 'hours', DATE_HOUR_MS],\n ['m', 'minutes', DATE_MINUTE_MS],\n ['s', 'seconds', DATE_SECOND_MS],\n ['S', 'milliseconds', 1],\n ] as const;\n\n const minIndex = defines.findIndex((item) => item[0] === maxPoint);\n const maxIndex = defines.findIndex((item) => item[0] === minPoint);\n\n let timeMsFinal = timeMs;\n const dao: TimeDuration = {\n years: 0,\n months: 0,\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n milliseconds: 0,\n };\n\n for (let i = minIndex; i <= maxIndex; i++) {\n const mode = defines[i];\n const base = mode[2];\n const value = Math.floor(timeMsFinal / base);\n timeMsFinal = timeMsFinal - value * base;\n dao[mode[1]] = value;\n }\n\n return dao;\n}\n\n/**\n * 将时间毫秒数解析为以天为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含天/小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToDays(timeMs: number) {\n return _timeAbsolute(timeMs, 'D');\n}\n\n/**\n * 将时间毫秒数解析为以小时为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToHours(timeMs: number) {\n return _timeAbsolute(timeMs, 'h');\n}\n\n/**\n * 将时间毫秒数解析为以分钟为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含分钟/秒/毫秒分解结果的对象\n */\nexport function timeToMinutes(timeMs: number) {\n return _timeAbsolute(timeMs, 'm');\n}\n\n/**\n * 将时间毫秒数解析为以秒为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含秒/毫秒分解结果的对象\n */\nexport function timeToSeconds(timeMs: number) {\n return _timeAbsolute(timeMs, 's');\n}\n"],"mappings":";;;;;;;;;;AAYA,IAAM,QAAmD;CACvD,CAAC,SAAS,aAAA,YAAY;CACtB,CAAC,UAAU,aAAA,aAAa;CACxB,CAAC,QAAQ,aAAA,WAAW;CACpB,CAAC,SAAS,aAAA,YAAY;CACtB,CAAC,WAAW,aAAA,cAAc;CAC1B,CAAC,WAAW,aAAA,cAAc;AAC5B;;;;;;;AAQA,SAAgB,SAAS,UAAiC;CACxD,MAAM,KAAK,aAAA,SAAS,QAAQ,IAAI,UAAU,QAAQ,IAAI;CACtD,OAAO,MAAM,QAAQ,KAAK,CAAC,KAAK,UAAU,OAAO,GAAG,QAAQ,KAAK,MAAM,CAAC;AAC1E;AAEA,IAAM,qBAA0D;CAC9D,CAAC,WAAW,OAAO;CACnB,CAAC,UAAU,QAAQ;CACnB,CAAC,WAAW,MAAM;CAClB,CAAC,WAAW,OAAO;CACnB,CAAC,UAAU,SAAS;CACpB,CAAC,UAAU,SAAS;AACtB;;;;;;AAOA,SAAgB,UAAU,UAAkB;CAC1C,MAAM,SAAS,CAAC;CAEhB,KAAK,MAAM,CAAC,OAAO,QAAQ,oBAAoB;EAC7C,MAAM,QAAQ,SAAS,MAAM,KAAK;EAClC,IAAI,OAAO,OAAO,OAAO,OAAO,MAAM,EAAE;OACnC,OAAO,OAAO;CACrB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;ACrBA,SAAS,cAAc,QAAgB,UAA0C;CAC/E,MAAM,WAA6B;CAEnC,MAAM,UAA8E;EAClF;GAAC;GAAK;GAAQ,aAAA;EAAW;EACzB;GAAC;GAAK;GAAS,aAAA;EAAY;EAC3B;GAAC;GAAK;GAAW,aAAA;EAAc;EAC/B;GAAC;GAAK;GAAW,aAAA;EAAc;EAC/B;GAAC;GAAK;GAAgB;EAAC;CACzB;CAEA,MAAM,WAAW,QAAQ,WAAW,SAAS,KAAK,OAAO,QAAQ;CACjE,MAAM,WAAW,QAAQ,WAAW,SAAS,KAAK,OAAO,QAAQ;CAEjE,IAAI,cAAc;CAClB,MAAM,MAAoB;EACxB,OAAO;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS;EACT,SAAS;EACT,cAAc;CAChB;CAEA,KAAK,IAAI,IAAI,UAAU,KAAK,UAAU,KAAK;EACzC,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,KAAK;EAClB,MAAM,QAAQ,KAAK,MAAM,cAAc,IAAI;EAC3C,cAAc,cAAc,QAAQ;EACpC,IAAI,KAAK,MAAM;CACjB;CAEA,OAAO;AACT;;;;;;AAOA,SAAgB,WAAW,QAAgB;CACzC,OAAO,cAAc,QAAQ,GAAG;AAClC;;;;;;AAOA,SAAgB,YAAY,QAAgB;CAC1C,OAAO,cAAc,QAAQ,GAAG;AAClC;;;;;;AAOA,SAAgB,cAAc,QAAgB;CAC5C,OAAO,cAAc,QAAQ,GAAG;AAClC;;;;;;AAOA,SAAgB,cAAc,QAAgB;CAC5C,OAAO,cAAc,QAAQ,GAAG;AAClC"}
|
package/dist/time.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.mjs","names":[],"sources":["../src/time/from.ts","../src/time/to.ts"],"sourcesContent":["// @rer https://day.js.org/docs/en/durations/creating\n\nimport { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_MONTH_MS, DATE_SECOND_MS, DATE_YEAR_MS } from '@/date';\nimport { isString } from '@/type';\nimport type { TimeDuration } from './to';\n\n/**\n * 时间转换规则数组\n * @type {Array<[RegExp, (match: RegExpMatchArray) => number]>}\n * @property {RegExp} 0 - 匹配时间单位正则表达式\n * @property {function} 1 - 将匹配结果转换为毫秒数的函数\n */\nconst rules: [key: keyof TimeDuration, time: number][] = [\n ['years', DATE_YEAR_MS],\n ['months', DATE_MONTH_MS],\n ['days', DATE_DAY_MS],\n ['hours', DATE_HOUR_MS],\n ['minutes', DATE_MINUTE_MS],\n ['seconds', DATE_SECOND_MS],\n];\n\n/**\n * 将时间持续时间字符串或对象转换为毫秒数\n *\n * @param duration - 可以是时间持续时间字符串(如 '1d2h')或 TimeDuration 对象\n * @returns 计算得到的总毫秒数\n */\nexport function timeFrom(duration: string | TimeDuration) {\n const td = isString(duration) ? timeParse(duration) : duration;\n return rules.reduce((acc, [key, time]) => acc + (td[key] || 0) * time, 0);\n}\n\nconst durationMatchRules: [RegExp, key: keyof TimeDuration][] = [\n [/(\\d+)y/i, 'years'],\n [/(\\d+)M/, 'months'],\n [/(\\d+)d/i, 'days'],\n [/(\\d+)h/i, 'hours'],\n [/(\\d+)m/, 'minutes'],\n [/(\\d+)s/, 'seconds'],\n];\n\n/**\n * 将时长字符串解析为时间对象\n * @param duration - 时长字符串(例如 \"1h30m\")\n * @returns 包含解析后时间单位的对象(小时、分钟等)\n */\nexport function timeParse(duration: string) {\n const result = {} as TimeDuration;\n\n for (const [regex, key] of durationMatchRules) {\n const match = duration.match(regex);\n if (match) result[key] = Number(match[1]);\n else result[key] = 0;\n }\n\n return result;\n}\n","import { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_SECOND_MS } from '../date';\n\nexport type TimeDuration = {\n years: number;\n months: number;\n /** 天数 */\n days: number;\n /** 小时数 */\n hours: number;\n /** 分钟数 */\n minutes: number;\n /** 秒数 */\n seconds: number;\n /** 毫秒数 */\n milliseconds: number;\n};\n\ntype _TTimeParsePoint = 'D' | 'h' | 'm' | 's' | 'S';\n\n/**\n * 解析时间毫秒数为绝对时间对象\n * @param timeMs 时间毫秒数\n * @param maxPoint 最大时间单位(决定分解的起始单位)\n * @returns 包含时间单位分解结果的对象\n * @example\n * ```typescript\n * // 默认以天为最大单位分解\n * timeInDay(123456789);\n * // { days: 1, hours: 10, minutes: 17, seconds: 36, milliseconds: 789 }\n *\n * // 指定最大单位为分钟,分解到分钟及以下单位\n * timeInMinute(123456789);\n * // { days: 0, hours: 0, minutes: 2057, seconds: 36, milliseconds: 789 }\n * ```\n */\nfunction _timeAbsolute(timeMs: number, maxPoint: _TTimeParsePoint): TimeDuration {\n const minPoint: _TTimeParsePoint = 'S';\n\n const defines: [point: _TTimeParsePoint, key: keyof TimeDuration, base: number][] = [\n ['D', 'days', DATE_DAY_MS],\n ['h', 'hours', DATE_HOUR_MS],\n ['m', 'minutes', DATE_MINUTE_MS],\n ['s', 'seconds', DATE_SECOND_MS],\n ['S', 'milliseconds', 1],\n ] as const;\n\n const minIndex = defines.findIndex((item) => item[0] === maxPoint);\n const maxIndex = defines.findIndex((item) => item[0] === minPoint);\n\n let timeMsFinal = timeMs;\n const dao: TimeDuration = {\n years: 0,\n months: 0,\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n milliseconds: 0,\n };\n\n for (let i = minIndex; i <= maxIndex; i++) {\n const mode = defines[i];\n const base = mode[2];\n const value = Math.floor(timeMsFinal / base);\n timeMsFinal = timeMsFinal - value * base;\n dao[mode[1]] = value;\n }\n\n return dao;\n}\n\n/**\n * 将时间毫秒数解析为以天为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含天/小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToDays(timeMs: number) {\n return _timeAbsolute(timeMs, 'D');\n}\n\n/**\n * 将时间毫秒数解析为以小时为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToHours(timeMs: number) {\n return _timeAbsolute(timeMs, 'h');\n}\n\n/**\n * 将时间毫秒数解析为以分钟为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含分钟/秒/毫秒分解结果的对象\n */\nexport function timeToMinutes(timeMs: number) {\n return _timeAbsolute(timeMs, 'm');\n}\n\n/**\n * 将时间毫秒数解析为以秒为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含秒/毫秒分解结果的对象\n */\nexport function timeToSeconds(timeMs: number) {\n return _timeAbsolute(timeMs, 's');\n}\n"],"mappings":";;;;;;;;;AAYA,IAAM,QAAmD;CACvD,CAAC,SAAS,
|
|
1
|
+
{"version":3,"file":"time.mjs","names":[],"sources":["../src/time/from.ts","../src/time/to.ts"],"sourcesContent":["// @rer https://day.js.org/docs/en/durations/creating\n\nimport { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_MONTH_MS, DATE_SECOND_MS, DATE_YEAR_MS } from '@/date';\nimport { isString } from '@/type';\nimport type { TimeDuration } from './to';\n\n/**\n * 时间转换规则数组\n * @type {Array<[RegExp, (match: RegExpMatchArray) => number]>}\n * @property {RegExp} 0 - 匹配时间单位正则表达式\n * @property {function} 1 - 将匹配结果转换为毫秒数的函数\n */\nconst rules: [key: keyof TimeDuration, time: number][] = [\n ['years', DATE_YEAR_MS],\n ['months', DATE_MONTH_MS],\n ['days', DATE_DAY_MS],\n ['hours', DATE_HOUR_MS],\n ['minutes', DATE_MINUTE_MS],\n ['seconds', DATE_SECOND_MS],\n];\n\n/**\n * 将时间持续时间字符串或对象转换为毫秒数\n *\n * @param duration - 可以是时间持续时间字符串(如 '1d2h')或 TimeDuration 对象\n * @returns 计算得到的总毫秒数\n */\nexport function timeFrom(duration: string | TimeDuration) {\n const td = isString(duration) ? timeParse(duration) : duration;\n return rules.reduce((acc, [key, time]) => acc + (td[key] || 0) * time, 0);\n}\n\nconst durationMatchRules: [RegExp, key: keyof TimeDuration][] = [\n [/(\\d+)y/i, 'years'],\n [/(\\d+)M/, 'months'],\n [/(\\d+)d/i, 'days'],\n [/(\\d+)h/i, 'hours'],\n [/(\\d+)m/, 'minutes'],\n [/(\\d+)s/, 'seconds'],\n];\n\n/**\n * 将时长字符串解析为时间对象\n * @param duration - 时长字符串(例如 \"1h30m\")\n * @returns 包含解析后时间单位的对象(小时、分钟等)\n */\nexport function timeParse(duration: string) {\n const result = {} as TimeDuration;\n\n for (const [regex, key] of durationMatchRules) {\n const match = duration.match(regex);\n if (match) result[key] = Number(match[1]);\n else result[key] = 0;\n }\n\n return result;\n}\n","import { DATE_DAY_MS, DATE_HOUR_MS, DATE_MINUTE_MS, DATE_SECOND_MS } from '../date';\n\nexport type TimeDuration = {\n years: number;\n months: number;\n /** 天数 */\n days: number;\n /** 小时数 */\n hours: number;\n /** 分钟数 */\n minutes: number;\n /** 秒数 */\n seconds: number;\n /** 毫秒数 */\n milliseconds: number;\n};\n\ntype _TTimeParsePoint = 'D' | 'h' | 'm' | 's' | 'S';\n\n/**\n * 解析时间毫秒数为绝对时间对象\n * @param timeMs 时间毫秒数\n * @param maxPoint 最大时间单位(决定分解的起始单位)\n * @returns 包含时间单位分解结果的对象\n * @example\n * ```typescript\n * // 默认以天为最大单位分解\n * timeInDay(123456789);\n * // { days: 1, hours: 10, minutes: 17, seconds: 36, milliseconds: 789 }\n *\n * // 指定最大单位为分钟,分解到分钟及以下单位\n * timeInMinute(123456789);\n * // { days: 0, hours: 0, minutes: 2057, seconds: 36, milliseconds: 789 }\n * ```\n */\nfunction _timeAbsolute(timeMs: number, maxPoint: _TTimeParsePoint): TimeDuration {\n const minPoint: _TTimeParsePoint = 'S';\n\n const defines: [point: _TTimeParsePoint, key: keyof TimeDuration, base: number][] = [\n ['D', 'days', DATE_DAY_MS],\n ['h', 'hours', DATE_HOUR_MS],\n ['m', 'minutes', DATE_MINUTE_MS],\n ['s', 'seconds', DATE_SECOND_MS],\n ['S', 'milliseconds', 1],\n ] as const;\n\n const minIndex = defines.findIndex((item) => item[0] === maxPoint);\n const maxIndex = defines.findIndex((item) => item[0] === minPoint);\n\n let timeMsFinal = timeMs;\n const dao: TimeDuration = {\n years: 0,\n months: 0,\n days: 0,\n hours: 0,\n minutes: 0,\n seconds: 0,\n milliseconds: 0,\n };\n\n for (let i = minIndex; i <= maxIndex; i++) {\n const mode = defines[i];\n const base = mode[2];\n const value = Math.floor(timeMsFinal / base);\n timeMsFinal = timeMsFinal - value * base;\n dao[mode[1]] = value;\n }\n\n return dao;\n}\n\n/**\n * 将时间毫秒数解析为以天为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含天/小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToDays(timeMs: number) {\n return _timeAbsolute(timeMs, 'D');\n}\n\n/**\n * 将时间毫秒数解析为以小时为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含小时/分钟/秒/毫秒分解结果的对象\n */\nexport function timeToHours(timeMs: number) {\n return _timeAbsolute(timeMs, 'h');\n}\n\n/**\n * 将时间毫秒数解析为以分钟为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含分钟/秒/毫秒分解结果的对象\n */\nexport function timeToMinutes(timeMs: number) {\n return _timeAbsolute(timeMs, 'm');\n}\n\n/**\n * 将时间毫秒数解析为以秒为最大单位的绝对时间对象\n * @param timeMs 时间毫秒数\n * @returns 包含秒/毫秒分解结果的对象\n */\nexport function timeToSeconds(timeMs: number) {\n return _timeAbsolute(timeMs, 's');\n}\n"],"mappings":";;;;;;;;;AAYA,IAAM,QAAmD;CACvD,CAAC,SAAS,YAAY;CACtB,CAAC,UAAU,aAAa;CACxB,CAAC,QAAQ,WAAW;CACpB,CAAC,SAAS,YAAY;CACtB,CAAC,WAAW,cAAc;CAC1B,CAAC,WAAW,cAAc;AAC5B;;;;;;;AAQA,SAAgB,SAAS,UAAiC;CACxD,MAAM,KAAK,SAAS,QAAQ,IAAI,UAAU,QAAQ,IAAI;CACtD,OAAO,MAAM,QAAQ,KAAK,CAAC,KAAK,UAAU,OAAO,GAAG,QAAQ,KAAK,MAAM,CAAC;AAC1E;AAEA,IAAM,qBAA0D;CAC9D,CAAC,WAAW,OAAO;CACnB,CAAC,UAAU,QAAQ;CACnB,CAAC,WAAW,MAAM;CAClB,CAAC,WAAW,OAAO;CACnB,CAAC,UAAU,SAAS;CACpB,CAAC,UAAU,SAAS;AACtB;;;;;;AAOA,SAAgB,UAAU,UAAkB;CAC1C,MAAM,SAAS,CAAC;CAEhB,KAAK,MAAM,CAAC,OAAO,QAAQ,oBAAoB;EAC7C,MAAM,QAAQ,SAAS,MAAM,KAAK;EAClC,IAAI,OAAO,OAAO,OAAO,OAAO,MAAM,EAAE;OACnC,OAAO,OAAO;CACrB;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;ACrBA,SAAS,cAAc,QAAgB,UAA0C;CAC/E,MAAM,WAA6B;CAEnC,MAAM,UAA8E;EAClF;GAAC;GAAK;GAAQ;EAAW;EACzB;GAAC;GAAK;GAAS;EAAY;EAC3B;GAAC;GAAK;GAAW;EAAc;EAC/B;GAAC;GAAK;GAAW;EAAc;EAC/B;GAAC;GAAK;GAAgB;EAAC;CACzB;CAEA,MAAM,WAAW,QAAQ,WAAW,SAAS,KAAK,OAAO,QAAQ;CACjE,MAAM,WAAW,QAAQ,WAAW,SAAS,KAAK,OAAO,QAAQ;CAEjE,IAAI,cAAc;CAClB,MAAM,MAAoB;EACxB,OAAO;EACP,QAAQ;EACR,MAAM;EACN,OAAO;EACP,SAAS;EACT,SAAS;EACT,cAAc;CAChB;CAEA,KAAK,IAAI,IAAI,UAAU,KAAK,UAAU,KAAK;EACzC,MAAM,OAAO,QAAQ;EACrB,MAAM,OAAO,KAAK;EAClB,MAAM,QAAQ,KAAK,MAAM,cAAc,IAAI;EAC3C,cAAc,cAAc,QAAQ;EACpC,IAAI,KAAK,MAAM;CACjB;CAEA,OAAO;AACT;;;;;;AAOA,SAAgB,WAAW,QAAgB;CACzC,OAAO,cAAc,QAAQ,GAAG;AAClC;;;;;;AAOA,SAAgB,YAAY,QAAgB;CAC1C,OAAO,cAAc,QAAQ,GAAG;AAClC;;;;;;AAOA,SAAgB,cAAc,QAAgB;CAC5C,OAAO,cAAc,QAAQ,GAAG;AAClC;;;;;;AAOA,SAAgB,cAAc,QAAgB;CAC5C,OAAO,cAAc,QAAQ,GAAG;AAClC"}
|
package/dist/timer.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timer.cjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态基础接口\n */\nexport type TimerStateBase = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\n/**\n * 定时器状态接口\n * @template T - condition 函数返回值类型,默认为 unknown\n */\nexport type TimerState<T = unknown> = TimerStateBase & {\n /**\n * condition 函数返回值,未传入 condition 时为 null\n */\n data: T;\n};\n\n/**\n * 定时器控制方法集合\n */\nexport type TimerHandler = {\n /**\n * 启动定时器\n */\n start: () => void;\n /**\n * 暂停定时器\n */\n pause: () => void;\n /**\n * 恢复定时器\n * @param immediate - 是否立即执行一次\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止定时器\n */\n stop: () => void;\n /**\n * 清除上一次定时器,立即执行,并开始下一次定时器\n */\n execute: () => void;\n};\n\n/**\n * 间隔定时器控制方法集合,包含状态查询方法\n */\nexport type IntervalHandler = TimerHandler & {\n /**\n * 是否可以启动(处于 READY 状态)\n */\n canStart: () => boolean;\n /**\n * 是否可以停止(处于 START 状态)\n */\n canStop: () => boolean;\n /**\n * 是否可以暂停(处于 START 状态)\n */\n canPause: () => boolean;\n /**\n * 是否可以恢复(处于 PAUSE 状态)\n */\n canResume: () => boolean;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * makeInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type MakeIntervalOptions<T> = {\n /**\n * 调度器函数,用于安排下一次执行\n */\n dispatcher: (dispatch: () => void) => unknown;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 使用 MaybePromise 支持同步或异步条件判断\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断\n */\n runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 true\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建可控制的间隔定时器核心函数\n *\n * @example\n * ```typescript\n * // 无 condition,state.data 为 null\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler {\n const { dispatcher, runner, condition, leading, trailing } = options;\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = async () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState<T> = {\n times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n data: null as T,\n };\n\n if (condition) {\n try {\n state.data = await condition(state);\n } catch {\n dispatcher(execute);\n return;\n }\n }\n\n state.times = ++times;\n\n await (runner as (timer: TimerState<T>) => unknown)(state);\n dispatcher(execute);\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n if (leading === false) {\n dispatcher(execute);\n } else {\n execute();\n }\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n if (trailing) execute();\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n if (trailing) execute();\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\n/**\n * timerInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type TimerIntervalOptions<T> = {\n /**\n * 间隔时间,单位为毫秒\n */\n interval: number;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n */\n runner: (state: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 false\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建基于 setTimeout 的间隔定时器\n *\n * @example\n * ```typescript\n * // 无 condition\n * timerInterval({\n * interval: 1000,\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * timerInterval({\n * interval: 1000,\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler {\n const { runner, interval, condition, leading, trailing } = options;\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({\n dispatcher: (dispatch) => {\n timeId = setTimeout(dispatch, interval);\n },\n runner,\n condition,\n leading: leading ?? false,\n trailing,\n });\n\n return {\n start() {\n if (!canStart()) return;\n start();\n },\n\n stop() {\n if (!canStop()) return;\n stop();\n clearTimeout(timeId);\n },\n\n pause() {\n if (!canPause()) return;\n pause();\n clearTimeout(timeId);\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n if (immediate || leading) {\n resume();\n } else {\n timeId = setTimeout(() => resume(), interval);\n }\n },\n\n execute() {\n clearTimeout(timeId);\n execute();\n },\n };\n}\n"],"mappings":";;AAsGA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAsDpB,SAAgB,aAAuB,SAAkD;CACvF,MAAM,EAAE,YAAY,QAAQ,WAAW,SAAS,aAAa;CAC7D,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,cAAc;CAElB,MAAM,UAAU,YAAY;EAC1B,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"timer.cjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态基础接口\n */\nexport type TimerStateBase = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\n/**\n * 定时器状态接口\n * @template T - condition 函数返回值类型,默认为 unknown\n */\nexport type TimerState<T = unknown> = TimerStateBase & {\n /**\n * condition 函数返回值,未传入 condition 时为 null\n */\n data: T;\n};\n\n/**\n * 定时器控制方法集合\n */\nexport type TimerHandler = {\n /**\n * 启动定时器\n */\n start: () => void;\n /**\n * 暂停定时器\n */\n pause: () => void;\n /**\n * 恢复定时器\n * @param immediate - 是否立即执行一次\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止定时器\n */\n stop: () => void;\n /**\n * 清除上一次定时器,立即执行,并开始下一次定时器\n */\n execute: () => void;\n};\n\n/**\n * 间隔定时器控制方法集合,包含状态查询方法\n */\nexport type IntervalHandler = TimerHandler & {\n /**\n * 是否可以启动(处于 READY 状态)\n */\n canStart: () => boolean;\n /**\n * 是否可以停止(处于 START 状态)\n */\n canStop: () => boolean;\n /**\n * 是否可以暂停(处于 START 状态)\n */\n canPause: () => boolean;\n /**\n * 是否可以恢复(处于 PAUSE 状态)\n */\n canResume: () => boolean;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * makeInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type MakeIntervalOptions<T> = {\n /**\n * 调度器函数,用于安排下一次执行\n */\n dispatcher: (dispatch: () => void) => unknown;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 使用 MaybePromise 支持同步或异步条件判断\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断\n */\n runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 true\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建可控制的间隔定时器核心函数\n *\n * @example\n * ```typescript\n * // 无 condition,state.data 为 null\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler {\n const { dispatcher, runner, condition, leading, trailing } = options;\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = async () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState<T> = {\n times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n data: null as T,\n };\n\n if (condition) {\n try {\n state.data = await condition(state);\n } catch {\n dispatcher(execute);\n return;\n }\n }\n\n state.times = ++times;\n\n await (runner as (timer: TimerState<T>) => unknown)(state);\n dispatcher(execute);\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n if (leading === false) {\n dispatcher(execute);\n } else {\n execute();\n }\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n if (trailing) execute();\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n if (trailing) execute();\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\n/**\n * timerInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type TimerIntervalOptions<T> = {\n /**\n * 间隔时间,单位为毫秒\n */\n interval: number;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n */\n runner: (state: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 false\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建基于 setTimeout 的间隔定时器\n *\n * @example\n * ```typescript\n * // 无 condition\n * timerInterval({\n * interval: 1000,\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * timerInterval({\n * interval: 1000,\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler {\n const { runner, interval, condition, leading, trailing } = options;\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({\n dispatcher: (dispatch) => {\n timeId = setTimeout(dispatch, interval);\n },\n runner,\n condition,\n leading: leading ?? false,\n trailing,\n });\n\n return {\n start() {\n if (!canStart()) return;\n start();\n },\n\n stop() {\n if (!canStop()) return;\n stop();\n clearTimeout(timeId);\n },\n\n pause() {\n if (!canPause()) return;\n pause();\n clearTimeout(timeId);\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n if (immediate || leading) {\n resume();\n } else {\n timeId = setTimeout(() => resume(), interval);\n }\n },\n\n execute() {\n clearTimeout(timeId);\n execute();\n },\n };\n}\n"],"mappings":";;AAsGA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAsDpB,SAAgB,aAAuB,SAAkD;CACvF,MAAM,EAAE,YAAY,QAAQ,WAAW,SAAS,aAAa;CAC7D,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,cAAc;CAElB,MAAM,UAAU,YAAY;EAC1B,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,eAAe,SAAS,IAAI,MAAM,SAAS;EACjD,eAAe;EACf,SAAS;EACT,MAAM,QAAuB;GAC3B;GACA;GACA;GACA;GACA;GACA,WAAW;GACX,aAAa,UAAU,IAAI,MAAM,UAAU;GAC3C;GACA;GACA,MAAM;EACR;EAEA,IAAI,WACF,IAAI;GACF,MAAM,OAAO,MAAM,UAAU,KAAK;EACpC,QAAQ;GACN,WAAW,OAAO;GAClB;EACF;EAGF,MAAM,QAAQ,EAAE;EAEhB,MAAO,OAA6C,KAAK;EACzD,WAAW,OAAO;CACpB;CAEA,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,SAAS,GAAG;EACjB,SAAS;EACT,UAAU,KAAK,IAAI;EACnB,IAAI,YAAY,OACd,WAAW,OAAO;OAElB,QAAQ;CAEZ;CAEA,MAAM,gBAAgB,WAAW;CACjC,MAAM,aAAa;EACjB,IAAI,CAAC,QAAQ,GAAG;EAChB,IAAI,UAAU,QAAQ;EACtB,SAAS;EACT,SAAS,KAAK,IAAI;CACpB;CAEA,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,SAAS,GAAG;EACjB,IAAI,UAAU,QAAQ;EACtB,SAAS;EACT,UAAU,KAAK,IAAI;CACrB;CAEA,MAAM,kBAAkB,WAAW;CACnC,MAAM,eAAe;EACnB,IAAI,CAAC,UAAU,GAAG;EAClB,SAAS;EACT,WAAW,KAAK,IAAI;EACpB,SAAS;EACT,QAAQ;CACV;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;AAoDA,SAAgB,cAAwB,SAAgD;CACtF,MAAM,EAAE,QAAQ,UAAU,WAAW,SAAS,aAAa;CAC3D,IAAI;CACJ,MAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,YAAY,aAAa;EACnG,aAAa,aAAa;GACxB,SAAS,WAAW,UAAU,QAAQ;EACxC;EACA;EACA;EACA,SAAS,WAAW;EACpB;CACF,CAAC;CAED,OAAO;EACL,QAAQ;GACN,IAAI,CAAC,SAAS,GAAG;GACjB,MAAM;EACR;EAEA,OAAO;GACL,IAAI,CAAC,QAAQ,GAAG;GAChB,KAAK;GACL,aAAa,MAAM;EACrB;EAEA,QAAQ;GACN,IAAI,CAAC,SAAS,GAAG;GACjB,MAAM;GACN,aAAa,MAAM;EACrB;EAEA,OAAO,WAAqB;GAC1B,IAAI,CAAC,UAAU,GAAG;GAClB,IAAI,aAAa,SACf,OAAO;QAEP,SAAS,iBAAiB,OAAO,GAAG,QAAQ;EAEhD;EAEA,UAAU;GACR,aAAa,MAAM;GACnB,QAAQ;EACV;CACF;AACF"}
|
package/dist/timer.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timer.mjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态基础接口\n */\nexport type TimerStateBase = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\n/**\n * 定时器状态接口\n * @template T - condition 函数返回值类型,默认为 unknown\n */\nexport type TimerState<T = unknown> = TimerStateBase & {\n /**\n * condition 函数返回值,未传入 condition 时为 null\n */\n data: T;\n};\n\n/**\n * 定时器控制方法集合\n */\nexport type TimerHandler = {\n /**\n * 启动定时器\n */\n start: () => void;\n /**\n * 暂停定时器\n */\n pause: () => void;\n /**\n * 恢复定时器\n * @param immediate - 是否立即执行一次\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止定时器\n */\n stop: () => void;\n /**\n * 清除上一次定时器,立即执行,并开始下一次定时器\n */\n execute: () => void;\n};\n\n/**\n * 间隔定时器控制方法集合,包含状态查询方法\n */\nexport type IntervalHandler = TimerHandler & {\n /**\n * 是否可以启动(处于 READY 状态)\n */\n canStart: () => boolean;\n /**\n * 是否可以停止(处于 START 状态)\n */\n canStop: () => boolean;\n /**\n * 是否可以暂停(处于 START 状态)\n */\n canPause: () => boolean;\n /**\n * 是否可以恢复(处于 PAUSE 状态)\n */\n canResume: () => boolean;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * makeInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type MakeIntervalOptions<T> = {\n /**\n * 调度器函数,用于安排下一次执行\n */\n dispatcher: (dispatch: () => void) => unknown;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 使用 MaybePromise 支持同步或异步条件判断\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断\n */\n runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 true\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建可控制的间隔定时器核心函数\n *\n * @example\n * ```typescript\n * // 无 condition,state.data 为 null\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler {\n const { dispatcher, runner, condition, leading, trailing } = options;\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = async () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState<T> = {\n times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n data: null as T,\n };\n\n if (condition) {\n try {\n state.data = await condition(state);\n } catch {\n dispatcher(execute);\n return;\n }\n }\n\n state.times = ++times;\n\n await (runner as (timer: TimerState<T>) => unknown)(state);\n dispatcher(execute);\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n if (leading === false) {\n dispatcher(execute);\n } else {\n execute();\n }\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n if (trailing) execute();\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n if (trailing) execute();\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\n/**\n * timerInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type TimerIntervalOptions<T> = {\n /**\n * 间隔时间,单位为毫秒\n */\n interval: number;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n */\n runner: (state: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 false\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建基于 setTimeout 的间隔定时器\n *\n * @example\n * ```typescript\n * // 无 condition\n * timerInterval({\n * interval: 1000,\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * timerInterval({\n * interval: 1000,\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler {\n const { runner, interval, condition, leading, trailing } = options;\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({\n dispatcher: (dispatch) => {\n timeId = setTimeout(dispatch, interval);\n },\n runner,\n condition,\n leading: leading ?? false,\n trailing,\n });\n\n return {\n start() {\n if (!canStart()) return;\n start();\n },\n\n stop() {\n if (!canStop()) return;\n stop();\n clearTimeout(timeId);\n },\n\n pause() {\n if (!canPause()) return;\n pause();\n clearTimeout(timeId);\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n if (immediate || leading) {\n resume();\n } else {\n timeId = setTimeout(() => resume(), interval);\n }\n },\n\n execute() {\n clearTimeout(timeId);\n execute();\n },\n };\n}\n"],"mappings":";AAsGA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAsDpB,SAAgB,aAAuB,SAAkD;CACvF,MAAM,EAAE,YAAY,QAAQ,WAAW,SAAS,aAAa;CAC7D,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,cAAc;CAElB,MAAM,UAAU,YAAY;EAC1B,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"timer.mjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态基础接口\n */\nexport type TimerStateBase = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\n/**\n * 定时器状态接口\n * @template T - condition 函数返回值类型,默认为 unknown\n */\nexport type TimerState<T = unknown> = TimerStateBase & {\n /**\n * condition 函数返回值,未传入 condition 时为 null\n */\n data: T;\n};\n\n/**\n * 定时器控制方法集合\n */\nexport type TimerHandler = {\n /**\n * 启动定时器\n */\n start: () => void;\n /**\n * 暂停定时器\n */\n pause: () => void;\n /**\n * 恢复定时器\n * @param immediate - 是否立即执行一次\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止定时器\n */\n stop: () => void;\n /**\n * 清除上一次定时器,立即执行,并开始下一次定时器\n */\n execute: () => void;\n};\n\n/**\n * 间隔定时器控制方法集合,包含状态查询方法\n */\nexport type IntervalHandler = TimerHandler & {\n /**\n * 是否可以启动(处于 READY 状态)\n */\n canStart: () => boolean;\n /**\n * 是否可以停止(处于 START 状态)\n */\n canStop: () => boolean;\n /**\n * 是否可以暂停(处于 START 状态)\n */\n canPause: () => boolean;\n /**\n * 是否可以恢复(处于 PAUSE 状态)\n */\n canResume: () => boolean;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * makeInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type MakeIntervalOptions<T> = {\n /**\n * 调度器函数,用于安排下一次执行\n */\n dispatcher: (dispatch: () => void) => unknown;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 使用 MaybePromise 支持同步或异步条件判断\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断\n */\n runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 true\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建可控制的间隔定时器核心函数\n *\n * @example\n * ```typescript\n * // 无 condition,state.data 为 null\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler {\n const { dispatcher, runner, condition, leading, trailing } = options;\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = async () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState<T> = {\n times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n data: null as T,\n };\n\n if (condition) {\n try {\n state.data = await condition(state);\n } catch {\n dispatcher(execute);\n return;\n }\n }\n\n state.times = ++times;\n\n await (runner as (timer: TimerState<T>) => unknown)(state);\n dispatcher(execute);\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n if (leading === false) {\n dispatcher(execute);\n } else {\n execute();\n }\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n if (trailing) execute();\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n if (trailing) execute();\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\n/**\n * timerInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type TimerIntervalOptions<T> = {\n /**\n * 间隔时间,单位为毫秒\n */\n interval: number;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n */\n runner: (state: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 false\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建基于 setTimeout 的间隔定时器\n *\n * @example\n * ```typescript\n * // 无 condition\n * timerInterval({\n * interval: 1000,\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * timerInterval({\n * interval: 1000,\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler {\n const { runner, interval, condition, leading, trailing } = options;\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({\n dispatcher: (dispatch) => {\n timeId = setTimeout(dispatch, interval);\n },\n runner,\n condition,\n leading: leading ?? false,\n trailing,\n });\n\n return {\n start() {\n if (!canStart()) return;\n start();\n },\n\n stop() {\n if (!canStop()) return;\n stop();\n clearTimeout(timeId);\n },\n\n pause() {\n if (!canPause()) return;\n pause();\n clearTimeout(timeId);\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n if (immediate || leading) {\n resume();\n } else {\n timeId = setTimeout(() => resume(), interval);\n }\n },\n\n execute() {\n clearTimeout(timeId);\n execute();\n },\n };\n}\n"],"mappings":";AAsGA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAsDpB,SAAgB,aAAuB,SAAkD;CACvF,MAAM,EAAE,YAAY,QAAQ,WAAW,SAAS,aAAa;CAC7D,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,cAAc;CAElB,MAAM,UAAU,YAAY;EAC1B,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,IAAI;EACrB,MAAM,eAAe,SAAS,IAAI,MAAM,SAAS;EACjD,eAAe;EACf,SAAS;EACT,MAAM,QAAuB;GAC3B;GACA;GACA;GACA;GACA;GACA,WAAW;GACX,aAAa,UAAU,IAAI,MAAM,UAAU;GAC3C;GACA;GACA,MAAM;EACR;EAEA,IAAI,WACF,IAAI;GACF,MAAM,OAAO,MAAM,UAAU,KAAK;EACpC,QAAQ;GACN,WAAW,OAAO;GAClB;EACF;EAGF,MAAM,QAAQ,EAAE;EAEhB,MAAO,OAA6C,KAAK;EACzD,WAAW,OAAO;CACpB;CAEA,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,SAAS,GAAG;EACjB,SAAS;EACT,UAAU,KAAK,IAAI;EACnB,IAAI,YAAY,OACd,WAAW,OAAO;OAElB,QAAQ;CAEZ;CAEA,MAAM,gBAAgB,WAAW;CACjC,MAAM,aAAa;EACjB,IAAI,CAAC,QAAQ,GAAG;EAChB,IAAI,UAAU,QAAQ;EACtB,SAAS;EACT,SAAS,KAAK,IAAI;CACpB;CAEA,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,SAAS,GAAG;EACjB,IAAI,UAAU,QAAQ;EACtB,SAAS;EACT,UAAU,KAAK,IAAI;CACrB;CAEA,MAAM,kBAAkB,WAAW;CACnC,MAAM,eAAe;EACnB,IAAI,CAAC,UAAU,GAAG;EAClB,SAAS;EACT,WAAW,KAAK,IAAI;EACpB,SAAS;EACT,QAAQ;CACV;CAEA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;AAoDA,SAAgB,cAAwB,SAAgD;CACtF,MAAM,EAAE,QAAQ,UAAU,WAAW,SAAS,aAAa;CAC3D,IAAI;CACJ,MAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,YAAY,aAAa;EACnG,aAAa,aAAa;GACxB,SAAS,WAAW,UAAU,QAAQ;EACxC;EACA;EACA;EACA,SAAS,WAAW;EACpB;CACF,CAAC;CAED,OAAO;EACL,QAAQ;GACN,IAAI,CAAC,SAAS,GAAG;GACjB,MAAM;EACR;EAEA,OAAO;GACL,IAAI,CAAC,QAAQ,GAAG;GAChB,KAAK;GACL,aAAa,MAAM;EACrB;EAEA,QAAQ;GACN,IAAI,CAAC,SAAS,GAAG;GACjB,MAAM;GACN,aAAa,MAAM;EACrB;EAEA,OAAO,WAAqB;GAC1B,IAAI,CAAC,UAAU,GAAG;GAClB,IAAI,aAAa,SACf,OAAO;QAEP,SAAS,iBAAiB,OAAO,GAAG,QAAQ;EAEhD;EAEA,UAAU;GACR,aAAa,MAAM;GACnB,QAAQ;EACV;CACF;AACF"}
|
package/dist/tree.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.cjs","names":[],"sources":["../src/tree.ts"],"sourcesContent":["import { arrayEach } from './array';\nimport { isArray, isNullish, isUndefined } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 表示深度遍历中的节点对象,包含子节点列表。\n */\nexport type TreeItem = AnyObject & {\n /**\n * 子节点列表。\n */\n children?: TreeItem[];\n};\n\n/**\n * 表示深度遍历中的节点列表。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeList<I extends TreeItem> = I[];\n\n/**\n * 表示深度遍历中的遍历器状态。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeWalker<I extends TreeItem> = {\n /**\n * 当前层级的节点列表。\n */\n list: TreeList<I>;\n\n /**\n * 当前节点的父节点,如果为根节点则为 `null`。\n */\n parent: I | null;\n\n /**\n * 当前节点的层级,从 1 开始计数。\n */\n level: number;\n\n /**\n * 从根节点到当前节点的路径。\n */\n path: TreeList<I>;\n};\n\n/**\n * 表示深度遍历中的节点信息。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeInfo<I extends TreeItem> = TreeWalker<I> & {\n /**\n * 当前节点。\n */\n item: I;\n\n /**\n * 当前节点在 `list` 中的索引。\n */\n index: number;\n};\n\n/**\n * 深度遍历的同步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIterator<I extends TreeItem> = (info: TreeInfo<I>) => false | unknown;\n\n/**\n * 深度遍历的异步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIteratorAsync<I extends TreeItem> = (info: TreeInfo<I>) => Promise<boolean | unknown>;\n\n/**\n * 深度遍历的同步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 遍历结果。\n */\nexport type TreeWalk<I extends TreeItem> = (walker: TreeWalker<I>) => unknown;\n\n/**\n * 深度遍历的异步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 异步遍历结果。\n */\nexport type TreeWalkAsync<I extends TreeItem> = (walker: TreeWalker<I>) => Promise<unknown>;\n\n/**\n * 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param treeList - 要遍历的深度数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * treeEach(treeList, (item) => {\n * console.log(item.value);\n * if (item.value === 2) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function treeEach<I extends TreeItem = TreeItem>(\n treeList: TreeList<I>,\n iterator: TreeEachIterator<I>,\n breadthFist = false,\n): void {\n const treeInfoList: TreeInfo<I>[] = [];\n let returnFalse = false;\n\n const iterate = (info: TreeInfo<I>) => {\n if (iterator(info) === false) {\n returnFalse = true;\n return false;\n }\n };\n\n const next = (info: TreeInfo<I>, walk: TreeWalk<I>) => {\n const { item, level } = info;\n const { children } = item;\n\n if (isArray(children)) {\n returnFalse =\n walk({\n ...info,\n parent: item,\n list: children as TreeList<I>,\n level: level + 1,\n }) === false;\n }\n };\n\n const walk: TreeWalk<I> = (walker) => {\n const { list, parent, path } = walker;\n\n const path2 = [...path];\n while (parent !== null && path2.length > 0 && path2[path2.length - 1] !== parent) {\n path2.pop();\n }\n\n arrayEach(list, (item, index) => {\n if (returnFalse) return false;\n\n const info: TreeInfo<I> = {\n ...walker,\n item,\n index,\n path: [...path2, item],\n };\n\n // 广度优先\n if (breadthFist) {\n treeInfoList.push(info);\n }\n // 深度优先\n else {\n iterate(info);\n if (returnFalse) return false;\n next(info, walk);\n }\n });\n\n if (breadthFist) {\n while (!returnFalse) {\n const info = treeInfoList.shift();\n if (!info) break;\n\n iterate(info);\n if (returnFalse) break;\n\n // 内部也会进入 walk\n next(info, walk);\n }\n }\n\n return !returnFalse;\n };\n\n walk({\n list: treeList,\n level: 1,\n parent: null,\n path: [],\n });\n}\n\n/**\n * 在深度数组中查找满足条件的第一个节点信息。\n *\n * @param treeList - 要查找的深度数组。\n * @param predicate - 判断节点是否满足条件的回调函数。\n * @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。\n * @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const found = treeFind(treeList, (info) => info.item.value === 3);\n * console.log(found);\n * // {\n * // item: { value: 3 },\n * // index: 1,\n * // list: [{ value: 2 }, { value: 3 }],\n * // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * // level: 2,\n * // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]\n * // }\n * ```\n */\nexport function treeFind<I extends TreeItem>(\n treeList: TreeList<I>,\n predicate: (info: TreeInfo<I>) => boolean,\n breadthFist = false,\n): TreeInfo<I> | undefined {\n let found: TreeInfo<I> | undefined;\n\n treeEach(\n treeList,\n (info) => {\n if (predicate(info)) {\n found = info;\n return false;\n }\n },\n breadthFist,\n );\n\n return found;\n}\n\n/**\n * 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。\n *\n * @template I - 树节点的类型,必须继承自 `TreeItem`。\n * @template T - 转换后的数据类型。\n * @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。\n * @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。\n * @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns {T[]} - 转换后的一维数组。\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const flattened = deepFlat(treeList, (info) => info.item.value);\n * console.log(flattened); // [1, 2, 3, 4]\n * ```\n */\nexport function deepFlat<I extends TreeItem, T>(\n deepList: TreeList<I>,\n flatten: (info: TreeInfo<I>) => T,\n breadthFist = false,\n): T[] {\n const list2: T[] = [];\n\n treeEach(\n deepList,\n (info) => {\n list2.push(flatten(info));\n },\n breadthFist,\n );\n\n return list2;\n}\n\ntype FromItemInfo<I> = {\n selfKey: unknown;\n parentKey: unknown;\n item: I;\n index: number;\n};\n\nexport type TreeFromOptions<I extends TreeItem> = {\n getSelfKey: (item: I, index: number) => unknown;\n getParentKey: (item: I, index: number) => unknown;\n appendChild: (parentInfo: FromItemInfo<I>, info: FromItemInfo<I>) => unknown;\n};\n\n/**\n * 从扁平列表构建树形结构。\n *\n * @template I - 节点对象的类型,必须继承自 `AnyObject`。\n * @param {I[]} list - 扁平化的节点列表。\n * @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。\n * @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。\n * @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。\n * @param {function} options.appendChild - 将子节点添加到父节点的函数。\n * @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const list = [\n * { id: 1, parentId: null, name: 'Root' },\n * { id: 2, parentId: 1, name: 'Child 1' },\n * { id: 3, parentId: 1, name: 'Child 2' }\n * ];\n *\n * const tree = treeFrom(list, {\n * getSelfKey: (item) => item.id,\n * getParentKey: (item) => item.parentId,\n * appendChild: (parent, info) => {\n * if (!parent.children) parent.children = [];\n * parent.children.push(info.item);\n * }\n * });\n *\n * console.log(tree);\n * // {\n * // id: 1,\n * // parentId: null,\n * // name: 'Root',\n * // children: [\n * // { id: 2, parentId: 1, name: 'Child 1' },\n * // { id: 3, parentId: 1, name: 'Child 2' }\n * // ]\n * // }\n * ```\n */\nexport function treeFrom<I extends TreeItem>(list: I[], options: TreeFromOptions<I>): TreeList<I> | undefined {\n const keyMap = new Map<unknown, FromItemInfo<I>>();\n const freeSet = new Set<FromItemInfo<I>>();\n const roots: TreeList<I> = [];\n\n // 分配节点\n const assign = (info: FromItemInfo<I>, isFirst = false) => {\n const { parentKey, item } = info;\n\n // 父级指向为空\n if (isNullish(parentKey)) {\n roots.push(item);\n }\n // 父级指向不为空\n else {\n const parent = keyMap.get(parentKey);\n\n // 未找到父级节点\n if (isUndefined(parent)) {\n // 游离节点\n if (isFirst) freeSet.add(info);\n }\n // 已找到父级节点\n else {\n options.appendChild(parent, info);\n }\n }\n };\n\n // 构建 map\n arrayEach(list, (item, index) => {\n const selfKey = options.getSelfKey(item, index);\n const parentKey = options.getParentKey(item, index);\n\n if (isNullish(selfKey)) return;\n\n const info = { selfKey, parentKey, item, index };\n keyMap.set(selfKey, info);\n\n assign(info, true);\n });\n\n // 处理游离节点\n for (const info of freeSet.values()) {\n assign(info);\n }\n\n return roots;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0HA,SAAgB,SACd,UACA,UACA,cAAc,OACR;CACN,MAAM,eAA8B,EAAE;CACtC,IAAI,cAAc;CAElB,MAAM,WAAW,SAAsB;EACrC,IAAI,SAAS,KAAK,KAAK,OAAO;GAC5B,cAAc;GACd,OAAO;;;CAIX,MAAM,QAAQ,MAAmB,SAAsB;EACrD,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,EAAE,aAAa;EAErB,IAAI,aAAA,QAAQ,SAAS,EACnB,cACE,KAAK;GACH,GAAG;GACH,QAAQ;GACR,MAAM;GACN,OAAO,QAAQ;GAChB,CAAC,KAAK;;CAIb,MAAM,QAAqB,WAAW;EACpC,MAAM,EAAE,MAAM,QAAQ,SAAS;EAE/B,MAAM,QAAQ,CAAC,GAAG,KAAK;EACvB,OAAO,WAAW,QAAQ,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,QACxE,MAAM,KAAK;EAGb,cAAA,UAAU,OAAO,MAAM,UAAU;GAC/B,IAAI,aAAa,OAAO;GAExB,MAAM,OAAoB;IACxB,GAAG;IACH;IACA;IACA,MAAM,CAAC,GAAG,OAAO,KAAK;IACvB;GAGD,IAAI,aACF,aAAa,KAAK,KAAK;QAGpB;IACH,QAAQ,KAAK;IACb,IAAI,aAAa,OAAO;IACxB,KAAK,MAAM,KAAK;;IAElB;EAEF,IAAI,aACF,OAAO,CAAC,aAAa;GACnB,MAAM,OAAO,aAAa,OAAO;GACjC,IAAI,CAAC,MAAM;GAEX,QAAQ,KAAK;GACb,IAAI,aAAa;GAGjB,KAAK,MAAM,KAAK;;EAIpB,OAAO,CAAC;;CAGV,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACR,MAAM,EAAE;EACT,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BJ,SAAgB,SACd,UACA,WACA,cAAc,OACW;CACzB,IAAI;CAEJ,SACE,WACC,SAAS;EACR,IAAI,UAAU,KAAK,EAAE;GACnB,QAAQ;GACR,OAAO;;IAGX,YACD;CAED,OAAO;;;;;;;;;;;;;;;;;;;;;;AAuBT,SAAgB,SACd,UACA,SACA,cAAc,OACT;CACL,MAAM,QAAa,EAAE;CAErB,SACE,WACC,SAAS;EACR,MAAM,KAAK,QAAQ,KAAK,CAAC;IAE3B,YACD;CAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDT,SAAgB,SAA6B,MAAW,SAAsD;CAC5G,MAAM,yBAAS,IAAI,KAA+B;CAClD,MAAM,0BAAU,IAAI,KAAsB;CAC1C,MAAM,QAAqB,EAAE;CAG7B,MAAM,UAAU,MAAuB,UAAU,UAAU;EACzD,MAAM,EAAE,WAAW,SAAS;EAG5B,IAAI,aAAA,UAAU,UAAU,EACtB,MAAM,KAAK,KAAK;OAGb;GACH,MAAM,SAAS,OAAO,IAAI,UAAU;GAGpC,IAAI,aAAA,YAAY,OAAO;QAEjB,SAAS,QAAQ,IAAI,KAAK;UAI9B,QAAQ,YAAY,QAAQ,KAAK;;;CAMvC,cAAA,UAAU,OAAO,MAAM,UAAU;EAC/B,MAAM,UAAU,QAAQ,WAAW,MAAM,MAAM;EAC/C,MAAM,YAAY,QAAQ,aAAa,MAAM,MAAM;EAEnD,IAAI,aAAA,UAAU,QAAQ,EAAE;EAExB,MAAM,OAAO;GAAE;GAAS;GAAW;GAAM;GAAO;EAChD,OAAO,IAAI,SAAS,KAAK;EAEzB,OAAO,MAAM,KAAK;GAClB;CAGF,KAAK,MAAM,QAAQ,QAAQ,QAAQ,EACjC,OAAO,KAAK;CAGd,OAAO"}
|
|
1
|
+
{"version":3,"file":"tree.cjs","names":[],"sources":["../src/tree.ts"],"sourcesContent":["import { arrayEach } from './array';\nimport { isArray, isNullish, isUndefined } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 表示深度遍历中的节点对象,包含子节点列表。\n */\nexport type TreeItem = AnyObject & {\n /**\n * 子节点列表。\n */\n children?: TreeItem[];\n};\n\n/**\n * 表示深度遍历中的节点列表。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeList<I extends TreeItem> = I[];\n\n/**\n * 表示深度遍历中的遍历器状态。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeWalker<I extends TreeItem> = {\n /**\n * 当前层级的节点列表。\n */\n list: TreeList<I>;\n\n /**\n * 当前节点的父节点,如果为根节点则为 `null`。\n */\n parent: I | null;\n\n /**\n * 当前节点的层级,从 1 开始计数。\n */\n level: number;\n\n /**\n * 从根节点到当前节点的路径。\n */\n path: TreeList<I>;\n};\n\n/**\n * 表示深度遍历中的节点信息。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeInfo<I extends TreeItem> = TreeWalker<I> & {\n /**\n * 当前节点。\n */\n item: I;\n\n /**\n * 当前节点在 `list` 中的索引。\n */\n index: number;\n};\n\n/**\n * 深度遍历的同步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIterator<I extends TreeItem> = (info: TreeInfo<I>) => false | unknown;\n\n/**\n * 深度遍历的异步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIteratorAsync<I extends TreeItem> = (info: TreeInfo<I>) => Promise<boolean | unknown>;\n\n/**\n * 深度遍历的同步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 遍历结果。\n */\nexport type TreeWalk<I extends TreeItem> = (walker: TreeWalker<I>) => unknown;\n\n/**\n * 深度遍历的异步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 异步遍历结果。\n */\nexport type TreeWalkAsync<I extends TreeItem> = (walker: TreeWalker<I>) => Promise<unknown>;\n\n/**\n * 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param treeList - 要遍历的深度数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * treeEach(treeList, (item) => {\n * console.log(item.value);\n * if (item.value === 2) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function treeEach<I extends TreeItem = TreeItem>(\n treeList: TreeList<I>,\n iterator: TreeEachIterator<I>,\n breadthFist = false,\n): void {\n const treeInfoList: TreeInfo<I>[] = [];\n let returnFalse = false;\n\n const iterate = (info: TreeInfo<I>) => {\n if (iterator(info) === false) {\n returnFalse = true;\n return false;\n }\n };\n\n const next = (info: TreeInfo<I>, walk: TreeWalk<I>) => {\n const { item, level } = info;\n const { children } = item;\n\n if (isArray(children)) {\n returnFalse =\n walk({\n ...info,\n parent: item,\n list: children as TreeList<I>,\n level: level + 1,\n }) === false;\n }\n };\n\n const walk: TreeWalk<I> = (walker) => {\n const { list, parent, path } = walker;\n\n const path2 = [...path];\n while (parent !== null && path2.length > 0 && path2[path2.length - 1] !== parent) {\n path2.pop();\n }\n\n arrayEach(list, (item, index) => {\n if (returnFalse) return false;\n\n const info: TreeInfo<I> = {\n ...walker,\n item,\n index,\n path: [...path2, item],\n };\n\n // 广度优先\n if (breadthFist) {\n treeInfoList.push(info);\n }\n // 深度优先\n else {\n iterate(info);\n if (returnFalse) return false;\n next(info, walk);\n }\n });\n\n if (breadthFist) {\n while (!returnFalse) {\n const info = treeInfoList.shift();\n if (!info) break;\n\n iterate(info);\n if (returnFalse) break;\n\n // 内部也会进入 walk\n next(info, walk);\n }\n }\n\n return !returnFalse;\n };\n\n walk({\n list: treeList,\n level: 1,\n parent: null,\n path: [],\n });\n}\n\n/**\n * 在深度数组中查找满足条件的第一个节点信息。\n *\n * @param treeList - 要查找的深度数组。\n * @param predicate - 判断节点是否满足条件的回调函数。\n * @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。\n * @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const found = treeFind(treeList, (info) => info.item.value === 3);\n * console.log(found);\n * // {\n * // item: { value: 3 },\n * // index: 1,\n * // list: [{ value: 2 }, { value: 3 }],\n * // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * // level: 2,\n * // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]\n * // }\n * ```\n */\nexport function treeFind<I extends TreeItem>(\n treeList: TreeList<I>,\n predicate: (info: TreeInfo<I>) => boolean,\n breadthFist = false,\n): TreeInfo<I> | undefined {\n let found: TreeInfo<I> | undefined;\n\n treeEach(\n treeList,\n (info) => {\n if (predicate(info)) {\n found = info;\n return false;\n }\n },\n breadthFist,\n );\n\n return found;\n}\n\n/**\n * 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。\n *\n * @template I - 树节点的类型,必须继承自 `TreeItem`。\n * @template T - 转换后的数据类型。\n * @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。\n * @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。\n * @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns {T[]} - 转换后的一维数组。\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const flattened = deepFlat(treeList, (info) => info.item.value);\n * console.log(flattened); // [1, 2, 3, 4]\n * ```\n */\nexport function deepFlat<I extends TreeItem, T>(\n deepList: TreeList<I>,\n flatten: (info: TreeInfo<I>) => T,\n breadthFist = false,\n): T[] {\n const list2: T[] = [];\n\n treeEach(\n deepList,\n (info) => {\n list2.push(flatten(info));\n },\n breadthFist,\n );\n\n return list2;\n}\n\ntype FromItemInfo<I> = {\n selfKey: unknown;\n parentKey: unknown;\n item: I;\n index: number;\n};\n\nexport type TreeFromOptions<I extends TreeItem> = {\n getSelfKey: (item: I, index: number) => unknown;\n getParentKey: (item: I, index: number) => unknown;\n appendChild: (parentInfo: FromItemInfo<I>, info: FromItemInfo<I>) => unknown;\n};\n\n/**\n * 从扁平列表构建树形结构。\n *\n * @template I - 节点对象的类型,必须继承自 `AnyObject`。\n * @param {I[]} list - 扁平化的节点列表。\n * @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。\n * @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。\n * @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。\n * @param {function} options.appendChild - 将子节点添加到父节点的函数。\n * @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const list = [\n * { id: 1, parentId: null, name: 'Root' },\n * { id: 2, parentId: 1, name: 'Child 1' },\n * { id: 3, parentId: 1, name: 'Child 2' }\n * ];\n *\n * const tree = treeFrom(list, {\n * getSelfKey: (item) => item.id,\n * getParentKey: (item) => item.parentId,\n * appendChild: (parent, info) => {\n * if (!parent.children) parent.children = [];\n * parent.children.push(info.item);\n * }\n * });\n *\n * console.log(tree);\n * // {\n * // id: 1,\n * // parentId: null,\n * // name: 'Root',\n * // children: [\n * // { id: 2, parentId: 1, name: 'Child 1' },\n * // { id: 3, parentId: 1, name: 'Child 2' }\n * // ]\n * // }\n * ```\n */\nexport function treeFrom<I extends TreeItem>(list: I[], options: TreeFromOptions<I>): TreeList<I> | undefined {\n const keyMap = new Map<unknown, FromItemInfo<I>>();\n const freeSet = new Set<FromItemInfo<I>>();\n const roots: TreeList<I> = [];\n\n // 分配节点\n const assign = (info: FromItemInfo<I>, isFirst = false) => {\n const { parentKey, item } = info;\n\n // 父级指向为空\n if (isNullish(parentKey)) {\n roots.push(item);\n }\n // 父级指向不为空\n else {\n const parent = keyMap.get(parentKey);\n\n // 未找到父级节点\n if (isUndefined(parent)) {\n // 游离节点\n if (isFirst) freeSet.add(info);\n }\n // 已找到父级节点\n else {\n options.appendChild(parent, info);\n }\n }\n };\n\n // 构建 map\n arrayEach(list, (item, index) => {\n const selfKey = options.getSelfKey(item, index);\n const parentKey = options.getParentKey(item, index);\n\n if (isNullish(selfKey)) return;\n\n const info = { selfKey, parentKey, item, index };\n keyMap.set(selfKey, info);\n\n assign(info, true);\n });\n\n // 处理游离节点\n for (const info of freeSet.values()) {\n assign(info);\n }\n\n return roots;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA0HA,SAAgB,SACd,UACA,UACA,cAAc,OACR;CACN,MAAM,eAA8B,CAAC;CACrC,IAAI,cAAc;CAElB,MAAM,WAAW,SAAsB;EACrC,IAAI,SAAS,IAAI,MAAM,OAAO;GAC5B,cAAc;GACd,OAAO;EACT;CACF;CAEA,MAAM,QAAQ,MAAmB,SAAsB;EACrD,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,EAAE,aAAa;EAErB,IAAI,aAAA,QAAQ,QAAQ,GAClB,cACE,KAAK;GACH,GAAG;GACH,QAAQ;GACR,MAAM;GACN,OAAO,QAAQ;EACjB,CAAC,MAAM;CAEb;CAEA,MAAM,QAAqB,WAAW;EACpC,MAAM,EAAE,MAAM,QAAQ,SAAS;EAE/B,MAAM,QAAQ,CAAC,GAAG,IAAI;EACtB,OAAO,WAAW,QAAQ,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,QACxE,MAAM,IAAI;EAGZ,cAAA,UAAU,OAAO,MAAM,UAAU;GAC/B,IAAI,aAAa,OAAO;GAExB,MAAM,OAAoB;IACxB,GAAG;IACH;IACA;IACA,MAAM,CAAC,GAAG,OAAO,IAAI;GACvB;GAGA,IAAI,aACF,aAAa,KAAK,IAAI;QAGnB;IACH,QAAQ,IAAI;IACZ,IAAI,aAAa,OAAO;IACxB,KAAK,MAAM,IAAI;GACjB;EACF,CAAC;EAED,IAAI,aACF,OAAO,CAAC,aAAa;GACnB,MAAM,OAAO,aAAa,MAAM;GAChC,IAAI,CAAC,MAAM;GAEX,QAAQ,IAAI;GACZ,IAAI,aAAa;GAGjB,KAAK,MAAM,IAAI;EACjB;EAGF,OAAO,CAAC;CACV;CAEA,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACR,MAAM,CAAC;CACT,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,SACd,UACA,WACA,cAAc,OACW;CACzB,IAAI;CAEJ,SACE,WACC,SAAS;EACR,IAAI,UAAU,IAAI,GAAG;GACnB,QAAQ;GACR,OAAO;EACT;CACF,GACA,WACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,SACd,UACA,SACA,cAAc,OACT;CACL,MAAM,QAAa,CAAC;CAEpB,SACE,WACC,SAAS;EACR,MAAM,KAAK,QAAQ,IAAI,CAAC;CAC1B,GACA,WACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,SAA6B,MAAW,SAAsD;CAC5G,MAAM,yBAAS,IAAI,IAA8B;CACjD,MAAM,0BAAU,IAAI,IAAqB;CACzC,MAAM,QAAqB,CAAC;CAG5B,MAAM,UAAU,MAAuB,UAAU,UAAU;EACzD,MAAM,EAAE,WAAW,SAAS;EAG5B,IAAI,aAAA,UAAU,SAAS,GACrB,MAAM,KAAK,IAAI;OAGZ;GACH,MAAM,SAAS,OAAO,IAAI,SAAS;GAGnC,IAAI,aAAA,YAAY,MAAM;QAEhB,SAAS,QAAQ,IAAI,IAAI;GAAA,OAI7B,QAAQ,YAAY,QAAQ,IAAI;EAEpC;CACF;CAGA,cAAA,UAAU,OAAO,MAAM,UAAU;EAC/B,MAAM,UAAU,QAAQ,WAAW,MAAM,KAAK;EAC9C,MAAM,YAAY,QAAQ,aAAa,MAAM,KAAK;EAElD,IAAI,aAAA,UAAU,OAAO,GAAG;EAExB,MAAM,OAAO;GAAE;GAAS;GAAW;GAAM;EAAM;EAC/C,OAAO,IAAI,SAAS,IAAI;EAExB,OAAO,MAAM,IAAI;CACnB,CAAC;CAGD,KAAK,MAAM,QAAQ,QAAQ,OAAO,GAChC,OAAO,IAAI;CAGb,OAAO;AACT"}
|
package/dist/tree.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.mjs","names":[],"sources":["../src/tree.ts"],"sourcesContent":["import { arrayEach } from './array';\nimport { isArray, isNullish, isUndefined } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 表示深度遍历中的节点对象,包含子节点列表。\n */\nexport type TreeItem = AnyObject & {\n /**\n * 子节点列表。\n */\n children?: TreeItem[];\n};\n\n/**\n * 表示深度遍历中的节点列表。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeList<I extends TreeItem> = I[];\n\n/**\n * 表示深度遍历中的遍历器状态。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeWalker<I extends TreeItem> = {\n /**\n * 当前层级的节点列表。\n */\n list: TreeList<I>;\n\n /**\n * 当前节点的父节点,如果为根节点则为 `null`。\n */\n parent: I | null;\n\n /**\n * 当前节点的层级,从 1 开始计数。\n */\n level: number;\n\n /**\n * 从根节点到当前节点的路径。\n */\n path: TreeList<I>;\n};\n\n/**\n * 表示深度遍历中的节点信息。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeInfo<I extends TreeItem> = TreeWalker<I> & {\n /**\n * 当前节点。\n */\n item: I;\n\n /**\n * 当前节点在 `list` 中的索引。\n */\n index: number;\n};\n\n/**\n * 深度遍历的同步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIterator<I extends TreeItem> = (info: TreeInfo<I>) => false | unknown;\n\n/**\n * 深度遍历的异步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIteratorAsync<I extends TreeItem> = (info: TreeInfo<I>) => Promise<boolean | unknown>;\n\n/**\n * 深度遍历的同步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 遍历结果。\n */\nexport type TreeWalk<I extends TreeItem> = (walker: TreeWalker<I>) => unknown;\n\n/**\n * 深度遍历的异步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 异步遍历结果。\n */\nexport type TreeWalkAsync<I extends TreeItem> = (walker: TreeWalker<I>) => Promise<unknown>;\n\n/**\n * 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param treeList - 要遍历的深度数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * treeEach(treeList, (item) => {\n * console.log(item.value);\n * if (item.value === 2) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function treeEach<I extends TreeItem = TreeItem>(\n treeList: TreeList<I>,\n iterator: TreeEachIterator<I>,\n breadthFist = false,\n): void {\n const treeInfoList: TreeInfo<I>[] = [];\n let returnFalse = false;\n\n const iterate = (info: TreeInfo<I>) => {\n if (iterator(info) === false) {\n returnFalse = true;\n return false;\n }\n };\n\n const next = (info: TreeInfo<I>, walk: TreeWalk<I>) => {\n const { item, level } = info;\n const { children } = item;\n\n if (isArray(children)) {\n returnFalse =\n walk({\n ...info,\n parent: item,\n list: children as TreeList<I>,\n level: level + 1,\n }) === false;\n }\n };\n\n const walk: TreeWalk<I> = (walker) => {\n const { list, parent, path } = walker;\n\n const path2 = [...path];\n while (parent !== null && path2.length > 0 && path2[path2.length - 1] !== parent) {\n path2.pop();\n }\n\n arrayEach(list, (item, index) => {\n if (returnFalse) return false;\n\n const info: TreeInfo<I> = {\n ...walker,\n item,\n index,\n path: [...path2, item],\n };\n\n // 广度优先\n if (breadthFist) {\n treeInfoList.push(info);\n }\n // 深度优先\n else {\n iterate(info);\n if (returnFalse) return false;\n next(info, walk);\n }\n });\n\n if (breadthFist) {\n while (!returnFalse) {\n const info = treeInfoList.shift();\n if (!info) break;\n\n iterate(info);\n if (returnFalse) break;\n\n // 内部也会进入 walk\n next(info, walk);\n }\n }\n\n return !returnFalse;\n };\n\n walk({\n list: treeList,\n level: 1,\n parent: null,\n path: [],\n });\n}\n\n/**\n * 在深度数组中查找满足条件的第一个节点信息。\n *\n * @param treeList - 要查找的深度数组。\n * @param predicate - 判断节点是否满足条件的回调函数。\n * @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。\n * @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const found = treeFind(treeList, (info) => info.item.value === 3);\n * console.log(found);\n * // {\n * // item: { value: 3 },\n * // index: 1,\n * // list: [{ value: 2 }, { value: 3 }],\n * // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * // level: 2,\n * // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]\n * // }\n * ```\n */\nexport function treeFind<I extends TreeItem>(\n treeList: TreeList<I>,\n predicate: (info: TreeInfo<I>) => boolean,\n breadthFist = false,\n): TreeInfo<I> | undefined {\n let found: TreeInfo<I> | undefined;\n\n treeEach(\n treeList,\n (info) => {\n if (predicate(info)) {\n found = info;\n return false;\n }\n },\n breadthFist,\n );\n\n return found;\n}\n\n/**\n * 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。\n *\n * @template I - 树节点的类型,必须继承自 `TreeItem`。\n * @template T - 转换后的数据类型。\n * @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。\n * @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。\n * @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns {T[]} - 转换后的一维数组。\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const flattened = deepFlat(treeList, (info) => info.item.value);\n * console.log(flattened); // [1, 2, 3, 4]\n * ```\n */\nexport function deepFlat<I extends TreeItem, T>(\n deepList: TreeList<I>,\n flatten: (info: TreeInfo<I>) => T,\n breadthFist = false,\n): T[] {\n const list2: T[] = [];\n\n treeEach(\n deepList,\n (info) => {\n list2.push(flatten(info));\n },\n breadthFist,\n );\n\n return list2;\n}\n\ntype FromItemInfo<I> = {\n selfKey: unknown;\n parentKey: unknown;\n item: I;\n index: number;\n};\n\nexport type TreeFromOptions<I extends TreeItem> = {\n getSelfKey: (item: I, index: number) => unknown;\n getParentKey: (item: I, index: number) => unknown;\n appendChild: (parentInfo: FromItemInfo<I>, info: FromItemInfo<I>) => unknown;\n};\n\n/**\n * 从扁平列表构建树形结构。\n *\n * @template I - 节点对象的类型,必须继承自 `AnyObject`。\n * @param {I[]} list - 扁平化的节点列表。\n * @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。\n * @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。\n * @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。\n * @param {function} options.appendChild - 将子节点添加到父节点的函数。\n * @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const list = [\n * { id: 1, parentId: null, name: 'Root' },\n * { id: 2, parentId: 1, name: 'Child 1' },\n * { id: 3, parentId: 1, name: 'Child 2' }\n * ];\n *\n * const tree = treeFrom(list, {\n * getSelfKey: (item) => item.id,\n * getParentKey: (item) => item.parentId,\n * appendChild: (parent, info) => {\n * if (!parent.children) parent.children = [];\n * parent.children.push(info.item);\n * }\n * });\n *\n * console.log(tree);\n * // {\n * // id: 1,\n * // parentId: null,\n * // name: 'Root',\n * // children: [\n * // { id: 2, parentId: 1, name: 'Child 1' },\n * // { id: 3, parentId: 1, name: 'Child 2' }\n * // ]\n * // }\n * ```\n */\nexport function treeFrom<I extends TreeItem>(list: I[], options: TreeFromOptions<I>): TreeList<I> | undefined {\n const keyMap = new Map<unknown, FromItemInfo<I>>();\n const freeSet = new Set<FromItemInfo<I>>();\n const roots: TreeList<I> = [];\n\n // 分配节点\n const assign = (info: FromItemInfo<I>, isFirst = false) => {\n const { parentKey, item } = info;\n\n // 父级指向为空\n if (isNullish(parentKey)) {\n roots.push(item);\n }\n // 父级指向不为空\n else {\n const parent = keyMap.get(parentKey);\n\n // 未找到父级节点\n if (isUndefined(parent)) {\n // 游离节点\n if (isFirst) freeSet.add(info);\n }\n // 已找到父级节点\n else {\n options.appendChild(parent, info);\n }\n }\n };\n\n // 构建 map\n arrayEach(list, (item, index) => {\n const selfKey = options.getSelfKey(item, index);\n const parentKey = options.getParentKey(item, index);\n\n if (isNullish(selfKey)) return;\n\n const info = { selfKey, parentKey, item, index };\n keyMap.set(selfKey, info);\n\n assign(info, true);\n });\n\n // 处理游离节点\n for (const info of freeSet.values()) {\n assign(info);\n }\n\n return roots;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0HA,SAAgB,SACd,UACA,UACA,cAAc,OACR;CACN,MAAM,eAA8B,EAAE;CACtC,IAAI,cAAc;CAElB,MAAM,WAAW,SAAsB;EACrC,IAAI,SAAS,KAAK,KAAK,OAAO;GAC5B,cAAc;GACd,OAAO;;;CAIX,MAAM,QAAQ,MAAmB,SAAsB;EACrD,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,EAAE,aAAa;EAErB,IAAI,QAAQ,SAAS,EACnB,cACE,KAAK;GACH,GAAG;GACH,QAAQ;GACR,MAAM;GACN,OAAO,QAAQ;GAChB,CAAC,KAAK;;CAIb,MAAM,QAAqB,WAAW;EACpC,MAAM,EAAE,MAAM,QAAQ,SAAS;EAE/B,MAAM,QAAQ,CAAC,GAAG,KAAK;EACvB,OAAO,WAAW,QAAQ,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,QACxE,MAAM,KAAK;EAGb,UAAU,OAAO,MAAM,UAAU;GAC/B,IAAI,aAAa,OAAO;GAExB,MAAM,OAAoB;IACxB,GAAG;IACH;IACA;IACA,MAAM,CAAC,GAAG,OAAO,KAAK;IACvB;GAGD,IAAI,aACF,aAAa,KAAK,KAAK;QAGpB;IACH,QAAQ,KAAK;IACb,IAAI,aAAa,OAAO;IACxB,KAAK,MAAM,KAAK;;IAElB;EAEF,IAAI,aACF,OAAO,CAAC,aAAa;GACnB,MAAM,OAAO,aAAa,OAAO;GACjC,IAAI,CAAC,MAAM;GAEX,QAAQ,KAAK;GACb,IAAI,aAAa;GAGjB,KAAK,MAAM,KAAK;;EAIpB,OAAO,CAAC;;CAGV,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACR,MAAM,EAAE;EACT,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BJ,SAAgB,SACd,UACA,WACA,cAAc,OACW;CACzB,IAAI;CAEJ,SACE,WACC,SAAS;EACR,IAAI,UAAU,KAAK,EAAE;GACnB,QAAQ;GACR,OAAO;;IAGX,YACD;CAED,OAAO;;;;;;;;;;;;;;;;;;;;;;AAuBT,SAAgB,SACd,UACA,SACA,cAAc,OACT;CACL,MAAM,QAAa,EAAE;CAErB,SACE,WACC,SAAS;EACR,MAAM,KAAK,QAAQ,KAAK,CAAC;IAE3B,YACD;CAED,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDT,SAAgB,SAA6B,MAAW,SAAsD;CAC5G,MAAM,yBAAS,IAAI,KAA+B;CAClD,MAAM,0BAAU,IAAI,KAAsB;CAC1C,MAAM,QAAqB,EAAE;CAG7B,MAAM,UAAU,MAAuB,UAAU,UAAU;EACzD,MAAM,EAAE,WAAW,SAAS;EAG5B,IAAI,UAAU,UAAU,EACtB,MAAM,KAAK,KAAK;OAGb;GACH,MAAM,SAAS,OAAO,IAAI,UAAU;GAGpC,IAAI,YAAY,OAAO;QAEjB,SAAS,QAAQ,IAAI,KAAK;UAI9B,QAAQ,YAAY,QAAQ,KAAK;;;CAMvC,UAAU,OAAO,MAAM,UAAU;EAC/B,MAAM,UAAU,QAAQ,WAAW,MAAM,MAAM;EAC/C,MAAM,YAAY,QAAQ,aAAa,MAAM,MAAM;EAEnD,IAAI,UAAU,QAAQ,EAAE;EAExB,MAAM,OAAO;GAAE;GAAS;GAAW;GAAM;GAAO;EAChD,OAAO,IAAI,SAAS,KAAK;EAEzB,OAAO,MAAM,KAAK;GAClB;CAGF,KAAK,MAAM,QAAQ,QAAQ,QAAQ,EACjC,OAAO,KAAK;CAGd,OAAO"}
|
|
1
|
+
{"version":3,"file":"tree.mjs","names":[],"sources":["../src/tree.ts"],"sourcesContent":["import { arrayEach } from './array';\nimport { isArray, isNullish, isUndefined } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 表示深度遍历中的节点对象,包含子节点列表。\n */\nexport type TreeItem = AnyObject & {\n /**\n * 子节点列表。\n */\n children?: TreeItem[];\n};\n\n/**\n * 表示深度遍历中的节点列表。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeList<I extends TreeItem> = I[];\n\n/**\n * 表示深度遍历中的遍历器状态。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeWalker<I extends TreeItem> = {\n /**\n * 当前层级的节点列表。\n */\n list: TreeList<I>;\n\n /**\n * 当前节点的父节点,如果为根节点则为 `null`。\n */\n parent: I | null;\n\n /**\n * 当前节点的层级,从 1 开始计数。\n */\n level: number;\n\n /**\n * 从根节点到当前节点的路径。\n */\n path: TreeList<I>;\n};\n\n/**\n * 表示深度遍历中的节点信息。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n */\nexport type TreeInfo<I extends TreeItem> = TreeWalker<I> & {\n /**\n * 当前节点。\n */\n item: I;\n\n /**\n * 当前节点在 `list` 中的索引。\n */\n index: number;\n};\n\n/**\n * 深度遍历的同步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIterator<I extends TreeItem> = (info: TreeInfo<I>) => false | unknown;\n\n/**\n * 深度遍历的异步迭代器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param info - 当前节点的信息。\n * @returns 如果返回 `false`,则提前终止遍历。\n */\nexport type TreeEachIteratorAsync<I extends TreeItem> = (info: TreeInfo<I>) => Promise<boolean | unknown>;\n\n/**\n * 深度遍历的同步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 遍历结果。\n */\nexport type TreeWalk<I extends TreeItem> = (walker: TreeWalker<I>) => unknown;\n\n/**\n * 深度遍历的异步遍历器函数类型。\n *\n * @template I - 节点对象的类型,必须继承自 `TreeItem`。\n * @param walker - 遍历器状态。\n * @returns 异步遍历结果。\n */\nexport type TreeWalkAsync<I extends TreeItem> = (walker: TreeWalker<I>) => Promise<unknown>;\n\n/**\n * 深度遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param treeList - 要遍历的深度数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param breadthFist - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * treeEach(treeList, (item) => {\n * console.log(item.value);\n * if (item.value === 2) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function treeEach<I extends TreeItem = TreeItem>(\n treeList: TreeList<I>,\n iterator: TreeEachIterator<I>,\n breadthFist = false,\n): void {\n const treeInfoList: TreeInfo<I>[] = [];\n let returnFalse = false;\n\n const iterate = (info: TreeInfo<I>) => {\n if (iterator(info) === false) {\n returnFalse = true;\n return false;\n }\n };\n\n const next = (info: TreeInfo<I>, walk: TreeWalk<I>) => {\n const { item, level } = info;\n const { children } = item;\n\n if (isArray(children)) {\n returnFalse =\n walk({\n ...info,\n parent: item,\n list: children as TreeList<I>,\n level: level + 1,\n }) === false;\n }\n };\n\n const walk: TreeWalk<I> = (walker) => {\n const { list, parent, path } = walker;\n\n const path2 = [...path];\n while (parent !== null && path2.length > 0 && path2[path2.length - 1] !== parent) {\n path2.pop();\n }\n\n arrayEach(list, (item, index) => {\n if (returnFalse) return false;\n\n const info: TreeInfo<I> = {\n ...walker,\n item,\n index,\n path: [...path2, item],\n };\n\n // 广度优先\n if (breadthFist) {\n treeInfoList.push(info);\n }\n // 深度优先\n else {\n iterate(info);\n if (returnFalse) return false;\n next(info, walk);\n }\n });\n\n if (breadthFist) {\n while (!returnFalse) {\n const info = treeInfoList.shift();\n if (!info) break;\n\n iterate(info);\n if (returnFalse) break;\n\n // 内部也会进入 walk\n next(info, walk);\n }\n }\n\n return !returnFalse;\n };\n\n walk({\n list: treeList,\n level: 1,\n parent: null,\n path: [],\n });\n}\n\n/**\n * 在深度数组中查找满足条件的第一个节点信息。\n *\n * @param treeList - 要查找的深度数组。\n * @param predicate - 判断节点是否满足条件的回调函数。\n * @param breadthFist - 是否使用广度优先查找,默认为 `false`(深度优先)。\n * @returns 如果找到满足条件的节点,则返回该节点的信息;否则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const found = treeFind(treeList, (info) => info.item.value === 3);\n * console.log(found);\n * // {\n * // item: { value: 3 },\n * // index: 1,\n * // list: [{ value: 2 }, { value: 3 }],\n * // parent: { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * // level: 2,\n * // path: [{ value: 1, children: [{ value: 2 }, { value: 3 }] }, { value: 3 }]\n * // }\n * ```\n */\nexport function treeFind<I extends TreeItem>(\n treeList: TreeList<I>,\n predicate: (info: TreeInfo<I>) => boolean,\n breadthFist = false,\n): TreeInfo<I> | undefined {\n let found: TreeInfo<I> | undefined;\n\n treeEach(\n treeList,\n (info) => {\n if (predicate(info)) {\n found = info;\n return false;\n }\n },\n breadthFist,\n );\n\n return found;\n}\n\n/**\n * 将深度嵌套的树形结构扁平化为一维数组,并对每个节点执行指定的转换函数。\n *\n * @template I - 树节点的类型,必须继承自 `TreeItem`。\n * @template T - 转换后的数据类型。\n * @param {TreeList<I>} deepList - 要扁平化的深度嵌套树形结构。\n * @param {(info: TreeInfo<I>) => T} flatten - 对每个节点执行的转换函数,返回转换后的数据。\n * @param {boolean} [breadthFist=false] - 是否使用广度优先遍历,默认为 `false`(深度优先)。\n * @returns {T[]} - 转换后的一维数组。\n * @example\n * ```typescript\n * const treeList = [\n * { value: 1, children: [{ value: 2 }, { value: 3 }] },\n * { value: 4 }\n * ];\n *\n * const flattened = deepFlat(treeList, (info) => info.item.value);\n * console.log(flattened); // [1, 2, 3, 4]\n * ```\n */\nexport function deepFlat<I extends TreeItem, T>(\n deepList: TreeList<I>,\n flatten: (info: TreeInfo<I>) => T,\n breadthFist = false,\n): T[] {\n const list2: T[] = [];\n\n treeEach(\n deepList,\n (info) => {\n list2.push(flatten(info));\n },\n breadthFist,\n );\n\n return list2;\n}\n\ntype FromItemInfo<I> = {\n selfKey: unknown;\n parentKey: unknown;\n item: I;\n index: number;\n};\n\nexport type TreeFromOptions<I extends TreeItem> = {\n getSelfKey: (item: I, index: number) => unknown;\n getParentKey: (item: I, index: number) => unknown;\n appendChild: (parentInfo: FromItemInfo<I>, info: FromItemInfo<I>) => unknown;\n};\n\n/**\n * 从扁平列表构建树形结构。\n *\n * @template I - 节点对象的类型,必须继承自 `AnyObject`。\n * @param {I[]} list - 扁平化的节点列表。\n * @param {TreeFromOptions<I>} options - 构建树形结构的配置选项。\n * @param {function} options.getSelfKey - 获取节点自身唯一标识的函数。\n * @param {function} options.getParentKey - 获取节点父节点唯一标识的函数。\n * @param {function} options.appendChild - 将子节点添加到父节点的函数。\n * @returns {I | undefined} - 构建的树形结构的根节点,如果未找到根节点则返回 `undefined`。\n *\n * @example\n * ```typescript\n * const list = [\n * { id: 1, parentId: null, name: 'Root' },\n * { id: 2, parentId: 1, name: 'Child 1' },\n * { id: 3, parentId: 1, name: 'Child 2' }\n * ];\n *\n * const tree = treeFrom(list, {\n * getSelfKey: (item) => item.id,\n * getParentKey: (item) => item.parentId,\n * appendChild: (parent, info) => {\n * if (!parent.children) parent.children = [];\n * parent.children.push(info.item);\n * }\n * });\n *\n * console.log(tree);\n * // {\n * // id: 1,\n * // parentId: null,\n * // name: 'Root',\n * // children: [\n * // { id: 2, parentId: 1, name: 'Child 1' },\n * // { id: 3, parentId: 1, name: 'Child 2' }\n * // ]\n * // }\n * ```\n */\nexport function treeFrom<I extends TreeItem>(list: I[], options: TreeFromOptions<I>): TreeList<I> | undefined {\n const keyMap = new Map<unknown, FromItemInfo<I>>();\n const freeSet = new Set<FromItemInfo<I>>();\n const roots: TreeList<I> = [];\n\n // 分配节点\n const assign = (info: FromItemInfo<I>, isFirst = false) => {\n const { parentKey, item } = info;\n\n // 父级指向为空\n if (isNullish(parentKey)) {\n roots.push(item);\n }\n // 父级指向不为空\n else {\n const parent = keyMap.get(parentKey);\n\n // 未找到父级节点\n if (isUndefined(parent)) {\n // 游离节点\n if (isFirst) freeSet.add(info);\n }\n // 已找到父级节点\n else {\n options.appendChild(parent, info);\n }\n }\n };\n\n // 构建 map\n arrayEach(list, (item, index) => {\n const selfKey = options.getSelfKey(item, index);\n const parentKey = options.getParentKey(item, index);\n\n if (isNullish(selfKey)) return;\n\n const info = { selfKey, parentKey, item, index };\n keyMap.set(selfKey, info);\n\n assign(info, true);\n });\n\n // 处理游离节点\n for (const info of freeSet.values()) {\n assign(info);\n }\n\n return roots;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0HA,SAAgB,SACd,UACA,UACA,cAAc,OACR;CACN,MAAM,eAA8B,CAAC;CACrC,IAAI,cAAc;CAElB,MAAM,WAAW,SAAsB;EACrC,IAAI,SAAS,IAAI,MAAM,OAAO;GAC5B,cAAc;GACd,OAAO;EACT;CACF;CAEA,MAAM,QAAQ,MAAmB,SAAsB;EACrD,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,EAAE,aAAa;EAErB,IAAI,QAAQ,QAAQ,GAClB,cACE,KAAK;GACH,GAAG;GACH,QAAQ;GACR,MAAM;GACN,OAAO,QAAQ;EACjB,CAAC,MAAM;CAEb;CAEA,MAAM,QAAqB,WAAW;EACpC,MAAM,EAAE,MAAM,QAAQ,SAAS;EAE/B,MAAM,QAAQ,CAAC,GAAG,IAAI;EACtB,OAAO,WAAW,QAAQ,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,OAAO,QACxE,MAAM,IAAI;EAGZ,UAAU,OAAO,MAAM,UAAU;GAC/B,IAAI,aAAa,OAAO;GAExB,MAAM,OAAoB;IACxB,GAAG;IACH;IACA;IACA,MAAM,CAAC,GAAG,OAAO,IAAI;GACvB;GAGA,IAAI,aACF,aAAa,KAAK,IAAI;QAGnB;IACH,QAAQ,IAAI;IACZ,IAAI,aAAa,OAAO;IACxB,KAAK,MAAM,IAAI;GACjB;EACF,CAAC;EAED,IAAI,aACF,OAAO,CAAC,aAAa;GACnB,MAAM,OAAO,aAAa,MAAM;GAChC,IAAI,CAAC,MAAM;GAEX,QAAQ,IAAI;GACZ,IAAI,aAAa;GAGjB,KAAK,MAAM,IAAI;EACjB;EAGF,OAAO,CAAC;CACV;CAEA,KAAK;EACH,MAAM;EACN,OAAO;EACP,QAAQ;EACR,MAAM,CAAC;CACT,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,SACd,UACA,WACA,cAAc,OACW;CACzB,IAAI;CAEJ,SACE,WACC,SAAS;EACR,IAAI,UAAU,IAAI,GAAG;GACnB,QAAQ;GACR,OAAO;EACT;CACF,GACA,WACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,SACd,UACA,SACA,cAAc,OACT;CACL,MAAM,QAAa,CAAC;CAEpB,SACE,WACC,SAAS;EACR,MAAM,KAAK,QAAQ,IAAI,CAAC;CAC1B,GACA,WACF;CAEA,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAgB,SAA6B,MAAW,SAAsD;CAC5G,MAAM,yBAAS,IAAI,IAA8B;CACjD,MAAM,0BAAU,IAAI,IAAqB;CACzC,MAAM,QAAqB,CAAC;CAG5B,MAAM,UAAU,MAAuB,UAAU,UAAU;EACzD,MAAM,EAAE,WAAW,SAAS;EAG5B,IAAI,UAAU,SAAS,GACrB,MAAM,KAAK,IAAI;OAGZ;GACH,MAAM,SAAS,OAAO,IAAI,SAAS;GAGnC,IAAI,YAAY,MAAM;QAEhB,SAAS,QAAQ,IAAI,IAAI;GAAA,OAI7B,QAAQ,YAAY,QAAQ,IAAI;EAEpC;CACF;CAGA,UAAU,OAAO,MAAM,UAAU;EAC/B,MAAM,UAAU,QAAQ,WAAW,MAAM,KAAK;EAC9C,MAAM,YAAY,QAAQ,aAAa,MAAM,KAAK;EAElD,IAAI,UAAU,OAAO,GAAG;EAExB,MAAM,OAAO;GAAE;GAAS;GAAW;GAAM;EAAM;EAC/C,OAAO,IAAI,SAAS,IAAI;EAExB,OAAO,MAAM,IAAI;CACnB,CAAC;CAGD,KAAK,MAAM,QAAQ,QAAQ,OAAO,GAChC,OAAO,IAAI;CAGb,OAAO;AACT"}
|
package/dist/try.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"try.cjs","names":[],"sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["export type Callback<T = void> = (err: null | undefined | undefined | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport { type AsyncFunction, type SyncFunction, tryAsync, trySync } from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble)) return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"mappings":";;;;AA4DA,SAAgB,cAAc,IAAa,GAAG,MAA2C;CACvF,OAAO,SAAS,gBAAgB,UAA6B;EAG3D,GAAG,MAAM,MAAM,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"try.cjs","names":[],"sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["export type Callback<T = void> = (err: null | undefined | undefined | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport { type AsyncFunction, type SyncFunction, tryAsync, trySync } from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble)) return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"mappings":";;;;AA4DA,SAAgB,cAAc,IAAa,GAAG,MAA2C;CACvF,OAAO,SAAS,gBAAgB,UAA6B;EAG3D,GAAG,MAAM,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC;CACpC;AACF;;;ACnBA,SAAgB,YAAY,IAAa,GAAG,MAAkD;CAC5F,OAAO,IAAI,SAAS,YAAY;EAG9B,cAAc,MAAM,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,KAAK,QAAQ;GACrD,IAAI,KACF,QAAQ,CAAC,cAAA,eAAe,GAAG,GAAG,KAAA,CAAS,CAAU;QAEjD,QAAQ,CAAC,KAAA,GAAW,GAAG,CAAU;EAErC,CAAC;CACH,CAAC;AACH;;;ACtDA,SAAgB,QAAW,QAA2C;CACpE,IAAI;EACF,OAAO,CAAC,KAAA,GAAW,OAAO,CAAC;CAC7B,SAAS,KAAK;EACZ,OAAO,CAAC,cAAA,eAAe,GAAG,GAAG,KAAA,CAAS;CACxC;AACF;AAIA,SAAgB,SAAY,SAAsD;CAChF,OAAO,QAAQ,EAAE,MACd,QAAQ,CAAC,KAAA,GAAW,GAAG,IACvB,QAAQ,CAAC,cAAA,eAAe,GAAG,GAAG,KAAA,CAAS,CAC1C;AACF;;;ACjBA,SAAgB,WAAc,SAAwD;CACpF,OAAO,QAAQ,MACZ,QAAQ,CAAC,KAAA,GAAW,GAAG,IACvB,QAAQ,CAAC,cAAA,eAAe,GAAG,GAAG,KAAA,CAAS,CAC1C;AACF;;;ACMA,SAAgB,WAAc,aAAsC;CAClE,IAAI,UAAU,aACZ,OAAO,WAAc,WAAW;CAIlC,IAAI,YAAY,WAAW,GAAG;EAC5B,IAAI,aAAA,gBAAgB,WAAW,GAAG,OAAO,SAAY,WAA+B;EACpF,OAAO,QAAW,WAA8B;CAClD;CAEA,OAAO,YAAe,WAAW;AACnC"}
|
package/dist/try.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"try.mjs","names":[],"sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["export type Callback<T = void> = (err: null | undefined | undefined | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport { type AsyncFunction, type SyncFunction, tryAsync, trySync } from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble)) return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"mappings":";;;AA4DA,SAAgB,cAAc,IAAa,GAAG,MAA2C;CACvF,OAAO,SAAS,gBAAgB,UAA6B;EAG3D,GAAG,MAAM,MAAM,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"try.mjs","names":[],"sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["export type Callback<T = void> = (err: null | undefined | undefined | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport { type AsyncFunction, type SyncFunction, tryAsync, trySync } from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble)) return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"mappings":";;;AA4DA,SAAgB,cAAc,IAAa,GAAG,MAA2C;CACvF,OAAO,SAAS,gBAAgB,UAA6B;EAG3D,GAAG,MAAM,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC;CACpC;AACF;;;ACnBA,SAAgB,YAAY,IAAa,GAAG,MAAkD;CAC5F,OAAO,IAAI,SAAS,YAAY;EAG9B,cAAc,MAAM,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,KAAK,QAAQ;GACrD,IAAI,KACF,QAAQ,CAAC,eAAe,GAAG,GAAG,KAAA,CAAS,CAAU;QAEjD,QAAQ,CAAC,KAAA,GAAW,GAAG,CAAU;EAErC,CAAC;CACH,CAAC;AACH;;;ACtDA,SAAgB,QAAW,QAA2C;CACpE,IAAI;EACF,OAAO,CAAC,KAAA,GAAW,OAAO,CAAC;CAC7B,SAAS,KAAK;EACZ,OAAO,CAAC,eAAe,GAAG,GAAG,KAAA,CAAS;CACxC;AACF;AAIA,SAAgB,SAAY,SAAsD;CAChF,OAAO,QAAQ,EAAE,MACd,QAAQ,CAAC,KAAA,GAAW,GAAG,IACvB,QAAQ,CAAC,eAAe,GAAG,GAAG,KAAA,CAAS,CAC1C;AACF;;;ACjBA,SAAgB,WAAc,SAAwD;CACpF,OAAO,QAAQ,MACZ,QAAQ,CAAC,KAAA,GAAW,GAAG,IACvB,QAAQ,CAAC,eAAe,GAAG,GAAG,KAAA,CAAS,CAC1C;AACF;;;ACMA,SAAgB,WAAc,aAAsC;CAClE,IAAI,UAAU,aACZ,OAAO,WAAc,WAAW;CAIlC,IAAI,YAAY,WAAW,GAAG;EAC5B,IAAI,gBAAgB,WAAW,GAAG,OAAO,SAAY,WAA+B;EACpF,OAAO,QAAW,WAA8B;CAClD;CAEA,OAAO,YAAe,WAAW;AACnC"}
|
package/dist/type.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type.cjs","names":[],"sources":["../src/type.ts"],"sourcesContent":["import type { AnyArray, AnyAsyncFunction, AnyFunction, AnyObject } from './types';\n\n/**\n * 获取未知类型的类型名称\n * @param unknown - 未知类型的值\n * @returns 类型名称字符串\n */\nexport function typeIs(\n unknown: unknown,\n):\n | 'string'\n | 'number'\n | 'boolean'\n | 'object'\n | 'array'\n | 'function'\n | 'null'\n | 'undefined'\n | 'symbol'\n | 'bigint'\n | 'error'\n | 'promise'\n | string {\n return Object.prototype.toString.call(unknown).slice(8, -1).toLowerCase();\n}\n\n/**\n * 检查值是否为字符串\n * @param unknown - 未知类型的值\n * @returns 如果值为字符串则返回 true,否则返回 false\n */\nexport function isString(unknown: unknown): unknown is string {\n return typeof unknown === 'string';\n}\n\n/**\n * 检查值是否为布尔值\n * @param unknown - 未知类型的值\n * @returns 如果值为布尔值则返回 true,否则返回 false\n */\nexport function isBoolean(unknown: unknown): unknown is boolean {\n return typeof unknown === 'boolean';\n}\n\n/**\n * 检查值是否为符号\n * @param unknown - 未知类型的值\n * @returns 如果值为符号则返回 true,否则返回 false\n */\nexport function isSymbol(unknown: unknown): unknown is symbol {\n return typeof unknown === 'symbol';\n}\n\n/**\n * 检查值是否为大整数\n * @param unknown - 未知类型的值\n * @returns 如果值为大整数则返回 true,否则返回 false\n */\nexport function isBigInt(unknown: unknown): unknown is bigint {\n return typeof unknown === 'bigint';\n}\n\n/**\n * 检查值是否为数字\n * @param unknown - 未知类型的值\n * @returns 如果值为数字且不是 NaN 则返回 true,否则返回 false\n */\nexport function isNumber(unknown: unknown): unknown is number {\n return typeof unknown === 'number' && !Number.isNaN(unknown);\n}\n\n/**\n * 检查值是否为 undefined\n * @param unknown - 未知类型的值\n * @returns 如果值为 undefined 则返回 true,否则返回 false\n */\nexport function isUndefined(unknown: unknown): unknown is undefined {\n return typeof unknown === 'undefined';\n}\n\n/**\n * 检查值是否为 void\n * @param unknown - 未知类型的值\n * @returns 如果值为 undefined 则返回 true,否则返回 false\n */\n// biome-ignore lint/suspicious/noConfusingVoidType: 必须使用 void 类型断言\nexport function isVoid(unknown: unknown): unknown is void {\n return isUndefined(unknown);\n}\n\n/**\n * 永不执行,用于 switch-case/if-else 类型断言\n * @param unknown - 永远不会执行的值\n */\nexport function isNever(_unknown: never) {\n //\n}\n\n/**\n * 检查值是否为 null\n * @param unknown - 未知类型的值\n * @returns 如果值为 null 则返回 true,否则返回 false\n */\nexport function isNull(unknown: unknown): unknown is null {\n return unknown === null;\n}\n\n/**\n * 检查值是否为 nullish(null 或 undefined 或 void)\n * @param unknown - 未知类型的值\n * @returns 如果值为 null 或 undefined 或 void 则返回 true,否则返回 false\n */\nexport function isNullish(unknown: unknown): unknown is null | undefined | undefined {\n return isNull(unknown) || isUndefined(unknown) || isVoid(unknown);\n}\n\n/**\n * 检查值是否为原始类型(null 或 非对象)\n * @param unknown - 未知类型的值\n * @returns 如果值为原始类型则返回 true,否则返回 false\n */\nexport function isPrimitive(\n unknown: unknown,\n): unknown is string | number | boolean | symbol | bigint | null | undefined {\n return isNull(unknown) || !(typeof unknown === 'object' || typeof unknown === 'function');\n}\n\n/**\n * 检查值是否为对象,但要注意,此时的对象类型是包含了数组和函数\n * @param unknown - 未知类型的值\n * @returns 如果值为对象则返回 true,否则返回 false\n */\nexport function isObject(unknown: unknown): unknown is AnyObject {\n return typeIs(unknown) === 'object';\n}\n\n/**\n * 检查值是否为数组\n * @param unknown - 未知类型的值\n * @returns 如果值为数组则返回 true,否则返回 false\n */\nexport function isArray(unknown: unknown): unknown is AnyArray {\n return Array.isArray(unknown);\n}\n\n/**\n * 检查值是否为函数\n * @param unknown - 未知类型的值\n * @returns 如果值为函数则返回 true,否则返回 false\n */\nexport function isFunction(unknown: unknown): unknown is AnyFunction {\n return typeof unknown === 'function';\n}\n\n/**\n * 检查值是否为异步函数\n * @param unknown - 需要检查的值\n * @returns 如果值为异步函数则返回 true,否则返回 false\n * @example\n * ```typescript\n * async function example() {}\n *\n * isAsyncFunction(example); // true\n * isAsyncFunction(() => {}); // false\n * ```\n */\nexport function isAsyncFunction(unknown: unknown): unknown is AnyAsyncFunction {\n return isFunction(unknown) && unknown.constructor.name === 'AsyncFunction';\n}\n\n/**\n * 检查值是否为 Error 类型\n * @param unknown - 未知类型的值\n * @returns 如果值为 Error 类型则返回 true,否则返回 false\n */\nexport function isError(unknown: unknown): unknown is Error {\n return unknown instanceof Error;\n}\n\n/**\n * 检查值是否为 Promise 类型\n * @param unknown - 未知类型的值\n * @returns 如果值为 Promise 类型则返回 true,否则返回 false\n */\nexport function isPromise<T>(unknown: unknown): unknown is Promise<T> {\n return typeIs(unknown) === 'promise';\n}\n\n/**\n * 检查值是否为 Date 类型\n * @param unknown - 未知类型的值\n * @returns 如果值为 Date 类型则返回 true,否则返回 false\n */\nexport function isDate(unknown: unknown): unknown is Date {\n return unknown instanceof Date;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,OACd,SAcS;CACT,OAAO,OAAO,UAAU,SAAS,KAAK,
|
|
1
|
+
{"version":3,"file":"type.cjs","names":[],"sources":["../src/type.ts"],"sourcesContent":["import type { AnyArray, AnyAsyncFunction, AnyFunction, AnyObject } from './types';\n\n/**\n * 获取未知类型的类型名称\n * @param unknown - 未知类型的值\n * @returns 类型名称字符串\n */\nexport function typeIs(\n unknown: unknown,\n):\n | 'string'\n | 'number'\n | 'boolean'\n | 'object'\n | 'array'\n | 'function'\n | 'null'\n | 'undefined'\n | 'symbol'\n | 'bigint'\n | 'error'\n | 'promise'\n | string {\n return Object.prototype.toString.call(unknown).slice(8, -1).toLowerCase();\n}\n\n/**\n * 检查值是否为字符串\n * @param unknown - 未知类型的值\n * @returns 如果值为字符串则返回 true,否则返回 false\n */\nexport function isString(unknown: unknown): unknown is string {\n return typeof unknown === 'string';\n}\n\n/**\n * 检查值是否为布尔值\n * @param unknown - 未知类型的值\n * @returns 如果值为布尔值则返回 true,否则返回 false\n */\nexport function isBoolean(unknown: unknown): unknown is boolean {\n return typeof unknown === 'boolean';\n}\n\n/**\n * 检查值是否为符号\n * @param unknown - 未知类型的值\n * @returns 如果值为符号则返回 true,否则返回 false\n */\nexport function isSymbol(unknown: unknown): unknown is symbol {\n return typeof unknown === 'symbol';\n}\n\n/**\n * 检查值是否为大整数\n * @param unknown - 未知类型的值\n * @returns 如果值为大整数则返回 true,否则返回 false\n */\nexport function isBigInt(unknown: unknown): unknown is bigint {\n return typeof unknown === 'bigint';\n}\n\n/**\n * 检查值是否为数字\n * @param unknown - 未知类型的值\n * @returns 如果值为数字且不是 NaN 则返回 true,否则返回 false\n */\nexport function isNumber(unknown: unknown): unknown is number {\n return typeof unknown === 'number' && !Number.isNaN(unknown);\n}\n\n/**\n * 检查值是否为 undefined\n * @param unknown - 未知类型的值\n * @returns 如果值为 undefined 则返回 true,否则返回 false\n */\nexport function isUndefined(unknown: unknown): unknown is undefined {\n return typeof unknown === 'undefined';\n}\n\n/**\n * 检查值是否为 void\n * @param unknown - 未知类型的值\n * @returns 如果值为 undefined 则返回 true,否则返回 false\n */\n// biome-ignore lint/suspicious/noConfusingVoidType: 必须使用 void 类型断言\nexport function isVoid(unknown: unknown): unknown is void {\n return isUndefined(unknown);\n}\n\n/**\n * 永不执行,用于 switch-case/if-else 类型断言\n * @param unknown - 永远不会执行的值\n */\nexport function isNever(_unknown: never) {\n //\n}\n\n/**\n * 检查值是否为 null\n * @param unknown - 未知类型的值\n * @returns 如果值为 null 则返回 true,否则返回 false\n */\nexport function isNull(unknown: unknown): unknown is null {\n return unknown === null;\n}\n\n/**\n * 检查值是否为 nullish(null 或 undefined 或 void)\n * @param unknown - 未知类型的值\n * @returns 如果值为 null 或 undefined 或 void 则返回 true,否则返回 false\n */\nexport function isNullish(unknown: unknown): unknown is null | undefined | undefined {\n return isNull(unknown) || isUndefined(unknown) || isVoid(unknown);\n}\n\n/**\n * 检查值是否为原始类型(null 或 非对象)\n * @param unknown - 未知类型的值\n * @returns 如果值为原始类型则返回 true,否则返回 false\n */\nexport function isPrimitive(\n unknown: unknown,\n): unknown is string | number | boolean | symbol | bigint | null | undefined {\n return isNull(unknown) || !(typeof unknown === 'object' || typeof unknown === 'function');\n}\n\n/**\n * 检查值是否为对象,但要注意,此时的对象类型是包含了数组和函数\n * @param unknown - 未知类型的值\n * @returns 如果值为对象则返回 true,否则返回 false\n */\nexport function isObject(unknown: unknown): unknown is AnyObject {\n return typeIs(unknown) === 'object';\n}\n\n/**\n * 检查值是否为数组\n * @param unknown - 未知类型的值\n * @returns 如果值为数组则返回 true,否则返回 false\n */\nexport function isArray(unknown: unknown): unknown is AnyArray {\n return Array.isArray(unknown);\n}\n\n/**\n * 检查值是否为函数\n * @param unknown - 未知类型的值\n * @returns 如果值为函数则返回 true,否则返回 false\n */\nexport function isFunction(unknown: unknown): unknown is AnyFunction {\n return typeof unknown === 'function';\n}\n\n/**\n * 检查值是否为异步函数\n * @param unknown - 需要检查的值\n * @returns 如果值为异步函数则返回 true,否则返回 false\n * @example\n * ```typescript\n * async function example() {}\n *\n * isAsyncFunction(example); // true\n * isAsyncFunction(() => {}); // false\n * ```\n */\nexport function isAsyncFunction(unknown: unknown): unknown is AnyAsyncFunction {\n return isFunction(unknown) && unknown.constructor.name === 'AsyncFunction';\n}\n\n/**\n * 检查值是否为 Error 类型\n * @param unknown - 未知类型的值\n * @returns 如果值为 Error 类型则返回 true,否则返回 false\n */\nexport function isError(unknown: unknown): unknown is Error {\n return unknown instanceof Error;\n}\n\n/**\n * 检查值是否为 Promise 类型\n * @param unknown - 未知类型的值\n * @returns 如果值为 Promise 类型则返回 true,否则返回 false\n */\nexport function isPromise<T>(unknown: unknown): unknown is Promise<T> {\n return typeIs(unknown) === 'promise';\n}\n\n/**\n * 检查值是否为 Date 类型\n * @param unknown - 未知类型的值\n * @returns 如果值为 Date 类型则返回 true,否则返回 false\n */\nexport function isDate(unknown: unknown): unknown is Date {\n return unknown instanceof Date;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,OACd,SAcS;CACT,OAAO,OAAO,UAAU,SAAS,KAAK,OAAO,EAAE,MAAM,GAAG,EAAE,EAAE,YAAY;AAC1E;;;;;;AAOA,SAAgB,SAAS,SAAqC;CAC5D,OAAO,OAAO,YAAY;AAC5B;;;;;;AAOA,SAAgB,UAAU,SAAsC;CAC9D,OAAO,OAAO,YAAY;AAC5B;;;;;;AAOA,SAAgB,SAAS,SAAqC;CAC5D,OAAO,OAAO,YAAY;AAC5B;;;;;;AAOA,SAAgB,SAAS,SAAqC;CAC5D,OAAO,OAAO,YAAY;AAC5B;;;;;;AAOA,SAAgB,SAAS,SAAqC;CAC5D,OAAO,OAAO,YAAY,YAAY,CAAC,OAAO,MAAM,OAAO;AAC7D;;;;;;AAOA,SAAgB,YAAY,SAAwC;CAClE,OAAO,OAAO,YAAY;AAC5B;;;;;;AAQA,SAAgB,OAAO,SAAmC;CACxD,OAAO,YAAY,OAAO;AAC5B;;;;;AAMA,SAAgB,QAAQ,UAAiB,CAEzC;;;;;;AAOA,SAAgB,OAAO,SAAmC;CACxD,OAAO,YAAY;AACrB;;;;;;AAOA,SAAgB,UAAU,SAA2D;CACnF,OAAO,OAAO,OAAO,KAAK,YAAY,OAAO,KAAK,OAAO,OAAO;AAClE;;;;;;AAOA,SAAgB,YACd,SAC2E;CAC3E,OAAO,OAAO,OAAO,KAAK,EAAE,OAAO,YAAY,YAAY,OAAO,YAAY;AAChF;;;;;;AAOA,SAAgB,SAAS,SAAwC;CAC/D,OAAO,OAAO,OAAO,MAAM;AAC7B;;;;;;AAOA,SAAgB,QAAQ,SAAuC;CAC7D,OAAO,MAAM,QAAQ,OAAO;AAC9B;;;;;;AAOA,SAAgB,WAAW,SAA0C;CACnE,OAAO,OAAO,YAAY;AAC5B;;;;;;;;;;;;;AAcA,SAAgB,gBAAgB,SAA+C;CAC7E,OAAO,WAAW,OAAO,KAAK,QAAQ,YAAY,SAAS;AAC7D;;;;;;AAOA,SAAgB,QAAQ,SAAoC;CAC1D,OAAO,mBAAmB;AAC5B;;;;;;AAOA,SAAgB,UAAa,SAAyC;CACpE,OAAO,OAAO,OAAO,MAAM;AAC7B;;;;;;AAOA,SAAgB,OAAO,SAAmC;CACxD,OAAO,mBAAmB;AAC5B"}
|