@cloudcome/utils-core 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +18 -0
  2. package/dist/async.cjs.map +1 -1
  3. package/dist/async.d.ts +3 -3
  4. package/dist/async.mjs.map +1 -1
  5. package/dist/cache.cjs.map +1 -1
  6. package/dist/cache.d.ts +14 -14
  7. package/dist/cache.mjs.map +1 -1
  8. package/dist/core.cjs.map +1 -1
  9. package/dist/core.mjs.map +1 -1
  10. package/dist/date/core.d.ts +4 -4
  11. package/dist/date/days.d.ts +3 -3
  12. package/dist/date/is.d.ts +7 -7
  13. package/dist/date/relative.d.ts +10 -10
  14. package/dist/date/start-end.d.ts +13 -13
  15. package/dist/date/timezone.d.ts +2 -2
  16. package/dist/date/weeks.d.ts +4 -4
  17. package/dist/date.cjs.map +1 -1
  18. package/dist/date.mjs.map +1 -1
  19. package/dist/enum.cjs +1 -1
  20. package/dist/enum.cjs.map +1 -1
  21. package/dist/enum.d.ts +1 -1
  22. package/dist/enum.mjs +1 -1
  23. package/dist/enum.mjs.map +1 -1
  24. package/dist/fn.cjs.map +1 -1
  25. package/dist/fn.d.ts +4 -4
  26. package/dist/fn.mjs.map +1 -1
  27. package/dist/index.cjs +1 -1
  28. package/dist/index.mjs +1 -1
  29. package/dist/merge.cjs.map +1 -1
  30. package/dist/merge.mjs.map +1 -1
  31. package/dist/object/get-set.d.ts +14 -14
  32. package/dist/object/merge.d.ts +1 -1
  33. package/dist/object.cjs.map +1 -1
  34. package/dist/object.mjs.map +1 -1
  35. package/dist/time/from.d.ts +4 -4
  36. package/dist/time/to.d.ts +5 -5
  37. package/dist/time.cjs.map +1 -1
  38. package/dist/time.mjs.map +1 -1
  39. package/dist/timer.cjs.map +1 -1
  40. package/dist/timer.d.ts +6 -6
  41. package/dist/timer.mjs.map +1 -1
  42. package/dist/tree.cjs.map +1 -1
  43. package/dist/tree.d.ts +19 -19
  44. package/dist/tree.mjs.map +1 -1
  45. package/dist/url.cjs.map +1 -1
  46. package/dist/url.d.ts +6 -6
  47. package/dist/url.mjs.map +1 -1
  48. package/dist/version.cjs.map +1 -1
  49. package/dist/version.d.ts +2 -2
  50. package/dist/version.mjs.map +1 -1
  51. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # 我的个人工具函数库
