@cloudcome/utils-core 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/async.cjs CHANGED
@@ -17,7 +17,7 @@ var __privateWrapper = (obj, member, setter, getter) => ({
17
17
  });
18
18
  var _tasks, _length, _AsyncQueue_instances, add_fn, addAndRun_fn, _startResolved, _startRejected, _startResults, _startPwr, _startLength, _running, run_fn, _stopResolved, _stopRejected, _stopLength, _stopResults, _stopPwr;
19
19
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
20
- const fn = require("./fn.cjs");
20
+ const _function = require("./function.cjs");
21
21
  class AsyncQueue {
22
22
  /**
23
23
  * 创建一个异步任务队列
@@ -209,7 +209,7 @@ function asyncShared(af, options) {
209
209
  var _a;
210
210
  (_a = options == null ? void 0 : options.onTrigger) == null ? void 0 : _a.call(options, ...inputs);
211
211
  const p = _sharedAf("trigger", ...inputs);
212
- p.catch(fn.fnNoop);
212
+ p.catch(_function.fnNoop);
213
213
  return p;
214
214
  };
215
215
  }
@@ -1 +1 @@
1
- {"version":3,"file":"async.cjs","sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './fn';\nimport type { AnyArray, AnyAsyncFunction } from './types';\n\n/**\n * 表示异步任务的类型\n * @template T - 任务返回值的类型\n */\ntype AsyncTask<T> = {\n /** 任务索引 */\n idx: number;\n /** 异步任务函数 */\n afn: () => Promise<T>;\n /** Promise 的解析器对象 */\n pwr?: PromiseWithResolvers<T>;\n};\n\n/**\n * 异步任务队列的配置选项\n */\nexport type AsyncQueueOptions = {\n /**\n * 并发限制数,0 表示无限制\n * @default 0\n */\n limit?: number;\n};\n\n/**\n * 异步任务队列,用于管理和控制异步任务的执行\n * @template T - 任务返回值的类型\n */\nexport class AsyncQueue<T> {\n #tasks: AsyncTask<T>[] = [];\n #length = 0;\n\n /**\n * 创建一个异步任务队列\n * @param asyncFns - 要执行的异步函数数组\n * @param options - 队列配置选项\n */\n constructor(\n asyncFns: Array<() => Promise<T>>,\n readonly options?: AsyncQueueOptions,\n ) {\n asyncFns.forEach((afn, idx) => {\n this.#add('push', afn);\n });\n }\n\n get length() {\n return this.#length;\n }\n\n get limit() {\n return this.options?.limit || 0;\n }\n\n #add(method: 'unshift' | 'push', afn: () => Promise<T>, pwr?: PromiseWithResolvers<T>) {\n this.#tasks[method]({\n idx: this.#length++,\n afn: afn,\n pwr: pwr,\n });\n }\n\n #addAndRun(method: 'unshift' | 'push', afn: () => Promise<T>) {\n // 明确终止了\n if (this.#stopLength >= 0) {\n throw new Error('异步队列已被终止,无法添加新的任务');\n }\n\n const pwr = Promise.withResolvers<T>();\n this.#add(method, afn, pwr);\n\n if (this.#startPwr && this.#running === 0) {\n this.#run();\n }\n\n return pwr.promise;\n }\n\n async push(afn: () => Promise<T>) {\n return this.#addAndRun('push', afn);\n }\n\n async unshift(afn: () => Promise<T>) {\n return this.#addAndRun('unshift', afn);\n }\n\n #startResolved = 0;\n #startRejected = 0;\n get startSettled() {\n return this.#startResolved === this.#startLength || this.#startRejected > 0;\n }\n\n #startResults: T[] = [];\n #startPwr: PromiseWithResolvers<T[]> | null = null;\n #startLength = 0;\n\n /**\n * 启动队列中的任务执行\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async start(): Promise<T[]> {\n if (this.#startPwr) return this.#startPwr.promise;\n\n // 固化启动时长度,便于判断 start 异步结果\n this.#startLength = this.#length;\n this.#startPwr = Promise.withResolvers<T[]>();\n\n if (this.#startLength === 0) {\n this.#startPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#startPwr.promise;\n }\n\n #running = 0;\n #run() {\n while (this.limit === 0 || this.#running < this.limit) {\n const task = this.#tasks.shift();\n\n // 无任务可执行\n if (!task) break;\n\n this.#running++;\n\n task\n .afn()\n .then((result) => {\n this.#running--;\n task.pwr?.resolve(result);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startResults[task.idx] = result;\n this.#startResolved++;\n }\n\n // 所有启动任务都已执行完毕\n if (this.#startResolved === this.#startLength) {\n this.#startPwr?.resolve(this.#startResults);\n }\n\n this.#stopResults[task.idx] = result;\n this.#stopResolved++;\n\n // 所有停止任务都已执行完毕\n if (this.#stopResolved === this.#stopLength) {\n this.#stopPwr?.resolve(this.#stopResults);\n } else {\n this.#run();\n }\n })\n .catch((reason) => {\n this.#running--;\n task.pwr?.reject(reason);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startRejected++;\n this.#startPwr?.reject(reason);\n }\n\n // 属于停止任务\n if (this.#stopLength > 0) {\n this.#stopRejected++;\n this.#stopPwr?.reject(reason);\n }\n });\n }\n }\n #stopResolved = 0;\n #stopRejected = 0;\n get stopSettled() {\n return this.#stopResolved === this.#stopLength || this.#stopRejected > 0;\n }\n\n #stopLength = -1;\n #stopResults: T[] = [];\n\n #stopPwr?: PromiseWithResolvers<T[]> | null = null;\n\n /**\n * 终止队列中的任务执行,终止队列后不再可以追加异步任务\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async stop() {\n if (this.#stopPwr) {\n return this.#stopPwr.promise;\n }\n\n this.#stopLength = this.#length;\n this.#stopPwr = Promise.withResolvers<T[]>();\n\n if (this.#stopLength === 0) {\n this.#stopPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#stopPwr.promise;\n }\n}\n\n/**\n * 使用给定的并发限制执行异步函数\n *\n * 此函数的目的是控制一组异步函数的并发执行数量,通过创建一个AsyncQueue实例来管理这些异步函数的执行\n * 它确保在任何给定时间只有最多`limit`数量的异步函数被执行,以避免潜在的性能问题或资源竞争\n *\n * @param asyncFns 一个包含异步函数的数组,每个异步函数都不需要参数,并返回一个Promise\n * @param limit 并发限制的数量,表示同时执行的异步函数的最大数量,0 表示不限制\n * @returns 返回一个Promise,当所有异步函数都执行完毕后,该Promise将被解析\n */\nexport function asyncLimit<T>(asyncFns: Array<() => Promise<T>>, limit: number) {\n const aq = new AsyncQueue<T>(asyncFns, { limit });\n return aq.start();\n}\n\n/**\n * 异步共享函数的配置选项\n */\nexport type AsyncSharedOptions<I extends AnyArray, O> = {\n /**\n * 是否在调用结束后再执行(只在运行期间有再次调用时才会生效)\n * @type {boolean}\n * @default false\n * @example\n * const sharedFn = asyncShared(fetchData, { trailing: true });\n * // 如果在 fetchData 执行期间多次调用 sharedFn,则会在 fetchData 结束后再次执行\n */\n trailing?: boolean;\n\n /**\n * 缓存结果的最大有效期(毫秒)\n * @type {number}\n * @example\n * const sharedFn = asyncShared(fetchData, { maxAge: 1000 });\n * // 在 1 秒内调用 sharedFn 会直接返回缓存结果\n */\n maxAge?: number;\n\n /**\n * 在调用共享函数时触发的回调函数\n * @param inputs - 传递给共享函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onTrigger: (...args) => console.log('Calling with:', args)\n * };\n */\n onTrigger?: (...inputs: I) => unknown;\n\n /**\n * 在执行异步函数时触发的回调函数\n * @param args - 传递给异步函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onExecute: (...args) => console.log('Executing with:', args)\n * };\n */\n onExecute?: (...args: I) => unknown;\n\n /**\n * 在异步函数成功执行后触发的回调函数\n * @param output - 异步函数的返回结果\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onSuccess: (result) => console.log('Success:', result)\n * };\n */\n onSuccess?: (output: O) => unknown;\n\n /**\n * 在异步函数执行失败时触发的回调函数\n * @param error - 异步函数抛出的错误\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onError: (error) => console.error('Error:', error)\n * };\n */\n onError?: (error: unknown) => unknown;\n\n /**\n * 在异步函数执行完成(无论成功或失败)时触发的回调函数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onFinally: () => console.log('Execution completed')\n * };\n */\n onFinally?: () => unknown;\n};\n\n/**\n * 创建一个共享执行结果的异步函数\n * @template F - 异步函数类型\n * @param {F} af - 要共享的异步函数\n * @param {AsyncSharedOptions} [options] - 配置选项\n * @returns {F} 返回一个新的异步函数,该函数会共享执行结果\n * @example\n * const fetchData = async (id) => {\n * // 模拟异步操作\n * return await fetch(`/api/data/${id}`);\n * };\n *\n * const sharedFetch = asyncShared(fetchData, { maxAge: 1000 });\n *\n * // 多次调用会共享同一个请求\n * const result1 = await sharedFetch(1);\n * const result2 = await sharedFetch(1); // 上次请求完成后 1000ms 内直接返回缓存结果\n */\nexport function asyncShared<I extends AnyArray, O>(\n af: (...inputs: I) => Promise<O>,\n options?: AsyncSharedOptions<I, O>,\n) {\n let executedPromise: Promise<O> | undefined;\n let executing = false;\n let executingInputs: I | undefined;\n let executedTime = 0;\n\n const _sharedAf = async (from: 'trigger' | 'trailing', ...inputs: I) => {\n executingInputs = inputs;\n\n // 如果正在运行,则复用运行结果\n if (executing && executedPromise) {\n return executedPromise;\n }\n\n // 如果已运行结束空闲时,判断是否在等待时间内\n if (executedPromise && Date.now() - executedTime < (options?.maxAge || 0)) {\n return executedPromise;\n }\n\n // 否则直接执行\n executing = true;\n options?.onExecute?.(...executingInputs);\n executedPromise = af(...executingInputs);\n executingInputs = undefined;\n executedPromise\n .then((res) => {\n options?.onSuccess?.(res);\n })\n .catch((err) => {\n options?.onError?.(err);\n })\n .finally(() => {\n executing = false;\n executedTime = Date.now();\n options?.onFinally?.();\n\n // 执行期间多次调用,则重新执行\n if (executingInputs && options?.trailing) {\n _sharedAf('trailing', ...executingInputs);\n }\n });\n\n return executedPromise;\n };\n\n return function sharedAf(...inputs: I): Promise<O> {\n options?.onTrigger?.(...inputs);\n const p = _sharedAf('trigger', ...inputs);\n // 必须捕获错误,否则单测错误边界时会抛错\n p.catch(fnNoop);\n return p;\n };\n}\n\n// const af1 = asyncShared(async () => {\n// return 1;\n// });\n// const n = await af1();\n\n// const af2 = asyncShared(async (a: number) => {\n// return a + 1;\n// });\n// const n2 = await af2(2);\n"],"names":["_a","fnNoop"],"mappings":"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"}
1
+ {"version":3,"file":"async.cjs","sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './function';\nimport type { AnyArray, AnyAsyncFunction } from './types';\n\n/**\n * 表示异步任务的类型\n * @template T - 任务返回值的类型\n */\ntype AsyncTask<T> = {\n /** 任务索引 */\n idx: number;\n /** 异步任务函数 */\n afn: () => Promise<T>;\n /** Promise 的解析器对象 */\n pwr?: PromiseWithResolvers<T>;\n};\n\n/**\n * 异步任务队列的配置选项\n */\nexport type AsyncQueueOptions = {\n /**\n * 并发限制数,0 表示无限制\n * @default 0\n */\n limit?: number;\n};\n\n/**\n * 异步任务队列,用于管理和控制异步任务的执行\n * @template T - 任务返回值的类型\n */\nexport class AsyncQueue<T> {\n #tasks: AsyncTask<T>[] = [];\n #length = 0;\n\n /**\n * 创建一个异步任务队列\n * @param asyncFns - 要执行的异步函数数组\n * @param options - 队列配置选项\n */\n constructor(\n asyncFns: Array<() => Promise<T>>,\n readonly options?: AsyncQueueOptions,\n ) {\n asyncFns.forEach((afn, idx) => {\n this.#add('push', afn);\n });\n }\n\n get length() {\n return this.#length;\n }\n\n get limit() {\n return this.options?.limit || 0;\n }\n\n #add(method: 'unshift' | 'push', afn: () => Promise<T>, pwr?: PromiseWithResolvers<T>) {\n this.#tasks[method]({\n idx: this.#length++,\n afn: afn,\n pwr: pwr,\n });\n }\n\n #addAndRun(method: 'unshift' | 'push', afn: () => Promise<T>) {\n // 明确终止了\n if (this.#stopLength >= 0) {\n throw new Error('异步队列已被终止,无法添加新的任务');\n }\n\n const pwr = Promise.withResolvers<T>();\n this.#add(method, afn, pwr);\n\n if (this.#startPwr && this.#running === 0) {\n this.#run();\n }\n\n return pwr.promise;\n }\n\n async push(afn: () => Promise<T>) {\n return this.#addAndRun('push', afn);\n }\n\n async unshift(afn: () => Promise<T>) {\n return this.#addAndRun('unshift', afn);\n }\n\n #startResolved = 0;\n #startRejected = 0;\n get startSettled() {\n return this.#startResolved === this.#startLength || this.#startRejected > 0;\n }\n\n #startResults: T[] = [];\n #startPwr: PromiseWithResolvers<T[]> | null = null;\n #startLength = 0;\n\n /**\n * 启动队列中的任务执行\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async start(): Promise<T[]> {\n if (this.#startPwr) return this.#startPwr.promise;\n\n // 固化启动时长度,便于判断 start 异步结果\n this.#startLength = this.#length;\n this.#startPwr = Promise.withResolvers<T[]>();\n\n if (this.#startLength === 0) {\n this.#startPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#startPwr.promise;\n }\n\n #running = 0;\n #run() {\n while (this.limit === 0 || this.#running < this.limit) {\n const task = this.#tasks.shift();\n\n // 无任务可执行\n if (!task) break;\n\n this.#running++;\n\n task\n .afn()\n .then((result) => {\n this.#running--;\n task.pwr?.resolve(result);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startResults[task.idx] = result;\n this.#startResolved++;\n }\n\n // 所有启动任务都已执行完毕\n if (this.#startResolved === this.#startLength) {\n this.#startPwr?.resolve(this.#startResults);\n }\n\n this.#stopResults[task.idx] = result;\n this.#stopResolved++;\n\n // 所有停止任务都已执行完毕\n if (this.#stopResolved === this.#stopLength) {\n this.#stopPwr?.resolve(this.#stopResults);\n } else {\n this.#run();\n }\n })\n .catch((reason) => {\n this.#running--;\n task.pwr?.reject(reason);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startRejected++;\n this.#startPwr?.reject(reason);\n }\n\n // 属于停止任务\n if (this.#stopLength > 0) {\n this.#stopRejected++;\n this.#stopPwr?.reject(reason);\n }\n });\n }\n }\n #stopResolved = 0;\n #stopRejected = 0;\n get stopSettled() {\n return this.#stopResolved === this.#stopLength || this.#stopRejected > 0;\n }\n\n #stopLength = -1;\n #stopResults: T[] = [];\n\n #stopPwr?: PromiseWithResolvers<T[]> | null = null;\n\n /**\n * 终止队列中的任务执行,终止队列后不再可以追加异步任务\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async stop() {\n if (this.#stopPwr) {\n return this.#stopPwr.promise;\n }\n\n this.#stopLength = this.#length;\n this.#stopPwr = Promise.withResolvers<T[]>();\n\n if (this.#stopLength === 0) {\n this.#stopPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#stopPwr.promise;\n }\n}\n\n/**\n * 使用给定的并发限制执行异步函数\n *\n * 此函数的目的是控制一组异步函数的并发执行数量,通过创建一个AsyncQueue实例来管理这些异步函数的执行\n * 它确保在任何给定时间只有最多`limit`数量的异步函数被执行,以避免潜在的性能问题或资源竞争\n *\n * @param asyncFns 一个包含异步函数的数组,每个异步函数都不需要参数,并返回一个Promise\n * @param limit 并发限制的数量,表示同时执行的异步函数的最大数量,0 表示不限制\n * @returns 返回一个Promise,当所有异步函数都执行完毕后,该Promise将被解析\n */\nexport function asyncLimit<T>(asyncFns: Array<() => Promise<T>>, limit: number) {\n const aq = new AsyncQueue<T>(asyncFns, { limit });\n return aq.start();\n}\n\n/**\n * 异步共享函数的配置选项\n */\nexport type AsyncSharedOptions<I extends AnyArray, O> = {\n /**\n * 是否在调用结束后再执行(只在运行期间有再次调用时才会生效)\n * @type {boolean}\n * @default false\n * @example\n * const sharedFn = asyncShared(fetchData, { trailing: true });\n * // 如果在 fetchData 执行期间多次调用 sharedFn,则会在 fetchData 结束后再次执行\n */\n trailing?: boolean;\n\n /**\n * 缓存结果的最大有效期(毫秒)\n * @type {number}\n * @example\n * const sharedFn = asyncShared(fetchData, { maxAge: 1000 });\n * // 在 1 秒内调用 sharedFn 会直接返回缓存结果\n */\n maxAge?: number;\n\n /**\n * 在调用共享函数时触发的回调函数\n * @param inputs - 传递给共享函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onTrigger: (...args) => console.log('Calling with:', args)\n * };\n */\n onTrigger?: (...inputs: I) => unknown;\n\n /**\n * 在执行异步函数时触发的回调函数\n * @param args - 传递给异步函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onExecute: (...args) => console.log('Executing with:', args)\n * };\n */\n onExecute?: (...args: I) => unknown;\n\n /**\n * 在异步函数成功执行后触发的回调函数\n * @param output - 异步函数的返回结果\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onSuccess: (result) => console.log('Success:', result)\n * };\n */\n onSuccess?: (output: O) => unknown;\n\n /**\n * 在异步函数执行失败时触发的回调函数\n * @param error - 异步函数抛出的错误\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onError: (error) => console.error('Error:', error)\n * };\n */\n onError?: (error: unknown) => unknown;\n\n /**\n * 在异步函数执行完成(无论成功或失败)时触发的回调函数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onFinally: () => console.log('Execution completed')\n * };\n */\n onFinally?: () => unknown;\n};\n\n/**\n * 创建一个共享执行结果的异步函数\n * @template F - 异步函数类型\n * @param {F} af - 要共享的异步函数\n * @param {AsyncSharedOptions} [options] - 配置选项\n * @returns {F} 返回一个新的异步函数,该函数会共享执行结果\n * @example\n * const fetchData = async (id) => {\n * // 模拟异步操作\n * return await fetch(`/api/data/${id}`);\n * };\n *\n * const sharedFetch = asyncShared(fetchData, { maxAge: 1000 });\n *\n * // 多次调用会共享同一个请求\n * const result1 = await sharedFetch(1);\n * const result2 = await sharedFetch(1); // 上次请求完成后 1000ms 内直接返回缓存结果\n */\nexport function asyncShared<I extends AnyArray, O>(\n af: (...inputs: I) => Promise<O>,\n options?: AsyncSharedOptions<I, O>,\n) {\n let executedPromise: Promise<O> | undefined;\n let executing = false;\n let executingInputs: I | undefined;\n let executedTime = 0;\n\n const _sharedAf = async (from: 'trigger' | 'trailing', ...inputs: I) => {\n executingInputs = inputs;\n\n // 如果正在运行,则复用运行结果\n if (executing && executedPromise) {\n return executedPromise;\n }\n\n // 如果已运行结束空闲时,判断是否在等待时间内\n if (executedPromise && Date.now() - executedTime < (options?.maxAge || 0)) {\n return executedPromise;\n }\n\n // 否则直接执行\n executing = true;\n options?.onExecute?.(...executingInputs);\n executedPromise = af(...executingInputs);\n executingInputs = undefined;\n executedPromise\n .then((res) => {\n options?.onSuccess?.(res);\n })\n .catch((err) => {\n options?.onError?.(err);\n })\n .finally(() => {\n executing = false;\n executedTime = Date.now();\n options?.onFinally?.();\n\n // 执行期间多次调用,则重新执行\n if (executingInputs && options?.trailing) {\n _sharedAf('trailing', ...executingInputs);\n }\n });\n\n return executedPromise;\n };\n\n return function sharedAf(...inputs: I): Promise<O> {\n options?.onTrigger?.(...inputs);\n const p = _sharedAf('trigger', ...inputs);\n // 必须捕获错误,否则单测错误边界时会抛错\n p.catch(fnNoop);\n return p;\n };\n}\n\n// const af1 = asyncShared(async () => {\n// return 1;\n// });\n// const n = await af1();\n\n// const af2 = asyncShared(async (a: number) => {\n// return a + 1;\n// });\n// const n2 = await af2(2);\n"],"names":["_a","fnNoop"],"mappings":"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"}
package/dist/async.mjs CHANGED
@@ -15,7 +15,7 @@ var __privateWrapper = (obj, member, setter, getter) => ({
15
15
  }
16
16
  });
