@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.
Files changed (64) hide show
  1. package/dist/array.cjs.map +1 -1
  2. package/dist/array.mjs.map +1 -1
  3. package/dist/async.cjs +1 -0
  4. package/dist/async.cjs.map +1 -1
  5. package/dist/async.mjs +1 -0
  6. package/dist/async.mjs.map +1 -1
  7. package/dist/base64.cjs.map +1 -1
  8. package/dist/base64.mjs.map +1 -1
  9. package/dist/cache.cjs.map +1 -1
  10. package/dist/cache.mjs.map +1 -1
  11. package/dist/color.cjs.map +1 -1
  12. package/dist/color.mjs.map +1 -1
  13. package/dist/crypto.cjs.map +1 -1
  14. package/dist/crypto.mjs.map +1 -1
  15. package/dist/date.cjs.map +1 -1
  16. package/dist/date.mjs.map +1 -1
  17. package/dist/dict.cjs.map +1 -1
  18. package/dist/dict.mjs.map +1 -1
  19. package/dist/easing.cjs.map +1 -1
  20. package/dist/easing.mjs.map +1 -1
  21. package/dist/emitter.cjs.map +1 -1
  22. package/dist/emitter.mjs.map +1 -1
  23. package/dist/env.cjs.map +1 -1
  24. package/dist/env.mjs.map +1 -1
  25. package/dist/error.cjs.map +1 -1
  26. package/dist/error.mjs.map +1 -1
  27. package/dist/function.cjs.map +1 -1
  28. package/dist/function.mjs.map +1 -1
  29. package/dist/index.cjs +1 -1
  30. package/dist/index.mjs +1 -1
  31. package/dist/object.cjs.map +1 -1
  32. package/dist/object.mjs.map +1 -1
  33. package/dist/path.cjs.map +1 -1
  34. package/dist/path.mjs.map +1 -1
  35. package/dist/promise.cjs.map +1 -1
  36. package/dist/promise.mjs.map +1 -1
  37. package/dist/qs.cjs.map +1 -1
  38. package/dist/qs.mjs.map +1 -1
  39. package/dist/regexp.cjs.map +1 -1
  40. package/dist/regexp.mjs.map +1 -1
  41. package/dist/string2.cjs.map +1 -1
  42. package/dist/string2.mjs.map +1 -1
  43. package/dist/time.cjs.map +1 -1
  44. package/dist/time.mjs.map +1 -1
  45. package/dist/timer.cjs.map +1 -1
  46. package/dist/timer.mjs.map +1 -1
  47. package/dist/tree.cjs.map +1 -1
  48. package/dist/tree.mjs.map +1 -1
  49. package/dist/try.cjs.map +1 -1
  50. package/dist/try.mjs.map +1 -1
  51. package/dist/type.cjs.map +1 -1
  52. package/dist/type.mjs.map +1 -1
  53. package/dist/unique.cjs.map +1 -1
  54. package/dist/unique.mjs.map +1 -1
  55. package/dist/url.cjs.map +1 -1
  56. package/dist/url.mjs.map +1 -1
  57. package/dist/version.cjs.map +1 -1
  58. package/dist/version.mjs.map +1 -1
  59. package/package.json +1 -9
  60. package/dist/exception.cjs +0 -40
  61. package/dist/exception.cjs.map +0 -1
  62. package/dist/exception.d.ts +0 -31
  63. package/dist/exception.mjs +0 -39
  64. package/dist/exception.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"object.mjs","names":[],"sources":["../src/object/each.ts","../src/object/get-set.ts","../src/object/is.ts","../src/object/merge.ts","../src/object/process.ts"],"sourcesContent":["import type { AnyObject, MaybePromise } from '@/types';\n\n/**\n * 遍历对象的每个键值对,并对每个键值对执行提供的回调函数。\n *\n * @param obj - 要遍历的对象。\n * @param iterator - 对每个键值对执行的回调函数。如果回调函数返回 false,则提前终止遍历。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const results: [string, number][] = [];\n * objectEach(obj, (val, key) => {\n * results.push([key, val]);\n * });\n * console.log(results); // [['a', 1], ['b', 2], ['c', 3]]\n * ```\n */\nexport function objectEach<O extends AnyObject, K extends keyof O & (string | number)>(\n obj: O,\n iterator: (this: O, val: O[K], key: K) => false | unknown,\n): void {\n for (const [key, val] of Object.entries(obj)) {\n if (iterator.call(obj, val as O[K], key as K) === false) {\n break;\n }\n }\n}\n\n/**\n * 异步遍历对象的每个键值对,并对每个键值对执行提供的回调函数。\n *\n * @param obj - 要遍历的对象。\n * @param iterator - 对每个键值对执行的异步回调函数。如果回调函数返回 false,则提前终止遍历。\n * @returns 返回一个 Promise,当所有异步操作完成后,Promise 会被 resolve。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const results: [string, number][] = [];\n * await objectEachAsync(obj, async (val, key) => {\n * results.push([key, val]);\n * });\n * console.log(results); // [['a', 1], ['b', 2], ['c', 3]]\n * ```\n */\nexport async function objectEachAsync<O extends AnyObject, K extends keyof O & (string | number)>(\n obj: O,\n iterator: (this: O, val: O[K], key: K) => MaybePromise<false | unknown>,\n): Promise<void> {\n for (const [key, val] of Object.entries(obj)) {\n if ((await iterator.call(obj, val as O[K], key as K)) === false) {\n break;\n }\n }\n}\n","import { isArray, isObject, isUndefined } from '@/type';\nimport type { AnyArray, AnyObject } from '@/types';\n\n// @ref https://stackoverflow.com/a/67609485\n\ntype Idx<T, K> = K extends keyof T\n ? T[K]\n : number extends keyof T\n ? K extends `${number}`\n ? T[number]\n : never\n : never;\n\ntype Join<K, P> = K extends string | number\n ? P extends string | number\n ? `${K}${'' extends P ? '' : '.'}${P}`\n : never\n : never;\n\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]];\n\nexport type ObjectPath<O, D extends number = 4> = [D] extends [never]\n ? never\n : O extends object\n ? {\n [K in keyof O]-?: K extends string | number ? `${K}` | Join<K, ObjectPath<O[K], Prev[D]>> : never;\n }[keyof O]\n : '';\n\nexport type ObjectLeafPath<O, D extends number = 4> = [D] extends [never]\n ? never\n : O extends object\n ? {\n [K in keyof O]-?: K extends string | number\n ? O[K] extends string | number\n ? `${K}` | Join<K, ObjectLeafPath<O[K], Prev[D]>>\n : Join<K, ObjectLeafPath<O[K], Prev[D]>>\n : never;\n }[keyof O]\n : '';\n\nexport type ObjectPathValue<O, P extends ObjectPath<O, 4>> = P extends `${infer Key}.${infer Rest}`\n ? Rest extends ObjectPath<Idx<O, Key>, 4>\n ? ObjectPathValue<Idx<O, Key>, Rest>\n : never\n : Idx<O, P>;\n\nfunction pathToKeys(path: string | string[]) {\n // 下文用到该数组时会进行修改操作,因此复制一份\n if (isArray(path)) return [...path];\n\n let pathFinal = path.replace(/\\[(\\w+)\\]/g, '.$1');\n pathFinal = pathFinal.replace(/^\\./, '');\n return pathFinal.split('.');\n}\n\nfunction isObjectOrArray(v: unknown) {\n return isObject(v) || isArray(v);\n}\n\n/**\n * 表示对象节点的信息。\n *\n * @template V - 键值的类型。\n */\nexport type ObjectNode<V = unknown | undefined> = {\n /**\n * 当前节点的父级对象。\n */\n parent: unknown | undefined;\n\n /**\n * 当前节点的键名路径。\n */\n keys: string[];\n\n /**\n * 当前节点的键名。\n */\n key: string | undefined;\n\n /**\n * 当前节点的键值。\n */\n value: V;\n};\n\n/**\n * 根据属性路径获取属性值\n * @param {O} obj\n * @param {string | string[] | P} path\n * @returns {ObjectNode<O>}\n * 根据属性路径获取属性值。\n *\n * @template O - 目标对象的类型。\n * @template P - 属性路径的类型。\n * @param {O} obj - 要操作的目标对象。\n * @param {P | string | string[]} path - 属性路径,可以是字符串或字符串数组。支持点分隔符(如 \"a.b.c\")或数组形式(如 [\"a\", \"b\", \"c\"])。\n * @returns {ObjectNode<O>} 返回一个包含父级、键名路径、键名和键值的对象节点。\n *\n * @example\n * ```typescript\n * const obj = { a: { b: { c: 42 } } };\n * const result = objectGet(obj, 'a.b.c');\n * console.log(result.value); // 输出 42\n * ```\n */\nexport function objectGet<O extends AnyObject, P extends ObjectPath<O>>(\n obj: O,\n path: P | string | string[],\n): ObjectNode<O> {\n const keys = pathToKeys(path);\n const lastKey = keys.pop();\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用\n let parent: any = obj;\n const keysFinal: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n\n keysFinal.push(key);\n if (!isObjectOrArray(parent)) break;\n\n // @ts-expect-error\n parent = parent[key];\n }\n\n return {\n parent: parent,\n keys: keysFinal,\n key: lastKey,\n // @ts-expect-error\n value: isObjectOrArray(parent) && lastKey ? parent[lastKey] : undefined,\n };\n}\n\n// /**\n// * 根据路径获取对象叶子节点值\n// * @param {O} obj\n// * @param {P} path\n// * @returns {ObjectNode<O>}\n// */\n// export function objectLeaf<O extends AnyObject, P extends ObjectLeafPath<O>>(obj: O, path: P) {\n// return objectGet(obj, path);\n// }\n\n/**\n * 配置选项,用于控制 `objectSet` 的行为。\n *\n * @template O - 目标对象的类型。\n */\nexport type ObjectSetOptions<O extends AnyObject> = {\n /**\n * 在设置值之前调用的钩子函数。\n * 如果返回 `false`,则阻止设置值。\n *\n * @param {ObjectNode<O> & { key: string }} node - 当前节点信息。\n * @returns {boolean | undefined | void} 返回 `false` 时阻止设置值。\n */\n beforeSet(node: ObjectNode<O> & { key: string }): boolean | undefined;\n\n /**\n * 当遇到未定义的中间节点时调用的钩子函数。\n * 返回值将用于创建中间节点。\n *\n * @param {ObjectNode<O>} node - 当前节点信息。\n * @returns {AnyObject | AnyArray | undefined | void} 返回值将用于创建中间节点。\n */\n undefinedSet(node: ObjectNode<O>): AnyObject | AnyArray | undefined;\n};\n\n// biome-ignore lint/suspicious/noExplicitAny: 内部使用 any\nconst defaultObjectSetOptions: ObjectSetOptions<any> = {\n beforeSet: () => true,\n undefinedSet: () => ({}),\n};\n\n/**\n * 根据属性路径设置属性值\n * @param {AnyObject} obj\n * @param {string} path\n * @param {V} val\n * @param {Partial<ObjectSetOptions<O>>} options\n * @returns {ObjectNode<O, V>}\n * 根据属性路径设置属性值。\n *\n * @template O - 目标对象的类型。\n * @template V - 要设置的值的类型。\n * @param {O} obj - 要操作的目标对象。\n * @param {string | string[]} path - 属性路径,可以是字符串或字符串数组。支持点分隔符(如 \"a.b.c\")或数组形式(如 [\"a\", \"b\", \"c\"])。\n * @param {V} val - 要设置的值。\n * @param {Partial<ObjectSetOptions<O>>} [options] - 可选配置项,用于控制设置行为。\n * @returns {ObjectNode<V>} 返回一个包含父级、键名路径、键名和键值的对象节点。\n *\n * @example\n * ```typescript\n * const obj = {};\n * objectSet(obj, 'a.b.c', 42);\n * console.log(obj); // 输出 { a: { b: { c: 42 } } }\n *\n * objectSet(obj, 'a.b.c', 100, {\n * beforeSet: (node) => node.key === 'c',\n * });\n * console.log(obj); // 输出 { a: { b: { c: 100 } } }\n * ```\n */\nexport function objectSet<O extends AnyObject, V>(\n obj: O,\n path: string | string[],\n val: V,\n options?: Partial<ObjectSetOptions<O>>,\n): ObjectNode<V> {\n const { beforeSet, undefinedSet } = Object.assign({}, defaultObjectSetOptions, options);\n const keys = pathToKeys(path);\n const lastKey = keys.pop();\n let parent = obj;\n let stopped = false;\n const keysFinal: string[] = [];\n\n for (const key of keys) {\n let val = parent[key];\n keysFinal.push(key);\n\n if (isUndefined(val)) {\n const seted = undefinedSet({\n parent: parent,\n keys: keysFinal,\n key: key,\n value: val,\n });\n\n if (!seted) {\n stopped = true;\n break;\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n val = parent[key] = seted;\n }\n\n // @ts-expect-error\n parent = val;\n }\n\n if (!stopped && !isUndefined(lastKey)) {\n keysFinal.push(lastKey);\n\n if (\n beforeSet({\n parent: parent,\n keys: keysFinal,\n key: lastKey,\n value: parent[lastKey],\n })\n ) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n parent[lastKey] = val;\n }\n }\n\n return {\n keys: keysFinal,\n parent: parent,\n key: lastKey,\n value: val,\n };\n}\n","import type { AnyObject } from '@/types';\n\n/**\n * 检查一个对象是否为空对象(不包含任何自有属性,包括符号属性)。\n *\n * @param obj - 要检查的对象\n * @returns 如果对象没有自有属性(包括符号属性)则返回 true,否则返回 false\n *\n * @example\n * ```typescript\n * isEmptyObject({}); // true\n * isEmptyObject({ a: 1 }); // false\n * isEmptyObject(Object.create(null)); // true\n * isEmptyObject({ [Symbol('key')]: 'value' }); // false\n * ```\n */\nexport function isEmptyObject(obj: AnyObject): boolean {\n return Object.getOwnPropertyNames(obj).length === 0 && Object.getOwnPropertySymbols(obj).length === 0;\n}\n\n/**\n * 检查一个对象是否为纯对象(通过对象字面量或Object构造函数创建,而非其他构造函数的实例)。\n *\n * @param obj - 要检查的对象\n * @returns 如果是纯对象则返回 true,否则返回 false\n *\n * @example\n * ```typescript\n * isPlainObject({}); // true\n * isPlainObject(Object.create(null)); // true\n * isPlainObject(new Date()); // false\n * isPlainObject([]); // false\n * isPlainObject(() => {}); // false\n * ```\n */\nexport function isPlainObject(obj: AnyObject): boolean {\n const proto: unknown = Object.getPrototypeOf(obj);\n\n // 对象无原型\n if (!proto) return true;\n\n // 是否对象直接实例\n return proto === Object.prototype;\n}\n\n// 移除,原因是,定义对象尽可能的使用 type 关键字即可避开此问题\n// /**\n// * 精确对象,常用于联合类型判断\n// * 相关 bug:https://l.ydr.me/Zp88vFKc\n// */\n// // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n// export type ExactObject<T = any> = T extends AnyFunction\n// ? never\n// : T extends AnyArray\n// ? never\n// : T extends object\n// ? T\n// : never;\n//\n// /**\n// * 检查值是否为精确接口对象\n// * @param object - 传入对象,必须是一个对象与其他类型的联合\n// * @returns 如果值为对象则返回 true,否则返回 false\n// * @example\n// * ```typescript\n// * type Id = string | string[] | (() => string);\n// *\n// * interface Cache {\n// * id?: Id;\n// * }\n// *\n// * type Share = {\n// * id?: Id;\n// * }\n// *\n// * interface Options {\n// * cache?: Id | Cache;\n// * share?: Id | Share;\n// * }\n// *\n// * function test(options: Options) {\n// * // string | string[] | (() => string) | Cache | undefined\n// * const cache = options.cache;\n// *\n// * // Cache\n// * // 需要使用\n// * if (isExactObject(cache)) {\n// * cache.id;\n// * }\n// * // string[]\n// * else if (isArray(cache)) {\n// * cache.push();\n// * }\n// * // string\n// * else if (isString(cache)) {\n// * cache.charCodeAt(0);\n// * }\n// * // (() => string) | undefined\n// * else {\n// * cache?.();\n// * }\n// *\n// * // string | string[] | (() => string) | Share | undefined\n// * const share = options.share;\n// *\n// * // Share\n// * if (isObject(share)) {\n// * share.id;\n// * }\n// * // string[]\n// * else if (isArray(share)) {\n// * share.push();\n// * }\n// * // string\n// * else if (isString(share)) {\n// * share.charCodeAt(0);\n// * }\n// * // (() => string) | undefined\n// * else {\n// * share?.();\n// * }\n// * }\n// * ```\n// */\n// export function isExactObject<T>(object: T): object is ExactObject<T> {\n// return typeIs(object) === 'object';\n// }\n","import { isArray, isObject, typeIs } from '@/type';\nimport type { AnyArray, AnyObject } from '@/types';\nimport { objectEach } from './each';\n\nexport type ObjectMergeRule = {\n /**\n * 处理冲突\n * @param target - 目标对象\n * @param source - 源对象\n * @param key - 键名\n * @returns 返回 true 表示继续处理,否则返回 false\n */\n next: (info: { target: AnyObject | AnyArray; source: AnyObject | AnyArray; key: string | number }) => boolean;\n\n /**\n * 处理赋值\n * @param target - 目标对象\n * @param source - 源对象\n * @param key - 键名\n * @returns 返回处理后的值\n */\n assign: (info: {\n target: AnyObject | AnyArray;\n source: AnyObject | AnyArray;\n key: string | number;\n merge: () => unknown;\n }) => unknown;\n};\n\nfunction _objectMerge(mergeRule: ObjectMergeRule, target: AnyObject | AnyArray, ...sources: (AnyObject | AnyArray)[]) {\n const seen = new WeakMap<AnyObject | AnyArray, AnyObject | AnyArray>();\n const { assign, next } = mergeRule;\n const align = (target: AnyObject | AnyArray, source: AnyObject | AnyArray) => {\n const targetType = typeIs(target);\n const sourceType = typeIs(source);\n\n if (targetType === sourceType) {\n return target;\n }\n\n return sourceType === 'array' ? [] : {};\n };\n const each = (\n source: AnyObject | AnyArray,\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用 any\n iterator: (val: any, key: string | number) => void,\n ) => {\n if (isObject(source)) {\n objectEach(source, iterator);\n } else {\n source.forEach(iterator);\n }\n };\n\n const merge = (target: AnyObject | AnyArray, source: AnyObject | AnyArray): AnyObject | AnyArray => {\n // 如果循环引用了,则直接返回目标对象\n if (seen.has(source)) {\n // biome-ignore lint/style/noNonNullAssertion: 必须存在\n return seen.get(source)!;\n }\n\n // 对齐目标对象和源对象\n const merged = align(target, source);\n\n // 存储循环引用\n seen.set(source, merged);\n\n // 遍历源对象\n each(source, (value, key) => {\n if (!next({ target: merged, source, key })) {\n return;\n }\n\n if (isObject(value) || isArray(value)) {\n // @ts-expect-error\n merged[key] = assign({\n target: merged,\n source,\n key,\n // @ts-expect-error\n merge: () => merge(merged[key], value),\n });\n } else {\n // @ts-expect-error\n merged[key] = assign({\n target: merged,\n source,\n key,\n merge: () => value,\n });\n }\n });\n\n return merged;\n };\n\n let returnTarget = target;\n\n for (const source of sources) {\n returnTarget = merge(target, source);\n }\n\n return returnTarget;\n}\n\n/**\n * 合并多个对象或数组。如果遇到循环引用,则直接返回目标对象。\n *\n * @param target - 目标对象或数组。\n * @param sources - 要合并的源对象或数组。\n * @returns 合并后的对象或数组。\n *\n * @example\n * ```typescript\n * const obj1 = { a: 1, b: { x: 10 } };\n * const obj2 = { b: { y: 20 }, c: 3 };\n * const merged = objectMerge(obj1, obj2);\n * console.log(merged); // { a: 1, b: { x: 10, y: 20 }, c: 3 }\n * ```\n */\nexport function objectMerge(target: AnyObject | AnyArray, ...sources: (AnyObject | AnyArray)[]) {\n return _objectMerge(\n {\n next() {\n return true;\n },\n assign({ merge }) {\n return merge();\n },\n },\n target,\n ...sources,\n );\n}\n\n/**\n * 为对象设置默认值。如果目标对象中的属性为 `undefined`,则使用默认对象中的属性值。\n * 支持多个默认对象,优先级从左到右依次降低。\n * 如果目标对象中的属性已经是对象或数组,则递归地设置默认值。\n *\n * @param target - 目标对象或数组。\n * @param defaults - 默认对象或数组。\n * @returns 合并后的对象或数组。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: undefined };\n * const defaults = { a: 4, b: 2, c: 3 };\n * const result = objectDefaults(obj, defaults);\n * console.log(result); // { a: 1, b: 2, c: 3 }\n *\n * const obj2 = { a: 1, b: 2 };\n * const defaults2 = { a: 5, b: 3, c: 4 };\n * const result2 = objectDefaults(obj2, defaults2);\n * console.log(result2); // { a: 1, b: 2, c: 4 }\n *\n * const obj3 = { a: { x: 1 }, b: undefined };\n * const defaults3 = { a: { x: 4, z: 3 }, b: { y: 2 } };\n * const result3 = objectDefaults(obj3, defaults3);\n * console.log(result3); // { a: { x: 1, z: 3 }, b: { y: 2 } }\n * ```\n */\nexport function objectDefaults<T extends AnyObject | AnyArray>(target: T, defaults: T): T {\n return _objectMerge(\n {\n next({ target, key }) {\n return (\n // @ts-expect-error\n target[key] === undefined ||\n // @ts-expect-error\n isObject(target[key]) ||\n // @ts-expect-error\n isArray(target[key])\n );\n },\n assign({ merge }) {\n return merge();\n },\n },\n target,\n defaults,\n ) as T;\n}\n","import type { AnyObject } from '@/types';\n\n/**\n * 从对象中选择指定键的属性,返回一个新的对象。\n *\n * @param object - 要从中选择属性的对象。\n * @param keys - 要选择的键数组。\n * @returns 包含指定键属性的新对象。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const result = objectPick(obj, ['a', 'c']);\n * console.log(result); // { a: 1, c: 3 }\n * ```\n */\nexport function objectPick<T extends AnyObject, K extends keyof T>(object: T, keys: K[]): Pick<T, K> {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in object) {\n result[key] = object[key];\n }\n }\n return result;\n}\n\n/**\n * 从对象中排除指定键的属性,返回一个新的对象。\n *\n * @param object - 要从中排除属性的对象。\n * @param keys - 要排除的键数组。\n * @returns 排除指定键属性后的新对象。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3, d: 4 };\n * const result = objectOmit(obj, ['a', 'd']);\n * console.log(result); // { b: 2, c: 3 }\n * ```\n */\nexport function objectOmit<T extends AnyObject, K extends keyof T>(object: T, keys: K[]): Omit<T, K> {\n const result = {} as Omit<T, K>;\n for (const key in object) {\n if (!keys.includes(key as unknown as K)) {\n // @ts-expect-error\n result[key] = object[key];\n }\n }\n return result;\n}\n\n/**\n * 遍历对象的每个键值对,并对每个键值对执行提供的映射函数,返回一个新的对象。\n *\n * @param object - 要遍历的对象。\n * @param mapper - 对每个键值对执行的映射函数。\n * @returns 返回一个新的对象,其中每个值都是通过映射函数处理后的结果。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const result = objectMap(obj, (val, key) => String(val * 2));\n * console.log(result); // { a: '2', b: '4', c: '6' }\n * ```\n */\nexport function objectMap<T extends AnyObject, V>(\n object: T,\n mapper: (value: T[keyof T], key: keyof T) => V,\n): Record<keyof T, V> {\n return Object.fromEntries(\n Object.entries(object).map(([key, value]) => [\n key,\n mapper(\n // @ts-expect-error\n value,\n key as keyof T,\n ),\n ]),\n ) as Record<keyof T, V>;\n}\n\n/**\n * 根据提供的过滤函数过滤对象的属性,返回一个新对象,只包含满足条件的属性。\n *\n * @param object - 要过滤的对象。\n * @param predicate - 过滤函数,接收值和键作为参数,返回布尔值。\n * @returns 包含满足过滤条件的属性的新对象。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3, d: 4 };\n * const result = objectFilter(obj, (value, key) => value > 2);\n * console.log(result); // { c: 3, d: 4 }\n * ```\n */\nexport function objectFilter<T extends AnyObject>(\n object: T,\n predicate: (value: T[keyof T], key: keyof T) => boolean,\n): Partial<T> {\n return Object.fromEntries(\n Object.entries(object).filter(([key, value]) => predicate(value as T[keyof T], key as keyof T)),\n ) as Partial<T>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"object.mjs","names":[],"sources":["../src/object/each.ts","../src/object/get-set.ts","../src/object/is.ts","../src/object/merge.ts","../src/object/process.ts"],"sourcesContent":["import type { AnyObject, MaybePromise } from '@/types';\n\n/**\n * 遍历对象的每个键值对,并对每个键值对执行提供的回调函数。\n *\n * @param obj - 要遍历的对象。\n * @param iterator - 对每个键值对执行的回调函数。如果回调函数返回 false,则提前终止遍历。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const results: [string, number][] = [];\n * objectEach(obj, (val, key) => {\n * results.push([key, val]);\n * });\n * console.log(results); // [['a', 1], ['b', 2], ['c', 3]]\n * ```\n */\nexport function objectEach<O extends AnyObject, K extends keyof O & (string | number)>(\n obj: O,\n iterator: (this: O, val: O[K], key: K) => false | unknown,\n): void {\n for (const [key, val] of Object.entries(obj)) {\n if (iterator.call(obj, val as O[K], key as K) === false) {\n break;\n }\n }\n}\n\n/**\n * 异步遍历对象的每个键值对,并对每个键值对执行提供的回调函数。\n *\n * @param obj - 要遍历的对象。\n * @param iterator - 对每个键值对执行的异步回调函数。如果回调函数返回 false,则提前终止遍历。\n * @returns 返回一个 Promise,当所有异步操作完成后,Promise 会被 resolve。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const results: [string, number][] = [];\n * await objectEachAsync(obj, async (val, key) => {\n * results.push([key, val]);\n * });\n * console.log(results); // [['a', 1], ['b', 2], ['c', 3]]\n * ```\n */\nexport async function objectEachAsync<O extends AnyObject, K extends keyof O & (string | number)>(\n obj: O,\n iterator: (this: O, val: O[K], key: K) => MaybePromise<false | unknown>,\n): Promise<void> {\n for (const [key, val] of Object.entries(obj)) {\n if ((await iterator.call(obj, val as O[K], key as K)) === false) {\n break;\n }\n }\n}\n","import { isArray, isObject, isUndefined } from '@/type';\nimport type { AnyArray, AnyObject } from '@/types';\n\n// @ref https://stackoverflow.com/a/67609485\n\ntype Idx<T, K> = K extends keyof T\n ? T[K]\n : number extends keyof T\n ? K extends `${number}`\n ? T[number]\n : never\n : never;\n\ntype Join<K, P> = K extends string | number\n ? P extends string | number\n ? `${K}${'' extends P ? '' : '.'}${P}`\n : never\n : never;\n\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]];\n\nexport type ObjectPath<O, D extends number = 4> = [D] extends [never]\n ? never\n : O extends object\n ? {\n [K in keyof O]-?: K extends string | number ? `${K}` | Join<K, ObjectPath<O[K], Prev[D]>> : never;\n }[keyof O]\n : '';\n\nexport type ObjectLeafPath<O, D extends number = 4> = [D] extends [never]\n ? never\n : O extends object\n ? {\n [K in keyof O]-?: K extends string | number\n ? O[K] extends string | number\n ? `${K}` | Join<K, ObjectLeafPath<O[K], Prev[D]>>\n : Join<K, ObjectLeafPath<O[K], Prev[D]>>\n : never;\n }[keyof O]\n : '';\n\nexport type ObjectPathValue<O, P extends ObjectPath<O, 4>> = P extends `${infer Key}.${infer Rest}`\n ? Rest extends ObjectPath<Idx<O, Key>, 4>\n ? ObjectPathValue<Idx<O, Key>, Rest>\n : never\n : Idx<O, P>;\n\nfunction pathToKeys(path: string | string[]) {\n // 下文用到该数组时会进行修改操作,因此复制一份\n if (isArray(path)) return [...path];\n\n let pathFinal = path.replace(/\\[(\\w+)\\]/g, '.$1');\n pathFinal = pathFinal.replace(/^\\./, '');\n return pathFinal.split('.');\n}\n\nfunction isObjectOrArray(v: unknown) {\n return isObject(v) || isArray(v);\n}\n\n/**\n * 表示对象节点的信息。\n *\n * @template V - 键值的类型。\n */\nexport type ObjectNode<V = unknown | undefined> = {\n /**\n * 当前节点的父级对象。\n */\n parent: unknown | undefined;\n\n /**\n * 当前节点的键名路径。\n */\n keys: string[];\n\n /**\n * 当前节点的键名。\n */\n key: string | undefined;\n\n /**\n * 当前节点的键值。\n */\n value: V;\n};\n\n/**\n * 根据属性路径获取属性值\n * @param {O} obj\n * @param {string | string[] | P} path\n * @returns {ObjectNode<O>}\n * 根据属性路径获取属性值。\n *\n * @template O - 目标对象的类型。\n * @template P - 属性路径的类型。\n * @param {O} obj - 要操作的目标对象。\n * @param {P | string | string[]} path - 属性路径,可以是字符串或字符串数组。支持点分隔符(如 \"a.b.c\")或数组形式(如 [\"a\", \"b\", \"c\"])。\n * @returns {ObjectNode<O>} 返回一个包含父级、键名路径、键名和键值的对象节点。\n *\n * @example\n * ```typescript\n * const obj = { a: { b: { c: 42 } } };\n * const result = objectGet(obj, 'a.b.c');\n * console.log(result.value); // 输出 42\n * ```\n */\nexport function objectGet<O extends AnyObject, P extends ObjectPath<O>>(\n obj: O,\n path: P | string | string[],\n): ObjectNode<O> {\n const keys = pathToKeys(path);\n const lastKey = keys.pop();\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用\n let parent: any = obj;\n const keysFinal: string[] = [];\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n\n keysFinal.push(key);\n if (!isObjectOrArray(parent)) break;\n\n // @ts-expect-error\n parent = parent[key];\n }\n\n return {\n parent: parent,\n keys: keysFinal,\n key: lastKey,\n // @ts-expect-error\n value: isObjectOrArray(parent) && lastKey ? parent[lastKey] : undefined,\n };\n}\n\n// /**\n// * 根据路径获取对象叶子节点值\n// * @param {O} obj\n// * @param {P} path\n// * @returns {ObjectNode<O>}\n// */\n// export function objectLeaf<O extends AnyObject, P extends ObjectLeafPath<O>>(obj: O, path: P) {\n// return objectGet(obj, path);\n// }\n\n/**\n * 配置选项,用于控制 `objectSet` 的行为。\n *\n * @template O - 目标对象的类型。\n */\nexport type ObjectSetOptions<O extends AnyObject> = {\n /**\n * 在设置值之前调用的钩子函数。\n * 如果返回 `false`,则阻止设置值。\n *\n * @param {ObjectNode<O> & { key: string }} node - 当前节点信息。\n * @returns {boolean | undefined | void} 返回 `false` 时阻止设置值。\n */\n beforeSet(node: ObjectNode<O> & { key: string }): boolean | undefined;\n\n /**\n * 当遇到未定义的中间节点时调用的钩子函数。\n * 返回值将用于创建中间节点。\n *\n * @param {ObjectNode<O>} node - 当前节点信息。\n * @returns {AnyObject | AnyArray | undefined | void} 返回值将用于创建中间节点。\n */\n undefinedSet(node: ObjectNode<O>): AnyObject | AnyArray | undefined;\n};\n\n// biome-ignore lint/suspicious/noExplicitAny: 内部使用 any\nconst defaultObjectSetOptions: ObjectSetOptions<any> = {\n beforeSet: () => true,\n undefinedSet: () => ({}),\n};\n\n/**\n * 根据属性路径设置属性值\n * @param {AnyObject} obj\n * @param {string} path\n * @param {V} val\n * @param {Partial<ObjectSetOptions<O>>} options\n * @returns {ObjectNode<O, V>}\n * 根据属性路径设置属性值。\n *\n * @template O - 目标对象的类型。\n * @template V - 要设置的值的类型。\n * @param {O} obj - 要操作的目标对象。\n * @param {string | string[]} path - 属性路径,可以是字符串或字符串数组。支持点分隔符(如 \"a.b.c\")或数组形式(如 [\"a\", \"b\", \"c\"])。\n * @param {V} val - 要设置的值。\n * @param {Partial<ObjectSetOptions<O>>} [options] - 可选配置项,用于控制设置行为。\n * @returns {ObjectNode<V>} 返回一个包含父级、键名路径、键名和键值的对象节点。\n *\n * @example\n * ```typescript\n * const obj = {};\n * objectSet(obj, 'a.b.c', 42);\n * console.log(obj); // 输出 { a: { b: { c: 42 } } }\n *\n * objectSet(obj, 'a.b.c', 100, {\n * beforeSet: (node) => node.key === 'c',\n * });\n * console.log(obj); // 输出 { a: { b: { c: 100 } } }\n * ```\n */\nexport function objectSet<O extends AnyObject, V>(\n obj: O,\n path: string | string[],\n val: V,\n options?: Partial<ObjectSetOptions<O>>,\n): ObjectNode<V> {\n const { beforeSet, undefinedSet } = Object.assign({}, defaultObjectSetOptions, options);\n const keys = pathToKeys(path);\n const lastKey = keys.pop();\n let parent = obj;\n let stopped = false;\n const keysFinal: string[] = [];\n\n for (const key of keys) {\n let val = parent[key];\n keysFinal.push(key);\n\n if (isUndefined(val)) {\n const seted = undefinedSet({\n parent: parent,\n keys: keysFinal,\n key: key,\n value: val,\n });\n\n if (!seted) {\n stopped = true;\n break;\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n val = parent[key] = seted;\n }\n\n // @ts-expect-error\n parent = val;\n }\n\n if (!stopped && !isUndefined(lastKey)) {\n keysFinal.push(lastKey);\n\n if (\n beforeSet({\n parent: parent,\n keys: keysFinal,\n key: lastKey,\n value: parent[lastKey],\n })\n ) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n parent[lastKey] = val;\n }\n }\n\n return {\n keys: keysFinal,\n parent: parent,\n key: lastKey,\n value: val,\n };\n}\n","import type { AnyObject } from '@/types';\n\n/**\n * 检查一个对象是否为空对象(不包含任何自有属性,包括符号属性)。\n *\n * @param obj - 要检查的对象\n * @returns 如果对象没有自有属性(包括符号属性)则返回 true,否则返回 false\n *\n * @example\n * ```typescript\n * isEmptyObject({}); // true\n * isEmptyObject({ a: 1 }); // false\n * isEmptyObject(Object.create(null)); // true\n * isEmptyObject({ [Symbol('key')]: 'value' }); // false\n * ```\n */\nexport function isEmptyObject(obj: AnyObject): boolean {\n return Object.getOwnPropertyNames(obj).length === 0 && Object.getOwnPropertySymbols(obj).length === 0;\n}\n\n/**\n * 检查一个对象是否为纯对象(通过对象字面量或Object构造函数创建,而非其他构造函数的实例)。\n *\n * @param obj - 要检查的对象\n * @returns 如果是纯对象则返回 true,否则返回 false\n *\n * @example\n * ```typescript\n * isPlainObject({}); // true\n * isPlainObject(Object.create(null)); // true\n * isPlainObject(new Date()); // false\n * isPlainObject([]); // false\n * isPlainObject(() => {}); // false\n * ```\n */\nexport function isPlainObject(obj: AnyObject): boolean {\n const proto: unknown = Object.getPrototypeOf(obj);\n\n // 对象无原型\n if (!proto) return true;\n\n // 是否对象直接实例\n return proto === Object.prototype;\n}\n\n// 移除,原因是,定义对象尽可能的使用 type 关键字即可避开此问题\n// /**\n// * 精确对象,常用于联合类型判断\n// * 相关 bug:https://l.ydr.me/Zp88vFKc\n// */\n// // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n// export type ExactObject<T = any> = T extends AnyFunction\n// ? never\n// : T extends AnyArray\n// ? never\n// : T extends object\n// ? T\n// : never;\n//\n// /**\n// * 检查值是否为精确接口对象\n// * @param object - 传入对象,必须是一个对象与其他类型的联合\n// * @returns 如果值为对象则返回 true,否则返回 false\n// * @example\n// * ```typescript\n// * type Id = string | string[] | (() => string);\n// *\n// * interface Cache {\n// * id?: Id;\n// * }\n// *\n// * type Share = {\n// * id?: Id;\n// * }\n// *\n// * interface Options {\n// * cache?: Id | Cache;\n// * share?: Id | Share;\n// * }\n// *\n// * function test(options: Options) {\n// * // string | string[] | (() => string) | Cache | undefined\n// * const cache = options.cache;\n// *\n// * // Cache\n// * // 需要使用\n// * if (isExactObject(cache)) {\n// * cache.id;\n// * }\n// * // string[]\n// * else if (isArray(cache)) {\n// * cache.push();\n// * }\n// * // string\n// * else if (isString(cache)) {\n// * cache.charCodeAt(0);\n// * }\n// * // (() => string) | undefined\n// * else {\n// * cache?.();\n// * }\n// *\n// * // string | string[] | (() => string) | Share | undefined\n// * const share = options.share;\n// *\n// * // Share\n// * if (isObject(share)) {\n// * share.id;\n// * }\n// * // string[]\n// * else if (isArray(share)) {\n// * share.push();\n// * }\n// * // string\n// * else if (isString(share)) {\n// * share.charCodeAt(0);\n// * }\n// * // (() => string) | undefined\n// * else {\n// * share?.();\n// * }\n// * }\n// * ```\n// */\n// export function isExactObject<T>(object: T): object is ExactObject<T> {\n// return typeIs(object) === 'object';\n// }\n","import { isArray, isObject, typeIs } from '@/type';\nimport type { AnyArray, AnyObject } from '@/types';\nimport { objectEach } from './each';\n\nexport type ObjectMergeRule = {\n /**\n * 处理冲突\n * @param target - 目标对象\n * @param source - 源对象\n * @param key - 键名\n * @returns 返回 true 表示继续处理,否则返回 false\n */\n next: (info: { target: AnyObject | AnyArray; source: AnyObject | AnyArray; key: string | number }) => boolean;\n\n /**\n * 处理赋值\n * @param target - 目标对象\n * @param source - 源对象\n * @param key - 键名\n * @returns 返回处理后的值\n */\n assign: (info: {\n target: AnyObject | AnyArray;\n source: AnyObject | AnyArray;\n key: string | number;\n merge: () => unknown;\n }) => unknown;\n};\n\nfunction _objectMerge(mergeRule: ObjectMergeRule, target: AnyObject | AnyArray, ...sources: (AnyObject | AnyArray)[]) {\n const seen = new WeakMap<AnyObject | AnyArray, AnyObject | AnyArray>();\n const { assign, next } = mergeRule;\n const align = (target: AnyObject | AnyArray, source: AnyObject | AnyArray) => {\n const targetType = typeIs(target);\n const sourceType = typeIs(source);\n\n if (targetType === sourceType) {\n return target;\n }\n\n return sourceType === 'array' ? [] : {};\n };\n const each = (\n source: AnyObject | AnyArray,\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用 any\n iterator: (val: any, key: string | number) => void,\n ) => {\n if (isObject(source)) {\n objectEach(source, iterator);\n } else {\n source.forEach(iterator);\n }\n };\n\n const merge = (target: AnyObject | AnyArray, source: AnyObject | AnyArray): AnyObject | AnyArray => {\n // 如果循环引用了,则直接返回目标对象\n if (seen.has(source)) {\n // biome-ignore lint/style/noNonNullAssertion: 必须存在\n return seen.get(source)!;\n }\n\n // 对齐目标对象和源对象\n const merged = align(target, source);\n\n // 存储循环引用\n seen.set(source, merged);\n\n // 遍历源对象\n each(source, (value, key) => {\n if (!next({ target: merged, source, key })) {\n return;\n }\n\n if (isObject(value) || isArray(value)) {\n // @ts-expect-error\n merged[key] = assign({\n target: merged,\n source,\n key,\n // @ts-expect-error\n merge: () => merge(merged[key], value),\n });\n } else {\n // @ts-expect-error\n merged[key] = assign({\n target: merged,\n source,\n key,\n merge: () => value,\n });\n }\n });\n\n return merged;\n };\n\n let returnTarget = target;\n\n for (const source of sources) {\n returnTarget = merge(target, source);\n }\n\n return returnTarget;\n}\n\n/**\n * 合并多个对象或数组。如果遇到循环引用,则直接返回目标对象。\n *\n * @param target - 目标对象或数组。\n * @param sources - 要合并的源对象或数组。\n * @returns 合并后的对象或数组。\n *\n * @example\n * ```typescript\n * const obj1 = { a: 1, b: { x: 10 } };\n * const obj2 = { b: { y: 20 }, c: 3 };\n * const merged = objectMerge(obj1, obj2);\n * console.log(merged); // { a: 1, b: { x: 10, y: 20 }, c: 3 }\n * ```\n */\nexport function objectMerge(target: AnyObject | AnyArray, ...sources: (AnyObject | AnyArray)[]) {\n return _objectMerge(\n {\n next() {\n return true;\n },\n assign({ merge }) {\n return merge();\n },\n },\n target,\n ...sources,\n );\n}\n\n/**\n * 为对象设置默认值。如果目标对象中的属性为 `undefined`,则使用默认对象中的属性值。\n * 支持多个默认对象,优先级从左到右依次降低。\n * 如果目标对象中的属性已经是对象或数组,则递归地设置默认值。\n *\n * @param target - 目标对象或数组。\n * @param defaults - 默认对象或数组。\n * @returns 合并后的对象或数组。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: undefined };\n * const defaults = { a: 4, b: 2, c: 3 };\n * const result = objectDefaults(obj, defaults);\n * console.log(result); // { a: 1, b: 2, c: 3 }\n *\n * const obj2 = { a: 1, b: 2 };\n * const defaults2 = { a: 5, b: 3, c: 4 };\n * const result2 = objectDefaults(obj2, defaults2);\n * console.log(result2); // { a: 1, b: 2, c: 4 }\n *\n * const obj3 = { a: { x: 1 }, b: undefined };\n * const defaults3 = { a: { x: 4, z: 3 }, b: { y: 2 } };\n * const result3 = objectDefaults(obj3, defaults3);\n * console.log(result3); // { a: { x: 1, z: 3 }, b: { y: 2 } }\n * ```\n */\nexport function objectDefaults<T extends AnyObject | AnyArray>(target: T, defaults: T): T {\n return _objectMerge(\n {\n next({ target, key }) {\n return (\n // @ts-expect-error\n target[key] === undefined ||\n // @ts-expect-error\n isObject(target[key]) ||\n // @ts-expect-error\n isArray(target[key])\n );\n },\n assign({ merge }) {\n return merge();\n },\n },\n target,\n defaults,\n ) as T;\n}\n","import type { AnyObject } from '@/types';\n\n/**\n * 从对象中选择指定键的属性,返回一个新的对象。\n *\n * @param object - 要从中选择属性的对象。\n * @param keys - 要选择的键数组。\n * @returns 包含指定键属性的新对象。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const result = objectPick(obj, ['a', 'c']);\n * console.log(result); // { a: 1, c: 3 }\n * ```\n */\nexport function objectPick<T extends AnyObject, K extends keyof T>(object: T, keys: K[]): Pick<T, K> {\n const result = {} as Pick<T, K>;\n for (const key of keys) {\n if (key in object) {\n result[key] = object[key];\n }\n }\n return result;\n}\n\n/**\n * 从对象中排除指定键的属性,返回一个新的对象。\n *\n * @param object - 要从中排除属性的对象。\n * @param keys - 要排除的键数组。\n * @returns 排除指定键属性后的新对象。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3, d: 4 };\n * const result = objectOmit(obj, ['a', 'd']);\n * console.log(result); // { b: 2, c: 3 }\n * ```\n */\nexport function objectOmit<T extends AnyObject, K extends keyof T>(object: T, keys: K[]): Omit<T, K> {\n const result = {} as Omit<T, K>;\n for (const key in object) {\n if (!keys.includes(key as unknown as K)) {\n // @ts-expect-error\n result[key] = object[key];\n }\n }\n return result;\n}\n\n/**\n * 遍历对象的每个键值对,并对每个键值对执行提供的映射函数,返回一个新的对象。\n *\n * @param object - 要遍历的对象。\n * @param mapper - 对每个键值对执行的映射函数。\n * @returns 返回一个新的对象,其中每个值都是通过映射函数处理后的结果。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3 };\n * const result = objectMap(obj, (val, key) => String(val * 2));\n * console.log(result); // { a: '2', b: '4', c: '6' }\n * ```\n */\nexport function objectMap<T extends AnyObject, V>(\n object: T,\n mapper: (value: T[keyof T], key: keyof T) => V,\n): Record<keyof T, V> {\n return Object.fromEntries(\n Object.entries(object).map(([key, value]) => [\n key,\n mapper(\n // @ts-expect-error\n value,\n key as keyof T,\n ),\n ]),\n ) as Record<keyof T, V>;\n}\n\n/**\n * 根据提供的过滤函数过滤对象的属性,返回一个新对象,只包含满足条件的属性。\n *\n * @param object - 要过滤的对象。\n * @param predicate - 过滤函数,接收值和键作为参数,返回布尔值。\n * @returns 包含满足过滤条件的属性的新对象。\n *\n * @example\n * ```typescript\n * const obj = { a: 1, b: 2, c: 3, d: 4 };\n * const result = objectFilter(obj, (value, key) => value > 2);\n * console.log(result); // { c: 3, d: 4 }\n * ```\n */\nexport function objectFilter<T extends AnyObject>(\n object: T,\n predicate: (value: T[keyof T], key: keyof T) => boolean,\n): Partial<T> {\n return Object.fromEntries(\n Object.entries(object).filter(([key, value]) => predicate(value as T[keyof T], key as keyof T)),\n ) as Partial<T>;\n}\n"],"mappings":"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"}
package/dist/path.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"path.cjs","names":[],"sources":["../src/path.ts"],"sourcesContent":["import { arrayEach } from './array';\n\n/**\n * 判断是否是当前目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是当前目录标记'.'则返回true,否则返回false\n */\nfunction _isCurrentSlice(slice: string): boolean {\n return slice === '.';\n}\n\n/**\n * 判断是否是上级目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是上级目录标记'..'则返回true,否则返回false\n */\nfunction _isParentSlice(slice: string): boolean {\n return slice === '..';\n}\n\n/**\n * 判断是否是绝对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是绝对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isAbs = isAbsolutePath('/path/to/file');\n * console.log(isAbs); // 输出: true\n * ```\n */\nexport function isAbsolutePath(path: string): boolean {\n return path.startsWith('/');\n}\n\n/**\n * 判断是否是相对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是相对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isRel = isRelativePath('path/to/file');\n * console.log(isRel); // 输出: true\n * ```\n */\nexport function isRelativePath(path: string): boolean {\n return !isAbsolutePath(path);\n}\n\n/**\n * 标准化路径\n * @param {string} path - 要标准化的路径字符串。\n * @returns {string} - 标准化后的路径字符串。\n * @example\n * ```typescript\n * const normalizedPath = pathNormalize('/path///to///file');\n * console.log(normalizedPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathNormalize(path: string): string {\n const slices = path\n .replace(/\\\\/g, '/')\n .replace(/\\/{2,}/g, '/')\n .replace(/\\.{3,}/g, '..')\n .replace(/\\/\\.\\//g, '/')\n .split('/')\n .map((point) => point.trim());\n const points: string[] = [];\n const isAbs = slices[0] === '';\n\n const push = (point: string) => {\n points.push(point);\n };\n\n const back = () => {\n // 绝对路径不能退到根目录\n if (points.length === 1 && isAbs) return;\n\n //\n if (points.length === 0 || points.at(-1) === '..') {\n points.push('..');\n } else {\n points.pop();\n }\n };\n\n for (const slice of slices) {\n const isCurrent = _isCurrentSlice(slice);\n const isParent = _isParentSlice(slice);\n\n // // 未进入实际路径\n // if (!inPoints) {\n // push(slice);\n // inPoints = !isCurrent && !isParent;\n // continue;\n // }\n\n if (isCurrent) {\n continue;\n }\n\n if (isParent) {\n back();\n continue;\n }\n\n push(slice);\n }\n\n return points.join('/') || (isAbs ? '/' : '.');\n}\n\n/**\n * 路径合并\n * @param {string} from - 起始路径。\n * @param {...string[]} to - 要合并的路径片段。\n * @returns {string} - 合并后的路径字符串。\n * @example\n * ```typescript\n * const fullPath = pathJoin('/path', '/to', 'file');\n * console.log(fullPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathJoin(from: string, ...to: string[]): string {\n return pathNormalize([from, ...to].join('/'));\n}\n\n/**\n * 解析路径\n * @param {string} from - 起始路径\n * @param {...string[]} to - 要解析的路径片段\n * @returns {string} - 解析后的绝对路径\n * @example\n * ```typescript\n * const resolvedPath = pathResolve('/path', '/to', 'file');\n * console.log(resolvedPath); // 输出: '/to/file'\n * ```\n */\nexport function pathResolve(from: string, ...to: string[]): string {\n const paths = [from, ...to].map(pathNormalize);\n\n let lastStartPath = from;\n let lastStartIndex = 0;\n\n arrayEach(\n paths,\n (path, index) => {\n if (isAbsolutePath(path)) {\n lastStartPath = path;\n lastStartIndex = index;\n return false;\n }\n },\n true,\n );\n\n return pathJoin(lastStartPath, ...paths.slice(lastStartIndex + 1));\n}\n\n/**\n * 将相对路径转换为标准的相对路径格式(添加'./'前缀)\n *\n * @param {string} path - 要处理的路径字符串\n * @returns {string} 处理后的路径字符串\n *\n * @example <caption>处理绝对路径</caption>\n * ```typescript\n * const result = pathRelativize('/path/to/file');\n * console.log(result); // 输出: '/path/to/file'\n * ```\n *\n * @example <caption>处理已带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('./path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n *\n * @example <caption>处理不带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n */\nexport function pathRelativize(path: string): string {\n if (isAbsolutePath(path)) return path;\n if (path.startsWith('./')) return path;\n if (path.startsWith('../')) return path;\n return `./${path}`;\n}\n\n/**\n * 获取路径的目录部分\n * @param {string} path - 输入的路径字符串\n * @returns {string} - 返回路径的目录部分\n * @example\n * ```typescript\n * const dir = pathDirname('/path/to/file.txt');\n * console.log(dir); // 输出: '/path/to'\n * ```\n */\nexport function pathDirname(path: string): string {\n return pathJoin(path, '..');\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,gBAAgB,OAAwB;CAC/C,OAAO,UAAU;;;;;;;AAQnB,SAAS,eAAe,OAAwB;CAC9C,OAAO,UAAU;;;;;;;;;;;;AAanB,SAAgB,eAAe,MAAuB;CACpD,OAAO,KAAK,WAAW,IAAI;;;;;;;;;;;;AAa7B,SAAgB,eAAe,MAAuB;CACpD,OAAO,CAAC,eAAe,KAAK;;;;;;;;;;;;AAa9B,SAAgB,cAAc,MAAsB;CAClD,MAAM,SAAS,KACZ,QAAQ,OAAO,IAAI,CACnB,QAAQ,WAAW,IAAI,CACvB,QAAQ,WAAW,KAAK,CACxB,QAAQ,WAAW,IAAI,CACvB,MAAM,IAAI,CACV,KAAK,UAAU,MAAM,MAAM,CAAC;CAC/B,MAAM,SAAmB,EAAE;CAC3B,MAAM,QAAQ,OAAO,OAAO;CAE5B,MAAM,QAAQ,UAAkB;EAC9B,OAAO,KAAK,MAAM;;CAGpB,MAAM,aAAa;EAEjB,IAAI,OAAO,WAAW,KAAK,OAAO;EAGlC,IAAI,OAAO,WAAW,KAAK,OAAO,GAAG,GAAG,KAAK,MAC3C,OAAO,KAAK,KAAK;OAEjB,OAAO,KAAK;;CAIhB,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,YAAY,gBAAgB,MAAM;EACxC,MAAM,WAAW,eAAe,MAAM;EAStC,IAAI,WACF;EAGF,IAAI,UAAU;GACZ,MAAM;GACN;;EAGF,KAAK,MAAM;;CAGb,OAAO,OAAO,KAAK,IAAI,KAAK,QAAQ,MAAM;;;;;;;;;;;;;AAc5C,SAAgB,SAAS,MAAc,GAAG,IAAsB;CAC9D,OAAO,cAAc,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,CAAC;;;;;;;;;;;;;AAc/C,SAAgB,YAAY,MAAc,GAAG,IAAsB;CACjE,MAAM,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,cAAc;CAE9C,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;CAErB,cAAA,UACE,QACC,MAAM,UAAU;EACf,IAAI,eAAe,KAAK,EAAE;GACxB,gBAAgB;GAChB,iBAAiB;GACjB,OAAO;;IAGX,KACD;CAED,OAAO,SAAS,eAAe,GAAG,MAAM,MAAM,iBAAiB,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BpE,SAAgB,eAAe,MAAsB;CACnD,IAAI,eAAe,KAAK,EAAE,OAAO;CACjC,IAAI,KAAK,WAAW,KAAK,EAAE,OAAO;CAClC,IAAI,KAAK,WAAW,MAAM,EAAE,OAAO;CACnC,OAAO,KAAK;;;;;;;;;;;;AAad,SAAgB,YAAY,MAAsB;CAChD,OAAO,SAAS,MAAM,KAAK"}
1
+ {"version":3,"file":"path.cjs","names":[],"sources":["../src/path.ts"],"sourcesContent":["import { arrayEach } from './array';\n\n/**\n * 判断是否是当前目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是当前目录标记'.'则返回true,否则返回false\n */\nfunction _isCurrentSlice(slice: string): boolean {\n return slice === '.';\n}\n\n/**\n * 判断是否是上级目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是上级目录标记'..'则返回true,否则返回false\n */\nfunction _isParentSlice(slice: string): boolean {\n return slice === '..';\n}\n\n/**\n * 判断是否是绝对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是绝对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isAbs = isAbsolutePath('/path/to/file');\n * console.log(isAbs); // 输出: true\n * ```\n */\nexport function isAbsolutePath(path: string): boolean {\n return path.startsWith('/');\n}\n\n/**\n * 判断是否是相对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是相对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isRel = isRelativePath('path/to/file');\n * console.log(isRel); // 输出: true\n * ```\n */\nexport function isRelativePath(path: string): boolean {\n return !isAbsolutePath(path);\n}\n\n/**\n * 标准化路径\n * @param {string} path - 要标准化的路径字符串。\n * @returns {string} - 标准化后的路径字符串。\n * @example\n * ```typescript\n * const normalizedPath = pathNormalize('/path///to///file');\n * console.log(normalizedPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathNormalize(path: string): string {\n const slices = path\n .replace(/\\\\/g, '/')\n .replace(/\\/{2,}/g, '/')\n .replace(/\\.{3,}/g, '..')\n .replace(/\\/\\.\\//g, '/')\n .split('/')\n .map((point) => point.trim());\n const points: string[] = [];\n const isAbs = slices[0] === '';\n\n const push = (point: string) => {\n points.push(point);\n };\n\n const back = () => {\n // 绝对路径不能退到根目录\n if (points.length === 1 && isAbs) return;\n\n //\n if (points.length === 0 || points.at(-1) === '..') {\n points.push('..');\n } else {\n points.pop();\n }\n };\n\n for (const slice of slices) {\n const isCurrent = _isCurrentSlice(slice);\n const isParent = _isParentSlice(slice);\n\n // // 未进入实际路径\n // if (!inPoints) {\n // push(slice);\n // inPoints = !isCurrent && !isParent;\n // continue;\n // }\n\n if (isCurrent) {\n continue;\n }\n\n if (isParent) {\n back();\n continue;\n }\n\n push(slice);\n }\n\n return points.join('/') || (isAbs ? '/' : '.');\n}\n\n/**\n * 路径合并\n * @param {string} from - 起始路径。\n * @param {...string[]} to - 要合并的路径片段。\n * @returns {string} - 合并后的路径字符串。\n * @example\n * ```typescript\n * const fullPath = pathJoin('/path', '/to', 'file');\n * console.log(fullPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathJoin(from: string, ...to: string[]): string {\n return pathNormalize([from, ...to].join('/'));\n}\n\n/**\n * 解析路径\n * @param {string} from - 起始路径\n * @param {...string[]} to - 要解析的路径片段\n * @returns {string} - 解析后的绝对路径\n * @example\n * ```typescript\n * const resolvedPath = pathResolve('/path', '/to', 'file');\n * console.log(resolvedPath); // 输出: '/to/file'\n * ```\n */\nexport function pathResolve(from: string, ...to: string[]): string {\n const paths = [from, ...to].map(pathNormalize);\n\n let lastStartPath = from;\n let lastStartIndex = 0;\n\n arrayEach(\n paths,\n (path, index) => {\n if (isAbsolutePath(path)) {\n lastStartPath = path;\n lastStartIndex = index;\n return false;\n }\n },\n true,\n );\n\n return pathJoin(lastStartPath, ...paths.slice(lastStartIndex + 1));\n}\n\n/**\n * 将相对路径转换为标准的相对路径格式(添加'./'前缀)\n *\n * @param {string} path - 要处理的路径字符串\n * @returns {string} 处理后的路径字符串\n *\n * @example <caption>处理绝对路径</caption>\n * ```typescript\n * const result = pathRelativize('/path/to/file');\n * console.log(result); // 输出: '/path/to/file'\n * ```\n *\n * @example <caption>处理已带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('./path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n *\n * @example <caption>处理不带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n */\nexport function pathRelativize(path: string): string {\n if (isAbsolutePath(path)) return path;\n if (path.startsWith('./')) return path;\n if (path.startsWith('../')) return path;\n return `./${path}`;\n}\n\n/**\n * 获取路径的目录部分\n * @param {string} path - 输入的路径字符串\n * @returns {string} - 返回路径的目录部分\n * @example\n * ```typescript\n * const dir = pathDirname('/path/to/file.txt');\n * console.log(dir); // 输出: '/path/to'\n * ```\n */\nexport function pathDirname(path: string): string {\n return pathJoin(path, '..');\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,gBAAgB,OAAwB;CAC/C,OAAO,UAAU;AACnB;;;;;;AAOA,SAAS,eAAe,OAAwB;CAC9C,OAAO,UAAU;AACnB;;;;;;;;;;;AAYA,SAAgB,eAAe,MAAuB;CACpD,OAAO,KAAK,WAAW,GAAG;AAC5B;;;;;;;;;;;AAYA,SAAgB,eAAe,MAAuB;CACpD,OAAO,CAAC,eAAe,IAAI;AAC7B;;;;;;;;;;;AAYA,SAAgB,cAAc,MAAsB;CAClD,MAAM,SAAS,KACZ,QAAQ,OAAO,GAAG,EAClB,QAAQ,WAAW,GAAG,EACtB,QAAQ,WAAW,IAAI,EACvB,QAAQ,WAAW,GAAG,EACtB,MAAM,GAAG,EACT,KAAK,UAAU,MAAM,KAAK,CAAC;CAC9B,MAAM,SAAmB,CAAC;CAC1B,MAAM,QAAQ,OAAO,OAAO;CAE5B,MAAM,QAAQ,UAAkB;EAC9B,OAAO,KAAK,KAAK;CACnB;CAEA,MAAM,aAAa;EAEjB,IAAI,OAAO,WAAW,KAAK,OAAO;EAGlC,IAAI,OAAO,WAAW,KAAK,OAAO,GAAG,EAAE,MAAM,MAC3C,OAAO,KAAK,IAAI;OAEhB,OAAO,IAAI;CAEf;CAEA,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,YAAY,gBAAgB,KAAK;EACvC,MAAM,WAAW,eAAe,KAAK;EASrC,IAAI,WACF;EAGF,IAAI,UAAU;GACZ,KAAK;GACL;EACF;EAEA,KAAK,KAAK;CACZ;CAEA,OAAO,OAAO,KAAK,GAAG,MAAM,QAAQ,MAAM;AAC5C;;;;;;;;;;;;AAaA,SAAgB,SAAS,MAAc,GAAG,IAAsB;CAC9D,OAAO,cAAc,CAAC,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC;AAC9C;;;;;;;;;;;;AAaA,SAAgB,YAAY,MAAc,GAAG,IAAsB;CACjE,MAAM,QAAQ,CAAC,MAAM,GAAG,EAAE,EAAE,IAAI,aAAa;CAE7C,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;CAErB,cAAA,UACE,QACC,MAAM,UAAU;EACf,IAAI,eAAe,IAAI,GAAG;GACxB,gBAAgB;GAChB,iBAAiB;GACjB,OAAO;EACT;CACF,GACA,IACF;CAEA,OAAO,SAAS,eAAe,GAAG,MAAM,MAAM,iBAAiB,CAAC,CAAC;AACnE;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,eAAe,MAAsB;CACnD,IAAI,eAAe,IAAI,GAAG,OAAO;CACjC,IAAI,KAAK,WAAW,IAAI,GAAG,OAAO;CAClC,IAAI,KAAK,WAAW,KAAK,GAAG,OAAO;CACnC,OAAO,KAAK;AACd;;;;;;;;;;;AAYA,SAAgB,YAAY,MAAsB;CAChD,OAAO,SAAS,MAAM,IAAI;AAC5B"}
package/dist/path.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"path.mjs","names":[],"sources":["../src/path.ts"],"sourcesContent":["import { arrayEach } from './array';\n\n/**\n * 判断是否是当前目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是当前目录标记'.'则返回true,否则返回false\n */\nfunction _isCurrentSlice(slice: string): boolean {\n return slice === '.';\n}\n\n/**\n * 判断是否是上级目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是上级目录标记'..'则返回true,否则返回false\n */\nfunction _isParentSlice(slice: string): boolean {\n return slice === '..';\n}\n\n/**\n * 判断是否是绝对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是绝对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isAbs = isAbsolutePath('/path/to/file');\n * console.log(isAbs); // 输出: true\n * ```\n */\nexport function isAbsolutePath(path: string): boolean {\n return path.startsWith('/');\n}\n\n/**\n * 判断是否是相对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是相对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isRel = isRelativePath('path/to/file');\n * console.log(isRel); // 输出: true\n * ```\n */\nexport function isRelativePath(path: string): boolean {\n return !isAbsolutePath(path);\n}\n\n/**\n * 标准化路径\n * @param {string} path - 要标准化的路径字符串。\n * @returns {string} - 标准化后的路径字符串。\n * @example\n * ```typescript\n * const normalizedPath = pathNormalize('/path///to///file');\n * console.log(normalizedPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathNormalize(path: string): string {\n const slices = path\n .replace(/\\\\/g, '/')\n .replace(/\\/{2,}/g, '/')\n .replace(/\\.{3,}/g, '..')\n .replace(/\\/\\.\\//g, '/')\n .split('/')\n .map((point) => point.trim());\n const points: string[] = [];\n const isAbs = slices[0] === '';\n\n const push = (point: string) => {\n points.push(point);\n };\n\n const back = () => {\n // 绝对路径不能退到根目录\n if (points.length === 1 && isAbs) return;\n\n //\n if (points.length === 0 || points.at(-1) === '..') {\n points.push('..');\n } else {\n points.pop();\n }\n };\n\n for (const slice of slices) {\n const isCurrent = _isCurrentSlice(slice);\n const isParent = _isParentSlice(slice);\n\n // // 未进入实际路径\n // if (!inPoints) {\n // push(slice);\n // inPoints = !isCurrent && !isParent;\n // continue;\n // }\n\n if (isCurrent) {\n continue;\n }\n\n if (isParent) {\n back();\n continue;\n }\n\n push(slice);\n }\n\n return points.join('/') || (isAbs ? '/' : '.');\n}\n\n/**\n * 路径合并\n * @param {string} from - 起始路径。\n * @param {...string[]} to - 要合并的路径片段。\n * @returns {string} - 合并后的路径字符串。\n * @example\n * ```typescript\n * const fullPath = pathJoin('/path', '/to', 'file');\n * console.log(fullPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathJoin(from: string, ...to: string[]): string {\n return pathNormalize([from, ...to].join('/'));\n}\n\n/**\n * 解析路径\n * @param {string} from - 起始路径\n * @param {...string[]} to - 要解析的路径片段\n * @returns {string} - 解析后的绝对路径\n * @example\n * ```typescript\n * const resolvedPath = pathResolve('/path', '/to', 'file');\n * console.log(resolvedPath); // 输出: '/to/file'\n * ```\n */\nexport function pathResolve(from: string, ...to: string[]): string {\n const paths = [from, ...to].map(pathNormalize);\n\n let lastStartPath = from;\n let lastStartIndex = 0;\n\n arrayEach(\n paths,\n (path, index) => {\n if (isAbsolutePath(path)) {\n lastStartPath = path;\n lastStartIndex = index;\n return false;\n }\n },\n true,\n );\n\n return pathJoin(lastStartPath, ...paths.slice(lastStartIndex + 1));\n}\n\n/**\n * 将相对路径转换为标准的相对路径格式(添加'./'前缀)\n *\n * @param {string} path - 要处理的路径字符串\n * @returns {string} 处理后的路径字符串\n *\n * @example <caption>处理绝对路径</caption>\n * ```typescript\n * const result = pathRelativize('/path/to/file');\n * console.log(result); // 输出: '/path/to/file'\n * ```\n *\n * @example <caption>处理已带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('./path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n *\n * @example <caption>处理不带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n */\nexport function pathRelativize(path: string): string {\n if (isAbsolutePath(path)) return path;\n if (path.startsWith('./')) return path;\n if (path.startsWith('../')) return path;\n return `./${path}`;\n}\n\n/**\n * 获取路径的目录部分\n * @param {string} path - 输入的路径字符串\n * @returns {string} - 返回路径的目录部分\n * @example\n * ```typescript\n * const dir = pathDirname('/path/to/file.txt');\n * console.log(dir); // 输出: '/path/to'\n * ```\n */\nexport function pathDirname(path: string): string {\n return pathJoin(path, '..');\n}\n"],"mappings":";;;;;;;AAOA,SAAS,gBAAgB,OAAwB;CAC/C,OAAO,UAAU;;;;;;;AAQnB,SAAS,eAAe,OAAwB;CAC9C,OAAO,UAAU;;;;;;;;;;;;AAanB,SAAgB,eAAe,MAAuB;CACpD,OAAO,KAAK,WAAW,IAAI;;;;;;;;;;;;AAa7B,SAAgB,eAAe,MAAuB;CACpD,OAAO,CAAC,eAAe,KAAK;;;;;;;;;;;;AAa9B,SAAgB,cAAc,MAAsB;CAClD,MAAM,SAAS,KACZ,QAAQ,OAAO,IAAI,CACnB,QAAQ,WAAW,IAAI,CACvB,QAAQ,WAAW,KAAK,CACxB,QAAQ,WAAW,IAAI,CACvB,MAAM,IAAI,CACV,KAAK,UAAU,MAAM,MAAM,CAAC;CAC/B,MAAM,SAAmB,EAAE;CAC3B,MAAM,QAAQ,OAAO,OAAO;CAE5B,MAAM,QAAQ,UAAkB;EAC9B,OAAO,KAAK,MAAM;;CAGpB,MAAM,aAAa;EAEjB,IAAI,OAAO,WAAW,KAAK,OAAO;EAGlC,IAAI,OAAO,WAAW,KAAK,OAAO,GAAG,GAAG,KAAK,MAC3C,OAAO,KAAK,KAAK;OAEjB,OAAO,KAAK;;CAIhB,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,YAAY,gBAAgB,MAAM;EACxC,MAAM,WAAW,eAAe,MAAM;EAStC,IAAI,WACF;EAGF,IAAI,UAAU;GACZ,MAAM;GACN;;EAGF,KAAK,MAAM;;CAGb,OAAO,OAAO,KAAK,IAAI,KAAK,QAAQ,MAAM;;;;;;;;;;;;;AAc5C,SAAgB,SAAS,MAAc,GAAG,IAAsB;CAC9D,OAAO,cAAc,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,CAAC;;;;;;;;;;;;;AAc/C,SAAgB,YAAY,MAAc,GAAG,IAAsB;CACjE,MAAM,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,cAAc;CAE9C,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;CAErB,UACE,QACC,MAAM,UAAU;EACf,IAAI,eAAe,KAAK,EAAE;GACxB,gBAAgB;GAChB,iBAAiB;GACjB,OAAO;;IAGX,KACD;CAED,OAAO,SAAS,eAAe,GAAG,MAAM,MAAM,iBAAiB,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BpE,SAAgB,eAAe,MAAsB;CACnD,IAAI,eAAe,KAAK,EAAE,OAAO;CACjC,IAAI,KAAK,WAAW,KAAK,EAAE,OAAO;CAClC,IAAI,KAAK,WAAW,MAAM,EAAE,OAAO;CACnC,OAAO,KAAK;;;;;;;;;;;;AAad,SAAgB,YAAY,MAAsB;CAChD,OAAO,SAAS,MAAM,KAAK"}
1
+ {"version":3,"file":"path.mjs","names":[],"sources":["../src/path.ts"],"sourcesContent":["import { arrayEach } from './array';\n\n/**\n * 判断是否是当前目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是当前目录标记'.'则返回true,否则返回false\n */\nfunction _isCurrentSlice(slice: string): boolean {\n return slice === '.';\n}\n\n/**\n * 判断是否是上级目录标记\n * @param {string} slice - 路径片段\n * @returns {boolean} - 如果是上级目录标记'..'则返回true,否则返回false\n */\nfunction _isParentSlice(slice: string): boolean {\n return slice === '..';\n}\n\n/**\n * 判断是否是绝对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是绝对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isAbs = isAbsolutePath('/path/to/file');\n * console.log(isAbs); // 输出: true\n * ```\n */\nexport function isAbsolutePath(path: string): boolean {\n return path.startsWith('/');\n}\n\n/**\n * 判断是否是相对路径\n * @param {string} path - 路径字符串\n * @returns {boolean} - 如果是相对路径则返回true,否则返回false\n * @example\n * ```typescript\n * const isRel = isRelativePath('path/to/file');\n * console.log(isRel); // 输出: true\n * ```\n */\nexport function isRelativePath(path: string): boolean {\n return !isAbsolutePath(path);\n}\n\n/**\n * 标准化路径\n * @param {string} path - 要标准化的路径字符串。\n * @returns {string} - 标准化后的路径字符串。\n * @example\n * ```typescript\n * const normalizedPath = pathNormalize('/path///to///file');\n * console.log(normalizedPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathNormalize(path: string): string {\n const slices = path\n .replace(/\\\\/g, '/')\n .replace(/\\/{2,}/g, '/')\n .replace(/\\.{3,}/g, '..')\n .replace(/\\/\\.\\//g, '/')\n .split('/')\n .map((point) => point.trim());\n const points: string[] = [];\n const isAbs = slices[0] === '';\n\n const push = (point: string) => {\n points.push(point);\n };\n\n const back = () => {\n // 绝对路径不能退到根目录\n if (points.length === 1 && isAbs) return;\n\n //\n if (points.length === 0 || points.at(-1) === '..') {\n points.push('..');\n } else {\n points.pop();\n }\n };\n\n for (const slice of slices) {\n const isCurrent = _isCurrentSlice(slice);\n const isParent = _isParentSlice(slice);\n\n // // 未进入实际路径\n // if (!inPoints) {\n // push(slice);\n // inPoints = !isCurrent && !isParent;\n // continue;\n // }\n\n if (isCurrent) {\n continue;\n }\n\n if (isParent) {\n back();\n continue;\n }\n\n push(slice);\n }\n\n return points.join('/') || (isAbs ? '/' : '.');\n}\n\n/**\n * 路径合并\n * @param {string} from - 起始路径。\n * @param {...string[]} to - 要合并的路径片段。\n * @returns {string} - 合并后的路径字符串。\n * @example\n * ```typescript\n * const fullPath = pathJoin('/path', '/to', 'file');\n * console.log(fullPath); // 输出: '/path/to/file'\n * ```\n */\nexport function pathJoin(from: string, ...to: string[]): string {\n return pathNormalize([from, ...to].join('/'));\n}\n\n/**\n * 解析路径\n * @param {string} from - 起始路径\n * @param {...string[]} to - 要解析的路径片段\n * @returns {string} - 解析后的绝对路径\n * @example\n * ```typescript\n * const resolvedPath = pathResolve('/path', '/to', 'file');\n * console.log(resolvedPath); // 输出: '/to/file'\n * ```\n */\nexport function pathResolve(from: string, ...to: string[]): string {\n const paths = [from, ...to].map(pathNormalize);\n\n let lastStartPath = from;\n let lastStartIndex = 0;\n\n arrayEach(\n paths,\n (path, index) => {\n if (isAbsolutePath(path)) {\n lastStartPath = path;\n lastStartIndex = index;\n return false;\n }\n },\n true,\n );\n\n return pathJoin(lastStartPath, ...paths.slice(lastStartIndex + 1));\n}\n\n/**\n * 将相对路径转换为标准的相对路径格式(添加'./'前缀)\n *\n * @param {string} path - 要处理的路径字符串\n * @returns {string} 处理后的路径字符串\n *\n * @example <caption>处理绝对路径</caption>\n * ```typescript\n * const result = pathRelativize('/path/to/file');\n * console.log(result); // 输出: '/path/to/file'\n * ```\n *\n * @example <caption>处理已带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('./path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n *\n * @example <caption>处理不带'./'前缀的相对路径</caption>\n * ```typescript\n * const result = pathRelativize('path/to/file');\n * console.log(result); // 输出: './path/to/file'\n * ```\n */\nexport function pathRelativize(path: string): string {\n if (isAbsolutePath(path)) return path;\n if (path.startsWith('./')) return path;\n if (path.startsWith('../')) return path;\n return `./${path}`;\n}\n\n/**\n * 获取路径的目录部分\n * @param {string} path - 输入的路径字符串\n * @returns {string} - 返回路径的目录部分\n * @example\n * ```typescript\n * const dir = pathDirname('/path/to/file.txt');\n * console.log(dir); // 输出: '/path/to'\n * ```\n */\nexport function pathDirname(path: string): string {\n return pathJoin(path, '..');\n}\n"],"mappings":";;;;;;;AAOA,SAAS,gBAAgB,OAAwB;CAC/C,OAAO,UAAU;AACnB;;;;;;AAOA,SAAS,eAAe,OAAwB;CAC9C,OAAO,UAAU;AACnB;;;;;;;;;;;AAYA,SAAgB,eAAe,MAAuB;CACpD,OAAO,KAAK,WAAW,GAAG;AAC5B;;;;;;;;;;;AAYA,SAAgB,eAAe,MAAuB;CACpD,OAAO,CAAC,eAAe,IAAI;AAC7B;;;;;;;;;;;AAYA,SAAgB,cAAc,MAAsB;CAClD,MAAM,SAAS,KACZ,QAAQ,OAAO,GAAG,EAClB,QAAQ,WAAW,GAAG,EACtB,QAAQ,WAAW,IAAI,EACvB,QAAQ,WAAW,GAAG,EACtB,MAAM,GAAG,EACT,KAAK,UAAU,MAAM,KAAK,CAAC;CAC9B,MAAM,SAAmB,CAAC;CAC1B,MAAM,QAAQ,OAAO,OAAO;CAE5B,MAAM,QAAQ,UAAkB;EAC9B,OAAO,KAAK,KAAK;CACnB;CAEA,MAAM,aAAa;EAEjB,IAAI,OAAO,WAAW,KAAK,OAAO;EAGlC,IAAI,OAAO,WAAW,KAAK,OAAO,GAAG,EAAE,MAAM,MAC3C,OAAO,KAAK,IAAI;OAEhB,OAAO,IAAI;CAEf;CAEA,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,YAAY,gBAAgB,KAAK;EACvC,MAAM,WAAW,eAAe,KAAK;EASrC,IAAI,WACF;EAGF,IAAI,UAAU;GACZ,KAAK;GACL;EACF;EAEA,KAAK,KAAK;CACZ;CAEA,OAAO,OAAO,KAAK,GAAG,MAAM,QAAQ,MAAM;AAC5C;;;;;;;;;;;;AAaA,SAAgB,SAAS,MAAc,GAAG,IAAsB;CAC9D,OAAO,cAAc,CAAC,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC;AAC9C;;;;;;;;;;;;AAaA,SAAgB,YAAY,MAAc,GAAG,IAAsB;CACjE,MAAM,QAAQ,CAAC,MAAM,GAAG,EAAE,EAAE,IAAI,aAAa;CAE7C,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;CAErB,UACE,QACC,MAAM,UAAU;EACf,IAAI,eAAe,IAAI,GAAG;GACxB,gBAAgB;GAChB,iBAAiB;GACjB,OAAO;EACT;CACF,GACA,IACF;CAEA,OAAO,SAAS,eAAe,GAAG,MAAM,MAAM,iBAAiB,CAAC,CAAC;AACnE;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,eAAe,MAAsB;CACnD,IAAI,eAAe,IAAI,GAAG,OAAO;CACjC,IAAI,KAAK,WAAW,IAAI,GAAG,OAAO;CAClC,IAAI,KAAK,WAAW,KAAK,GAAG,OAAO;CACnC,OAAO,KAAK;AACd;;;;;;;;;;;AAYA,SAAgB,YAAY,MAAsB;CAChD,OAAO,SAAS,MAAM,IAAI;AAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"promise.cjs","names":[],"sources":["../src/promise.ts"],"sourcesContent":["import { isObject, isPromise } from './type';\n\n/**\n * 检查给定的值是否为 Promise 类似对象。\n * @param unknown - 要检查的值。\n * @returns 如果值是 Promise 类似对象,则返回 `true`,否则返回 `false`。\n */\nexport function isPromiseLike<T>(unknown: unknown): unknown is Promise<T> {\n return isPromise(unknown) || (isObject(unknown) && typeof (unknown as unknown as Promise<T>).then === 'function');\n}\n\n/**\n * 等待一定时间后解决 Promise\n * @param ms - 等待的毫秒数,默认为 0\n * @param ctrl - 可选的 AbortController,用于提前终止等待\n * @returns 一个 Promise,等待指定时间后解决\n */\nexport async function promiseDelay(ms = 0, ctrl?: AbortController) {\n return new Promise<void>((resolve) => {\n const t = setTimeout(resolve, ms);\n\n if (ctrl) {\n ctrl.signal.addEventListener('abort', () => {\n clearTimeout(t);\n resolve();\n });\n }\n });\n}\n\n/**\n * 使 Promise 在指定时间内执行,超时则拒绝\n * @param promise - 要执行的 Promise\n * @param ms - 超时的毫秒数\n * @returns 如果 Promise 在指定时间内解决,则返回其结果;否则抛出 \"timeout\" 错误\n * @throws {Error} 如果 Promise 超时,抛出 \"timeout\" 错误\n */\nexport async function promiseTimeout<T>(promise: Promise<T>, ms: number) {\n const ctrl = new AbortController();\n const result = await Promise.race([\n promise,\n promiseDelay(ms, ctrl).then(() => {\n throw new Error('timeout');\n }),\n ]);\n ctrl.abort();\n return result;\n}\n\n/**\n * 在指定条件满足时解决 Promise\n * @param condition - 一个返回布尔值的函数,用于检查条件是否满足\n * @param ms - 检查条件的时间间隔(毫秒),默认为 10\n * @returns 一个 Promise,在条件满足时解决\n */\nexport function promiseWhen(condition: () => boolean, ms = 10) {\n return new Promise<void>((resolve, _reject) => {\n const check = () => {\n if (condition()) {\n resolve();\n } else {\n setTimeout(check, ms);\n }\n };\n\n check();\n });\n}\n\n/**\n * 创建一个与给定 Promise 共享状态的新 Promise。\n * 新的 Promise 不具备 resolve 或 reject 的能力,它仅反映原始 Promise 的状态。\n * @param promise - 要共享状态的原始 Promise。\n * @returns 一个新的 Promise,其状态与给定的 Promise 完全相同。\n * @example\n * const { promise: p1 } = Promise.withResolvers();\n * const sp1 = sharedPromise(p1);\n * const sp2 = sharedPromise(p1);\n * // 此时 sp1、sp2 完全共享 p1 的状态,自身并不具备 resolve 或 reject 的能力\n */\nexport function promiseShared<T>(promise: Promise<T>) {\n return new Promise<T>((resolve, reject) => {\n promise.then(resolve, reject);\n });\n}\n\n/**\n * 创建一个最小等待时间的函数\n * @param {number} ms - 最小等待时间(毫秒)\n * @returns {function} 返回一个异步函数,该函数会确保从 createMinDelayPromise 调用到其执行的时间至少为 ms 毫秒\n * @example\n * const end = createMinDelayPromise(1000);\n * // 执行一些操作\n * await end(); // 确保从 createMinDelayPromise 调用到这里的总时间至少为 1000 毫秒\n */\nexport function createMinDelayPromise(ms: number) {\n const startTime = Date.now();\n /**\n * 确保最小等待时间的结束函数\n * @async\n * @function end\n * @returns {Promise<void>} 在达到最小等待时间后解决\n */\n return async function end() {\n const endTime = Date.now();\n const waitTime = ms - (endTime - startTime);\n if (waitTime > 0) {\n await promiseDelay(waitTime);\n }\n };\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,cAAiB,SAAyC;CACxE,OAAO,aAAA,UAAU,QAAQ,IAAK,aAAA,SAAS,QAAQ,IAAI,OAAQ,QAAkC,SAAS;;;;;;;;AASxG,eAAsB,aAAa,KAAK,GAAG,MAAwB;CACjE,OAAO,IAAI,SAAe,YAAY;EACpC,MAAM,IAAI,WAAW,SAAS,GAAG;EAEjC,IAAI,MACF,KAAK,OAAO,iBAAiB,eAAe;GAC1C,aAAa,EAAE;GACf,SAAS;IACT;GAEJ;;;;;;;;;AAUJ,eAAsB,eAAkB,SAAqB,IAAY;CACvE,MAAM,OAAO,IAAI,iBAAiB;CAClC,MAAM,SAAS,MAAM,QAAQ,KAAK,CAChC,SACA,aAAa,IAAI,KAAK,CAAC,WAAW;EAChC,MAAM,IAAI,MAAM,UAAU;GAC1B,CACH,CAAC;CACF,KAAK,OAAO;CACZ,OAAO;;;;;;;;AAST,SAAgB,YAAY,WAA0B,KAAK,IAAI;CAC7D,OAAO,IAAI,SAAe,SAAS,YAAY;EAC7C,MAAM,cAAc;GAClB,IAAI,WAAW,EACb,SAAS;QAET,WAAW,OAAO,GAAG;;EAIzB,OAAO;GACP;;;;;;;;;;;;;AAcJ,SAAgB,cAAiB,SAAqB;CACpD,OAAO,IAAI,SAAY,SAAS,WAAW;EACzC,QAAQ,KAAK,SAAS,OAAO;GAC7B;;;;;;;;;;;AAYJ,SAAgB,sBAAsB,IAAY;CAChD,MAAM,YAAY,KAAK,KAAK;;;;;;;CAO5B,OAAO,eAAe,MAAM;EAE1B,MAAM,WAAW,MADD,KAAK,KACE,GAAU;EACjC,IAAI,WAAW,GACb,MAAM,aAAa,SAAS"}
1
+ {"version":3,"file":"promise.cjs","names":[],"sources":["../src/promise.ts"],"sourcesContent":["import { isObject, isPromise } from './type';\n\n/**\n * 检查给定的值是否为 Promise 类似对象。\n * @param unknown - 要检查的值。\n * @returns 如果值是 Promise 类似对象,则返回 `true`,否则返回 `false`。\n */\nexport function isPromiseLike<T>(unknown: unknown): unknown is Promise<T> {\n return isPromise(unknown) || (isObject(unknown) && typeof (unknown as unknown as Promise<T>).then === 'function');\n}\n\n/**\n * 等待一定时间后解决 Promise\n * @param ms - 等待的毫秒数,默认为 0\n * @param ctrl - 可选的 AbortController,用于提前终止等待\n * @returns 一个 Promise,等待指定时间后解决\n */\nexport async function promiseDelay(ms = 0, ctrl?: AbortController) {\n return new Promise<void>((resolve) => {\n const t = setTimeout(resolve, ms);\n\n if (ctrl) {\n ctrl.signal.addEventListener('abort', () => {\n clearTimeout(t);\n resolve();\n });\n }\n });\n}\n\n/**\n * 使 Promise 在指定时间内执行,超时则拒绝\n * @param promise - 要执行的 Promise\n * @param ms - 超时的毫秒数\n * @returns 如果 Promise 在指定时间内解决,则返回其结果;否则抛出 \"timeout\" 错误\n * @throws {Error} 如果 Promise 超时,抛出 \"timeout\" 错误\n */\nexport async function promiseTimeout<T>(promise: Promise<T>, ms: number) {\n const ctrl = new AbortController();\n const result = await Promise.race([\n promise,\n promiseDelay(ms, ctrl).then(() => {\n throw new Error('timeout');\n }),\n ]);\n ctrl.abort();\n return result;\n}\n\n/**\n * 在指定条件满足时解决 Promise\n * @param condition - 一个返回布尔值的函数,用于检查条件是否满足\n * @param ms - 检查条件的时间间隔(毫秒),默认为 10\n * @returns 一个 Promise,在条件满足时解决\n */\nexport function promiseWhen(condition: () => boolean, ms = 10) {\n return new Promise<void>((resolve, _reject) => {\n const check = () => {\n if (condition()) {\n resolve();\n } else {\n setTimeout(check, ms);\n }\n };\n\n check();\n });\n}\n\n/**\n * 创建一个与给定 Promise 共享状态的新 Promise。\n * 新的 Promise 不具备 resolve 或 reject 的能力,它仅反映原始 Promise 的状态。\n * @param promise - 要共享状态的原始 Promise。\n * @returns 一个新的 Promise,其状态与给定的 Promise 完全相同。\n * @example\n * const { promise: p1 } = Promise.withResolvers();\n * const sp1 = sharedPromise(p1);\n * const sp2 = sharedPromise(p1);\n * // 此时 sp1、sp2 完全共享 p1 的状态,自身并不具备 resolve 或 reject 的能力\n */\nexport function promiseShared<T>(promise: Promise<T>) {\n return new Promise<T>((resolve, reject) => {\n promise.then(resolve, reject);\n });\n}\n\n/**\n * 创建一个最小等待时间的函数\n * @param {number} ms - 最小等待时间(毫秒)\n * @returns {function} 返回一个异步函数,该函数会确保从 createMinDelayPromise 调用到其执行的时间至少为 ms 毫秒\n * @example\n * const end = createMinDelayPromise(1000);\n * // 执行一些操作\n * await end(); // 确保从 createMinDelayPromise 调用到这里的总时间至少为 1000 毫秒\n */\nexport function createMinDelayPromise(ms: number) {\n const startTime = Date.now();\n /**\n * 确保最小等待时间的结束函数\n * @async\n * @function end\n * @returns {Promise<void>} 在达到最小等待时间后解决\n */\n return async function end() {\n const endTime = Date.now();\n const waitTime = ms - (endTime - startTime);\n if (waitTime > 0) {\n await promiseDelay(waitTime);\n }\n };\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,cAAiB,SAAyC;CACxE,OAAO,aAAA,UAAU,OAAO,KAAM,aAAA,SAAS,OAAO,KAAK,OAAQ,QAAkC,SAAS;AACxG;;;;;;;AAQA,eAAsB,aAAa,KAAK,GAAG,MAAwB;CACjE,OAAO,IAAI,SAAe,YAAY;EACpC,MAAM,IAAI,WAAW,SAAS,EAAE;EAEhC,IAAI,MACF,KAAK,OAAO,iBAAiB,eAAe;GAC1C,aAAa,CAAC;GACd,QAAQ;EACV,CAAC;CAEL,CAAC;AACH;;;;;;;;AASA,eAAsB,eAAkB,SAAqB,IAAY;CACvE,MAAM,OAAO,IAAI,gBAAgB;CACjC,MAAM,SAAS,MAAM,QAAQ,KAAK,CAChC,SACA,aAAa,IAAI,IAAI,EAAE,WAAW;EAChC,MAAM,IAAI,MAAM,SAAS;CAC3B,CAAC,CACH,CAAC;CACD,KAAK,MAAM;CACX,OAAO;AACT;;;;;;;AAQA,SAAgB,YAAY,WAA0B,KAAK,IAAI;CAC7D,OAAO,IAAI,SAAe,SAAS,YAAY;EAC7C,MAAM,cAAc;GAClB,IAAI,UAAU,GACZ,QAAQ;QAER,WAAW,OAAO,EAAE;EAExB;EAEA,MAAM;CACR,CAAC;AACH;;;;;;;;;;;;AAaA,SAAgB,cAAiB,SAAqB;CACpD,OAAO,IAAI,SAAY,SAAS,WAAW;EACzC,QAAQ,KAAK,SAAS,MAAM;CAC9B,CAAC;AACH;;;;;;;;;;AAWA,SAAgB,sBAAsB,IAAY;CAChD,MAAM,YAAY,KAAK,IAAI;;;;;;;CAO3B,OAAO,eAAe,MAAM;EAE1B,MAAM,WAAW,MADD,KAAK,IACE,IAAU;EACjC,IAAI,WAAW,GACb,MAAM,aAAa,QAAQ;CAE/B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"promise.mjs","names":[],"sources":["../src/promise.ts"],"sourcesContent":["import { isObject, isPromise } from './type';\n\n/**\n * 检查给定的值是否为 Promise 类似对象。\n * @param unknown - 要检查的值。\n * @returns 如果值是 Promise 类似对象,则返回 `true`,否则返回 `false`。\n */\nexport function isPromiseLike<T>(unknown: unknown): unknown is Promise<T> {\n return isPromise(unknown) || (isObject(unknown) && typeof (unknown as unknown as Promise<T>).then === 'function');\n}\n\n/**\n * 等待一定时间后解决 Promise\n * @param ms - 等待的毫秒数,默认为 0\n * @param ctrl - 可选的 AbortController,用于提前终止等待\n * @returns 一个 Promise,等待指定时间后解决\n */\nexport async function promiseDelay(ms = 0, ctrl?: AbortController) {\n return new Promise<void>((resolve) => {\n const t = setTimeout(resolve, ms);\n\n if (ctrl) {\n ctrl.signal.addEventListener('abort', () => {\n clearTimeout(t);\n resolve();\n });\n }\n });\n}\n\n/**\n * 使 Promise 在指定时间内执行,超时则拒绝\n * @param promise - 要执行的 Promise\n * @param ms - 超时的毫秒数\n * @returns 如果 Promise 在指定时间内解决,则返回其结果;否则抛出 \"timeout\" 错误\n * @throws {Error} 如果 Promise 超时,抛出 \"timeout\" 错误\n */\nexport async function promiseTimeout<T>(promise: Promise<T>, ms: number) {\n const ctrl = new AbortController();\n const result = await Promise.race([\n promise,\n promiseDelay(ms, ctrl).then(() => {\n throw new Error('timeout');\n }),\n ]);\n ctrl.abort();\n return result;\n}\n\n/**\n * 在指定条件满足时解决 Promise\n * @param condition - 一个返回布尔值的函数,用于检查条件是否满足\n * @param ms - 检查条件的时间间隔(毫秒),默认为 10\n * @returns 一个 Promise,在条件满足时解决\n */\nexport function promiseWhen(condition: () => boolean, ms = 10) {\n return new Promise<void>((resolve, _reject) => {\n const check = () => {\n if (condition()) {\n resolve();\n } else {\n setTimeout(check, ms);\n }\n };\n\n check();\n });\n}\n\n/**\n * 创建一个与给定 Promise 共享状态的新 Promise。\n * 新的 Promise 不具备 resolve 或 reject 的能力,它仅反映原始 Promise 的状态。\n * @param promise - 要共享状态的原始 Promise。\n * @returns 一个新的 Promise,其状态与给定的 Promise 完全相同。\n * @example\n * const { promise: p1 } = Promise.withResolvers();\n * const sp1 = sharedPromise(p1);\n * const sp2 = sharedPromise(p1);\n * // 此时 sp1、sp2 完全共享 p1 的状态,自身并不具备 resolve 或 reject 的能力\n */\nexport function promiseShared<T>(promise: Promise<T>) {\n return new Promise<T>((resolve, reject) => {\n promise.then(resolve, reject);\n });\n}\n\n/**\n * 创建一个最小等待时间的函数\n * @param {number} ms - 最小等待时间(毫秒)\n * @returns {function} 返回一个异步函数,该函数会确保从 createMinDelayPromise 调用到其执行的时间至少为 ms 毫秒\n * @example\n * const end = createMinDelayPromise(1000);\n * // 执行一些操作\n * await end(); // 确保从 createMinDelayPromise 调用到这里的总时间至少为 1000 毫秒\n */\nexport function createMinDelayPromise(ms: number) {\n const startTime = Date.now();\n /**\n * 确保最小等待时间的结束函数\n * @async\n * @function end\n * @returns {Promise<void>} 在达到最小等待时间后解决\n */\n return async function end() {\n const endTime = Date.now();\n const waitTime = ms - (endTime - startTime);\n if (waitTime > 0) {\n await promiseDelay(waitTime);\n }\n };\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,cAAiB,SAAyC;CACxE,OAAO,UAAU,QAAQ,IAAK,SAAS,QAAQ,IAAI,OAAQ,QAAkC,SAAS;;;;;;;;AASxG,eAAsB,aAAa,KAAK,GAAG,MAAwB;CACjE,OAAO,IAAI,SAAe,YAAY;EACpC,MAAM,IAAI,WAAW,SAAS,GAAG;EAEjC,IAAI,MACF,KAAK,OAAO,iBAAiB,eAAe;GAC1C,aAAa,EAAE;GACf,SAAS;IACT;GAEJ;;;;;;;;;AAUJ,eAAsB,eAAkB,SAAqB,IAAY;CACvE,MAAM,OAAO,IAAI,iBAAiB;CAClC,MAAM,SAAS,MAAM,QAAQ,KAAK,CAChC,SACA,aAAa,IAAI,KAAK,CAAC,WAAW;EAChC,MAAM,IAAI,MAAM,UAAU;GAC1B,CACH,CAAC;CACF,KAAK,OAAO;CACZ,OAAO;;;;;;;;AAST,SAAgB,YAAY,WAA0B,KAAK,IAAI;CAC7D,OAAO,IAAI,SAAe,SAAS,YAAY;EAC7C,MAAM,cAAc;GAClB,IAAI,WAAW,EACb,SAAS;QAET,WAAW,OAAO,GAAG;;EAIzB,OAAO;GACP;;;;;;;;;;;;;AAcJ,SAAgB,cAAiB,SAAqB;CACpD,OAAO,IAAI,SAAY,SAAS,WAAW;EACzC,QAAQ,KAAK,SAAS,OAAO;GAC7B;;;;;;;;;;;AAYJ,SAAgB,sBAAsB,IAAY;CAChD,MAAM,YAAY,KAAK,KAAK;;;;;;;CAO5B,OAAO,eAAe,MAAM;EAE1B,MAAM,WAAW,MADD,KAAK,KACE,GAAU;EACjC,IAAI,WAAW,GACb,MAAM,aAAa,SAAS"}
1
+ {"version":3,"file":"promise.mjs","names":[],"sources":["../src/promise.ts"],"sourcesContent":["import { isObject, isPromise } from './type';\n\n/**\n * 检查给定的值是否为 Promise 类似对象。\n * @param unknown - 要检查的值。\n * @returns 如果值是 Promise 类似对象,则返回 `true`,否则返回 `false`。\n */\nexport function isPromiseLike<T>(unknown: unknown): unknown is Promise<T> {\n return isPromise(unknown) || (isObject(unknown) && typeof (unknown as unknown as Promise<T>).then === 'function');\n}\n\n/**\n * 等待一定时间后解决 Promise\n * @param ms - 等待的毫秒数,默认为 0\n * @param ctrl - 可选的 AbortController,用于提前终止等待\n * @returns 一个 Promise,等待指定时间后解决\n */\nexport async function promiseDelay(ms = 0, ctrl?: AbortController) {\n return new Promise<void>((resolve) => {\n const t = setTimeout(resolve, ms);\n\n if (ctrl) {\n ctrl.signal.addEventListener('abort', () => {\n clearTimeout(t);\n resolve();\n });\n }\n });\n}\n\n/**\n * 使 Promise 在指定时间内执行,超时则拒绝\n * @param promise - 要执行的 Promise\n * @param ms - 超时的毫秒数\n * @returns 如果 Promise 在指定时间内解决,则返回其结果;否则抛出 \"timeout\" 错误\n * @throws {Error} 如果 Promise 超时,抛出 \"timeout\" 错误\n */\nexport async function promiseTimeout<T>(promise: Promise<T>, ms: number) {\n const ctrl = new AbortController();\n const result = await Promise.race([\n promise,\n promiseDelay(ms, ctrl).then(() => {\n throw new Error('timeout');\n }),\n ]);\n ctrl.abort();\n return result;\n}\n\n/**\n * 在指定条件满足时解决 Promise\n * @param condition - 一个返回布尔值的函数,用于检查条件是否满足\n * @param ms - 检查条件的时间间隔(毫秒),默认为 10\n * @returns 一个 Promise,在条件满足时解决\n */\nexport function promiseWhen(condition: () => boolean, ms = 10) {\n return new Promise<void>((resolve, _reject) => {\n const check = () => {\n if (condition()) {\n resolve();\n } else {\n setTimeout(check, ms);\n }\n };\n\n check();\n });\n}\n\n/**\n * 创建一个与给定 Promise 共享状态的新 Promise。\n * 新的 Promise 不具备 resolve 或 reject 的能力,它仅反映原始 Promise 的状态。\n * @param promise - 要共享状态的原始 Promise。\n * @returns 一个新的 Promise,其状态与给定的 Promise 完全相同。\n * @example\n * const { promise: p1 } = Promise.withResolvers();\n * const sp1 = sharedPromise(p1);\n * const sp2 = sharedPromise(p1);\n * // 此时 sp1、sp2 完全共享 p1 的状态,自身并不具备 resolve 或 reject 的能力\n */\nexport function promiseShared<T>(promise: Promise<T>) {\n return new Promise<T>((resolve, reject) => {\n promise.then(resolve, reject);\n });\n}\n\n/**\n * 创建一个最小等待时间的函数\n * @param {number} ms - 最小等待时间(毫秒)\n * @returns {function} 返回一个异步函数,该函数会确保从 createMinDelayPromise 调用到其执行的时间至少为 ms 毫秒\n * @example\n * const end = createMinDelayPromise(1000);\n * // 执行一些操作\n * await end(); // 确保从 createMinDelayPromise 调用到这里的总时间至少为 1000 毫秒\n */\nexport function createMinDelayPromise(ms: number) {\n const startTime = Date.now();\n /**\n * 确保最小等待时间的结束函数\n * @async\n * @function end\n * @returns {Promise<void>} 在达到最小等待时间后解决\n */\n return async function end() {\n const endTime = Date.now();\n const waitTime = ms - (endTime - startTime);\n if (waitTime > 0) {\n await promiseDelay(waitTime);\n }\n };\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,cAAiB,SAAyC;CACxE,OAAO,UAAU,OAAO,KAAM,SAAS,OAAO,KAAK,OAAQ,QAAkC,SAAS;AACxG;;;;;;;AAQA,eAAsB,aAAa,KAAK,GAAG,MAAwB;CACjE,OAAO,IAAI,SAAe,YAAY;EACpC,MAAM,IAAI,WAAW,SAAS,EAAE;EAEhC,IAAI,MACF,KAAK,OAAO,iBAAiB,eAAe;GAC1C,aAAa,CAAC;GACd,QAAQ;EACV,CAAC;CAEL,CAAC;AACH;;;;;;;;AASA,eAAsB,eAAkB,SAAqB,IAAY;CACvE,MAAM,OAAO,IAAI,gBAAgB;CACjC,MAAM,SAAS,MAAM,QAAQ,KAAK,CAChC,SACA,aAAa,IAAI,IAAI,EAAE,WAAW;EAChC,MAAM,IAAI,MAAM,SAAS;CAC3B,CAAC,CACH,CAAC;CACD,KAAK,MAAM;CACX,OAAO;AACT;;;;;;;AAQA,SAAgB,YAAY,WAA0B,KAAK,IAAI;CAC7D,OAAO,IAAI,SAAe,SAAS,YAAY;EAC7C,MAAM,cAAc;GAClB,IAAI,UAAU,GACZ,QAAQ;QAER,WAAW,OAAO,EAAE;EAExB;EAEA,MAAM;CACR,CAAC;AACH;;;;;;;;;;;;AAaA,SAAgB,cAAiB,SAAqB;CACpD,OAAO,IAAI,SAAY,SAAS,WAAW;EACzC,QAAQ,KAAK,SAAS,MAAM;CAC9B,CAAC;AACH;;;;;;;;;;AAWA,SAAgB,sBAAsB,IAAY;CAChD,MAAM,YAAY,KAAK,IAAI;;;;;;;CAO3B,OAAO,eAAe,MAAM;EAE1B,MAAM,WAAW,MADD,KAAK,IACE,IAAU;EACjC,IAAI,WAAW,GACb,MAAM,aAAa,QAAQ;CAE/B;AACF"}
package/dist/qs.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"qs.cjs","names":[],"sources":["../src/qs.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNullish, isNumber, isString } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 查询字符串解析函数\n * @template T - 解析后返回的对象类型\n * @callback QSReader\n * @param {string} value - 查询字符串的值\n * @param {string} key - 查询字符串的键\n * @param {T} qsObject - 当前解析的对象\n * @returns {unknown} 解析后的值,如果返回 undefined 或 null 则不会添加到对象中\n * @example\n * const parser: QSReader<MyObject> = (value, key, obj) => {\n * if (key === 'date') return new Date(value);\n * return value;\n * };\n */\nexport type QSReader<T extends AnyObject> = (value: string, key: string, qsObject: T) => unknown;\n\n/**\n * 解析查询字符串为对象\n * @template T - 返回的对象类型\n * @param {string} queryString - 要解析的查询字符串\n * @param {QSReader<T>} [parser] - 自定义解析函数\n * @returns {T} 解析后的对象\n * @example\n * const obj = qsParse('name=John&age=30');\n * // { name: 'John', age: '30' }\n *\n * const obj2 = qsParse('date=2023-01-01', (val, key) => {\n * if (key === 'date') return new Date(val);\n * return val;\n * });\n * // { date: Date('2023-01-01') }\n */\nexport function qsParse<T extends AnyObject>(queryString: string, parser?: QSReader<T>): T {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams(queryString.replace(/^.*\\?/, ''));\n const qsObject = {} as T;\n\n for (const [key, val] of sp.entries()) {\n const valFinal = parser ? parser(val, key, qsObject) : val;\n\n if (isNullish(valFinal)) continue;\n\n if (Object.hasOwn(qsObject, key)) {\n // @ts-expect-error\n if (!isArray(qsObject[key])) qsObject[key] = [qsObject[key]];\n (qsObject[key] as unknown[]).push(val);\n } else {\n // @ts-expect-error\n qsObject[key] = valFinal;\n }\n }\n\n return qsObject;\n}\n\n/**\n * 查询字符串序列化函数\n * @template T - 要序列化的对象类型\n * @callback QSWriter\n * @param {unknown} value - 要序列化的值\n * @param {string} key - 对象的键\n * @param {T} query - 当前序列化的对象\n * @returns {string | null} 序列化后的字符串,如果返回 null 则忽略该键值对\n * @example\n * const writer: QSWriter<MyObject> = (val, key) => {\n * if (val instanceof Date) return val.toISOString();\n * return String(val);\n * };\n */\nexport type QSWriter<T extends AnyObject = AnyObject> = (value: unknown, key: string, query: T) => string | null;\nconst defaultWriter: QSWriter<AnyObject> = (val: unknown) => {\n if (isString(val)) return val;\n if (isNumber(val)) return String(val);\n if (isBoolean(val)) return val ? 'true' : 'false';\n if (isDate(val)) return val.toISOString();\n return null;\n};\n\n/**\n * 将对象序列化为查询字符串\n * @template T - 要序列化的对象类型\n * @param {T} qsObject - 要序列化的对象\n * @param {QSWriter<T>} [stringify=defaultWriter] - 自定义序列化函数\n * @returns {string} 序列化后的查询字符串\n * @example\n * const str = qsStringify({ name: 'John', age: 30 });\n * // 'name=John&age=30'\n *\n * const str2 = qsStringify({ date: new Date('2023-01-01') });\n * // 'date=2023-01-01T00:00:00.000Z'\n */\nexport function qsStringify<T extends AnyObject>(qsObject: T, stringify: QSWriter<T> = defaultWriter): string {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams();\n const pushPairs = (val: unknown, key: string) => {\n const valFinal = stringify(val, String(key), qsObject);\n if (isNullish(valFinal)) return;\n\n sp.append(key, valFinal);\n };\n\n objectEach(qsObject, (val, key: string) => {\n if (isArray(val)) {\n for (const it of val) {\n pushPairs(it, key);\n }\n } else {\n pushPairs(val, key);\n }\n });\n\n return sp.toString();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,QAA6B,aAAqB,QAAyB;CAGzF,MAAM,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,GAAG,CAAC;CAC3E,MAAM,WAAW,EAAE;CAEnB,KAAK,MAAM,CAAC,KAAK,QAAQ,GAAG,SAAS,EAAE;EACrC,MAAM,WAAW,SAAS,OAAO,KAAK,KAAK,SAAS,GAAG;EAEvD,IAAI,aAAA,UAAU,SAAS,EAAE;EAEzB,IAAI,OAAO,OAAO,UAAU,IAAI,EAAE;GAEhC,IAAI,CAAC,aAAA,QAAQ,SAAS,KAAK,EAAE,SAAS,OAAO,CAAC,SAAS,KAAK;GAC5D,SAAU,KAAmB,KAAK,IAAI;SAGtC,SAAS,OAAO;;CAIpB,OAAO;;AAkBT,IAAM,iBAAsC,QAAiB;CAC3D,IAAI,aAAA,SAAS,IAAI,EAAE,OAAO;CAC1B,IAAI,aAAA,SAAS,IAAI,EAAE,OAAO,OAAO,IAAI;CACrC,IAAI,aAAA,UAAU,IAAI,EAAE,OAAO,MAAM,SAAS;CAC1C,IAAI,aAAA,OAAO,IAAI,EAAE,OAAO,IAAI,aAAa;CACzC,OAAO;;;;;;;;;;;;;;;AAgBT,SAAgB,YAAiC,UAAa,YAAyB,eAAuB;CAG5G,MAAM,KAAK,IAAI,WAAW,iBAAiB;CAC3C,MAAM,aAAa,KAAc,QAAgB;EAC/C,MAAM,WAAW,UAAU,KAAK,OAAO,IAAI,EAAE,SAAS;EACtD,IAAI,aAAA,UAAU,SAAS,EAAE;EAEzB,GAAG,OAAO,KAAK,SAAS;;CAG1B,eAAA,WAAW,WAAW,KAAK,QAAgB;EACzC,IAAI,aAAA,QAAQ,IAAI,EACd,KAAK,MAAM,MAAM,KACf,UAAU,IAAI,IAAI;OAGpB,UAAU,KAAK,IAAI;GAErB;CAEF,OAAO,GAAG,UAAU"}
1
+ {"version":3,"file":"qs.cjs","names":[],"sources":["../src/qs.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNullish, isNumber, isString } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 查询字符串解析函数\n * @template T - 解析后返回的对象类型\n * @callback QSReader\n * @param {string} value - 查询字符串的值\n * @param {string} key - 查询字符串的键\n * @param {T} qsObject - 当前解析的对象\n * @returns {unknown} 解析后的值,如果返回 undefined 或 null 则不会添加到对象中\n * @example\n * const parser: QSReader<MyObject> = (value, key, obj) => {\n * if (key === 'date') return new Date(value);\n * return value;\n * };\n */\nexport type QSReader<T extends AnyObject> = (value: string, key: string, qsObject: T) => unknown;\n\n/**\n * 解析查询字符串为对象\n * @template T - 返回的对象类型\n * @param {string} queryString - 要解析的查询字符串\n * @param {QSReader<T>} [parser] - 自定义解析函数\n * @returns {T} 解析后的对象\n * @example\n * const obj = qsParse('name=John&age=30');\n * // { name: 'John', age: '30' }\n *\n * const obj2 = qsParse('date=2023-01-01', (val, key) => {\n * if (key === 'date') return new Date(val);\n * return val;\n * });\n * // { date: Date('2023-01-01') }\n */\nexport function qsParse<T extends AnyObject>(queryString: string, parser?: QSReader<T>): T {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams(queryString.replace(/^.*\\?/, ''));\n const qsObject = {} as T;\n\n for (const [key, val] of sp.entries()) {\n const valFinal = parser ? parser(val, key, qsObject) : val;\n\n if (isNullish(valFinal)) continue;\n\n if (Object.hasOwn(qsObject, key)) {\n // @ts-expect-error\n if (!isArray(qsObject[key])) qsObject[key] = [qsObject[key]];\n (qsObject[key] as unknown[]).push(val);\n } else {\n // @ts-expect-error\n qsObject[key] = valFinal;\n }\n }\n\n return qsObject;\n}\n\n/**\n * 查询字符串序列化函数\n * @template T - 要序列化的对象类型\n * @callback QSWriter\n * @param {unknown} value - 要序列化的值\n * @param {string} key - 对象的键\n * @param {T} query - 当前序列化的对象\n * @returns {string | null} 序列化后的字符串,如果返回 null 则忽略该键值对\n * @example\n * const writer: QSWriter<MyObject> = (val, key) => {\n * if (val instanceof Date) return val.toISOString();\n * return String(val);\n * };\n */\nexport type QSWriter<T extends AnyObject = AnyObject> = (value: unknown, key: string, query: T) => string | null;\nconst defaultWriter: QSWriter<AnyObject> = (val: unknown) => {\n if (isString(val)) return val;\n if (isNumber(val)) return String(val);\n if (isBoolean(val)) return val ? 'true' : 'false';\n if (isDate(val)) return val.toISOString();\n return null;\n};\n\n/**\n * 将对象序列化为查询字符串\n * @template T - 要序列化的对象类型\n * @param {T} qsObject - 要序列化的对象\n * @param {QSWriter<T>} [stringify=defaultWriter] - 自定义序列化函数\n * @returns {string} 序列化后的查询字符串\n * @example\n * const str = qsStringify({ name: 'John', age: 30 });\n * // 'name=John&age=30'\n *\n * const str2 = qsStringify({ date: new Date('2023-01-01') });\n * // 'date=2023-01-01T00:00:00.000Z'\n */\nexport function qsStringify<T extends AnyObject>(qsObject: T, stringify: QSWriter<T> = defaultWriter): string {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams();\n const pushPairs = (val: unknown, key: string) => {\n const valFinal = stringify(val, String(key), qsObject);\n if (isNullish(valFinal)) return;\n\n sp.append(key, valFinal);\n };\n\n objectEach(qsObject, (val, key: string) => {\n if (isArray(val)) {\n for (const it of val) {\n pushPairs(it, key);\n }\n } else {\n pushPairs(val, key);\n }\n });\n\n return sp.toString();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,QAA6B,aAAqB,QAAyB;CAGzF,MAAM,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,EAAE,CAAC;CAC1E,MAAM,WAAW,CAAC;CAElB,KAAK,MAAM,CAAC,KAAK,QAAQ,GAAG,QAAQ,GAAG;EACrC,MAAM,WAAW,SAAS,OAAO,KAAK,KAAK,QAAQ,IAAI;EAEvD,IAAI,aAAA,UAAU,QAAQ,GAAG;EAEzB,IAAI,OAAO,OAAO,UAAU,GAAG,GAAG;GAEhC,IAAI,CAAC,aAAA,QAAQ,SAAS,IAAI,GAAG,SAAS,OAAO,CAAC,SAAS,IAAI;GAC3D,SAAU,KAAmB,KAAK,GAAG;EACvC,OAEE,SAAS,OAAO;CAEpB;CAEA,OAAO;AACT;AAiBA,IAAM,iBAAsC,QAAiB;CAC3D,IAAI,aAAA,SAAS,GAAG,GAAG,OAAO;CAC1B,IAAI,aAAA,SAAS,GAAG,GAAG,OAAO,OAAO,GAAG;CACpC,IAAI,aAAA,UAAU,GAAG,GAAG,OAAO,MAAM,SAAS;CAC1C,IAAI,aAAA,OAAO,GAAG,GAAG,OAAO,IAAI,YAAY;CACxC,OAAO;AACT;;;;;;;;;;;;;;AAeA,SAAgB,YAAiC,UAAa,YAAyB,eAAuB;CAG5G,MAAM,KAAK,IAAI,WAAW,gBAAgB;CAC1C,MAAM,aAAa,KAAc,QAAgB;EAC/C,MAAM,WAAW,UAAU,KAAK,OAAO,GAAG,GAAG,QAAQ;EACrD,IAAI,aAAA,UAAU,QAAQ,GAAG;EAEzB,GAAG,OAAO,KAAK,QAAQ;CACzB;CAEA,eAAA,WAAW,WAAW,KAAK,QAAgB;EACzC,IAAI,aAAA,QAAQ,GAAG,GACb,KAAK,MAAM,MAAM,KACf,UAAU,IAAI,GAAG;OAGnB,UAAU,KAAK,GAAG;CAEtB,CAAC;CAED,OAAO,GAAG,SAAS;AACrB"}
package/dist/qs.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"qs.mjs","names":[],"sources":["../src/qs.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNullish, isNumber, isString } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 查询字符串解析函数\n * @template T - 解析后返回的对象类型\n * @callback QSReader\n * @param {string} value - 查询字符串的值\n * @param {string} key - 查询字符串的键\n * @param {T} qsObject - 当前解析的对象\n * @returns {unknown} 解析后的值,如果返回 undefined 或 null 则不会添加到对象中\n * @example\n * const parser: QSReader<MyObject> = (value, key, obj) => {\n * if (key === 'date') return new Date(value);\n * return value;\n * };\n */\nexport type QSReader<T extends AnyObject> = (value: string, key: string, qsObject: T) => unknown;\n\n/**\n * 解析查询字符串为对象\n * @template T - 返回的对象类型\n * @param {string} queryString - 要解析的查询字符串\n * @param {QSReader<T>} [parser] - 自定义解析函数\n * @returns {T} 解析后的对象\n * @example\n * const obj = qsParse('name=John&age=30');\n * // { name: 'John', age: '30' }\n *\n * const obj2 = qsParse('date=2023-01-01', (val, key) => {\n * if (key === 'date') return new Date(val);\n * return val;\n * });\n * // { date: Date('2023-01-01') }\n */\nexport function qsParse<T extends AnyObject>(queryString: string, parser?: QSReader<T>): T {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams(queryString.replace(/^.*\\?/, ''));\n const qsObject = {} as T;\n\n for (const [key, val] of sp.entries()) {\n const valFinal = parser ? parser(val, key, qsObject) : val;\n\n if (isNullish(valFinal)) continue;\n\n if (Object.hasOwn(qsObject, key)) {\n // @ts-expect-error\n if (!isArray(qsObject[key])) qsObject[key] = [qsObject[key]];\n (qsObject[key] as unknown[]).push(val);\n } else {\n // @ts-expect-error\n qsObject[key] = valFinal;\n }\n }\n\n return qsObject;\n}\n\n/**\n * 查询字符串序列化函数\n * @template T - 要序列化的对象类型\n * @callback QSWriter\n * @param {unknown} value - 要序列化的值\n * @param {string} key - 对象的键\n * @param {T} query - 当前序列化的对象\n * @returns {string | null} 序列化后的字符串,如果返回 null 则忽略该键值对\n * @example\n * const writer: QSWriter<MyObject> = (val, key) => {\n * if (val instanceof Date) return val.toISOString();\n * return String(val);\n * };\n */\nexport type QSWriter<T extends AnyObject = AnyObject> = (value: unknown, key: string, query: T) => string | null;\nconst defaultWriter: QSWriter<AnyObject> = (val: unknown) => {\n if (isString(val)) return val;\n if (isNumber(val)) return String(val);\n if (isBoolean(val)) return val ? 'true' : 'false';\n if (isDate(val)) return val.toISOString();\n return null;\n};\n\n/**\n * 将对象序列化为查询字符串\n * @template T - 要序列化的对象类型\n * @param {T} qsObject - 要序列化的对象\n * @param {QSWriter<T>} [stringify=defaultWriter] - 自定义序列化函数\n * @returns {string} 序列化后的查询字符串\n * @example\n * const str = qsStringify({ name: 'John', age: 30 });\n * // 'name=John&age=30'\n *\n * const str2 = qsStringify({ date: new Date('2023-01-01') });\n * // 'date=2023-01-01T00:00:00.000Z'\n */\nexport function qsStringify<T extends AnyObject>(qsObject: T, stringify: QSWriter<T> = defaultWriter): string {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams();\n const pushPairs = (val: unknown, key: string) => {\n const valFinal = stringify(val, String(key), qsObject);\n if (isNullish(valFinal)) return;\n\n sp.append(key, valFinal);\n };\n\n objectEach(qsObject, (val, key: string) => {\n if (isArray(val)) {\n for (const it of val) {\n pushPairs(it, key);\n }\n } else {\n pushPairs(val, key);\n }\n });\n\n return sp.toString();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,QAA6B,aAAqB,QAAyB;CAGzF,MAAM,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,GAAG,CAAC;CAC3E,MAAM,WAAW,EAAE;CAEnB,KAAK,MAAM,CAAC,KAAK,QAAQ,GAAG,SAAS,EAAE;EACrC,MAAM,WAAW,SAAS,OAAO,KAAK,KAAK,SAAS,GAAG;EAEvD,IAAI,UAAU,SAAS,EAAE;EAEzB,IAAI,OAAO,OAAO,UAAU,IAAI,EAAE;GAEhC,IAAI,CAAC,QAAQ,SAAS,KAAK,EAAE,SAAS,OAAO,CAAC,SAAS,KAAK;GAC5D,SAAU,KAAmB,KAAK,IAAI;SAGtC,SAAS,OAAO;;CAIpB,OAAO;;AAkBT,IAAM,iBAAsC,QAAiB;CAC3D,IAAI,SAAS,IAAI,EAAE,OAAO;CAC1B,IAAI,SAAS,IAAI,EAAE,OAAO,OAAO,IAAI;CACrC,IAAI,UAAU,IAAI,EAAE,OAAO,MAAM,SAAS;CAC1C,IAAI,OAAO,IAAI,EAAE,OAAO,IAAI,aAAa;CACzC,OAAO;;;;;;;;;;;;;;;AAgBT,SAAgB,YAAiC,UAAa,YAAyB,eAAuB;CAG5G,MAAM,KAAK,IAAI,WAAW,iBAAiB;CAC3C,MAAM,aAAa,KAAc,QAAgB;EAC/C,MAAM,WAAW,UAAU,KAAK,OAAO,IAAI,EAAE,SAAS;EACtD,IAAI,UAAU,SAAS,EAAE;EAEzB,GAAG,OAAO,KAAK,SAAS;;CAG1B,WAAW,WAAW,KAAK,QAAgB;EACzC,IAAI,QAAQ,IAAI,EACd,KAAK,MAAM,MAAM,KACf,UAAU,IAAI,IAAI;OAGpB,UAAU,KAAK,IAAI;GAErB;CAEF,OAAO,GAAG,UAAU"}
1
+ {"version":3,"file":"qs.mjs","names":[],"sources":["../src/qs.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNullish, isNumber, isString } from './type';\nimport type { AnyObject } from './types';\n\n/**\n * 查询字符串解析函数\n * @template T - 解析后返回的对象类型\n * @callback QSReader\n * @param {string} value - 查询字符串的值\n * @param {string} key - 查询字符串的键\n * @param {T} qsObject - 当前解析的对象\n * @returns {unknown} 解析后的值,如果返回 undefined 或 null 则不会添加到对象中\n * @example\n * const parser: QSReader<MyObject> = (value, key, obj) => {\n * if (key === 'date') return new Date(value);\n * return value;\n * };\n */\nexport type QSReader<T extends AnyObject> = (value: string, key: string, qsObject: T) => unknown;\n\n/**\n * 解析查询字符串为对象\n * @template T - 返回的对象类型\n * @param {string} queryString - 要解析的查询字符串\n * @param {QSReader<T>} [parser] - 自定义解析函数\n * @returns {T} 解析后的对象\n * @example\n * const obj = qsParse('name=John&age=30');\n * // { name: 'John', age: '30' }\n *\n * const obj2 = qsParse('date=2023-01-01', (val, key) => {\n * if (key === 'date') return new Date(val);\n * return val;\n * });\n * // { date: Date('2023-01-01') }\n */\nexport function qsParse<T extends AnyObject>(queryString: string, parser?: QSReader<T>): T {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams(queryString.replace(/^.*\\?/, ''));\n const qsObject = {} as T;\n\n for (const [key, val] of sp.entries()) {\n const valFinal = parser ? parser(val, key, qsObject) : val;\n\n if (isNullish(valFinal)) continue;\n\n if (Object.hasOwn(qsObject, key)) {\n // @ts-expect-error\n if (!isArray(qsObject[key])) qsObject[key] = [qsObject[key]];\n (qsObject[key] as unknown[]).push(val);\n } else {\n // @ts-expect-error\n qsObject[key] = valFinal;\n }\n }\n\n return qsObject;\n}\n\n/**\n * 查询字符串序列化函数\n * @template T - 要序列化的对象类型\n * @callback QSWriter\n * @param {unknown} value - 要序列化的值\n * @param {string} key - 对象的键\n * @param {T} query - 当前序列化的对象\n * @returns {string | null} 序列化后的字符串,如果返回 null 则忽略该键值对\n * @example\n * const writer: QSWriter<MyObject> = (val, key) => {\n * if (val instanceof Date) return val.toISOString();\n * return String(val);\n * };\n */\nexport type QSWriter<T extends AnyObject = AnyObject> = (value: unknown, key: string, query: T) => string | null;\nconst defaultWriter: QSWriter<AnyObject> = (val: unknown) => {\n if (isString(val)) return val;\n if (isNumber(val)) return String(val);\n if (isBoolean(val)) return val ? 'true' : 'false';\n if (isDate(val)) return val.toISOString();\n return null;\n};\n\n/**\n * 将对象序列化为查询字符串\n * @template T - 要序列化的对象类型\n * @param {T} qsObject - 要序列化的对象\n * @param {QSWriter<T>} [stringify=defaultWriter] - 自定义序列化函数\n * @returns {string} 序列化后的查询字符串\n * @example\n * const str = qsStringify({ name: 'John', age: 30 });\n * // 'name=John&age=30'\n *\n * const str2 = qsStringify({ date: new Date('2023-01-01') });\n * // 'date=2023-01-01T00:00:00.000Z'\n */\nexport function qsStringify<T extends AnyObject>(qsObject: T, stringify: QSWriter<T> = defaultWriter): string {\n // 添加 globalThis 是便于对接外部环境 URL 的自行实现\n // 例如在 uni-app、微信小程序等运行环境。\n const sp = new globalThis.URLSearchParams();\n const pushPairs = (val: unknown, key: string) => {\n const valFinal = stringify(val, String(key), qsObject);\n if (isNullish(valFinal)) return;\n\n sp.append(key, valFinal);\n };\n\n objectEach(qsObject, (val, key: string) => {\n if (isArray(val)) {\n for (const it of val) {\n pushPairs(it, key);\n }\n } else {\n pushPairs(val, key);\n }\n });\n\n return sp.toString();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,QAA6B,aAAqB,QAAyB;CAGzF,MAAM,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,EAAE,CAAC;CAC1E,MAAM,WAAW,CAAC;CAElB,KAAK,MAAM,CAAC,KAAK,QAAQ,GAAG,QAAQ,GAAG;EACrC,MAAM,WAAW,SAAS,OAAO,KAAK,KAAK,QAAQ,IAAI;EAEvD,IAAI,UAAU,QAAQ,GAAG;EAEzB,IAAI,OAAO,OAAO,UAAU,GAAG,GAAG;GAEhC,IAAI,CAAC,QAAQ,SAAS,IAAI,GAAG,SAAS,OAAO,CAAC,SAAS,IAAI;GAC3D,SAAU,KAAmB,KAAK,GAAG;EACvC,OAEE,SAAS,OAAO;CAEpB;CAEA,OAAO;AACT;AAiBA,IAAM,iBAAsC,QAAiB;CAC3D,IAAI,SAAS,GAAG,GAAG,OAAO;CAC1B,IAAI,SAAS,GAAG,GAAG,OAAO,OAAO,GAAG;CACpC,IAAI,UAAU,GAAG,GAAG,OAAO,MAAM,SAAS;CAC1C,IAAI,OAAO,GAAG,GAAG,OAAO,IAAI,YAAY;CACxC,OAAO;AACT;;;;;;;;;;;;;;AAeA,SAAgB,YAAiC,UAAa,YAAyB,eAAuB;CAG5G,MAAM,KAAK,IAAI,WAAW,gBAAgB;CAC1C,MAAM,aAAa,KAAc,QAAgB;EAC/C,MAAM,WAAW,UAAU,KAAK,OAAO,GAAG,GAAG,QAAQ;EACrD,IAAI,UAAU,QAAQ,GAAG;EAEzB,GAAG,OAAO,KAAK,QAAQ;CACzB;CAEA,WAAW,WAAW,KAAK,QAAgB;EACzC,IAAI,QAAQ,GAAG,GACb,KAAK,MAAM,MAAM,KACf,UAAU,IAAI,GAAG;OAGnB,UAAU,KAAK,GAAG;CAEtB,CAAC;CAED,OAAO,GAAG,SAAS;AACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"regexp.cjs","names":[],"sources":["../src/regexp.ts"],"sourcesContent":["const specialRE = /[.*+?^=!:${}()|[\\]/\\\\-]/g;\n\n/**\n * 编码处理正则表达式\n * @example\n * ```js\n * reEscape('/$')\n * // => '\\\\/\\\\$'\n * ```\n * @param {string} string\n * @returns {string}\n */\nexport function regexpEscape(string: string): string {\n return string.replace(specialRE, '\\\\$&');\n}\n\n// 邮箱\nconst EMAIL_RE = /^\\w+[-+.\\w]*@([a-z\\d-]+\\.)+[a-z]{2,5}$/i;\n/**\n * 判断字符串是否为邮箱格式,不对邮箱真实性做验证,如域名是否正确等\n * @param {string} value\n * @returns {boolean}\n */\nexport function isEmail(value: string): boolean {\n return EMAIL_RE.test(value);\n}\n\n// 手机号码\nconst PHONE_RE = /^1\\d{10}$/;\n/**\n * 判断字符串是否为宽松手机格式,即首位为 1 的 11 位数字都属于手机号\n * @param {string} value\n * @returns {boolean}\n */\nexport function isPhone(value: string): boolean {\n return PHONE_RE.test(value);\n}\n\n// 身份证号码\n// http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/\n// [\"北京市\", \"天津市\", \"河北省\", \"山西省\", \"内蒙古自治区\",\n// \"辽宁省\", \"吉林省\", \"黑龙江省\",\n// \"上海市\", \"江苏省\", \"浙江省\", \"安徽省\", \"福建省\", \"江西省\", \"山东省\",\n// \"河南省\", \"湖北省\", \"湖南省\", \"广东省\", \"广西壮族自治区\", \"海南省\",\n// \"重庆市\", \"四川省\", \"贵州省\", \"云南省\", \"西藏自治区\",\n// \"陕西省\", \"甘肃省\", \"青海省\",\"宁夏回族自治区\", \"新疆维吾尔自治区\",\n// \"台湾省\",\n// \"香港特别行政区\", \"澳门特别行政区\"]\n// [\"11\", \"12\", \"13\", \"14\", \"15\",\n// \"21\", \"22\", \"23\",\n// \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\",\n// \"41\", \"42\", \"43\", \"44\", \"45\", \"46\",\n// \"50\", \"51\", \"52\", \"53\", \"54\",\n// \"61\", \"62\", \"63\", \"64\", \"65\",\n// \"71\",\n// \"81\", \"82\"]\n// 91 国外\nconst IDNO_RE =\n /^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|7[1]|8[1-2]|9[1])\\d{4}(18|19|20)\\d{2}[01]\\d[0123]\\d{4}[\\dxX]$/;\n/**\n * 判断字符串是否为身份证号码格式\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIDNo(value: string): boolean {\n const isSameFormat = IDNO_RE.test(value);\n\n if (!isSameFormat) return false;\n\n const year = Number(value.slice(6, 10));\n const month = Number(value.slice(10, 12));\n const date = Number(value.slice(12, 14));\n const d = new Date(year, month - 1, date);\n const isSameDate = d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === date;\n\n if (!isSameDate) return false;\n\n // 将身份证号码前面的17位数分别乘以不同的系数;\n // 从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2\n // 将这17位数字和系数相乘的结果相加;\n // 用加出来和除以11,看余数是多少;\n // 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字;\n // 其分别对应的最后一位身份证的号码为1-0-X-9-8-7-6-5-4-3-2\n // 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。\n const coefficientList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];\n const residueList = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];\n let sum = 0;\n\n for (let start = 0; start < 17; start++) {\n sum += Number(value.slice(start, start + 1)) * coefficientList[start];\n }\n\n return residueList[sum % 11] === value.slice(-1);\n}\n\n// url\nconst URL_RE = /^https?:\\/\\//i;\n/**\n * 判断字符串是否为 url 格式,仅支持 http 协议,支持域名或者 ipV4\n * @param {string} value\n * @returns {boolean}\n */\nexport function isURL(value: string): boolean {\n return URL_RE.test(value);\n}\n\n// ipv4\nconst IPV4_RE = /^(?:(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$/;\n/**\n * 判断字符串是否为 IPV4 格式,不对 ip 真实性做验证\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIPV4(value: string): boolean {\n return IPV4_RE.test(value);\n}\n\nconst INTEGER_RE = /^(-?[1-9]\\d*|0)$/;\n/**\n * 判断字符串是否为整数(自然数),即 ...,-3,-2,-1,0,1,2,3,...\n * @param {string} value\n * @returns {boolean}\n */\nexport function isInteger(value: string): boolean {\n return INTEGER_RE.test(value);\n}\n\nconst FLOAT_RE = /^-?([1-9]\\d*|0)\\.\\d+$/;\n/**\n * 判断字符串是否为浮点数,即必须有小数点的有理数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isFloat(value: string): boolean {\n return FLOAT_RE.test(value);\n}\n\n/**\n * 判断字符串是否为正确数值,包括整数和浮点数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isNumerical(value: string): boolean {\n return isInteger(value) || isFloat(value);\n}\n\nconst DIGIT_RE = /^\\d+$/;\n/**\n * 判断字符串是否为数字,例如六位数字短信验证码(093031)\n * @param {string} value\n * @returns {boolean}\n */\nexport function isDigit(value: string): boolean {\n return DIGIT_RE.test(value);\n}\n"],"mappings":";;AAAA,IAAM,YAAY;;;;;;;;;;;AAYlB,SAAgB,aAAa,QAAwB;CACnD,OAAO,OAAO,QAAQ,WAAW,OAAO;;AAI1C,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM;;AAI7B,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM;;AAsB7B,IAAM,UACJ;;;;;;AAMF,SAAgB,OAAO,OAAwB;CAG7C,IAAI,CAFiB,QAAQ,KAAK,MAE7B,EAAc,OAAO;CAE1B,MAAM,OAAO,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC;CACvC,MAAM,QAAQ,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;CACzC,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;CACxC,MAAM,IAAI,IAAI,KAAK,MAAM,QAAQ,GAAG,KAAK;CAGzC,IAAI,EAFe,EAAE,aAAa,KAAK,QAAQ,EAAE,UAAU,GAAG,MAAM,SAAS,EAAE,SAAS,KAAK,OAE5E,OAAO;CASxB,MAAM,kBAAkB;EAAC;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;EAAE;CAC7E,MAAM,cAAc;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAI;CAC3E,IAAI,MAAM;CAEV,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAC9B,OAAO,OAAO,MAAM,MAAM,OAAO,QAAQ,EAAE,CAAC,GAAG,gBAAgB;CAGjE,OAAO,YAAY,MAAM,QAAQ,MAAM,MAAM,GAAG;;AAIlD,IAAM,SAAS;;;;;;AAMf,SAAgB,MAAM,OAAwB;CAC5C,OAAO,OAAO,KAAK,MAAM;;AAI3B,IAAM,UAAU;;;;;;AAMhB,SAAgB,OAAO,OAAwB;CAC7C,OAAO,QAAQ,KAAK,MAAM;;AAG5B,IAAM,aAAa;;;;;;AAMnB,SAAgB,UAAU,OAAwB;CAChD,OAAO,WAAW,KAAK,MAAM;;AAG/B,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM;;;;;;;AAQ7B,SAAgB,YAAY,OAAwB;CAClD,OAAO,UAAU,MAAM,IAAI,QAAQ,MAAM;;AAG3C,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM"}
1
+ {"version":3,"file":"regexp.cjs","names":[],"sources":["../src/regexp.ts"],"sourcesContent":["const specialRE = /[.*+?^=!:${}()|[\\]/\\\\-]/g;\n\n/**\n * 编码处理正则表达式\n * @example\n * ```js\n * reEscape('/$')\n * // => '\\\\/\\\\$'\n * ```\n * @param {string} string\n * @returns {string}\n */\nexport function regexpEscape(string: string): string {\n return string.replace(specialRE, '\\\\$&');\n}\n\n// 邮箱\nconst EMAIL_RE = /^\\w+[-+.\\w]*@([a-z\\d-]+\\.)+[a-z]{2,5}$/i;\n/**\n * 判断字符串是否为邮箱格式,不对邮箱真实性做验证,如域名是否正确等\n * @param {string} value\n * @returns {boolean}\n */\nexport function isEmail(value: string): boolean {\n return EMAIL_RE.test(value);\n}\n\n// 手机号码\nconst PHONE_RE = /^1\\d{10}$/;\n/**\n * 判断字符串是否为宽松手机格式,即首位为 1 的 11 位数字都属于手机号\n * @param {string} value\n * @returns {boolean}\n */\nexport function isPhone(value: string): boolean {\n return PHONE_RE.test(value);\n}\n\n// 身份证号码\n// http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/\n// [\"北京市\", \"天津市\", \"河北省\", \"山西省\", \"内蒙古自治区\",\n// \"辽宁省\", \"吉林省\", \"黑龙江省\",\n// \"上海市\", \"江苏省\", \"浙江省\", \"安徽省\", \"福建省\", \"江西省\", \"山东省\",\n// \"河南省\", \"湖北省\", \"湖南省\", \"广东省\", \"广西壮族自治区\", \"海南省\",\n// \"重庆市\", \"四川省\", \"贵州省\", \"云南省\", \"西藏自治区\",\n// \"陕西省\", \"甘肃省\", \"青海省\",\"宁夏回族自治区\", \"新疆维吾尔自治区\",\n// \"台湾省\",\n// \"香港特别行政区\", \"澳门特别行政区\"]\n// [\"11\", \"12\", \"13\", \"14\", \"15\",\n// \"21\", \"22\", \"23\",\n// \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\",\n// \"41\", \"42\", \"43\", \"44\", \"45\", \"46\",\n// \"50\", \"51\", \"52\", \"53\", \"54\",\n// \"61\", \"62\", \"63\", \"64\", \"65\",\n// \"71\",\n// \"81\", \"82\"]\n// 91 国外\nconst IDNO_RE =\n /^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|7[1]|8[1-2]|9[1])\\d{4}(18|19|20)\\d{2}[01]\\d[0123]\\d{4}[\\dxX]$/;\n/**\n * 判断字符串是否为身份证号码格式\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIDNo(value: string): boolean {\n const isSameFormat = IDNO_RE.test(value);\n\n if (!isSameFormat) return false;\n\n const year = Number(value.slice(6, 10));\n const month = Number(value.slice(10, 12));\n const date = Number(value.slice(12, 14));\n const d = new Date(year, month - 1, date);\n const isSameDate = d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === date;\n\n if (!isSameDate) return false;\n\n // 将身份证号码前面的17位数分别乘以不同的系数;\n // 从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2\n // 将这17位数字和系数相乘的结果相加;\n // 用加出来和除以11,看余数是多少;\n // 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字;\n // 其分别对应的最后一位身份证的号码为1-0-X-9-8-7-6-5-4-3-2\n // 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。\n const coefficientList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];\n const residueList = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];\n let sum = 0;\n\n for (let start = 0; start < 17; start++) {\n sum += Number(value.slice(start, start + 1)) * coefficientList[start];\n }\n\n return residueList[sum % 11] === value.slice(-1);\n}\n\n// url\nconst URL_RE = /^https?:\\/\\//i;\n/**\n * 判断字符串是否为 url 格式,仅支持 http 协议,支持域名或者 ipV4\n * @param {string} value\n * @returns {boolean}\n */\nexport function isURL(value: string): boolean {\n return URL_RE.test(value);\n}\n\n// ipv4\nconst IPV4_RE = /^(?:(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$/;\n/**\n * 判断字符串是否为 IPV4 格式,不对 ip 真实性做验证\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIPV4(value: string): boolean {\n return IPV4_RE.test(value);\n}\n\nconst INTEGER_RE = /^(-?[1-9]\\d*|0)$/;\n/**\n * 判断字符串是否为整数(自然数),即 ...,-3,-2,-1,0,1,2,3,...\n * @param {string} value\n * @returns {boolean}\n */\nexport function isInteger(value: string): boolean {\n return INTEGER_RE.test(value);\n}\n\nconst FLOAT_RE = /^-?([1-9]\\d*|0)\\.\\d+$/;\n/**\n * 判断字符串是否为浮点数,即必须有小数点的有理数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isFloat(value: string): boolean {\n return FLOAT_RE.test(value);\n}\n\n/**\n * 判断字符串是否为正确数值,包括整数和浮点数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isNumerical(value: string): boolean {\n return isInteger(value) || isFloat(value);\n}\n\nconst DIGIT_RE = /^\\d+$/;\n/**\n * 判断字符串是否为数字,例如六位数字短信验证码(093031)\n * @param {string} value\n * @returns {boolean}\n */\nexport function isDigit(value: string): boolean {\n return DIGIT_RE.test(value);\n}\n"],"mappings":";;AAAA,IAAM,YAAY;;;;;;;;;;;AAYlB,SAAgB,aAAa,QAAwB;CACnD,OAAO,OAAO,QAAQ,WAAW,MAAM;AACzC;AAGA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;AAGA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;AAqBA,IAAM,UACJ;;;;;;AAMF,SAAgB,OAAO,OAAwB;CAG7C,IAAI,CAFiB,QAAQ,KAAK,KAE7B,GAAc,OAAO;CAE1B,MAAM,OAAO,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC;CACtC,MAAM,QAAQ,OAAO,MAAM,MAAM,IAAI,EAAE,CAAC;CACxC,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,EAAE,CAAC;CACvC,MAAM,IAAI,IAAI,KAAK,MAAM,QAAQ,GAAG,IAAI;CAGxC,IAAI,EAFe,EAAE,YAAY,MAAM,QAAQ,EAAE,SAAS,IAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAE5E,OAAO;CASxB,MAAM,kBAAkB;EAAC;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;CAAC;CAC5E,MAAM,cAAc;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG;CAC1E,IAAI,MAAM;CAEV,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAC9B,OAAO,OAAO,MAAM,MAAM,OAAO,QAAQ,CAAC,CAAC,IAAI,gBAAgB;CAGjE,OAAO,YAAY,MAAM,QAAQ,MAAM,MAAM,EAAE;AACjD;AAGA,IAAM,SAAS;;;;;;AAMf,SAAgB,MAAM,OAAwB;CAC5C,OAAO,OAAO,KAAK,KAAK;AAC1B;AAGA,IAAM,UAAU;;;;;;AAMhB,SAAgB,OAAO,OAAwB;CAC7C,OAAO,QAAQ,KAAK,KAAK;AAC3B;AAEA,IAAM,aAAa;;;;;;AAMnB,SAAgB,UAAU,OAAwB;CAChD,OAAO,WAAW,KAAK,KAAK;AAC9B;AAEA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;;;;;;AAOA,SAAgB,YAAY,OAAwB;CAClD,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK;AAC1C;AAEA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"regexp.mjs","names":[],"sources":["../src/regexp.ts"],"sourcesContent":["const specialRE = /[.*+?^=!:${}()|[\\]/\\\\-]/g;\n\n/**\n * 编码处理正则表达式\n * @example\n * ```js\n * reEscape('/$')\n * // => '\\\\/\\\\$'\n * ```\n * @param {string} string\n * @returns {string}\n */\nexport function regexpEscape(string: string): string {\n return string.replace(specialRE, '\\\\$&');\n}\n\n// 邮箱\nconst EMAIL_RE = /^\\w+[-+.\\w]*@([a-z\\d-]+\\.)+[a-z]{2,5}$/i;\n/**\n * 判断字符串是否为邮箱格式,不对邮箱真实性做验证,如域名是否正确等\n * @param {string} value\n * @returns {boolean}\n */\nexport function isEmail(value: string): boolean {\n return EMAIL_RE.test(value);\n}\n\n// 手机号码\nconst PHONE_RE = /^1\\d{10}$/;\n/**\n * 判断字符串是否为宽松手机格式,即首位为 1 的 11 位数字都属于手机号\n * @param {string} value\n * @returns {boolean}\n */\nexport function isPhone(value: string): boolean {\n return PHONE_RE.test(value);\n}\n\n// 身份证号码\n// http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/\n// [\"北京市\", \"天津市\", \"河北省\", \"山西省\", \"内蒙古自治区\",\n// \"辽宁省\", \"吉林省\", \"黑龙江省\",\n// \"上海市\", \"江苏省\", \"浙江省\", \"安徽省\", \"福建省\", \"江西省\", \"山东省\",\n// \"河南省\", \"湖北省\", \"湖南省\", \"广东省\", \"广西壮族自治区\", \"海南省\",\n// \"重庆市\", \"四川省\", \"贵州省\", \"云南省\", \"西藏自治区\",\n// \"陕西省\", \"甘肃省\", \"青海省\",\"宁夏回族自治区\", \"新疆维吾尔自治区\",\n// \"台湾省\",\n// \"香港特别行政区\", \"澳门特别行政区\"]\n// [\"11\", \"12\", \"13\", \"14\", \"15\",\n// \"21\", \"22\", \"23\",\n// \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\",\n// \"41\", \"42\", \"43\", \"44\", \"45\", \"46\",\n// \"50\", \"51\", \"52\", \"53\", \"54\",\n// \"61\", \"62\", \"63\", \"64\", \"65\",\n// \"71\",\n// \"81\", \"82\"]\n// 91 国外\nconst IDNO_RE =\n /^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|7[1]|8[1-2]|9[1])\\d{4}(18|19|20)\\d{2}[01]\\d[0123]\\d{4}[\\dxX]$/;\n/**\n * 判断字符串是否为身份证号码格式\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIDNo(value: string): boolean {\n const isSameFormat = IDNO_RE.test(value);\n\n if (!isSameFormat) return false;\n\n const year = Number(value.slice(6, 10));\n const month = Number(value.slice(10, 12));\n const date = Number(value.slice(12, 14));\n const d = new Date(year, month - 1, date);\n const isSameDate = d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === date;\n\n if (!isSameDate) return false;\n\n // 将身份证号码前面的17位数分别乘以不同的系数;\n // 从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2\n // 将这17位数字和系数相乘的结果相加;\n // 用加出来和除以11,看余数是多少;\n // 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字;\n // 其分别对应的最后一位身份证的号码为1-0-X-9-8-7-6-5-4-3-2\n // 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。\n const coefficientList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];\n const residueList = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];\n let sum = 0;\n\n for (let start = 0; start < 17; start++) {\n sum += Number(value.slice(start, start + 1)) * coefficientList[start];\n }\n\n return residueList[sum % 11] === value.slice(-1);\n}\n\n// url\nconst URL_RE = /^https?:\\/\\//i;\n/**\n * 判断字符串是否为 url 格式,仅支持 http 协议,支持域名或者 ipV4\n * @param {string} value\n * @returns {boolean}\n */\nexport function isURL(value: string): boolean {\n return URL_RE.test(value);\n}\n\n// ipv4\nconst IPV4_RE = /^(?:(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$/;\n/**\n * 判断字符串是否为 IPV4 格式,不对 ip 真实性做验证\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIPV4(value: string): boolean {\n return IPV4_RE.test(value);\n}\n\nconst INTEGER_RE = /^(-?[1-9]\\d*|0)$/;\n/**\n * 判断字符串是否为整数(自然数),即 ...,-3,-2,-1,0,1,2,3,...\n * @param {string} value\n * @returns {boolean}\n */\nexport function isInteger(value: string): boolean {\n return INTEGER_RE.test(value);\n}\n\nconst FLOAT_RE = /^-?([1-9]\\d*|0)\\.\\d+$/;\n/**\n * 判断字符串是否为浮点数,即必须有小数点的有理数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isFloat(value: string): boolean {\n return FLOAT_RE.test(value);\n}\n\n/**\n * 判断字符串是否为正确数值,包括整数和浮点数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isNumerical(value: string): boolean {\n return isInteger(value) || isFloat(value);\n}\n\nconst DIGIT_RE = /^\\d+$/;\n/**\n * 判断字符串是否为数字,例如六位数字短信验证码(093031)\n * @param {string} value\n * @returns {boolean}\n */\nexport function isDigit(value: string): boolean {\n return DIGIT_RE.test(value);\n}\n"],"mappings":";AAAA,IAAM,YAAY;;;;;;;;;;;AAYlB,SAAgB,aAAa,QAAwB;CACnD,OAAO,OAAO,QAAQ,WAAW,OAAO;;AAI1C,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM;;AAI7B,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM;;AAsB7B,IAAM,UACJ;;;;;;AAMF,SAAgB,OAAO,OAAwB;CAG7C,IAAI,CAFiB,QAAQ,KAAK,MAE7B,EAAc,OAAO;CAE1B,MAAM,OAAO,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC;CACvC,MAAM,QAAQ,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;CACzC,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,GAAG,CAAC;CACxC,MAAM,IAAI,IAAI,KAAK,MAAM,QAAQ,GAAG,KAAK;CAGzC,IAAI,EAFe,EAAE,aAAa,KAAK,QAAQ,EAAE,UAAU,GAAG,MAAM,SAAS,EAAE,SAAS,KAAK,OAE5E,OAAO;CASxB,MAAM,kBAAkB;EAAC;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;EAAE;CAC7E,MAAM,cAAc;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAI;CAC3E,IAAI,MAAM;CAEV,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAC9B,OAAO,OAAO,MAAM,MAAM,OAAO,QAAQ,EAAE,CAAC,GAAG,gBAAgB;CAGjE,OAAO,YAAY,MAAM,QAAQ,MAAM,MAAM,GAAG;;AAIlD,IAAM,SAAS;;;;;;AAMf,SAAgB,MAAM,OAAwB;CAC5C,OAAO,OAAO,KAAK,MAAM;;AAI3B,IAAM,UAAU;;;;;;AAMhB,SAAgB,OAAO,OAAwB;CAC7C,OAAO,QAAQ,KAAK,MAAM;;AAG5B,IAAM,aAAa;;;;;;AAMnB,SAAgB,UAAU,OAAwB;CAChD,OAAO,WAAW,KAAK,MAAM;;AAG/B,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM;;;;;;;AAQ7B,SAAgB,YAAY,OAAwB;CAClD,OAAO,UAAU,MAAM,IAAI,QAAQ,MAAM;;AAG3C,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,MAAM"}
1
+ {"version":3,"file":"regexp.mjs","names":[],"sources":["../src/regexp.ts"],"sourcesContent":["const specialRE = /[.*+?^=!:${}()|[\\]/\\\\-]/g;\n\n/**\n * 编码处理正则表达式\n * @example\n * ```js\n * reEscape('/$')\n * // => '\\\\/\\\\$'\n * ```\n * @param {string} string\n * @returns {string}\n */\nexport function regexpEscape(string: string): string {\n return string.replace(specialRE, '\\\\$&');\n}\n\n// 邮箱\nconst EMAIL_RE = /^\\w+[-+.\\w]*@([a-z\\d-]+\\.)+[a-z]{2,5}$/i;\n/**\n * 判断字符串是否为邮箱格式,不对邮箱真实性做验证,如域名是否正确等\n * @param {string} value\n * @returns {boolean}\n */\nexport function isEmail(value: string): boolean {\n return EMAIL_RE.test(value);\n}\n\n// 手机号码\nconst PHONE_RE = /^1\\d{10}$/;\n/**\n * 判断字符串是否为宽松手机格式,即首位为 1 的 11 位数字都属于手机号\n * @param {string} value\n * @returns {boolean}\n */\nexport function isPhone(value: string): boolean {\n return PHONE_RE.test(value);\n}\n\n// 身份证号码\n// http://www.stats.gov.cn/tjsj/tjbz/xzqhdm/\n// [\"北京市\", \"天津市\", \"河北省\", \"山西省\", \"内蒙古自治区\",\n// \"辽宁省\", \"吉林省\", \"黑龙江省\",\n// \"上海市\", \"江苏省\", \"浙江省\", \"安徽省\", \"福建省\", \"江西省\", \"山东省\",\n// \"河南省\", \"湖北省\", \"湖南省\", \"广东省\", \"广西壮族自治区\", \"海南省\",\n// \"重庆市\", \"四川省\", \"贵州省\", \"云南省\", \"西藏自治区\",\n// \"陕西省\", \"甘肃省\", \"青海省\",\"宁夏回族自治区\", \"新疆维吾尔自治区\",\n// \"台湾省\",\n// \"香港特别行政区\", \"澳门特别行政区\"]\n// [\"11\", \"12\", \"13\", \"14\", \"15\",\n// \"21\", \"22\", \"23\",\n// \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\",\n// \"41\", \"42\", \"43\", \"44\", \"45\", \"46\",\n// \"50\", \"51\", \"52\", \"53\", \"54\",\n// \"61\", \"62\", \"63\", \"64\", \"65\",\n// \"71\",\n// \"81\", \"82\"]\n// 91 国外\nconst IDNO_RE =\n /^(1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|7[1]|8[1-2]|9[1])\\d{4}(18|19|20)\\d{2}[01]\\d[0123]\\d{4}[\\dxX]$/;\n/**\n * 判断字符串是否为身份证号码格式\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIDNo(value: string): boolean {\n const isSameFormat = IDNO_RE.test(value);\n\n if (!isSameFormat) return false;\n\n const year = Number(value.slice(6, 10));\n const month = Number(value.slice(10, 12));\n const date = Number(value.slice(12, 14));\n const d = new Date(year, month - 1, date);\n const isSameDate = d.getFullYear() === year && d.getMonth() + 1 === month && d.getDate() === date;\n\n if (!isSameDate) return false;\n\n // 将身份证号码前面的17位数分别乘以不同的系数;\n // 从第一位到第十七位的系数分别为:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2\n // 将这17位数字和系数相乘的结果相加;\n // 用加出来和除以11,看余数是多少;\n // 余数只可能有0-1-2-3-4-5-6-7-8-9-10这11个数字;\n // 其分别对应的最后一位身份证的号码为1-0-X-9-8-7-6-5-4-3-2\n // 通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2。\n const coefficientList = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];\n const residueList = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];\n let sum = 0;\n\n for (let start = 0; start < 17; start++) {\n sum += Number(value.slice(start, start + 1)) * coefficientList[start];\n }\n\n return residueList[sum % 11] === value.slice(-1);\n}\n\n// url\nconst URL_RE = /^https?:\\/\\//i;\n/**\n * 判断字符串是否为 url 格式,仅支持 http 协议,支持域名或者 ipV4\n * @param {string} value\n * @returns {boolean}\n */\nexport function isURL(value: string): boolean {\n return URL_RE.test(value);\n}\n\n// ipv4\nconst IPV4_RE = /^(?:(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$/;\n/**\n * 判断字符串是否为 IPV4 格式,不对 ip 真实性做验证\n * @param {string} value\n * @returns {boolean}\n */\nexport function isIPV4(value: string): boolean {\n return IPV4_RE.test(value);\n}\n\nconst INTEGER_RE = /^(-?[1-9]\\d*|0)$/;\n/**\n * 判断字符串是否为整数(自然数),即 ...,-3,-2,-1,0,1,2,3,...\n * @param {string} value\n * @returns {boolean}\n */\nexport function isInteger(value: string): boolean {\n return INTEGER_RE.test(value);\n}\n\nconst FLOAT_RE = /^-?([1-9]\\d*|0)\\.\\d+$/;\n/**\n * 判断字符串是否为浮点数,即必须有小数点的有理数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isFloat(value: string): boolean {\n return FLOAT_RE.test(value);\n}\n\n/**\n * 判断字符串是否为正确数值,包括整数和浮点数\n * @param {string} value\n * @returns {boolean}\n */\nexport function isNumerical(value: string): boolean {\n return isInteger(value) || isFloat(value);\n}\n\nconst DIGIT_RE = /^\\d+$/;\n/**\n * 判断字符串是否为数字,例如六位数字短信验证码(093031)\n * @param {string} value\n * @returns {boolean}\n */\nexport function isDigit(value: string): boolean {\n return DIGIT_RE.test(value);\n}\n"],"mappings":";AAAA,IAAM,YAAY;;;;;;;;;;;AAYlB,SAAgB,aAAa,QAAwB;CACnD,OAAO,OAAO,QAAQ,WAAW,MAAM;AACzC;AAGA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;AAGA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;AAqBA,IAAM,UACJ;;;;;;AAMF,SAAgB,OAAO,OAAwB;CAG7C,IAAI,CAFiB,QAAQ,KAAK,KAE7B,GAAc,OAAO;CAE1B,MAAM,OAAO,OAAO,MAAM,MAAM,GAAG,EAAE,CAAC;CACtC,MAAM,QAAQ,OAAO,MAAM,MAAM,IAAI,EAAE,CAAC;CACxC,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,EAAE,CAAC;CACvC,MAAM,IAAI,IAAI,KAAK,MAAM,QAAQ,GAAG,IAAI;CAGxC,IAAI,EAFe,EAAE,YAAY,MAAM,QAAQ,EAAE,SAAS,IAAI,MAAM,SAAS,EAAE,QAAQ,MAAM,OAE5E,OAAO;CASxB,MAAM,kBAAkB;EAAC;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAG;EAAI;EAAG;EAAG;EAAG;CAAC;CAC5E,MAAM,cAAc;EAAC;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;EAAK;CAAG;CAC1E,IAAI,MAAM;CAEV,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAC9B,OAAO,OAAO,MAAM,MAAM,OAAO,QAAQ,CAAC,CAAC,IAAI,gBAAgB;CAGjE,OAAO,YAAY,MAAM,QAAQ,MAAM,MAAM,EAAE;AACjD;AAGA,IAAM,SAAS;;;;;;AAMf,SAAgB,MAAM,OAAwB;CAC5C,OAAO,OAAO,KAAK,KAAK;AAC1B;AAGA,IAAM,UAAU;;;;;;AAMhB,SAAgB,OAAO,OAAwB;CAC7C,OAAO,QAAQ,KAAK,KAAK;AAC3B;AAEA,IAAM,aAAa;;;;;;AAMnB,SAAgB,UAAU,OAAwB;CAChD,OAAO,WAAW,KAAK,KAAK;AAC9B;AAEA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B;;;;;;AAOA,SAAgB,YAAY,OAAwB;CAClD,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK;AAC1C;AAEA,IAAM,WAAW;;;;;;AAMjB,SAAgB,QAAQ,OAAwB;CAC9C,OAAO,SAAS,KAAK,KAAK;AAC5B"}
@@ -1 +1 @@
1
- {"version":3,"file":"string2.cjs","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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"}
1
+ {"version":3,"file":"string2.cjs","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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"}