2
+
3
+ [![code-review](https://github.com/cloudcome/utils/actions/workflows/code-review.yml/badge.svg)](https://github.com/cloudcome/utils/actions/workflows/code-review.yml)
4
+ [![dependency-review](https://github.com/cloudcome/utils/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/cloudcome/utils/actions/workflows/dependency-review.yml)
5
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/4fa1acaeb717469caddfe21a84c50bb2)](https://app.codacy.com/gh/cloudcome/utils/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
6
+ [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/4fa1acaeb717469caddfe21a84c50bb2)](https://app.codacy.com/gh/cloudcome/utils/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage)
7
+
8
+
9
+ | 名称 | 版本 | 描述 |
10
+ | --- | --- | --- |
11
+ | @cloudcome/utils-core | [![npm version](https://badge.fury.io/js/@cloudcome%2Futils-core.svg)](https://npmjs.com/package/@cloudcome/utils-core) | 核心工具库 |
12
+ | @cloudcome/utils-browser | [![npm version](https://badge.fury.io/js/@cloudcome%2Futils-browser.svg)](https://npmjs.com/package/@cloudcome/utils-browser) | 浏览器工具库 |
13
+ | @cloudcome/utils-node| [![npm version](https://badge.fury.io/js/@cloudcome%2Futils-node.svg)](https://npmjs.com/package/@cloudcome/utils-node) | Node.js 工具库 |
14
+ | @cloudcome/utils-vue| [![npm version](https://badge.fury.io/js/@cloudcome%2Futils-vue.svg)](https://npmjs.com/package/@cloudcome/utils-vue) | Vue 工具库 |
15
+ | @cloudcome/utils-react| [![npm version](https://badge.fury.io/js/@cloudcome%2Futils-react.svg)](https://npmjs.com/package/@cloudcome/utils-react) | React 工具库 |
16
+ | @cloudcome/utils-uni| [![npm version](https://badge.fury.io/js/@cloudcome%2Futils-uni.svg)](https://npmjs.com/package/@cloudcome/utils-uni) | UniApp 工具库 |
17
+
18
+
@@ -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 TAsyncQueueOptions = {\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?: TAsyncQueueOptions,\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 './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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"}
package/dist/async.d.ts CHANGED
@@ -2,7 +2,7 @@ import { AnyArray } from './types';
2
2
  /**
3
3
  * 异步任务队列的配置选项
4
4
  */
5
- export type TAsyncQueueOptions = {
5
+ export type AsyncQueueOptions = {
6
6
  /**
7
7
  * 并发限制数,0 表示无限制
8
8
  * @default 0
@@ -15,13 +15,13 @@ export type TAsyncQueueOptions = {
15
15
  */
16
16
  export declare class AsyncQueue<T> {
17
17
  #private;
18
- readonly options?: TAsyncQueueOptions | undefined;
18
+ readonly options?: AsyncQueueOptions | undefined;
19
19
  /**
20
20
  * 创建一个异步任务队列
21
21
  * @param asyncFns - 要执行的异步函数数组
22
22
  * @param options - 队列配置选项
23
23
  */
24
- constructor(asyncFns: Array<() => Promise<T>>, options?: TAsyncQueueOptions | undefined);
24
+ constructor(asyncFns: Array<() => Promise<T>>, options?: AsyncQueueOptions | undefined);
25
25
  get length(): number;
26
26
  get limit(): number;
27
27
  push(afn: () => Promise<T>): Promise<T>;
@@ -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 TAsyncQueueOptions = {\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?: TAsyncQueueOptions,\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 './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 +1 @@
1
- {"version":3,"file":"cache.cjs","sources":["../src/cache.ts"],"sourcesContent":["import { type TDateValue, dateParse } from './date';\nimport type { MaybePromise } from './types';\n\n/**\n * 缓存选项\n */\nexport type TCacheOptions = {\n /**\n * 缓存的最大时长(毫秒),为 0 时表示永久缓存\n */\n maxAge?: number;\n\n /**\n * 缓存的过期时间(时间戳、日期字符串、日期对象等)\n * 优先级比 maxAge 更高\n */\n expiredAt?: TDateValue;\n};\n\n/**\n * 缓存项\n * @template T 缓存数据的类型\n */\nexport type TCached<T> = {\n /**\n * 缓存项的唯一标识\n */\n id: string;\n /**\n * 缓存的数据\n */\n data: T;\n /**\n * 缓存项的创建时间(时间戳)\n */\n createdAt: number;\n /**\n * 缓存项的过期时间(时间戳)\n */\n expiredAt: number;\n};\n\nexport type TCache<T> = {\n get(id: string): MaybePromise<TCached<T> | null>;\n\n set(id: string, data: T, options?: TCacheOptions): MaybePromise<void>;\n\n del(id: string): MaybePromise<void>;\n};\n\n/**\n * 缓存抽象类\n * @template T 缓存数据的类型\n */\nexport class AbstractCache<T> implements TCache<T> {\n isExpired(cached: TCached<T>) {\n return cached.expiredAt > 0 && Date.now() > cached.expiredAt;\n }\n\n normalizeCached(id: string, data: T, options?: TCacheOptions): TCached<T> {\n const { expiredAt = 0, maxAge = 0 } = options || {};\n const now = Date.now();\n return {\n id,\n data,\n createdAt: now,\n expiredAt: expiredAt ? dateParse(expiredAt).getTime() : maxAge > 0 ? now + maxAge : 0,\n };\n }\n\n /**\n * 获取缓存项\n * @param id 缓存项的唯一标识\n * @returns 返回缓存项或 null\n */\n get(id: string): MaybePromise<TCached<T> | null> {\n return null;\n }\n\n /**\n * 设置缓存项\n * @param id 缓存项的唯一标识\n * @param data 要缓存的数据\n * @param options 缓存选项\n */\n set(id: string, data: T, options?: TCacheOptions): MaybePromise<void> {\n //\n }\n\n /**\n * 删除缓存项\n * @param id 缓存项的唯一标识\n */\n del(id: string): MaybePromise<void> {\n //\n }\n\n /**\n * 清空缓存\n */\n clear(): MaybePromise<void> {\n //\n }\n}\n\n/**\n * 内存缓存实现类\n * @template T 缓存数据的类型\n */\nexport class MemoryCache<T> extends AbstractCache<T> {\n private cache: Map<string, TCached<T>> = new Map();\n\n get(id: string) {\n const cached = this.cache.get(id);\n\n if (!cached) return null;\n\n if (this.isExpired(cached)) {\n this.del(id);\n return null;\n }\n\n return cached;\n }\n\n set(id: string, data: T, options?: TCacheOptions) {\n this.cache.set(id, this.normalizeCached(id, data, options));\n }\n\n del(id: string) {\n this.cache.delete(id);\n }\n\n clear() {\n this.cache.clear();\n }\n}\n\n/**\n * 创建一个新的内存缓存实例\n * @template T 缓存数据的类型\n * @returns 返回一个新的 MemoryCache 实例\n */\nexport function createMemCache<T>() {\n return new MemoryCache<T>();\n}\n"],"names":["dateParse"],"mappings":";;;;;;AAsDO,MAAM,cAAsC;AAAA,EACjD,UAAU,QAAoB;AAC5B,WAAO,OAAO,YAAY,KAAK,KAAK,IAAA,IAAQ,OAAO;AAAA,EAAA;AAAA,EAGrD,gBAAgB,IAAY,MAAS,SAAqC;AACxE,UAAM,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,WAAW,CAAC;AAC5C,UAAA,MAAM,KAAK,IAAI;AACd,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,WAAW,YAAYA,KAAA,UAAU,SAAS,EAAE,QAAY,IAAA,SAAS,IAAI,MAAM,SAAS;AAAA,IACtF;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF,IAAI,IAA6C;AACxC,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,IAAI,IAAY,MAAS,SAA6C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtE,IAAI,IAAgC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAOpC,QAA4B;AAAA,EAAA;AAG9B;AAMO,MAAM,oBAAuB,cAAiB;AAAA,EAA9C;AAAA;AACG,qDAAqC,IAAI;AAAA;AAAA,EAEjD,IAAI,IAAY;AACd,UAAM,SAAS,KAAK,MAAM,IAAI,EAAE;AAE5B,QAAA,CAAC,OAAe,QAAA;AAEhB,QAAA,KAAK,UAAU,MAAM,GAAG;AAC1B,WAAK,IAAI,EAAE;AACJ,aAAA;AAAA,IAAA;AAGF,WAAA;AAAA,EAAA;AAAA,EAGT,IAAI,IAAY,MAAS,SAAyB;AAC3C,SAAA,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;AAAA,EAAA;AAAA,EAG5D,IAAI,IAAY;AACT,SAAA,MAAM,OAAO,EAAE;AAAA,EAAA;AAAA,EAGtB,QAAQ;AACN,SAAK,MAAM,MAAM;AAAA,EAAA;AAErB;AAOO,SAAS,iBAAoB;AAClC,SAAO,IAAI,YAAe;AAC5B;;;;"}
1
+ {"version":3,"file":"cache.cjs","sources":["../src/cache.ts"],"sourcesContent":["import { type DateValue, dateParse } from './date';\nimport type { MaybePromise } from './types';\n\n/**\n * 缓存选项\n */\nexport type CacheOptions = {\n /**\n * 缓存的最大时长(毫秒),为 0 时表示永久缓存\n */\n maxAge?: number;\n\n /**\n * 缓存的过期时间(时间戳、日期字符串、日期对象等)\n * 优先级比 maxAge 更高\n */\n expiredAt?: DateValue;\n};\n\n/**\n * 缓存项\n * @template T 缓存数据的类型\n */\nexport type Cached<T> = {\n /**\n * 缓存项的唯一标识\n */\n id: string;\n /**\n * 缓存的数据\n */\n data: T;\n /**\n * 缓存项的创建时间(时间戳)\n */\n createdAt: number;\n /**\n * 缓存项的过期时间(时间戳)\n */\n expiredAt: number;\n};\n\nexport type Cache<T> = {\n get(id: string): MaybePromise<Cached<T> | null>;\n\n set(id: string, data: T, options?: CacheOptions): MaybePromise<void>;\n\n del(id: string): MaybePromise<void>;\n};\n\n/**\n * 缓存抽象类\n * @template T 缓存数据的类型\n */\nexport class AbstractCache<T> implements Cache<T> {\n isExpired(cached: Cached<T>) {\n return cached.expiredAt > 0 && Date.now() > cached.expiredAt;\n }\n\n normalizeCached(id: string, data: T, options?: CacheOptions): Cached<T> {\n const { expiredAt = 0, maxAge = 0 } = options || {};\n const now = Date.now();\n return {\n id,\n data,\n createdAt: now,\n expiredAt: expiredAt ? dateParse(expiredAt).getTime() : maxAge > 0 ? now + maxAge : 0,\n };\n }\n\n /**\n * 获取缓存项\n * @param id 缓存项的唯一标识\n * @returns 返回缓存项或 null\n */\n get(id: string): MaybePromise<Cached<T> | null> {\n return null;\n }\n\n /**\n * 设置缓存项\n * @param id 缓存项的唯一标识\n * @param data 要缓存的数据\n * @param options 缓存选项\n */\n set(id: string, data: T, options?: CacheOptions): MaybePromise<void> {\n //\n }\n\n /**\n * 删除缓存项\n * @param id 缓存项的唯一标识\n */\n del(id: string): MaybePromise<void> {\n //\n }\n\n /**\n * 清空缓存\n */\n clear(): MaybePromise<void> {\n //\n }\n}\n\n/**\n * 内存缓存实现类\n * @template T 缓存数据的类型\n */\nexport class MemoryCache<T> extends AbstractCache<T> {\n private cache: Map<string, Cached<T>> = new Map();\n\n get(id: string) {\n const cached = this.cache.get(id);\n\n if (!cached) return null;\n\n if (this.isExpired(cached)) {\n this.del(id);\n return null;\n }\n\n return cached;\n }\n\n set(id: string, data: T, options?: CacheOptions) {\n this.cache.set(id, this.normalizeCached(id, data, options));\n }\n\n del(id: string) {\n this.cache.delete(id);\n }\n\n clear() {\n this.cache.clear();\n }\n}\n\n/**\n * 创建一个新的内存缓存实例\n * @template T 缓存数据的类型\n * @returns 返回一个新的 MemoryCache 实例\n */\nexport function createMemCache<T>() {\n return new MemoryCache<T>();\n}\n"],"names":["dateParse"],"mappings":";;;;;;AAsDO,MAAM,cAAqC;AAAA,EAChD,UAAU,QAAmB;AAC3B,WAAO,OAAO,YAAY,KAAK,KAAK,IAAA,IAAQ,OAAO;AAAA,EAAA;AAAA,EAGrD,gBAAgB,IAAY,MAAS,SAAmC;AACtE,UAAM,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,WAAW,CAAC;AAC5C,UAAA,MAAM,KAAK,IAAI;AACd,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,WAAW,YAAYA,KAAA,UAAU,SAAS,EAAE,QAAY,IAAA,SAAS,IAAI,MAAM,SAAS;AAAA,IACtF;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF,IAAI,IAA4C;AACvC,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,IAAI,IAAY,MAAS,SAA4C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrE,IAAI,IAAgC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAOpC,QAA4B;AAAA,EAAA;AAG9B;AAMO,MAAM,oBAAuB,cAAiB;AAAA,EAA9C;AAAA;AACG,qDAAoC,IAAI;AAAA;AAAA,EAEhD,IAAI,IAAY;AACd,UAAM,SAAS,KAAK,MAAM,IAAI,EAAE;AAE5B,QAAA,CAAC,OAAe,QAAA;AAEhB,QAAA,KAAK,UAAU,MAAM,GAAG;AAC1B,WAAK,IAAI,EAAE;AACJ,aAAA;AAAA,IAAA;AAGF,WAAA;AAAA,EAAA;AAAA,EAGT,IAAI,IAAY,MAAS,SAAwB;AAC1C,SAAA,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;AAAA,EAAA;AAAA,EAG5D,IAAI,IAAY;AACT,SAAA,MAAM,OAAO,EAAE;AAAA,EAAA;AAAA,EAGtB,QAAQ;AACN,SAAK,MAAM,MAAM;AAAA,EAAA;AAErB;AAOO,SAAS,iBAAoB;AAClC,SAAO,IAAI,YAAe;AAC5B;;;;"}
package/dist/cache.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { TDateValue } from './date';
1
+ import { DateValue } from './date';
2
2
  import { MaybePromise } from './types';
3
3
  /**
4
4
  * 缓存选项
5
5
  */
6
- export type TCacheOptions = {
6
+ export type CacheOptions = {
7
7
  /**
8
8
  * 缓存的最大时长(毫秒),为 0 时表示永久缓存
9
9
  */
@@ -12,13 +12,13 @@ export type TCacheOptions = {
12
12
  * 缓存的过期时间(时间戳、日期字符串、日期对象等)
13
13
  * 优先级比 maxAge 更高
14
14
  */
15
- expiredAt?: TDateValue;
15
+ expiredAt?: DateValue;
16
16
  };
17
17
  /**
18
18
  * 缓存项
19
19
  * @template T 缓存数据的类型
20
20
  */
21
- export type TCached<T> = {
21
+ export type Cached<T> = {
22
22
  /**
23
23
  * 缓存项的唯一标识
24
24
  */
@@ -36,31 +36,31 @@ export type TCached<T> = {
36
36
  */
37
37
  expiredAt: number;
38
38
  };
39
- export type TCache<T> = {
40
- get(id: string): MaybePromise<TCached<T> | null>;
41
- set(id: string, data: T, options?: TCacheOptions): MaybePromise<void>;
39
+ export type Cache<T> = {
40
+ get(id: string): MaybePromise<Cached<T> | null>;
41
+ set(id: string, data: T, options?: CacheOptions): MaybePromise<void>;
42
42
  del(id: string): MaybePromise<void>;
43
43
  };
44
44
  /**
45
45
  * 缓存抽象类
46
46
  * @template T 缓存数据的类型
47
47
  */
48
- export declare class AbstractCache<T> implements TCache<T> {
49
- isExpired(cached: TCached<T>): boolean;
50
- normalizeCached(id: string, data: T, options?: TCacheOptions): TCached<T>;
48
+ export declare class AbstractCache<T> implements Cache<T> {
49
+ isExpired(cached: Cached<T>): boolean;
50
+ normalizeCached(id: string, data: T, options?: CacheOptions): Cached<T>;
51
51
  /**
52
52
  * 获取缓存项
53
53
  * @param id 缓存项的唯一标识
54
54
  * @returns 返回缓存项或 null
55
55
  */
56
- get(id: string): MaybePromise<TCached<T> | null>;
56
+ get(id: string): MaybePromise<Cached<T> | null>;
57
57
  /**
58
58
  * 设置缓存项
59
59
  * @param id 缓存项的唯一标识
60
60
  * @param data 要缓存的数据
61
61
  * @param options 缓存选项
62
62
  */
63
- set(id: string, data: T, options?: TCacheOptions): MaybePromise<void>;
63
+ set(id: string, data: T, options?: CacheOptions): MaybePromise<void>;
64
64
  /**
65
65
  * 删除缓存项
66
66
  * @param id 缓存项的唯一标识
@@ -77,8 +77,8 @@ export declare class AbstractCache<T> implements TCache<T> {
77
77
  */
78
78
  export declare class MemoryCache<T> extends AbstractCache<T> {
79
79
  private cache;
80
- get(id: string): TCached<T> | null;
81
- set(id: string, data: T, options?: TCacheOptions): void;
80
+ get(id: string): Cached<T> | null;
81
+ set(id: string, data: T, options?: CacheOptions): void;
82
82
  del(id: string): void;
83
83
  clear(): void;
84
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cache.mjs","sources":["../src/cache.ts"],"sourcesContent":["import { type TDateValue, dateParse } from './date';\nimport type { MaybePromise } from './types';\n\n/**\n * 缓存选项\n */\nexport type TCacheOptions = {\n /**\n * 缓存的最大时长(毫秒),为 0 时表示永久缓存\n */\n maxAge?: number;\n\n /**\n * 缓存的过期时间(时间戳、日期字符串、日期对象等)\n * 优先级比 maxAge 更高\n */\n expiredAt?: TDateValue;\n};\n\n/**\n * 缓存项\n * @template T 缓存数据的类型\n */\nexport type TCached<T> = {\n /**\n * 缓存项的唯一标识\n */\n id: string;\n /**\n * 缓存的数据\n */\n data: T;\n /**\n * 缓存项的创建时间(时间戳)\n */\n createdAt: number;\n /**\n * 缓存项的过期时间(时间戳)\n */\n expiredAt: number;\n};\n\nexport type TCache<T> = {\n get(id: string): MaybePromise<TCached<T> | null>;\n\n set(id: string, data: T, options?: TCacheOptions): MaybePromise<void>;\n\n del(id: string): MaybePromise<void>;\n};\n\n/**\n * 缓存抽象类\n * @template T 缓存数据的类型\n */\nexport class AbstractCache<T> implements TCache<T> {\n isExpired(cached: TCached<T>) {\n return cached.expiredAt > 0 && Date.now() > cached.expiredAt;\n }\n\n normalizeCached(id: string, data: T, options?: TCacheOptions): TCached<T> {\n const { expiredAt = 0, maxAge = 0 } = options || {};\n const now = Date.now();\n return {\n id,\n data,\n createdAt: now,\n expiredAt: expiredAt ? dateParse(expiredAt).getTime() : maxAge > 0 ? now + maxAge : 0,\n };\n }\n\n /**\n * 获取缓存项\n * @param id 缓存项的唯一标识\n * @returns 返回缓存项或 null\n */\n get(id: string): MaybePromise<TCached<T> | null> {\n return null;\n }\n\n /**\n * 设置缓存项\n * @param id 缓存项的唯一标识\n * @param data 要缓存的数据\n * @param options 缓存选项\n */\n set(id: string, data: T, options?: TCacheOptions): MaybePromise<void> {\n //\n }\n\n /**\n * 删除缓存项\n * @param id 缓存项的唯一标识\n */\n del(id: string): MaybePromise<void> {\n //\n }\n\n /**\n * 清空缓存\n */\n clear(): MaybePromise<void> {\n //\n }\n}\n\n/**\n * 内存缓存实现类\n * @template T 缓存数据的类型\n */\nexport class MemoryCache<T> extends AbstractCache<T> {\n private cache: Map<string, TCached<T>> = new Map();\n\n get(id: string) {\n const cached = this.cache.get(id);\n\n if (!cached) return null;\n\n if (this.isExpired(cached)) {\n this.del(id);\n return null;\n }\n\n return cached;\n }\n\n set(id: string, data: T, options?: TCacheOptions) {\n this.cache.set(id, this.normalizeCached(id, data, options));\n }\n\n del(id: string) {\n this.cache.delete(id);\n }\n\n clear() {\n this.cache.clear();\n }\n}\n\n/**\n * 创建一个新的内存缓存实例\n * @template T 缓存数据的类型\n * @returns 返回一个新的 MemoryCache 实例\n */\nexport function createMemCache<T>() {\n return new MemoryCache<T>();\n}\n"],"names":[],"mappings":";;;;AAsDO,MAAM,cAAsC;AAAA,EACjD,UAAU,QAAoB;AAC5B,WAAO,OAAO,YAAY,KAAK,KAAK,IAAA,IAAQ,OAAO;AAAA,EAAA;AAAA,EAGrD,gBAAgB,IAAY,MAAS,SAAqC;AACxE,UAAM,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,WAAW,CAAC;AAC5C,UAAA,MAAM,KAAK,IAAI;AACd,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,WAAW,YAAY,UAAU,SAAS,EAAE,QAAY,IAAA,SAAS,IAAI,MAAM,SAAS;AAAA,IACtF;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF,IAAI,IAA6C;AACxC,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,IAAI,IAAY,MAAS,SAA6C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtE,IAAI,IAAgC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAOpC,QAA4B;AAAA,EAAA;AAG9B;AAMO,MAAM,oBAAuB,cAAiB;AAAA,EAA9C;AAAA;AACG,qDAAqC,IAAI;AAAA;AAAA,EAEjD,IAAI,IAAY;AACd,UAAM,SAAS,KAAK,MAAM,IAAI,EAAE;AAE5B,QAAA,CAAC,OAAe,QAAA;AAEhB,QAAA,KAAK,UAAU,MAAM,GAAG;AAC1B,WAAK,IAAI,EAAE;AACJ,aAAA;AAAA,IAAA;AAGF,WAAA;AAAA,EAAA;AAAA,EAGT,IAAI,IAAY,MAAS,SAAyB;AAC3C,SAAA,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;AAAA,EAAA;AAAA,EAG5D,IAAI,IAAY;AACT,SAAA,MAAM,OAAO,EAAE;AAAA,EAAA;AAAA,EAGtB,QAAQ;AACN,SAAK,MAAM,MAAM;AAAA,EAAA;AAErB;AAOO,SAAS,iBAAoB;AAClC,SAAO,IAAI,YAAe;AAC5B;"}
1
+ {"version":3,"file":"cache.mjs","sources":["../src/cache.ts"],"sourcesContent":["import { type DateValue, dateParse } from './date';\nimport type { MaybePromise } from './types';\n\n/**\n * 缓存选项\n */\nexport type CacheOptions = {\n /**\n * 缓存的最大时长(毫秒),为 0 时表示永久缓存\n */\n maxAge?: number;\n\n /**\n * 缓存的过期时间(时间戳、日期字符串、日期对象等)\n * 优先级比 maxAge 更高\n */\n expiredAt?: DateValue;\n};\n\n/**\n * 缓存项\n * @template T 缓存数据的类型\n */\nexport type Cached<T> = {\n /**\n * 缓存项的唯一标识\n */\n id: string;\n /**\n * 缓存的数据\n */\n data: T;\n /**\n * 缓存项的创建时间(时间戳)\n */\n createdAt: number;\n /**\n * 缓存项的过期时间(时间戳)\n */\n expiredAt: number;\n};\n\nexport type Cache<T> = {\n get(id: string): MaybePromise<Cached<T> | null>;\n\n set(id: string, data: T, options?: CacheOptions): MaybePromise<void>;\n\n del(id: string): MaybePromise<void>;\n};\n\n/**\n * 缓存抽象类\n * @template T 缓存数据的类型\n */\nexport class AbstractCache<T> implements Cache<T> {\n isExpired(cached: Cached<T>) {\n return cached.expiredAt > 0 && Date.now() > cached.expiredAt;\n }\n\n normalizeCached(id: string, data: T, options?: CacheOptions): Cached<T> {\n const { expiredAt = 0, maxAge = 0 } = options || {};\n const now = Date.now();\n return {\n id,\n data,\n createdAt: now,\n expiredAt: expiredAt ? dateParse(expiredAt).getTime() : maxAge > 0 ? now + maxAge : 0,\n };\n }\n\n /**\n * 获取缓存项\n * @param id 缓存项的唯一标识\n * @returns 返回缓存项或 null\n */\n get(id: string): MaybePromise<Cached<T> | null> {\n return null;\n }\n\n /**\n * 设置缓存项\n * @param id 缓存项的唯一标识\n * @param data 要缓存的数据\n * @param options 缓存选项\n */\n set(id: string, data: T, options?: CacheOptions): MaybePromise<void> {\n //\n }\n\n /**\n * 删除缓存项\n * @param id 缓存项的唯一标识\n */\n del(id: string): MaybePromise<void> {\n //\n }\n\n /**\n * 清空缓存\n */\n clear(): MaybePromise<void> {\n //\n }\n}\n\n/**\n * 内存缓存实现类\n * @template T 缓存数据的类型\n */\nexport class MemoryCache<T> extends AbstractCache<T> {\n private cache: Map<string, Cached<T>> = new Map();\n\n get(id: string) {\n const cached = this.cache.get(id);\n\n if (!cached) return null;\n\n if (this.isExpired(cached)) {\n this.del(id);\n return null;\n }\n\n return cached;\n }\n\n set(id: string, data: T, options?: CacheOptions) {\n this.cache.set(id, this.normalizeCached(id, data, options));\n }\n\n del(id: string) {\n this.cache.delete(id);\n }\n\n clear() {\n this.cache.clear();\n }\n}\n\n/**\n * 创建一个新的内存缓存实例\n * @template T 缓存数据的类型\n * @returns 返回一个新的 MemoryCache 实例\n */\nexport function createMemCache<T>() {\n return new MemoryCache<T>();\n}\n"],"names":[],"mappings":";;;;AAsDO,MAAM,cAAqC;AAAA,EAChD,UAAU,QAAmB;AAC3B,WAAO,OAAO,YAAY,KAAK,KAAK,IAAA,IAAQ,OAAO;AAAA,EAAA;AAAA,EAGrD,gBAAgB,IAAY,MAAS,SAAmC;AACtE,UAAM,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,WAAW,CAAC;AAC5C,UAAA,MAAM,KAAK,IAAI;AACd,WAAA;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,WAAW,YAAY,UAAU,SAAS,EAAE,QAAY,IAAA,SAAS,IAAI,MAAM,SAAS;AAAA,IACtF;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQF,IAAI,IAA4C;AACvC,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAST,IAAI,IAAY,MAAS,SAA4C;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrE,IAAI,IAAgC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAOpC,QAA4B;AAAA,EAAA;AAG9B;AAMO,MAAM,oBAAuB,cAAiB;AAAA,EAA9C;AAAA;AACG,qDAAoC,IAAI;AAAA;AAAA,EAEhD,IAAI,IAAY;AACd,UAAM,SAAS,KAAK,MAAM,IAAI,EAAE;AAE5B,QAAA,CAAC,OAAe,QAAA;AAEhB,QAAA,KAAK,UAAU,MAAM,GAAG;AAC1B,WAAK,IAAI,EAAE;AACJ,aAAA;AAAA,IAAA;AAGF,WAAA;AAAA,EAAA;AAAA,EAGT,IAAI,IAAY,MAAS,SAAwB;AAC1C,SAAA,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;AAAA,EAAA;AAAA,EAG5D,IAAI,IAAY;AACT,SAAA,MAAM,OAAO,EAAE;AAAA,EAAA;AAAA,EAGtB,QAAQ;AACN,SAAK,MAAM,MAAM;AAAA,EAAA;AAErB;AAOO,SAAS,iBAAoB;AAClC,SAAO,IAAI,YAAe;AAC5B;"}
package/dist/core.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.cjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TTzDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * 时区偏移量,单位为分钟,默认为当前时区\n */\n offset?: number;\n};\n\nconst TZ_OFFSET_MS = 60 * 1000;\n\nexport class TzDate {\n #timestamp: number;\n #targetDate: Date;\n #utcDate: Date;\n\n #localTZOffset = TzDate.getOffset();\n #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;\n\n #targetTzOffset = 0;\n #targetTzOffsetMS = 0;\n\n #options: TTzDateOptions;\n\n constructor(options?: TTzDateOptions | TzDate) {\n this.#options = (options instanceof TzDate ? options.#options : options) || {};\n const { offset, timestamp, value } = this.#options;\n this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;\n this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTzOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n getTimezoneOffset() {\n return this.#targetTzOffset;\n }\n\n getTimezoneOrder() {\n return TzDate.getOrder(this.#targetTzOffset);\n }\n\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n getDate() {\n return this.#targetDate.getDate();\n }\n\n getHours() {\n return this.#targetDate.getHours();\n }\n\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n getTime() {\n return this.#timestamp;\n }\n\n getDay() {\n return this.#targetDate.getDay();\n }\n\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 创建一个 TzDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TzDate 对象\n * @example\n * ```js\n * const tzDate = TzDate.from(new TzDate());\n * ```\n */\n static from(td: TzDate, offset = TzDate.getOffset()) {\n return new TzDate({\n offset: offset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区序号\n * @param offset - 默认使用当前时区分钟偏移量\n */\n static getOrder(offset = TzDate.getOffset()) {\n return offset / -60;\n }\n\n /**\n * 获取时区分钟偏移量\n * @param gmtOrder - 默认使用当前时区序号\n */\n static getOffset(gmtOrder?: number) {\n return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TzDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TzDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TzDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type TDateLike = Date | TzDate;\nexport type TDateValue = number | string | TDateLike;\n\nfunction _guessDateSeparator(value: TDateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: TDateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: TDateValue): TDateLike {\n // 传入的 Date 对象有 Date、TzDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TzDate\n ? new TzDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: TDateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: TDateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["isNumber","timestamp","isString","isDate"],"mappings":"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"}
1
+ {"version":3,"file":"core.cjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TzDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * 时区偏移量,单位为分钟,默认为当前时区\n */\n offset?: number;\n};\n\nconst TZ_OFFSET_MS = 60 * 1000;\n\nexport class TzDate {\n #timestamp: number;\n #targetDate: Date;\n #utcDate: Date;\n\n #localTZOffset = TzDate.getOffset();\n #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;\n\n #targetTzOffset = 0;\n #targetTzOffsetMS = 0;\n\n #options: TzDateOptions;\n\n constructor(options?: TzDateOptions | TzDate) {\n this.#options = (options instanceof TzDate ? options.#options : options) || {};\n const { offset, timestamp, value } = this.#options;\n this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;\n this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTzOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n getTimezoneOffset() {\n return this.#targetTzOffset;\n }\n\n getTimezoneOrder() {\n return TzDate.getOrder(this.#targetTzOffset);\n }\n\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n getDate() {\n return this.#targetDate.getDate();\n }\n\n getHours() {\n return this.#targetDate.getHours();\n }\n\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n getTime() {\n return this.#timestamp;\n }\n\n getDay() {\n return this.#targetDate.getDay();\n }\n\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 创建一个 TzDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TzDate 对象\n * @example\n * ```js\n * const tzDate = TzDate.from(new TzDate());\n * ```\n */\n static from(td: TzDate, offset = TzDate.getOffset()) {\n return new TzDate({\n offset: offset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区序号\n * @param offset - 默认使用当前时区分钟偏移量\n */\n static getOrder(offset = TzDate.getOffset()) {\n return offset / -60;\n }\n\n /**\n * 获取时区分钟偏移量\n * @param gmtOrder - 默认使用当前时区序号\n */\n static getOffset(gmtOrder?: number) {\n return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TzDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TzDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TzDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type DateLike = Date | TzDate;\nexport type DateValue = number | string | DateLike;\n\nfunction _guessDateSeparator(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: DateValue): DateLike {\n // 传入的 Date 对象有 Date、TzDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TzDate\n ? new TzDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: DateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["isNumber","timestamp","isString","isDate"],"mappings":"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"}
package/dist/core.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.mjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TTzDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * 时区偏移量,单位为分钟,默认为当前时区\n */\n offset?: number;\n};\n\nconst TZ_OFFSET_MS = 60 * 1000;\n\nexport class TzDate {\n #timestamp: number;\n #targetDate: Date;\n #utcDate: Date;\n\n #localTZOffset = TzDate.getOffset();\n #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;\n\n #targetTzOffset = 0;\n #targetTzOffsetMS = 0;\n\n #options: TTzDateOptions;\n\n constructor(options?: TTzDateOptions | TzDate) {\n this.#options = (options instanceof TzDate ? options.#options : options) || {};\n const { offset, timestamp, value } = this.#options;\n this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;\n this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTzOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n getTimezoneOffset() {\n return this.#targetTzOffset;\n }\n\n getTimezoneOrder() {\n return TzDate.getOrder(this.#targetTzOffset);\n }\n\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n getDate() {\n return this.#targetDate.getDate();\n }\n\n getHours() {\n return this.#targetDate.getHours();\n }\n\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n getTime() {\n return this.#timestamp;\n }\n\n getDay() {\n return this.#targetDate.getDay();\n }\n\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 创建一个 TzDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TzDate 对象\n * @example\n * ```js\n * const tzDate = TzDate.from(new TzDate());\n * ```\n */\n static from(td: TzDate, offset = TzDate.getOffset()) {\n return new TzDate({\n offset: offset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区序号\n * @param offset - 默认使用当前时区分钟偏移量\n */\n static getOrder(offset = TzDate.getOffset()) {\n return offset / -60;\n }\n\n /**\n * 获取时区分钟偏移量\n * @param gmtOrder - 默认使用当前时区序号\n */\n static getOffset(gmtOrder?: number) {\n return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TzDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TzDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TzDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type TDateLike = Date | TzDate;\nexport type TDateValue = number | string | TDateLike;\n\nfunction _guessDateSeparator(value: TDateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: TDateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: TDateValue): TDateLike {\n // 传入的 Date 对象有 Date、TzDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TzDate\n ? new TzDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: TDateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: TDateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["timestamp"],"mappings":"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"}
1
+ {"version":3,"file":"core.mjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TzDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * 时区偏移量,单位为分钟,默认为当前时区\n */\n offset?: number;\n};\n\nconst TZ_OFFSET_MS = 60 * 1000;\n\nexport class TzDate {\n #timestamp: number;\n #targetDate: Date;\n #utcDate: Date;\n\n #localTZOffset = TzDate.getOffset();\n #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;\n\n #targetTzOffset = 0;\n #targetTzOffsetMS = 0;\n\n #options: TzDateOptions;\n\n constructor(options?: TzDateOptions | TzDate) {\n this.#options = (options instanceof TzDate ? options.#options : options) || {};\n const { offset, timestamp, value } = this.#options;\n this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;\n this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTzOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n getTimezoneOffset() {\n return this.#targetTzOffset;\n }\n\n getTimezoneOrder() {\n return TzDate.getOrder(this.#targetTzOffset);\n }\n\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n getDate() {\n return this.#targetDate.getDate();\n }\n\n getHours() {\n return this.#targetDate.getHours();\n }\n\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n getTime() {\n return this.#timestamp;\n }\n\n getDay() {\n return this.#targetDate.getDay();\n }\n\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 创建一个 TzDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TzDate 对象\n * @example\n * ```js\n * const tzDate = TzDate.from(new TzDate());\n * ```\n */\n static from(td: TzDate, offset = TzDate.getOffset()) {\n return new TzDate({\n offset: offset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区序号\n * @param offset - 默认使用当前时区分钟偏移量\n */\n static getOrder(offset = TzDate.getOffset()) {\n return offset / -60;\n }\n\n /**\n * 获取时区分钟偏移量\n * @param gmtOrder - 默认使用当前时区序号\n */\n static getOffset(gmtOrder?: number) {\n return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TzDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TzDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TzDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type DateLike = Date | TzDate;\nexport type DateValue = number | string | DateLike;\n\nfunction _guessDateSeparator(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: DateValue): DateLike {\n // 传入的 Date 对象有 Date、TzDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TzDate\n ? new TzDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: DateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["timestamp"],"mappings":"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"}
@@ -11,8 +11,8 @@ import { TzDate } from './timezone';
11
11
  * ```
12
12
  */
13
13
  export declare function isValidDate(unknown: unknown): unknown is Date | TzDate;
14
- export type TDateLike = Date | TzDate;
15
- export type TDateValue = number | string | TDateLike;
14
+ export type DateLike = Date | TzDate;
15
+ export type DateValue = number | string | DateLike;
16
16
  /**
17
17
  * 解析为Date对象
18
18
  * @param dateValue - 可以是数值、字符串或 Date 对象
@@ -26,7 +26,7 @@ export type TDateValue = number | string | TDateLike;
26
26
  * dateParse('invalid date'); // 抛出 SyntaxError
27
27
  * ```
28
28
  */
29
- export declare function dateParse(dateValue: TDateValue): TDateLike;
29
+ export declare function dateParse(dateValue: DateValue): DateLike;
30
30
  /**
31
31
  * 格式化为日期字符串(带自定义格式化模板)
32
32
  * @param dateValue - 可以是数值、字符串或 Date 对象
@@ -49,4 +49,4 @@ export declare function dateParse(dateValue: TDateValue): TDateLike;
49
49
  * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'
50
50
  * ```
51
51
  */
52
- export declare function dateFormat(dateValue: TDateValue, format?: string): string;
52
+ export declare function dateFormat(dateValue: DateValue, format?: string): string;
@@ -1,4 +1,4 @@
1
- import { TDateValue } from './core';
1
+ import { DateValue } from './core';
2
2
  /**
3
3
  * 计算指定日期所在月份的天数
4
4
  * @param dateValue - 可以是数值、字符串或 Date 对象
@@ -9,7 +9,7 @@ import { TDateValue } from './core';
9
9
  * dateDaysInMonth(new Date('2024-02-15')); // 29 (闰年)
10
10
  * ```
11
11
  */
12
- export declare function dateDaysInMonth(dateValue: TDateValue): number;
12
+ export declare function dateDaysInMonth(dateValue: DateValue): number;
13
13
  /**
14
14
  * 计算指定日期所在年份的天数
15
15
  * @param dateValue - 可以是数值、字符串或 Date 对象
@@ -20,4 +20,4 @@ export declare function dateDaysInMonth(dateValue: TDateValue): number;
20
20
  * dateDaysInYear(new Date('2024-02-15')); // 366 (闰年)
21
21
  * ```
22
22
  */
23
- export declare function dateDaysInYear(dateValue: TDateValue): number;
23
+ export declare function dateDaysInYear(dateValue: DateValue): number;
package/dist/date/is.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { TDateValue } from './core';
1
+ import { DateValue } from './core';
2
2
  /**
3
3
  * 判断给定的年份是否为闰年
4
4
  * @param year - 需要判断的年份
@@ -24,7 +24,7 @@ export declare function isLeapYear(year: number): boolean;
24
24
  * isSameDateInYear(date1, date2); // true
25
25
  * ```
26
26
  */
27
- export declare function isSameDateInYear(date1: TDateValue, date2: TDateValue): boolean;
27
+ export declare function isSameDateInYear(date1: DateValue, date2: DateValue): boolean;
28
28
  /**
29
29
  * 比较两个日期的年份和月份是否相同
30
30
  * @param date1 - 第一个日期,可以是数值、字符串或 Date 对象
@@ -37,7 +37,7 @@ export declare function isSameDateInYear(date1: TDateValue, date2: TDateValue):
37
37
  * isSameDateInMonth(date1, date2); // true
38
38
  * ```
39
39
  */
40
- export declare function isSameDateInMonth(date1: TDateValue, date2: TDateValue): boolean;
40
+ export declare function isSameDateInMonth(date1: DateValue, date2: DateValue): boolean;
41
41
  /**
42
42
  * 比较两个日期的年份、月份和天数是否相同
43
43
  * @param date1 - 第一个日期,可以是数值、字符串或 Date 对象
@@ -50,7 +50,7 @@ export declare function isSameDateInMonth(date1: TDateValue, date2: TDateValue):
50
50
  * isSameDateInDay(date1, date2); // true
51
51
  * ```
52
52
  */
53
- export declare function isSameDateInDay(date1: TDateValue, date2: TDateValue): boolean;
53
+ export declare function isSameDateInDay(date1: DateValue, date2: DateValue): boolean;
54
54
  /**
55
55
  * 比较两个日期的年份、月份、天数和小时是否相同
56
56
  * @param date1 - 第一个日期,可以是数值、字符串或 Date 对象
@@ -63,7 +63,7 @@ export declare function isSameDateInDay(date1: TDateValue, date2: TDateValue): b
63
63
  * isSameDateInHour(date1, date2); // true
64
64
  * ```
65
65
  */
66
- export declare function isSameDateInHour(date1: TDateValue, date2: TDateValue): boolean;
66
+ export declare function isSameDateInHour(date1: DateValue, date2: DateValue): boolean;
67
67
  /**
68
68
  * 比较两个日期的年份、月份、天数、小时和分钟是否相同
69
69
  * @param date1 - 第一个日期,可以是数值、字符串或 Date 对象
@@ -76,7 +76,7 @@ export declare function isSameDateInHour(date1: TDateValue, date2: TDateValue):
76
76
  * isSameDateInMinute(date1, date2); // true
77
77
  * ```
78
78
  */
79
- export declare function isSameDateInMinute(date1: TDateValue, date2: TDateValue): boolean;
79
+ export declare function isSameDateInMinute(date1: DateValue, date2: DateValue): boolean;
80
80
  /**
81
81
  * 比较两个日期的年份、月份、天数、小时、分钟和秒数是否相同
82
82
  * @param date1 - 第一个日期,可以是数值、字符串或 Date 对象
@@ -89,4 +89,4 @@ export declare function isSameDateInMinute(date1: TDateValue, date2: TDateValue)
89
89
  * isSameDateInSecond(date1, date2); // true
90
90
  * ```
91
91
  */
92
- export declare function isSameDateInSecond(date1: TDateValue, date2: TDateValue): boolean;
92
+ export declare function isSameDateInSecond(date1: DateValue, date2: DateValue): boolean;