17
17
  var _tasks, _length, _AsyncQueue_instances, add_fn, addAndRun_fn, _startResolved, _startRejected, _startResults, _startPwr, _startLength, _running, run_fn, _stopResolved, _stopRejected, _stopLength, _stopResults, _stopPwr;
18
- import { fnNoop } from "./fn.mjs";
18
+ import { fnNoop } from "./function.mjs";
19
19
  class AsyncQueue {
20
20
  /**
21
21
  * 创建一个异步任务队列
@@ -1 +1 @@
1
- {"version":3,"file":"async.mjs","sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './fn';\nimport type { AnyArray, AnyAsyncFunction } from './types';\n\n/**\n * 表示异步任务的类型\n * @template T - 任务返回值的类型\n */\ntype AsyncTask<T> = {\n /** 任务索引 */\n idx: number;\n /** 异步任务函数 */\n afn: () => Promise<T>;\n /** Promise 的解析器对象 */\n pwr?: PromiseWithResolvers<T>;\n};\n\n/**\n * 异步任务队列的配置选项\n */\nexport type AsyncQueueOptions = {\n /**\n * 并发限制数,0 表示无限制\n * @default 0\n */\n limit?: number;\n};\n\n/**\n * 异步任务队列,用于管理和控制异步任务的执行\n * @template T - 任务返回值的类型\n */\nexport class AsyncQueue<T> {\n #tasks: AsyncTask<T>[] = [];\n #length = 0;\n\n /**\n * 创建一个异步任务队列\n * @param asyncFns - 要执行的异步函数数组\n * @param options - 队列配置选项\n */\n constructor(\n asyncFns: Array<() => Promise<T>>,\n readonly options?: AsyncQueueOptions,\n ) {\n asyncFns.forEach((afn, idx) => {\n this.#add('push', afn);\n });\n }\n\n get length() {\n return this.#length;\n }\n\n get limit() {\n return this.options?.limit || 0;\n }\n\n #add(method: 'unshift' | 'push', afn: () => Promise<T>, pwr?: PromiseWithResolvers<T>) {\n this.#tasks[method]({\n idx: this.#length++,\n afn: afn,\n pwr: pwr,\n });\n }\n\n #addAndRun(method: 'unshift' | 'push', afn: () => Promise<T>) {\n // 明确终止了\n if (this.#stopLength >= 0) {\n throw new Error('异步队列已被终止,无法添加新的任务');\n }\n\n const pwr = Promise.withResolvers<T>();\n this.#add(method, afn, pwr);\n\n if (this.#startPwr && this.#running === 0) {\n this.#run();\n }\n\n return pwr.promise;\n }\n\n async push(afn: () => Promise<T>) {\n return this.#addAndRun('push', afn);\n }\n\n async unshift(afn: () => Promise<T>) {\n return this.#addAndRun('unshift', afn);\n }\n\n #startResolved = 0;\n #startRejected = 0;\n get startSettled() {\n return this.#startResolved === this.#startLength || this.#startRejected > 0;\n }\n\n #startResults: T[] = [];\n #startPwr: PromiseWithResolvers<T[]> | null = null;\n #startLength = 0;\n\n /**\n * 启动队列中的任务执行\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async start(): Promise<T[]> {\n if (this.#startPwr) return this.#startPwr.promise;\n\n // 固化启动时长度,便于判断 start 异步结果\n this.#startLength = this.#length;\n this.#startPwr = Promise.withResolvers<T[]>();\n\n if (this.#startLength === 0) {\n this.#startPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#startPwr.promise;\n }\n\n #running = 0;\n #run() {\n while (this.limit === 0 || this.#running < this.limit) {\n const task = this.#tasks.shift();\n\n // 无任务可执行\n if (!task) break;\n\n this.#running++;\n\n task\n .afn()\n .then((result) => {\n this.#running--;\n task.pwr?.resolve(result);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startResults[task.idx] = result;\n this.#startResolved++;\n }\n\n // 所有启动任务都已执行完毕\n if (this.#startResolved === this.#startLength) {\n this.#startPwr?.resolve(this.#startResults);\n }\n\n this.#stopResults[task.idx] = result;\n this.#stopResolved++;\n\n // 所有停止任务都已执行完毕\n if (this.#stopResolved === this.#stopLength) {\n this.#stopPwr?.resolve(this.#stopResults);\n } else {\n this.#run();\n }\n })\n .catch((reason) => {\n this.#running--;\n task.pwr?.reject(reason);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startRejected++;\n this.#startPwr?.reject(reason);\n }\n\n // 属于停止任务\n if (this.#stopLength > 0) {\n this.#stopRejected++;\n this.#stopPwr?.reject(reason);\n }\n });\n }\n }\n #stopResolved = 0;\n #stopRejected = 0;\n get stopSettled() {\n return this.#stopResolved === this.#stopLength || this.#stopRejected > 0;\n }\n\n #stopLength = -1;\n #stopResults: T[] = [];\n\n #stopPwr?: PromiseWithResolvers<T[]> | null = null;\n\n /**\n * 终止队列中的任务执行,终止队列后不再可以追加异步任务\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async stop() {\n if (this.#stopPwr) {\n return this.#stopPwr.promise;\n }\n\n this.#stopLength = this.#length;\n this.#stopPwr = Promise.withResolvers<T[]>();\n\n if (this.#stopLength === 0) {\n this.#stopPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#stopPwr.promise;\n }\n}\n\n/**\n * 使用给定的并发限制执行异步函数\n *\n * 此函数的目的是控制一组异步函数的并发执行数量,通过创建一个AsyncQueue实例来管理这些异步函数的执行\n * 它确保在任何给定时间只有最多`limit`数量的异步函数被执行,以避免潜在的性能问题或资源竞争\n *\n * @param asyncFns 一个包含异步函数的数组,每个异步函数都不需要参数,并返回一个Promise\n * @param limit 并发限制的数量,表示同时执行的异步函数的最大数量,0 表示不限制\n * @returns 返回一个Promise,当所有异步函数都执行完毕后,该Promise将被解析\n */\nexport function asyncLimit<T>(asyncFns: Array<() => Promise<T>>, limit: number) {\n const aq = new AsyncQueue<T>(asyncFns, { limit });\n return aq.start();\n}\n\n/**\n * 异步共享函数的配置选项\n */\nexport type AsyncSharedOptions<I extends AnyArray, O> = {\n /**\n * 是否在调用结束后再执行(只在运行期间有再次调用时才会生效)\n * @type {boolean}\n * @default false\n * @example\n * const sharedFn = asyncShared(fetchData, { trailing: true });\n * // 如果在 fetchData 执行期间多次调用 sharedFn,则会在 fetchData 结束后再次执行\n */\n trailing?: boolean;\n\n /**\n * 缓存结果的最大有效期(毫秒)\n * @type {number}\n * @example\n * const sharedFn = asyncShared(fetchData, { maxAge: 1000 });\n * // 在 1 秒内调用 sharedFn 会直接返回缓存结果\n */\n maxAge?: number;\n\n /**\n * 在调用共享函数时触发的回调函数\n * @param inputs - 传递给共享函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onTrigger: (...args) => console.log('Calling with:', args)\n * };\n */\n onTrigger?: (...inputs: I) => unknown;\n\n /**\n * 在执行异步函数时触发的回调函数\n * @param args - 传递给异步函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onExecute: (...args) => console.log('Executing with:', args)\n * };\n */\n onExecute?: (...args: I) => unknown;\n\n /**\n * 在异步函数成功执行后触发的回调函数\n * @param output - 异步函数的返回结果\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onSuccess: (result) => console.log('Success:', result)\n * };\n */\n onSuccess?: (output: O) => unknown;\n\n /**\n * 在异步函数执行失败时触发的回调函数\n * @param error - 异步函数抛出的错误\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onError: (error) => console.error('Error:', error)\n * };\n */\n onError?: (error: unknown) => unknown;\n\n /**\n * 在异步函数执行完成(无论成功或失败)时触发的回调函数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onFinally: () => console.log('Execution completed')\n * };\n */\n onFinally?: () => unknown;\n};\n\n/**\n * 创建一个共享执行结果的异步函数\n * @template F - 异步函数类型\n * @param {F} af - 要共享的异步函数\n * @param {AsyncSharedOptions} [options] - 配置选项\n * @returns {F} 返回一个新的异步函数,该函数会共享执行结果\n * @example\n * const fetchData = async (id) => {\n * // 模拟异步操作\n * return await fetch(`/api/data/${id}`);\n * };\n *\n * const sharedFetch = asyncShared(fetchData, { maxAge: 1000 });\n *\n * // 多次调用会共享同一个请求\n * const result1 = await sharedFetch(1);\n * const result2 = await sharedFetch(1); // 上次请求完成后 1000ms 内直接返回缓存结果\n */\nexport function asyncShared<I extends AnyArray, O>(\n af: (...inputs: I) => Promise<O>,\n options?: AsyncSharedOptions<I, O>,\n) {\n let executedPromise: Promise<O> | undefined;\n let executing = false;\n let executingInputs: I | undefined;\n let executedTime = 0;\n\n const _sharedAf = async (from: 'trigger' | 'trailing', ...inputs: I) => {\n executingInputs = inputs;\n\n // 如果正在运行,则复用运行结果\n if (executing && executedPromise) {\n return executedPromise;\n }\n\n // 如果已运行结束空闲时,判断是否在等待时间内\n if (executedPromise && Date.now() - executedTime < (options?.maxAge || 0)) {\n return executedPromise;\n }\n\n // 否则直接执行\n executing = true;\n options?.onExecute?.(...executingInputs);\n executedPromise = af(...executingInputs);\n executingInputs = undefined;\n executedPromise\n .then((res) => {\n options?.onSuccess?.(res);\n })\n .catch((err) => {\n options?.onError?.(err);\n })\n .finally(() => {\n executing = false;\n executedTime = Date.now();\n options?.onFinally?.();\n\n // 执行期间多次调用,则重新执行\n if (executingInputs && options?.trailing) {\n _sharedAf('trailing', ...executingInputs);\n }\n });\n\n return executedPromise;\n };\n\n return function sharedAf(...inputs: I): Promise<O> {\n options?.onTrigger?.(...inputs);\n const p = _sharedAf('trigger', ...inputs);\n // 必须捕获错误,否则单测错误边界时会抛错\n p.catch(fnNoop);\n return p;\n };\n}\n\n// const af1 = asyncShared(async () => {\n// return 1;\n// });\n// const n = await af1();\n\n// const af2 = asyncShared(async (a: number) => {\n// return a + 1;\n// });\n// const n2 = await af2(2);\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"async.mjs","sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './function';\nimport type { AnyArray, AnyAsyncFunction } from './types';\n\n/**\n * 表示异步任务的类型\n * @template T - 任务返回值的类型\n */\ntype AsyncTask<T> = {\n /** 任务索引 */\n idx: number;\n /** 异步任务函数 */\n afn: () => Promise<T>;\n /** Promise 的解析器对象 */\n pwr?: PromiseWithResolvers<T>;\n};\n\n/**\n * 异步任务队列的配置选项\n */\nexport type AsyncQueueOptions = {\n /**\n * 并发限制数,0 表示无限制\n * @default 0\n */\n limit?: number;\n};\n\n/**\n * 异步任务队列,用于管理和控制异步任务的执行\n * @template T - 任务返回值的类型\n */\nexport class AsyncQueue<T> {\n #tasks: AsyncTask<T>[] = [];\n #length = 0;\n\n /**\n * 创建一个异步任务队列\n * @param asyncFns - 要执行的异步函数数组\n * @param options - 队列配置选项\n */\n constructor(\n asyncFns: Array<() => Promise<T>>,\n readonly options?: AsyncQueueOptions,\n ) {\n asyncFns.forEach((afn, idx) => {\n this.#add('push', afn);\n });\n }\n\n get length() {\n return this.#length;\n }\n\n get limit() {\n return this.options?.limit || 0;\n }\n\n #add(method: 'unshift' | 'push', afn: () => Promise<T>, pwr?: PromiseWithResolvers<T>) {\n this.#tasks[method]({\n idx: this.#length++,\n afn: afn,\n pwr: pwr,\n });\n }\n\n #addAndRun(method: 'unshift' | 'push', afn: () => Promise<T>) {\n // 明确终止了\n if (this.#stopLength >= 0) {\n throw new Error('异步队列已被终止,无法添加新的任务');\n }\n\n const pwr = Promise.withResolvers<T>();\n this.#add(method, afn, pwr);\n\n if (this.#startPwr && this.#running === 0) {\n this.#run();\n }\n\n return pwr.promise;\n }\n\n async push(afn: () => Promise<T>) {\n return this.#addAndRun('push', afn);\n }\n\n async unshift(afn: () => Promise<T>) {\n return this.#addAndRun('unshift', afn);\n }\n\n #startResolved = 0;\n #startRejected = 0;\n get startSettled() {\n return this.#startResolved === this.#startLength || this.#startRejected > 0;\n }\n\n #startResults: T[] = [];\n #startPwr: PromiseWithResolvers<T[]> | null = null;\n #startLength = 0;\n\n /**\n * 启动队列中的任务执行\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async start(): Promise<T[]> {\n if (this.#startPwr) return this.#startPwr.promise;\n\n // 固化启动时长度,便于判断 start 异步结果\n this.#startLength = this.#length;\n this.#startPwr = Promise.withResolvers<T[]>();\n\n if (this.#startLength === 0) {\n this.#startPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#startPwr.promise;\n }\n\n #running = 0;\n #run() {\n while (this.limit === 0 || this.#running < this.limit) {\n const task = this.#tasks.shift();\n\n // 无任务可执行\n if (!task) break;\n\n this.#running++;\n\n task\n .afn()\n .then((result) => {\n this.#running--;\n task.pwr?.resolve(result);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startResults[task.idx] = result;\n this.#startResolved++;\n }\n\n // 所有启动任务都已执行完毕\n if (this.#startResolved === this.#startLength) {\n this.#startPwr?.resolve(this.#startResults);\n }\n\n this.#stopResults[task.idx] = result;\n this.#stopResolved++;\n\n // 所有停止任务都已执行完毕\n if (this.#stopResolved === this.#stopLength) {\n this.#stopPwr?.resolve(this.#stopResults);\n } else {\n this.#run();\n }\n })\n .catch((reason) => {\n this.#running--;\n task.pwr?.reject(reason);\n\n // 属于启动任务\n if (task.idx < this.#startLength) {\n this.#startRejected++;\n this.#startPwr?.reject(reason);\n }\n\n // 属于停止任务\n if (this.#stopLength > 0) {\n this.#stopRejected++;\n this.#stopPwr?.reject(reason);\n }\n });\n }\n }\n #stopResolved = 0;\n #stopRejected = 0;\n get stopSettled() {\n return this.#stopResolved === this.#stopLength || this.#stopRejected > 0;\n }\n\n #stopLength = -1;\n #stopResults: T[] = [];\n\n #stopPwr?: PromiseWithResolvers<T[]> | null = null;\n\n /**\n * 终止队列中的任务执行,终止队列后不再可以追加异步任务\n * @returns 返回一个 Promise,在所有启动任务完成后解析为结果数组\n */\n async stop() {\n if (this.#stopPwr) {\n return this.#stopPwr.promise;\n }\n\n this.#stopLength = this.#length;\n this.#stopPwr = Promise.withResolvers<T[]>();\n\n if (this.#stopLength === 0) {\n this.#stopPwr.resolve([]);\n } else {\n this.#run();\n }\n\n return this.#stopPwr.promise;\n }\n}\n\n/**\n * 使用给定的并发限制执行异步函数\n *\n * 此函数的目的是控制一组异步函数的并发执行数量,通过创建一个AsyncQueue实例来管理这些异步函数的执行\n * 它确保在任何给定时间只有最多`limit`数量的异步函数被执行,以避免潜在的性能问题或资源竞争\n *\n * @param asyncFns 一个包含异步函数的数组,每个异步函数都不需要参数,并返回一个Promise\n * @param limit 并发限制的数量,表示同时执行的异步函数的最大数量,0 表示不限制\n * @returns 返回一个Promise,当所有异步函数都执行完毕后,该Promise将被解析\n */\nexport function asyncLimit<T>(asyncFns: Array<() => Promise<T>>, limit: number) {\n const aq = new AsyncQueue<T>(asyncFns, { limit });\n return aq.start();\n}\n\n/**\n * 异步共享函数的配置选项\n */\nexport type AsyncSharedOptions<I extends AnyArray, O> = {\n /**\n * 是否在调用结束后再执行(只在运行期间有再次调用时才会生效)\n * @type {boolean}\n * @default false\n * @example\n * const sharedFn = asyncShared(fetchData, { trailing: true });\n * // 如果在 fetchData 执行期间多次调用 sharedFn,则会在 fetchData 结束后再次执行\n */\n trailing?: boolean;\n\n /**\n * 缓存结果的最大有效期(毫秒)\n * @type {number}\n * @example\n * const sharedFn = asyncShared(fetchData, { maxAge: 1000 });\n * // 在 1 秒内调用 sharedFn 会直接返回缓存结果\n */\n maxAge?: number;\n\n /**\n * 在调用共享函数时触发的回调函数\n * @param inputs - 传递给共享函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onTrigger: (...args) => console.log('Calling with:', args)\n * };\n */\n onTrigger?: (...inputs: I) => unknown;\n\n /**\n * 在执行异步函数时触发的回调函数\n * @param args - 传递给异步函数的参数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onExecute: (...args) => console.log('Executing with:', args)\n * };\n */\n onExecute?: (...args: I) => unknown;\n\n /**\n * 在异步函数成功执行后触发的回调函数\n * @param output - 异步函数的返回结果\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onSuccess: (result) => console.log('Success:', result)\n * };\n */\n onSuccess?: (output: O) => unknown;\n\n /**\n * 在异步函数执行失败时触发的回调函数\n * @param error - 异步函数抛出的错误\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onError: (error) => console.error('Error:', error)\n * };\n */\n onError?: (error: unknown) => unknown;\n\n /**\n * 在异步函数执行完成(无论成功或失败)时触发的回调函数\n * @example\n * const options: AsyncSharedOptions<typeof fetchData> = {\n * onFinally: () => console.log('Execution completed')\n * };\n */\n onFinally?: () => unknown;\n};\n\n/**\n * 创建一个共享执行结果的异步函数\n * @template F - 异步函数类型\n * @param {F} af - 要共享的异步函数\n * @param {AsyncSharedOptions} [options] - 配置选项\n * @returns {F} 返回一个新的异步函数,该函数会共享执行结果\n * @example\n * const fetchData = async (id) => {\n * // 模拟异步操作\n * return await fetch(`/api/data/${id}`);\n * };\n *\n * const sharedFetch = asyncShared(fetchData, { maxAge: 1000 });\n *\n * // 多次调用会共享同一个请求\n * const result1 = await sharedFetch(1);\n * const result2 = await sharedFetch(1); // 上次请求完成后 1000ms 内直接返回缓存结果\n */\nexport function asyncShared<I extends AnyArray, O>(\n af: (...inputs: I) => Promise<O>,\n options?: AsyncSharedOptions<I, O>,\n) {\n let executedPromise: Promise<O> | undefined;\n let executing = false;\n let executingInputs: I | undefined;\n let executedTime = 0;\n\n const _sharedAf = async (from: 'trigger' | 'trailing', ...inputs: I) => {\n executingInputs = inputs;\n\n // 如果正在运行,则复用运行结果\n if (executing && executedPromise) {\n return executedPromise;\n }\n\n // 如果已运行结束空闲时,判断是否在等待时间内\n if (executedPromise && Date.now() - executedTime < (options?.maxAge || 0)) {\n return executedPromise;\n }\n\n // 否则直接执行\n executing = true;\n options?.onExecute?.(...executingInputs);\n executedPromise = af(...executingInputs);\n executingInputs = undefined;\n executedPromise\n .then((res) => {\n options?.onSuccess?.(res);\n })\n .catch((err) => {\n options?.onError?.(err);\n })\n .finally(() => {\n executing = false;\n executedTime = Date.now();\n options?.onFinally?.();\n\n // 执行期间多次调用,则重新执行\n if (executingInputs && options?.trailing) {\n _sharedAf('trailing', ...executingInputs);\n }\n });\n\n return executedPromise;\n };\n\n return function sharedAf(...inputs: I): Promise<O> {\n options?.onTrigger?.(...inputs);\n const p = _sharedAf('trigger', ...inputs);\n // 必须捕获错误,否则单测错误边界时会抛错\n p.catch(fnNoop);\n return p;\n };\n}\n\n// const af1 = asyncShared(async () => {\n// return 1;\n// });\n// const n = await af1();\n\n// const af2 = asyncShared(async (a: number) => {\n// return a + 1;\n// });\n// const n2 = await af2(2);\n"],"names":["_a"],"mappings":"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"}
@@ -73,4 +73,4 @@ exports.fnDebounce = fnDebounce;
73
73
  exports.fnNoop = fnNoop;
74
74
  exports.fnOnce = fnOnce;
75
75
  exports.fnThrottle = fnThrottle;
76
- //# sourceMappingURL=fn.cjs.map
76
+ //# sourceMappingURL=function.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function.cjs","sources":["../src/function.ts"],"sourcesContent":["import { isNumber } from './type';\nimport type { AnyFunction } from './types';\n\n/**\n * 一个空操作函数,不执行任何操作。\n *\n * @example\n * ```typescript\n * fnNoop(); // 不执行任何操作\n * ```\n */\nexport function fnNoop() {\n //\n}\n\n/**\n * 防抖函数的配置选项。\n */\nexport type DebounceOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n /**\n * 是否在等待开始时立即执行一次\n * @default false\n */\n leading?: boolean;\n};\n\n/**\n * 创建一个防抖函数,该函数会在指定的等待时间后执行,如果在等待时间内再次调用,则重新计时。\n *\n * @param fn - 需要防抖的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait` 和 `leading` 选项的对象。\n * @returns 返回一个防抖函数,该函数具有 `cancel` 方法,用于取消防抖操作。\n *\n * @example\n * ```typescript\n * const debouncedFn = fnDebounce(() => {\n * console.log('Debounced!');\n * }, 100);\n *\n * debouncedFn(); // 不会立即执行\n * debouncedFn(); // 重新计时\n * debouncedFn.cancel(); // 取消防抖操作\n * ```\n */\nexport function fnDebounce<F extends AnyFunction>(fn: F, wait: number | DebounceOptions) {\n const options: DebounceOptions = isNumber(wait) ? { wait } : wait;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n let leading = false;\n\n const debounced = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n // 第一次执行\n if (options.leading && !leading) {\n leading = true;\n fn.apply(this, args);\n return;\n }\n\n // 最后一次执行\n clearTimeout(timer);\n timer = setTimeout(() => {\n if (canceled) return;\n\n fn.apply(this, args);\n }, options.wait);\n };\n\n debounced.cancel = () => {\n clearTimeout(timer);\n canceled = true;\n };\n\n return debounced;\n}\n\nexport type ThrottleOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n\n /**\n * 是否在第一次调用时立即执行\n * @default false\n */\n leading?: boolean;\n\n /**\n * 是否在调用结束后等待一段时间再执行\n * @default false\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个节流函数,该函数会在指定的等待时间内最多执行一次,如果在等待时间内再次调用,则忽略后续调用。\n *\n * @param fn - 需要节流的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait`、`leading` 和 `trailing` 选项的对象。\n * @returns 返回一个节流函数,该函数具有 `cancel` 方法,用于取消节流操作。\n *\n * @example\n * ```typescript\n * const throttledFn = fnThrottle(() => {\n * console.log('Throttled!');\n * }, 100);\n *\n * throttledFn(); // 立即执行\n * throttledFn(); // 忽略\n * throttledFn.cancel(); // 取消节流操作\n * ```\n */\nexport function fnThrottle<F extends AnyFunction>(fn: F, wait: number | ThrottleOptions) {\n const options = isNumber(wait) ? { wait } : wait;\n const waitFinal = options.wait;\n let lastTime = 0;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n\n const throttled = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n const now = Date.now();\n\n // 第一次执行\n if (options.leading && lastTime === 0) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 中间控频执行\n else if (lastTime > 0 && now - lastTime >= waitFinal) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 首次计时\n else if (lastTime === 0) {\n lastTime = now;\n }\n\n // 最后一次执行\n if (options.trailing) {\n clearTimeout(timer);\n timer = setTimeout(() => {\n fn.apply(this, args);\n }, waitFinal);\n }\n };\n\n throttled.cancel = () => {\n canceled = true;\n clearTimeout(timer);\n };\n\n return throttled;\n}\n\n/**\n * 创建一个只执行一次的函数,无论调用多少次,实际执行的函数体也只会执行一次。\n *\n * @param fn - 需要只执行一次的函数。\n * @returns 返回一个只执行一次的函数,该函数在第一次调用后会缓存结果并返回缓存的结果。\n *\n * @example\n * ```typescript\n * const onceFn = fnOnce(() => {\n * console.log('This will be logged only once.');\n * return 42;\n * });\n *\n * console.log(onceFn()); // 输出: This will be logged only once. 42\n * console.log(onceFn()); // 输出: 42\n * ```\n */\nexport function fnOnce<F extends AnyFunction>(fn: F) {\n let called = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let result: any;\n\n return function (this: unknown, ...args: Parameters<F>) {\n if (!called) {\n called = true;\n result = fn.apply(this, args);\n }\n\n return result;\n };\n}\n"],"names":["isNumber"],"mappings":";;;AAWO,SAAS,SAAS;AAEzB;AAmCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAA2BA,KAAAA,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC7D,MAAI,WAAW;AAEX,MAAA;AACJ,MAAI,UAAU;AAER,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAGV,QAAA,QAAQ,WAAW,CAAC,SAAS;AACrB,gBAAA;AACP,SAAA,MAAM,MAAM,IAAI;AACnB;AAAA,IAAA;AAIF,iBAAa,KAAK;AAClB,YAAQ,WAAW,MAAM;AACvB,UAAI,SAAU;AAEX,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,GAClB,QAAQ,IAAI;AAAA,EACjB;AAEA,YAAU,SAAS,MAAM;AACvB,iBAAa,KAAK;AACP,eAAA;AAAA,EACb;AAEO,SAAA;AACT;AAuCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAAUA,KAAAA,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC5C,QAAM,YAAY,QAAQ;AAC1B,MAAI,WAAW;AACf,MAAI,WAAW;AAEX,MAAA;AAEE,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAER,UAAA,MAAM,KAAK,IAAI;AAGjB,QAAA,QAAQ,WAAW,aAAa,GAAG;AAC1B,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAIZ,WAAA,WAAW,KAAK,MAAM,YAAY,WAAW;AACzC,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,WAIZ,aAAa,GAAG;AACZ,iBAAA;AAAA,IAAA;AAIb,QAAI,QAAQ,UAAU;AACpB,mBAAa,KAAK;AAClB,cAAQ,WAAW,MAAM;AACpB,WAAA,MAAM,MAAM,IAAI;AAAA,SAClB,SAAS;AAAA,IAAA;AAAA,EAEhB;AAEA,YAAU,SAAS,MAAM;AACZ,eAAA;AACX,iBAAa,KAAK;AAAA,EACpB;AAEO,SAAA;AACT;AAmBO,SAAS,OAA8B,IAAO;AACnD,MAAI,SAAS;AAET,MAAA;AAEJ,SAAO,YAA4B,MAAqB;AACtD,QAAI,CAAC,QAAQ;AACF,eAAA;AACA,eAAA,GAAG,MAAM,MAAM,IAAI;AAAA,IAAA;AAGvB,WAAA;AAAA,EACT;AACF;;;;;"}
@@ -73,4 +73,4 @@ export {
73
73
  fnOnce,
74
74
  fnThrottle
75
75
  };
76
- //# sourceMappingURL=fn.mjs.map
76
+ //# sourceMappingURL=function.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"function.mjs","sources":["../src/function.ts"],"sourcesContent":["import { isNumber } from './type';\nimport type { AnyFunction } from './types';\n\n/**\n * 一个空操作函数,不执行任何操作。\n *\n * @example\n * ```typescript\n * fnNoop(); // 不执行任何操作\n * ```\n */\nexport function fnNoop() {\n //\n}\n\n/**\n * 防抖函数的配置选项。\n */\nexport type DebounceOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n /**\n * 是否在等待开始时立即执行一次\n * @default false\n */\n leading?: boolean;\n};\n\n/**\n * 创建一个防抖函数,该函数会在指定的等待时间后执行,如果在等待时间内再次调用,则重新计时。\n *\n * @param fn - 需要防抖的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait` 和 `leading` 选项的对象。\n * @returns 返回一个防抖函数,该函数具有 `cancel` 方法,用于取消防抖操作。\n *\n * @example\n * ```typescript\n * const debouncedFn = fnDebounce(() => {\n * console.log('Debounced!');\n * }, 100);\n *\n * debouncedFn(); // 不会立即执行\n * debouncedFn(); // 重新计时\n * debouncedFn.cancel(); // 取消防抖操作\n * ```\n */\nexport function fnDebounce<F extends AnyFunction>(fn: F, wait: number | DebounceOptions) {\n const options: DebounceOptions = isNumber(wait) ? { wait } : wait;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n let leading = false;\n\n const debounced = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n // 第一次执行\n if (options.leading && !leading) {\n leading = true;\n fn.apply(this, args);\n return;\n }\n\n // 最后一次执行\n clearTimeout(timer);\n timer = setTimeout(() => {\n if (canceled) return;\n\n fn.apply(this, args);\n }, options.wait);\n };\n\n debounced.cancel = () => {\n clearTimeout(timer);\n canceled = true;\n };\n\n return debounced;\n}\n\nexport type ThrottleOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n\n /**\n * 是否在第一次调用时立即执行\n * @default false\n */\n leading?: boolean;\n\n /**\n * 是否在调用结束后等待一段时间再执行\n * @default false\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个节流函数,该函数会在指定的等待时间内最多执行一次,如果在等待时间内再次调用,则忽略后续调用。\n *\n * @param fn - 需要节流的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait`、`leading` 和 `trailing` 选项的对象。\n * @returns 返回一个节流函数,该函数具有 `cancel` 方法,用于取消节流操作。\n *\n * @example\n * ```typescript\n * const throttledFn = fnThrottle(() => {\n * console.log('Throttled!');\n * }, 100);\n *\n * throttledFn(); // 立即执行\n * throttledFn(); // 忽略\n * throttledFn.cancel(); // 取消节流操作\n * ```\n */\nexport function fnThrottle<F extends AnyFunction>(fn: F, wait: number | ThrottleOptions) {\n const options = isNumber(wait) ? { wait } : wait;\n const waitFinal = options.wait;\n let lastTime = 0;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n\n const throttled = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n const now = Date.now();\n\n // 第一次执行\n if (options.leading && lastTime === 0) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 中间控频执行\n else if (lastTime > 0 && now - lastTime >= waitFinal) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 首次计时\n else if (lastTime === 0) {\n lastTime = now;\n }\n\n // 最后一次执行\n if (options.trailing) {\n clearTimeout(timer);\n timer = setTimeout(() => {\n fn.apply(this, args);\n }, waitFinal);\n }\n };\n\n throttled.cancel = () => {\n canceled = true;\n clearTimeout(timer);\n };\n\n return throttled;\n}\n\n/**\n * 创建一个只执行一次的函数,无论调用多少次,实际执行的函数体也只会执行一次。\n *\n * @param fn - 需要只执行一次的函数。\n * @returns 返回一个只执行一次的函数,该函数在第一次调用后会缓存结果并返回缓存的结果。\n *\n * @example\n * ```typescript\n * const onceFn = fnOnce(() => {\n * console.log('This will be logged only once.');\n * return 42;\n * });\n *\n * console.log(onceFn()); // 输出: This will be logged only once. 42\n * console.log(onceFn()); // 输出: 42\n * ```\n */\nexport function fnOnce<F extends AnyFunction>(fn: F) {\n let called = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let result: any;\n\n return function (this: unknown, ...args: Parameters<F>) {\n if (!called) {\n called = true;\n result = fn.apply(this, args);\n }\n\n return result;\n };\n}\n"],"names":[],"mappings":";AAWO,SAAS,SAAS;AAEzB;AAmCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAA2B,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC7D,MAAI,WAAW;AAEX,MAAA;AACJ,MAAI,UAAU;AAER,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAGV,QAAA,QAAQ,WAAW,CAAC,SAAS;AACrB,gBAAA;AACP,SAAA,MAAM,MAAM,IAAI;AACnB;AAAA,IAAA;AAIF,iBAAa,KAAK;AAClB,YAAQ,WAAW,MAAM;AACvB,UAAI,SAAU;AAEX,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,GAClB,QAAQ,IAAI;AAAA,EACjB;AAEA,YAAU,SAAS,MAAM;AACvB,iBAAa,KAAK;AACP,eAAA;AAAA,EACb;AAEO,SAAA;AACT;AAuCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAAU,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC5C,QAAM,YAAY,QAAQ;AAC1B,MAAI,WAAW;AACf,MAAI,WAAW;AAEX,MAAA;AAEE,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAER,UAAA,MAAM,KAAK,IAAI;AAGjB,QAAA,QAAQ,WAAW,aAAa,GAAG;AAC1B,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAIZ,WAAA,WAAW,KAAK,MAAM,YAAY,WAAW;AACzC,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,WAIZ,aAAa,GAAG;AACZ,iBAAA;AAAA,IAAA;AAIb,QAAI,QAAQ,UAAU;AACpB,mBAAa,KAAK;AAClB,cAAQ,WAAW,MAAM;AACpB,WAAA,MAAM,MAAM,IAAI;AAAA,SAClB,SAAS;AAAA,IAAA;AAAA,EAEhB;AAEA,YAAU,SAAS,MAAM;AACZ,eAAA;AACX,iBAAa,KAAK;AAAA,EACpB;AAEO,SAAA;AACT;AAmBO,SAAS,OAA8B,IAAO;AACnD,MAAI,SAAS;AAET,MAAA;AAEJ,SAAO,YAA4B,MAAqB;AACtD,QAAI,CAAC,QAAQ;AACF,eAAA;AACA,eAAA,GAAG,MAAM,MAAM,IAAI;AAAA,IAAA;AAGvB,WAAA;AAAA,EACT;AACF;"}
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const VERSION = "1.5.0";
3
+ const VERSION = "1.6.0";
4
4
  exports.VERSION = VERSION;
5
5
  //# sourceMappingURL=index.cjs.map
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "1.5.0";
1
+ const VERSION = "1.6.0";
2
2
  export {
3
3
  VERSION
4
4
  };
@@ -44,4 +44,4 @@ function qsStringify(qsObject, stringify = defaultWriter) {
44
44
  }
45
45
  exports.qsParse = qsParse;
46
46
  exports.qsStringify = qsStringify;
47
- //# sourceMappingURL=qs.cjs.map
47
+ //# sourceMappingURL=query.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.cjs","sources":["../src/query.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNull, isNullish, isNumber, isString, isUndefined } 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"],"names":["isNullish","isArray","isString","isNumber","isBoolean","isDate","objectEach"],"mappings":";;;;AAoCgB,SAAA,QAA6B,aAAqB,QAAyB;AAGnF,QAAA,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,EAAE,CAAC;AAC1E,QAAM,WAAW,CAAC;AAElB,aAAW,CAAC,KAAK,GAAG,KAAK,GAAG,WAAW;AACrC,UAAM,WAAW,SAAS,OAAO,KAAK,KAAK,QAAQ,IAAI;AAEnD,QAAAA,KAAAA,UAAU,QAAQ,EAAG;AAEzB,QAAI,OAAO,OAAO,UAAU,GAAG,GAAG;AAEhC,UAAI,CAACC,KAAA,QAAQ,SAAS,GAAG,CAAC,EAAY,UAAA,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC;AAC1D,eAAS,GAAG,EAAgB,KAAK,GAAG;AAAA,IAAA,OAChC;AAEL,eAAS,GAAG,IAAI;AAAA,IAAA;AAAA,EAClB;AAGK,SAAA;AACT;AAiBA,MAAM,gBAAqC,CAAC,QAAiB;AACvD,MAAAC,KAAA,SAAS,GAAG,EAAU,QAAA;AAC1B,MAAIC,KAAS,SAAA,GAAG,EAAG,QAAO,OAAO,GAAG;AACpC,MAAIC,KAAU,UAAA,GAAG,EAAG,QAAO,MAAM,SAAS;AAC1C,MAAIC,KAAO,OAAA,GAAG,EAAG,QAAO,IAAI,YAAY;AACjC,SAAA;AACT;AAegB,SAAA,YAAiC,UAAa,YAAyB,eAAuB;AAGtG,QAAA,KAAK,IAAI,WAAW,gBAAgB;AACpC,QAAA,YAAY,CAAC,KAAc,QAAgB;AAC/C,UAAM,WAAW,UAAU,KAAK,OAAO,GAAG,GAAG,QAAQ;AACjD,QAAAL,KAAAA,UAAU,QAAQ,EAAG;AAEtB,OAAA,OAAO,KAAK,QAAQ;AAAA,EACzB;AAEWM,OAAAA,WAAA,UAAU,CAAC,KAAK,QAAgB;AACrC,QAAAL,KAAAA,QAAQ,GAAG,GAAG;AAChB,iBAAW,MAAM,KAAK;AACpB,kBAAU,IAAI,GAAG;AAAA,MAAA;AAAA,IACnB,OACK;AACL,gBAAU,KAAK,GAAG;AAAA,IAAA;AAAA,EACpB,CACD;AAED,SAAO,GAAG,SAAS;AACrB;;;"}
@@ -44,4 +44,4 @@ export {
44
44
  qsParse,
45
45
  qsStringify
46
46
  };
47
- //# sourceMappingURL=qs.mjs.map
47
+ //# sourceMappingURL=query.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.mjs","sources":["../src/query.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNull, isNullish, isNumber, isString, isUndefined } 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"],"names":[],"mappings":";;AAoCgB,SAAA,QAA6B,aAAqB,QAAyB;AAGnF,QAAA,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,EAAE,CAAC;AAC1E,QAAM,WAAW,CAAC;AAElB,aAAW,CAAC,KAAK,GAAG,KAAK,GAAG,WAAW;AACrC,UAAM,WAAW,SAAS,OAAO,KAAK,KAAK,QAAQ,IAAI;AAEnD,QAAA,UAAU,QAAQ,EAAG;AAEzB,QAAI,OAAO,OAAO,UAAU,GAAG,GAAG;AAEhC,UAAI,CAAC,QAAQ,SAAS,GAAG,CAAC,EAAY,UAAA,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC;AAC1D,eAAS,GAAG,EAAgB,KAAK,GAAG;AAAA,IAAA,OAChC;AAEL,eAAS,GAAG,IAAI;AAAA,IAAA;AAAA,EAClB;AAGK,SAAA;AACT;AAiBA,MAAM,gBAAqC,CAAC,QAAiB;AACvD,MAAA,SAAS,GAAG,EAAU,QAAA;AAC1B,MAAI,SAAS,GAAG,EAAG,QAAO,OAAO,GAAG;AACpC,MAAI,UAAU,GAAG,EAAG,QAAO,MAAM,SAAS;AAC1C,MAAI,OAAO,GAAG,EAAG,QAAO,IAAI,YAAY;AACjC,SAAA;AACT;AAegB,SAAA,YAAiC,UAAa,YAAyB,eAAuB;AAGtG,QAAA,KAAK,IAAI,WAAW,gBAAgB;AACpC,QAAA,YAAY,CAAC,KAAc,QAAgB;AAC/C,UAAM,WAAW,UAAU,KAAK,OAAO,GAAG,GAAG,QAAQ;AACjD,QAAA,UAAU,QAAQ,EAAG;AAEtB,OAAA,OAAO,KAAK,QAAQ;AAAA,EACzB;AAEW,aAAA,UAAU,CAAC,KAAK,QAAgB;AACrC,QAAA,QAAQ,GAAG,GAAG;AAChB,iBAAW,MAAM,KAAK;AACpB,kBAAU,IAAI,GAAG;AAAA,MAAA;AAAA,IACnB,OACK;AACL,gBAAU,KAAK,GAAG;AAAA,IAAA;AAAA,EACpB,CACD;AAED,SAAO,GAAG,SAAS;AACrB;"}
@@ -1,4 +1,4 @@
1
- import { CallbackFunction0, CallbackFunction1, CallbackFunction2, CallbackFunction3, CallbackFunction4, CallbackFunction5, CallbackFunction6 } from './callbackCurry';
1
+ import { CallbackFunction0, CallbackFunction1, CallbackFunction2, CallbackFunction3, CallbackFunction4, CallbackFunction5, CallbackFunction6 } from './curry';
2
2
  import { FlattenReturn } from './types';
3
3
  export declare function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;
4
4
  export declare function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;
@@ -0,0 +1,5 @@
1
+ import { FlattenReturn } from './types';
2
+ export type SyncFunction<T> = () => T;
3
+ export declare function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T>;
4
+ export type AsyncFunction<T> = () => Promise<T>;
5
+ export declare function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>>;
@@ -0,0 +1,7 @@
1
+ import { CallbackFunction0 } from './curry';
2
+ import { AsyncFunction, SyncFunction } from './function';
3
+ import { FlattenReturn } from './types';
4
+ export type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;
5
+ export declare function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;
6
+ export declare function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;
7
+ export declare function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;
@@ -1 +1 @@
1
- export type FlattenReturn<T = void> = readonly [Error, undefined] | readonly [null, T];
1
+ export type FlattenReturn<T = void> = readonly [Error, undefined] | readonly [undefined, T];
package/dist/try.cjs CHANGED
@@ -1,34 +1,39 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const type = require("./type.cjs");
3
4
  const error = require("./error.cjs");
4
- const pkgName = "@cloudcome/utils-core";
5
- const pkgVersion = "1.5.0";
6
5
  function callbackCurry(cf, ...args) {
7
6
  return function callbackCurried(callback) {
8
7
  cf.apply(this, [...args, callback]);
9
8
  };
10
9
  }
11
- function tryFunction(syncFn) {
12
- try {
13
- return [null, syncFn()];
14
- } catch (err) {
15
- return [error.errorNormalize(err), void 0];
16
- }
17
- }
18
10
  function tryCallback(cf, ...args) {
19
11
  return new Promise((resolve) => {
20
12
  callbackCurry.apply(this, [cf, ...args])((err, res) => {
21
13
  if (err) {
22
14
  resolve([error.errorNormalize(err), void 0]);
23
15
  } else {
24
- resolve([null, res]);
16
+ resolve([void 0, res]);
25
17
  }
26
18
  });
27
19
  });
28
20
  }
21
+ function trySync(syncFn) {
22
+ try {
23
+ return [void 0, syncFn()];
24
+ } catch (err) {
25
+ return [error.errorNormalize(err), void 0];
26
+ }
27
+ }
28
+ function tryAsync(asyncFn) {
29
+ return asyncFn().then(
30
+ (res) => [void 0, res],
31
+ (err) => [error.errorNormalize(err), void 0]
32
+ );
33
+ }
29
34
  function tryPromise(promise) {
30
35
  return promise.then(
31
- (res) => [null, res],
36
+ (res) => [void 0, res],
32
37
  (err) => [error.errorNormalize(err), void 0]
33
38
  );
34
39
  }
@@ -37,15 +42,10 @@ function tryFlatten(flattenAble) {
37
42
  return tryPromise(flattenAble);
38
43
  }
39
44
  if (flattenAble.length === 0) {
40
- return tryFunction(flattenAble);
45
+ if (type.isAsyncFunction(flattenAble)) return tryAsync(flattenAble);
46
+ return trySync(flattenAble);
41
47
  }
42
48
  return tryCallback(flattenAble);
43
49
  }
44
- exports.callbackCurry = callbackCurry;
45
- exports.pkgName = pkgName;
46
- exports.pkgVersion = pkgVersion;
47
- exports.tryCallback = tryCallback;
48
50
  exports.tryFlatten = tryFlatten;
49
- exports.tryFunction = tryFunction;
50
- exports.tryPromise = tryPromise;
51
51
  //# sourceMappingURL=try.cjs.map
package/dist/try.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"try.cjs","sources":["../src/try/const.ts","../src/try/callbackCurry.ts","../src/try/tryFunction.ts","../src/try/tryCallback.ts","../src/try/tryPromise.ts","../src/try/tryFlatten.ts"],"sourcesContent":["export const pkgName = PKG_NAME;\nexport const pkgVersion = PKG_VERSION;\n","// biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\nexport type Callback<T = void> = (err: null | undefined | void | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function tryFunction<T>(syncFn: () => T): FlattenReturn<T> {\n try {\n return [null, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './callbackCurry';\nimport { callbackCurry } from './callbackCurry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([null, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [null, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import type { CallbackFunction0 } from './callbackCurry';\nimport { tryCallback } from './tryCallback';\nimport { type SyncFunction, tryFunction } from './tryFunction';\nimport { tryPromise } from './tryPromise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n if (flattenAble.length === 0) {\n return tryFunction<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"names":["errorNormalize"],"mappings":";;;AAAO,MAAM,UAAU;AAChB,MAAM,aAAa;AC4DV,SAAA,cAAc,OAAgB,MAA2C;AAChF,SAAA,SAAS,gBAAgB,UAA6B;AAG3D,OAAG,MAAM,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC;AAAA,EACpC;AACF;AC9DO,SAAS,YAAe,QAAmC;AAC5D,MAAA;AACK,WAAA,CAAC,MAAM,QAAQ;AAAA,WACf,KAAK;AACZ,WAAO,CAACA,MAAA,eAAe,GAAG,GAAG,MAAS;AAAA,EAAA;AAE1C;ACoCgB,SAAA,YAAY,OAAgB,MAAkD;AACrF,SAAA,IAAI,QAAQ,CAAC,YAAY;AAGhB,kBAAA,MAAM,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,QAAQ;AACrD,UAAI,KAAK;AACP,gBAAQ,CAACA,MAAA,eAAe,GAAG,GAAG,MAAS,CAAU;AAAA,MAAA,OAC5C;AACG,gBAAA,CAAC,MAAM,GAAG,CAAU;AAAA,MAAA;AAAA,IAC9B,CACD;AAAA,EAAA,CACF;AACH;ACxDO,SAAS,WAAc,SAAwD;AACpF,SAAO,QAAQ;AAAA,IACb,CAAC,QAAQ,CAAC,MAAM,GAAG;AAAA,IACnB,CAAC,QAAQ,CAACA,qBAAe,GAAG,GAAG,MAAS;AAAA,EAC1C;AACF;ACEO,SAAS,WAAc,aAAsC;AAClE,MAAI,UAAU,aAAa;AACzB,WAAO,WAAc,WAAW;AAAA,EAAA;AAG9B,MAAA,YAAY,WAAW,GAAG;AAC5B,WAAO,YAAe,WAA8B;AAAA,EAAA;AAGtD,SAAO,YAAe,WAAW;AACnC;;;;;;;;"}
1
+ {"version":3,"file":"try.cjs","sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\nexport type Callback<T = void> = (err: null | undefined | void | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport { type AsyncFunction, type SyncFunction, tryAsync, trySync } from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble)) return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"names":["errorNormalize","isAsyncFunction"],"mappings":";;;;AA6DgB,SAAA,cAAc,OAAgB,MAA2C;AAChF,SAAA,SAAS,gBAAgB,UAA6B;AAG3D,OAAG,MAAM,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC;AAAA,EACpC;AACF;ACpBgB,SAAA,YAAY,OAAgB,MAAkD;AACrF,SAAA,IAAI,QAAQ,CAAC,YAAY;AAGhB,kBAAA,MAAM,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,QAAQ;AACrD,UAAI,KAAK;AACP,gBAAQ,CAACA,MAAA,eAAe,GAAG,GAAG,MAAS,CAAU;AAAA,MAAA,OAC5C;AACG,gBAAA,CAAC,QAAW,GAAG,CAAU;AAAA,MAAA;AAAA,IACnC,CACD;AAAA,EAAA,CACF;AACH;ACtDO,SAAS,QAAW,QAA2C;AAChE,MAAA;AACK,WAAA,CAAC,QAAW,QAAQ;AAAA,WACpB,KAAK;AACZ,WAAO,CAACA,MAAA,eAAe,GAAG,GAAG,MAAS;AAAA,EAAA;AAE1C;AAIO,SAAS,SAAY,SAAsD;AAChF,SAAO,QAAU,EAAA;AAAA,IACf,CAAC,QAAQ,CAAC,QAAW,GAAG;AAAA,IACxB,CAAC,QAAQ,CAACA,qBAAe,GAAG,GAAG,MAAS;AAAA,EAC1C;AACF;ACjBO,SAAS,WAAc,SAAwD;AACpF,SAAO,QAAQ;AAAA,IACb,CAAC,QAAQ,CAAC,QAAW,GAAG;AAAA,IACxB,CAAC,QAAQ,CAACA,qBAAe,GAAG,GAAG,MAAS;AAAA,EAC1C;AACF;ACMO,SAAS,WAAc,aAAsC;AAClE,MAAI,UAAU,aAAa;AACzB,WAAO,WAAc,WAAW;AAAA,EAAA;AAI9B,MAAA,YAAY,WAAW,GAAG;AAC5B,QAAIC,KAAgB,gBAAA,WAAW,EAAG,QAAO,SAAY,WAA+B;AACpF,WAAO,QAAW,WAA8B;AAAA,EAAA;AAGlD,SAAO,YAAe,WAAW;AACnC;;"}
package/dist/try.d.ts CHANGED
@@ -1 +1,2 @@
1
- export * from './try/index';
1
+ export * from './try/main';
2
+ export * from './try/types';
package/dist/try.mjs CHANGED
@@ -1,32 +1,37 @@
1
+ import { isAsyncFunction } from "./type.mjs";
1
2
  import { errorNormalize } from "./error.mjs";
2
- const pkgName = "@cloudcome/utils-core";
3
- const pkgVersion = "1.5.0";
4
3
  function callbackCurry(cf, ...args) {
5
4
  return function callbackCurried(callback) {
6
5
  cf.apply(this, [...args, callback]);
7
6
  };
8
7
  }
9
- function tryFunction(syncFn) {
10
- try {
11
- return [null, syncFn()];
12
- } catch (err) {
13
- return [errorNormalize(err), void 0];
14
- }
15
- }
16
8
  function tryCallback(cf, ...args) {
17
9
  return new Promise((resolve) => {
18
10
  callbackCurry.apply(this, [cf, ...args])((err, res) => {
19
11
  if (err) {
20
12
  resolve([errorNormalize(err), void 0]);
21
13
  } else {
22
- resolve([null, res]);
14
+ resolve([void 0, res]);
23
15
  }
24
16
  });
25
17
  });
26
18
  }
19
+ function trySync(syncFn) {
20
+ try {
21
+ return [void 0, syncFn()];
22
+ } catch (err) {
23
+ return [errorNormalize(err), void 0];
24
+ }
25
+ }
26
+ function tryAsync(asyncFn) {
27
+ return asyncFn().then(
28
+ (res) => [void 0, res],
29
+ (err) => [errorNormalize(err), void 0]
30
+ );
31
+ }
27
32
  function tryPromise(promise) {
28
33
  return promise.then(
29
- (res) => [null, res],
34
+ (res) => [void 0, res],
30
35
  (err) => [errorNormalize(err), void 0]
31
36
  );
32
37
  }
@@ -35,17 +40,12 @@ function tryFlatten(flattenAble) {
35
40
  return tryPromise(flattenAble);
36
41
  }
37
42
  if (flattenAble.length === 0) {
38
- return tryFunction(flattenAble);
43
+ if (isAsyncFunction(flattenAble)) return tryAsync(flattenAble);
44
+ return trySync(flattenAble);
39
45
  }
40
46
  return tryCallback(flattenAble);
41
47
  }
42
48
  export {
43
- callbackCurry,
44
- pkgName,
45
- pkgVersion,
46
- tryCallback,
47
- tryFlatten,
48
- tryFunction,
49
- tryPromise
49
+ tryFlatten
50
50
  };
51
51
  //# sourceMappingURL=try.mjs.map
package/dist/try.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"try.mjs","sources":["../src/try/const.ts","../src/try/callbackCurry.ts","../src/try/tryFunction.ts","../src/try/tryCallback.ts","../src/try/tryPromise.ts","../src/try/tryFlatten.ts"],"sourcesContent":["export const pkgName = PKG_NAME;\nexport const pkgVersion = PKG_VERSION;\n","// biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\nexport type Callback<T = void> = (err: null | undefined | void | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function tryFunction<T>(syncFn: () => T): FlattenReturn<T> {\n try {\n return [null, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './callbackCurry';\nimport { callbackCurry } from './callbackCurry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([null, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [null, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import type { CallbackFunction0 } from './callbackCurry';\nimport { tryCallback } from './tryCallback';\nimport { type SyncFunction, tryFunction } from './tryFunction';\nimport { tryPromise } from './tryPromise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n if (flattenAble.length === 0) {\n return tryFunction<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"names":[],"mappings":";AAAO,MAAM,UAAU;AAChB,MAAM,aAAa;AC4DV,SAAA,cAAc,OAAgB,MAA2C;AAChF,SAAA,SAAS,gBAAgB,UAA6B;AAG3D,OAAG,MAAM,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC;AAAA,EACpC;AACF;AC9DO,SAAS,YAAe,QAAmC;AAC5D,MAAA;AACK,WAAA,CAAC,MAAM,QAAQ;AAAA,WACf,KAAK;AACZ,WAAO,CAAC,eAAe,GAAG,GAAG,MAAS;AAAA,EAAA;AAE1C;ACoCgB,SAAA,YAAY,OAAgB,MAAkD;AACrF,SAAA,IAAI,QAAQ,CAAC,YAAY;AAGhB,kBAAA,MAAM,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,QAAQ;AACrD,UAAI,KAAK;AACP,gBAAQ,CAAC,eAAe,GAAG,GAAG,MAAS,CAAU;AAAA,MAAA,OAC5C;AACG,gBAAA,CAAC,MAAM,GAAG,CAAU;AAAA,MAAA;AAAA,IAC9B,CACD;AAAA,EAAA,CACF;AACH;ACxDO,SAAS,WAAc,SAAwD;AACpF,SAAO,QAAQ;AAAA,IACb,CAAC,QAAQ,CAAC,MAAM,GAAG;AAAA,IACnB,CAAC,QAAQ,CAAC,eAAe,GAAG,GAAG,MAAS;AAAA,EAC1C;AACF;ACEO,SAAS,WAAc,aAAsC;AAClE,MAAI,UAAU,aAAa;AACzB,WAAO,WAAc,WAAW;AAAA,EAAA;AAG9B,MAAA,YAAY,WAAW,GAAG;AAC5B,WAAO,YAAe,WAA8B;AAAA,EAAA;AAGtD,SAAO,YAAe,WAAW;AACnC;"}
1
+ {"version":3,"file":"try.mjs","sources":["../src/try/curry.ts","../src/try/callback.ts","../src/try/function.ts","../src/try/promise.ts","../src/try/main.ts"],"sourcesContent":["// biome-ignore lint/suspicious/noConfusingVoidType: <explanation>\nexport type Callback<T = void> = (err: null | undefined | void | Error, res: T) => unknown;\n\nexport type CallbackFunction0<T = void> = (callback: Callback<T>) => unknown;\nexport type CallbackFunction1<A, T = void> = (a: A, callback: Callback<T>) => unknown;\nexport type CallbackFunction2<A, B, T = void> = (a: A, b: B, callback: Callback<T>) => unknown;\nexport type CallbackFunction3<A, B, C, T = void> = (a: A, b: B, c: C, callback: Callback<T>) => unknown;\nexport type CallbackFunction4<A, B, C, D, T = void> = (a: A, b: B, c: C, d: D, callback: Callback<T>) => unknown;\nexport type CallbackFunction5<A, B, C, D, E, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n callback: Callback<T>,\n) => unknown;\nexport type CallbackFunction6<A, B, C, D, E, F, T = void> = (\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n callback: Callback<T>,\n) => unknown;\n\nexport type CallbackCurried<T> = (callback: Callback<T>) => unknown;\n\nexport function callbackCurry<T = void>(cf: CallbackFunction0<T>): CallbackCurried<T>;\nexport function callbackCurry<A, T = void>(cf: CallbackFunction1<A, T>, a: A): CallbackCurried<T>;\nexport function callbackCurry<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): CallbackCurried<T>;\nexport function callbackCurry<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): CallbackCurried<T>;\nexport function callbackCurry(cf: unknown, ...args: unknown[]): CallbackCurried<unknown> {\n return function callbackCurried(callback: Callback<unknown>) {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n cf.apply(this, [...args, callback]);\n };\n}\n","import { errorNormalize } from '@/error';\nimport type {\n CallbackFunction0,\n CallbackFunction1,\n CallbackFunction2,\n CallbackFunction3,\n CallbackFunction4,\n CallbackFunction5,\n CallbackFunction6,\n} from './curry';\nimport { callbackCurry } from './curry';\nimport type { FlattenReturn } from './types';\n\nexport function tryCallback(cf: CallbackFunction0): Promise<FlattenReturn>;\nexport function tryCallback<T = void>(cf: CallbackFunction0<T>): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, T = void>(cf: CallbackFunction1<A, T>, a: A): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, T = void>(cf: CallbackFunction2<A, B, T>, a: A, b: B): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, T = void>(\n cf: CallbackFunction3<A, B, C, T>,\n a: A,\n b: B,\n c: C,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, T = void>(\n cf: CallbackFunction4<A, B, C, D>,\n a: A,\n b: B,\n c: C,\n d: D,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, T = void>(\n cf: CallbackFunction5<A, B, C, D, E, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback<A, B, C, D, E, F, T = void>(\n cf: CallbackFunction6<A, B, C, D, E, F, T>,\n a: A,\n b: B,\n c: C,\n d: D,\n e: E,\n f: F,\n): Promise<FlattenReturn<T>>;\nexport function tryCallback(cf: unknown, ...args: unknown[]): Promise<FlattenReturn<unknown>> {\n return new Promise((resolve) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n callbackCurry.apply(this, [cf, ...args])((err, res) => {\n if (err) {\n resolve([errorNormalize(err), undefined] as const);\n } else {\n resolve([undefined, res] as const);\n }\n });\n });\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport type SyncFunction<T> = () => T;\n\nexport function trySync<T>(syncFn: SyncFunction<T>): FlattenReturn<T> {\n try {\n return [undefined, syncFn()] as const;\n } catch (err) {\n return [errorNormalize(err), undefined] as const;\n }\n}\n\nexport type AsyncFunction<T> = () => Promise<T>;\n\nexport function tryAsync<T>(asyncFn: AsyncFunction<T>): Promise<FlattenReturn<T>> {\n return asyncFn().then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { errorNormalize } from '@/error';\nimport type { FlattenReturn } from './types';\n\nexport function tryPromise<T>(promise: PromiseLike<T>): PromiseLike<FlattenReturn<T>> {\n return promise.then(\n (res) => [undefined, res] as const,\n (err) => [errorNormalize(err), undefined] as const,\n );\n}\n","import { isAsyncFunction } from '@/type';\nimport { tryCallback } from './callback';\nimport type { CallbackFunction0 } from './curry';\nimport { type AsyncFunction, type SyncFunction, tryAsync, trySync } from './function';\nimport { tryPromise } from './promise';\nimport type { FlattenReturn } from './types';\n\nexport type FlattenAble<T> = SyncFunction<T> | AsyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;\n\n// 注意顺序 AsyncFunction > SyncFunction > CallbackFunction0 > PromiseLike\n// 需要先匹配 AsyncFunction,否则会把入参当做同步函数\nexport function tryFlatten<T>(flattenAble: AsyncFunction<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;\nexport function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;\nexport function tryFlatten<T>(flattenAble: FlattenAble<T>): unknown {\n if ('then' in flattenAble) {\n return tryPromise<T>(flattenAble);\n }\n\n // SyncFunction | AsyncFunction\n if (flattenAble.length === 0) {\n if (isAsyncFunction(flattenAble)) return tryAsync<T>(flattenAble as AsyncFunction<T>);\n return trySync<T>(flattenAble as SyncFunction<T>);\n }\n\n return tryCallback<T>(flattenAble);\n}\n"],"names":[],"mappings":";;AA6DgB,SAAA,cAAc,OAAgB,MAA2C;AAChF,SAAA,SAAS,gBAAgB,UAA6B;AAG3D,OAAG,MAAM,MAAM,CAAC,GAAG,MAAM,QAAQ,CAAC;AAAA,EACpC;AACF;ACpBgB,SAAA,YAAY,OAAgB,MAAkD;AACrF,SAAA,IAAI,QAAQ,CAAC,YAAY;AAGhB,kBAAA,MAAM,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,QAAQ;AACrD,UAAI,KAAK;AACP,gBAAQ,CAAC,eAAe,GAAG,GAAG,MAAS,CAAU;AAAA,MAAA,OAC5C;AACG,gBAAA,CAAC,QAAW,GAAG,CAAU;AAAA,MAAA;AAAA,IACnC,CACD;AAAA,EAAA,CACF;AACH;ACtDO,SAAS,QAAW,QAA2C;AAChE,MAAA;AACK,WAAA,CAAC,QAAW,QAAQ;AAAA,WACpB,KAAK;AACZ,WAAO,CAAC,eAAe,GAAG,GAAG,MAAS;AAAA,EAAA;AAE1C;AAIO,SAAS,SAAY,SAAsD;AAChF,SAAO,QAAU,EAAA;AAAA,IACf,CAAC,QAAQ,CAAC,QAAW,GAAG;AAAA,IACxB,CAAC,QAAQ,CAAC,eAAe,GAAG,GAAG,MAAS;AAAA,EAC1C;AACF;ACjBO,SAAS,WAAc,SAAwD;AACpF,SAAO,QAAQ;AAAA,IACb,CAAC,QAAQ,CAAC,QAAW,GAAG;AAAA,IACxB,CAAC,QAAQ,CAAC,eAAe,GAAG,GAAG,MAAS;AAAA,EAC1C;AACF;ACMO,SAAS,WAAc,aAAsC;AAClE,MAAI,UAAU,aAAa;AACzB,WAAO,WAAc,WAAW;AAAA,EAAA;AAI9B,MAAA,YAAY,WAAW,GAAG;AAC5B,QAAI,gBAAgB,WAAW,EAAG,QAAO,SAAY,WAA+B;AACpF,WAAO,QAAW,WAA8B;AAAA,EAAA;AAGlD,SAAO,YAAe,WAAW;AACnC;"}
package/dist/types.d.ts CHANGED
@@ -54,4 +54,12 @@ export type UnionToTuple<U, Last = _UnionLast<U>> = [U] extends [never] ? [] : [
54
54
  export type MergeIntersection<A> = A extends infer T ? {
55
55
  [Key in keyof T]: T[Key];
56
56
  } : never;
57
+ /**
58
+ * 以小写字母开头的字符串类型
59
+ */
60
+ export type LowercaseStartString = `${'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'}${string}`;
61
+ /**
62
+ * 以大写字母开头的字符串类型
63
+ */
64
+ export type UppercaseStartString = `${'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'}${string}`;
57
65
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcome/utils-core",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "cloudcome core utils",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -84,10 +84,10 @@
84
84
  "import": "./dist/exception.mjs",
85
85
  "require": "./dist/exception.cjs"
86
86
  },
87
- "./fn": {
88
- "types": "./dist/fn.d.ts",
89
- "import": "./dist/fn.mjs",
90
- "require": "./dist/fn.cjs"
87
+ "./function": {
88
+ "types": "./dist/function.d.ts",
89
+ "import": "./dist/function.mjs",
90
+ "require": "./dist/function.cjs"
91
91
  },
92
92
  "./number": {
93
93
  "types": "./dist/number.d.ts",
@@ -109,10 +109,10 @@
109
109
  "import": "./dist/promise.mjs",
110
110
  "require": "./dist/promise.cjs"
111
111
  },
112
- "./qs": {
113
- "types": "./dist/qs.d.ts",
114
- "import": "./dist/qs.mjs",
115
- "require": "./dist/qs.cjs"
112
+ "./query": {
113
+ "types": "./dist/query.d.ts",
114
+ "import": "./dist/query.mjs",
115
+ "require": "./dist/query.cjs"
116
116
  },
117
117
  "./regexp": {
118
118
  "types": "./dist/regexp.d.ts",
@@ -214,8 +214,8 @@
214
214
  "exception": [
215
215
  "./dist/exception.d.ts"
216
216
  ],
217
- "fn": [
218
- "./dist/fn.d.ts"
217
+ "function": [
218
+ "./dist/function.d.ts"
219
219
  ],
220
220
  "number": [
221
221
  "./dist/number.d.ts"
@@ -229,8 +229,8 @@
229
229
  "promise": [
230
230
  "./dist/promise.d.ts"
231
231
  ],
232
- "qs": [
233
- "./dist/qs.d.ts"
232
+ "query": [
233
+ "./dist/query.d.ts"
234
234
  ],
235
235
  "regexp": [
236
236
  "./dist/regexp.d.ts"
package/dist/fn.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"fn.cjs","sources":["../src/fn.ts"],"sourcesContent":["import { isNumber } from './type';\nimport type { AnyFunction } from './types';\n\n/**\n * 一个空操作函数,不执行任何操作。\n *\n * @example\n * ```typescript\n * fnNoop(); // 不执行任何操作\n * ```\n */\nexport function fnNoop() {\n //\n}\n\n/**\n * 防抖函数的配置选项。\n */\nexport type DebounceOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n /**\n * 是否在等待开始时立即执行一次\n * @default false\n */\n leading?: boolean;\n};\n\n/**\n * 创建一个防抖函数,该函数会在指定的等待时间后执行,如果在等待时间内再次调用,则重新计时。\n *\n * @param fn - 需要防抖的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait` 和 `leading` 选项的对象。\n * @returns 返回一个防抖函数,该函数具有 `cancel` 方法,用于取消防抖操作。\n *\n * @example\n * ```typescript\n * const debouncedFn = fnDebounce(() => {\n * console.log('Debounced!');\n * }, 100);\n *\n * debouncedFn(); // 不会立即执行\n * debouncedFn(); // 重新计时\n * debouncedFn.cancel(); // 取消防抖操作\n * ```\n */\nexport function fnDebounce<F extends AnyFunction>(fn: F, wait: number | DebounceOptions) {\n const options: DebounceOptions = isNumber(wait) ? { wait } : wait;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n let leading = false;\n\n const debounced = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n // 第一次执行\n if (options.leading && !leading) {\n leading = true;\n fn.apply(this, args);\n return;\n }\n\n // 最后一次执行\n clearTimeout(timer);\n timer = setTimeout(() => {\n if (canceled) return;\n\n fn.apply(this, args);\n }, options.wait);\n };\n\n debounced.cancel = () => {\n clearTimeout(timer);\n canceled = true;\n };\n\n return debounced;\n}\n\nexport type ThrottleOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n\n /**\n * 是否在第一次调用时立即执行\n * @default false\n */\n leading?: boolean;\n\n /**\n * 是否在调用结束后等待一段时间再执行\n * @default false\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个节流函数,该函数会在指定的等待时间内最多执行一次,如果在等待时间内再次调用,则忽略后续调用。\n *\n * @param fn - 需要节流的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait`、`leading` 和 `trailing` 选项的对象。\n * @returns 返回一个节流函数,该函数具有 `cancel` 方法,用于取消节流操作。\n *\n * @example\n * ```typescript\n * const throttledFn = fnThrottle(() => {\n * console.log('Throttled!');\n * }, 100);\n *\n * throttledFn(); // 立即执行\n * throttledFn(); // 忽略\n * throttledFn.cancel(); // 取消节流操作\n * ```\n */\nexport function fnThrottle<F extends AnyFunction>(fn: F, wait: number | ThrottleOptions) {\n const options = isNumber(wait) ? { wait } : wait;\n const waitFinal = options.wait;\n let lastTime = 0;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n\n const throttled = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n const now = Date.now();\n\n // 第一次执行\n if (options.leading && lastTime === 0) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 中间控频执行\n else if (lastTime > 0 && now - lastTime >= waitFinal) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 首次计时\n else if (lastTime === 0) {\n lastTime = now;\n }\n\n // 最后一次执行\n if (options.trailing) {\n clearTimeout(timer);\n timer = setTimeout(() => {\n fn.apply(this, args);\n }, waitFinal);\n }\n };\n\n throttled.cancel = () => {\n canceled = true;\n clearTimeout(timer);\n };\n\n return throttled;\n}\n\n/**\n * 创建一个只执行一次的函数,无论调用多少次,实际执行的函数体也只会执行一次。\n *\n * @param fn - 需要只执行一次的函数。\n * @returns 返回一个只执行一次的函数,该函数在第一次调用后会缓存结果并返回缓存的结果。\n *\n * @example\n * ```typescript\n * const onceFn = fnOnce(() => {\n * console.log('This will be logged only once.');\n * return 42;\n * });\n *\n * console.log(onceFn()); // 输出: This will be logged only once. 42\n * console.log(onceFn()); // 输出: 42\n * ```\n */\nexport function fnOnce<F extends AnyFunction>(fn: F) {\n let called = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let result: any;\n\n return function (this: unknown, ...args: Parameters<F>) {\n if (!called) {\n called = true;\n result = fn.apply(this, args);\n }\n\n return result;\n };\n}\n"],"names":["isNumber"],"mappings":";;;AAWO,SAAS,SAAS;AAEzB;AAmCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAA2BA,KAAAA,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC7D,MAAI,WAAW;AAEX,MAAA;AACJ,MAAI,UAAU;AAER,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAGV,QAAA,QAAQ,WAAW,CAAC,SAAS;AACrB,gBAAA;AACP,SAAA,MAAM,MAAM,IAAI;AACnB;AAAA,IAAA;AAIF,iBAAa,KAAK;AAClB,YAAQ,WAAW,MAAM;AACvB,UAAI,SAAU;AAEX,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,GAClB,QAAQ,IAAI;AAAA,EACjB;AAEA,YAAU,SAAS,MAAM;AACvB,iBAAa,KAAK;AACP,eAAA;AAAA,EACb;AAEO,SAAA;AACT;AAuCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAAUA,KAAAA,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC5C,QAAM,YAAY,QAAQ;AAC1B,MAAI,WAAW;AACf,MAAI,WAAW;AAEX,MAAA;AAEE,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAER,UAAA,MAAM,KAAK,IAAI;AAGjB,QAAA,QAAQ,WAAW,aAAa,GAAG;AAC1B,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAIZ,WAAA,WAAW,KAAK,MAAM,YAAY,WAAW;AACzC,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,WAIZ,aAAa,GAAG;AACZ,iBAAA;AAAA,IAAA;AAIb,QAAI,QAAQ,UAAU;AACpB,mBAAa,KAAK;AAClB,cAAQ,WAAW,MAAM;AACpB,WAAA,MAAM,MAAM,IAAI;AAAA,SAClB,SAAS;AAAA,IAAA;AAAA,EAEhB;AAEA,YAAU,SAAS,MAAM;AACZ,eAAA;AACX,iBAAa,KAAK;AAAA,EACpB;AAEO,SAAA;AACT;AAmBO,SAAS,OAA8B,IAAO;AACnD,MAAI,SAAS;AAET,MAAA;AAEJ,SAAO,YAA4B,MAAqB;AACtD,QAAI,CAAC,QAAQ;AACF,eAAA;AACA,eAAA,GAAG,MAAM,MAAM,IAAI;AAAA,IAAA;AAGvB,WAAA;AAAA,EACT;AACF;;;;;"}
package/dist/fn.mjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"fn.mjs","sources":["../src/fn.ts"],"sourcesContent":["import { isNumber } from './type';\nimport type { AnyFunction } from './types';\n\n/**\n * 一个空操作函数,不执行任何操作。\n *\n * @example\n * ```typescript\n * fnNoop(); // 不执行任何操作\n * ```\n */\nexport function fnNoop() {\n //\n}\n\n/**\n * 防抖函数的配置选项。\n */\nexport type DebounceOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n /**\n * 是否在等待开始时立即执行一次\n * @default false\n */\n leading?: boolean;\n};\n\n/**\n * 创建一个防抖函数,该函数会在指定的等待时间后执行,如果在等待时间内再次调用,则重新计时。\n *\n * @param fn - 需要防抖的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait` 和 `leading` 选项的对象。\n * @returns 返回一个防抖函数,该函数具有 `cancel` 方法,用于取消防抖操作。\n *\n * @example\n * ```typescript\n * const debouncedFn = fnDebounce(() => {\n * console.log('Debounced!');\n * }, 100);\n *\n * debouncedFn(); // 不会立即执行\n * debouncedFn(); // 重新计时\n * debouncedFn.cancel(); // 取消防抖操作\n * ```\n */\nexport function fnDebounce<F extends AnyFunction>(fn: F, wait: number | DebounceOptions) {\n const options: DebounceOptions = isNumber(wait) ? { wait } : wait;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n let leading = false;\n\n const debounced = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n // 第一次执行\n if (options.leading && !leading) {\n leading = true;\n fn.apply(this, args);\n return;\n }\n\n // 最后一次执行\n clearTimeout(timer);\n timer = setTimeout(() => {\n if (canceled) return;\n\n fn.apply(this, args);\n }, options.wait);\n };\n\n debounced.cancel = () => {\n clearTimeout(timer);\n canceled = true;\n };\n\n return debounced;\n}\n\nexport type ThrottleOptions = {\n /**\n * 等待时间(毫秒)。\n */\n wait: number;\n\n /**\n * 是否在第一次调用时立即执行\n * @default false\n */\n leading?: boolean;\n\n /**\n * 是否在调用结束后等待一段时间再执行\n * @default false\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个节流函数,该函数会在指定的等待时间内最多执行一次,如果在等待时间内再次调用,则忽略后续调用。\n *\n * @param fn - 需要节流的函数。\n * @param wait - 等待时间(毫秒)或包含 `wait`、`leading` 和 `trailing` 选项的对象。\n * @returns 返回一个节流函数,该函数具有 `cancel` 方法,用于取消节流操作。\n *\n * @example\n * ```typescript\n * const throttledFn = fnThrottle(() => {\n * console.log('Throttled!');\n * }, 100);\n *\n * throttledFn(); // 立即执行\n * throttledFn(); // 忽略\n * throttledFn.cancel(); // 取消节流操作\n * ```\n */\nexport function fnThrottle<F extends AnyFunction>(fn: F, wait: number | ThrottleOptions) {\n const options = isNumber(wait) ? { wait } : wait;\n const waitFinal = options.wait;\n let lastTime = 0;\n let canceled = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let timer: any;\n\n const throttled = function (this: unknown, ...args: Parameters<F>) {\n if (canceled) return;\n\n const now = Date.now();\n\n // 第一次执行\n if (options.leading && lastTime === 0) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 中间控频执行\n else if (lastTime > 0 && now - lastTime >= waitFinal) {\n lastTime = now;\n fn.apply(this, args);\n }\n\n // 首次计时\n else if (lastTime === 0) {\n lastTime = now;\n }\n\n // 最后一次执行\n if (options.trailing) {\n clearTimeout(timer);\n timer = setTimeout(() => {\n fn.apply(this, args);\n }, waitFinal);\n }\n };\n\n throttled.cancel = () => {\n canceled = true;\n clearTimeout(timer);\n };\n\n return throttled;\n}\n\n/**\n * 创建一个只执行一次的函数,无论调用多少次,实际执行的函数体也只会执行一次。\n *\n * @param fn - 需要只执行一次的函数。\n * @returns 返回一个只执行一次的函数,该函数在第一次调用后会缓存结果并返回缓存的结果。\n *\n * @example\n * ```typescript\n * const onceFn = fnOnce(() => {\n * console.log('This will be logged only once.');\n * return 42;\n * });\n *\n * console.log(onceFn()); // 输出: This will be logged only once. 42\n * console.log(onceFn()); // 输出: 42\n * ```\n */\nexport function fnOnce<F extends AnyFunction>(fn: F) {\n let called = false;\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n let result: any;\n\n return function (this: unknown, ...args: Parameters<F>) {\n if (!called) {\n called = true;\n result = fn.apply(this, args);\n }\n\n return result;\n };\n}\n"],"names":[],"mappings":";AAWO,SAAS,SAAS;AAEzB;AAmCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAA2B,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC7D,MAAI,WAAW;AAEX,MAAA;AACJ,MAAI,UAAU;AAER,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAGV,QAAA,QAAQ,WAAW,CAAC,SAAS;AACrB,gBAAA;AACP,SAAA,MAAM,MAAM,IAAI;AACnB;AAAA,IAAA;AAIF,iBAAa,KAAK;AAClB,YAAQ,WAAW,MAAM;AACvB,UAAI,SAAU;AAEX,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,GAClB,QAAQ,IAAI;AAAA,EACjB;AAEA,YAAU,SAAS,MAAM;AACvB,iBAAa,KAAK;AACP,eAAA;AAAA,EACb;AAEO,SAAA;AACT;AAuCgB,SAAA,WAAkC,IAAO,MAAgC;AACvF,QAAM,UAAU,SAAS,IAAI,IAAI,EAAE,KAAS,IAAA;AAC5C,QAAM,YAAY,QAAQ;AAC1B,MAAI,WAAW;AACf,MAAI,WAAW;AAEX,MAAA;AAEE,QAAA,YAAY,YAA4B,MAAqB;AACjE,QAAI,SAAU;AAER,UAAA,MAAM,KAAK,IAAI;AAGjB,QAAA,QAAQ,WAAW,aAAa,GAAG;AAC1B,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAIZ,WAAA,WAAW,KAAK,MAAM,YAAY,WAAW;AACzC,iBAAA;AACR,SAAA,MAAM,MAAM,IAAI;AAAA,IAAA,WAIZ,aAAa,GAAG;AACZ,iBAAA;AAAA,IAAA;AAIb,QAAI,QAAQ,UAAU;AACpB,mBAAa,KAAK;AAClB,cAAQ,WAAW,MAAM;AACpB,WAAA,MAAM,MAAM,IAAI;AAAA,SAClB,SAAS;AAAA,IAAA;AAAA,EAEhB;AAEA,YAAU,SAAS,MAAM;AACZ,eAAA;AACX,iBAAa,KAAK;AAAA,EACpB;AAEO,SAAA;AACT;AAmBO,SAAS,OAA8B,IAAO;AACnD,MAAI,SAAS;AAET,MAAA;AAEJ,SAAO,YAA4B,MAAqB;AACtD,QAAI,CAAC,QAAQ;AACF,eAAA;AACA,eAAA,GAAG,MAAM,MAAM,IAAI;AAAA,IAAA;AAGvB,WAAA;AAAA,EACT;AACF;"}
package/dist/qs.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"qs.cjs","sources":["../src/qs.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNull, isNullish, isNumber, isString, isUndefined } 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"],"names":["isNullish","isArray","isString","isNumber","isBoolean","isDate","objectEach"],"mappings":";;;;AAoCgB,SAAA,QAA6B,aAAqB,QAAyB;AAGnF,QAAA,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,EAAE,CAAC;AAC1E,QAAM,WAAW,CAAC;AAElB,aAAW,CAAC,KAAK,GAAG,KAAK,GAAG,WAAW;AACrC,UAAM,WAAW,SAAS,OAAO,KAAK,KAAK,QAAQ,IAAI;AAEnD,QAAAA,KAAAA,UAAU,QAAQ,EAAG;AAEzB,QAAI,OAAO,OAAO,UAAU,GAAG,GAAG;AAEhC,UAAI,CAACC,KAAA,QAAQ,SAAS,GAAG,CAAC,EAAY,UAAA,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC;AAC1D,eAAS,GAAG,EAAgB,KAAK,GAAG;AAAA,IAAA,OAChC;AAEL,eAAS,GAAG,IAAI;AAAA,IAAA;AAAA,EAClB;AAGK,SAAA;AACT;AAiBA,MAAM,gBAAqC,CAAC,QAAiB;AACvD,MAAAC,KAAA,SAAS,GAAG,EAAU,QAAA;AAC1B,MAAIC,KAAS,SAAA,GAAG,EAAG,QAAO,OAAO,GAAG;AACpC,MAAIC,KAAU,UAAA,GAAG,EAAG,QAAO,MAAM,SAAS;AAC1C,MAAIC,KAAO,OAAA,GAAG,EAAG,QAAO,IAAI,YAAY;AACjC,SAAA;AACT;AAegB,SAAA,YAAiC,UAAa,YAAyB,eAAuB;AAGtG,QAAA,KAAK,IAAI,WAAW,gBAAgB;AACpC,QAAA,YAAY,CAAC,KAAc,QAAgB;AAC/C,UAAM,WAAW,UAAU,KAAK,OAAO,GAAG,GAAG,QAAQ;AACjD,QAAAL,KAAAA,UAAU,QAAQ,EAAG;AAEtB,OAAA,OAAO,KAAK,QAAQ;AAAA,EACzB;AAEWM,OAAAA,WAAA,UAAU,CAAC,KAAK,QAAgB;AACrC,QAAAL,KAAAA,QAAQ,GAAG,GAAG;AAChB,iBAAW,MAAM,KAAK;AACpB,kBAAU,IAAI,GAAG;AAAA,MAAA;AAAA,IACnB,OACK;AACL,gBAAU,KAAK,GAAG;AAAA,IAAA;AAAA,EACpB,CACD;AAED,SAAO,GAAG,SAAS;AACrB;;;"}
package/dist/qs.mjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"qs.mjs","sources":["../src/qs.ts"],"sourcesContent":["import { objectEach } from './object';\nimport { isArray, isBoolean, isDate, isNull, isNullish, isNumber, isString, isUndefined } 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"],"names":[],"mappings":";;AAoCgB,SAAA,QAA6B,aAAqB,QAAyB;AAGnF,QAAA,KAAK,IAAI,WAAW,gBAAgB,YAAY,QAAQ,SAAS,EAAE,CAAC;AAC1E,QAAM,WAAW,CAAC;AAElB,aAAW,CAAC,KAAK,GAAG,KAAK,GAAG,WAAW;AACrC,UAAM,WAAW,SAAS,OAAO,KAAK,KAAK,QAAQ,IAAI;AAEnD,QAAA,UAAU,QAAQ,EAAG;AAEzB,QAAI,OAAO,OAAO,UAAU,GAAG,GAAG;AAEhC,UAAI,CAAC,QAAQ,SAAS,GAAG,CAAC,EAAY,UAAA,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC;AAC1D,eAAS,GAAG,EAAgB,KAAK,GAAG;AAAA,IAAA,OAChC;AAEL,eAAS,GAAG,IAAI;AAAA,IAAA;AAAA,EAClB;AAGK,SAAA;AACT;AAiBA,MAAM,gBAAqC,CAAC,QAAiB;AACvD,MAAA,SAAS,GAAG,EAAU,QAAA;AAC1B,MAAI,SAAS,GAAG,EAAG,QAAO,OAAO,GAAG;AACpC,MAAI,UAAU,GAAG,EAAG,QAAO,MAAM,SAAS;AAC1C,MAAI,OAAO,GAAG,EAAG,QAAO,IAAI,YAAY;AACjC,SAAA;AACT;AAegB,SAAA,YAAiC,UAAa,YAAyB,eAAuB;AAGtG,QAAA,KAAK,IAAI,WAAW,gBAAgB;AACpC,QAAA,YAAY,CAAC,KAAc,QAAgB;AAC/C,UAAM,WAAW,UAAU,KAAK,OAAO,GAAG,GAAG,QAAQ;AACjD,QAAA,UAAU,QAAQ,EAAG;AAEtB,OAAA,OAAO,KAAK,QAAQ;AAAA,EACzB;AAEW,aAAA,UAAU,CAAC,KAAK,QAAgB;AACrC,QAAA,QAAQ,GAAG,GAAG;AAChB,iBAAW,MAAM,KAAK;AACpB,kBAAU,IAAI,GAAG;AAAA,MAAA;AAAA,IACnB,OACK;AACL,gBAAU,KAAK,GAAG;AAAA,IAAA;AAAA,EACpB,CACD;AAED,SAAO,GAAG,SAAS;AACrB;"}
@@ -1,2 +0,0 @@
1
- export declare const pkgName: string;
2
- export declare const pkgVersion: string;
@@ -1,7 +0,0 @@
1
- export * from './const';
2
- export * from './callbackCurry';
3
- export * from './tryFunction';
4
- export * from './tryCallback';
5
- export * from './tryPromise';
6
- export * from './tryFlatten';
7
- export * from './types';
@@ -1,6 +0,0 @@
1
- import { CallbackFunction0 } from './callbackCurry';
2
- import { SyncFunction } from './tryFunction';
3
- import { FlattenReturn } from './types';
4
- export type FlattenAble<T> = SyncFunction<T> | CallbackFunction0<T> | PromiseLike<T>;
5
- export declare function tryFlatten<T>(flattenAble: SyncFunction<T>): FlattenReturn<T>;
6
- export declare function tryFlatten<T>(flattenAble: CallbackFunction0<T> | PromiseLike<T>): Promise<FlattenReturn<T>>;
@@ -1,3 +0,0 @@
1
- import { FlattenReturn } from './types';
2
- export type SyncFunction<T> = () => T;
3
- export declare function tryFunction<T>(syncFn: () => T): FlattenReturn<T>;
File without changes
File without changes
File without changes
File without changes