@cloudcome/utils-core 1.22.0 → 1.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/array.cjs.map +1 -1
- package/dist/array.mjs.map +1 -1
- package/dist/async.cjs +1 -0
- package/dist/async.cjs.map +1 -1
- package/dist/async.mjs +1 -0
- package/dist/async.mjs.map +1 -1
- package/dist/base64.cjs.map +1 -1
- package/dist/base64.mjs.map +1 -1
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.mjs.map +1 -1
- package/dist/color.cjs.map +1 -1
- package/dist/color.mjs.map +1 -1
- package/dist/crypto.cjs.map +1 -1
- package/dist/crypto.mjs.map +1 -1
- package/dist/date.cjs.map +1 -1
- package/dist/date.mjs.map +1 -1
- package/dist/dict.cjs.map +1 -1
- package/dist/dict.mjs.map +1 -1
- package/dist/easing.cjs.map +1 -1
- package/dist/easing.mjs.map +1 -1
- package/dist/emitter.cjs.map +1 -1
- package/dist/emitter.mjs.map +1 -1
- package/dist/env.cjs.map +1 -1
- package/dist/env.mjs.map +1 -1
- package/dist/error.cjs.map +1 -1
- package/dist/error.mjs.map +1 -1
- package/dist/function.cjs.map +1 -1
- package/dist/function.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/object.cjs.map +1 -1
- package/dist/object.mjs.map +1 -1
- package/dist/path.cjs.map +1 -1
- package/dist/path.mjs.map +1 -1
- package/dist/promise.cjs.map +1 -1
- package/dist/promise.mjs.map +1 -1
- package/dist/qs.cjs.map +1 -1
- package/dist/qs.mjs.map +1 -1
- package/dist/regexp.cjs.map +1 -1
- package/dist/regexp.mjs.map +1 -1
- package/dist/string2.cjs.map +1 -1
- package/dist/string2.mjs.map +1 -1
- package/dist/time.cjs.map +1 -1
- package/dist/time.mjs.map +1 -1
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.mjs.map +1 -1
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.mjs.map +1 -1
- package/dist/try.cjs.map +1 -1
- package/dist/try.mjs.map +1 -1
- package/dist/type.cjs.map +1 -1
- package/dist/type.mjs.map +1 -1
- package/dist/unique.cjs.map +1 -1
- package/dist/unique.mjs.map +1 -1
- package/dist/url.cjs.map +1 -1
- package/dist/url.mjs.map +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +1 -9
- package/dist/exception.cjs +0 -40
- package/dist/exception.cjs.map +0 -1
- package/dist/exception.d.ts +0 -31
- package/dist/exception.mjs +0 -39
- package/dist/exception.mjs.map +0 -1
package/dist/array.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array.cjs","names":[],"sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T[]}\n */\n refValues: T[];\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T[]}\n */\n refValues: T[];\n /**\n * 当前数组中的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n};\n\nexport type ArrayDiffOptions<T> = {\n getItemKey: (item: T) => unknown;\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T> {\n const { getItemKey = (item: T) => item } = options || {};\n\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用\n type Key = any;\n\n const toKeyIndexes = (map: Map<Key, number[]>, item: T) => {\n const key = getItemKey(item);\n return {\n key,\n indexes: map.get(key) || [],\n };\n };\n\n const buildMap = (arr: T[]) => {\n const map = new Map<Key, number[]>();\n\n arr.forEach((item, index) => {\n const { key, indexes } = toKeyIndexes(map, item);\n indexes.push(index);\n map.set(key, indexes);\n });\n\n return map;\n };\n\n const toIndexesArr = (arr: T[], indexes: number[]) => {\n return indexes.map((index) => arr[index]);\n };\n\n const refMap = buildMap(refArray);\n const curMap = buildMap(curArray);\n const deleteSet = new Set<Key>();\n const addSet = new Set<Key>();\n const equalSet = new Set<Key>();\n\n for (const key of refMap.keys()) {\n if (curMap.has(key)) {\n equalSet.add(key);\n } else {\n deleteSet.add(key);\n }\n }\n\n for (const key of curMap.keys()) {\n if (!refMap.has(key)) {\n addSet.add(key);\n }\n }\n\n return {\n deletes: [...deleteSet].map((key) => {\n const indexes = refMap.get(key) || [];\n return {\n refIndexes: indexes,\n refValues: toIndexesArr(refArray, indexes),\n };\n }),\n\n adds: [...addSet].map((key) => {\n const indexes = curMap.get(key) || [];\n return {\n curIndexes: indexes,\n curValues: toIndexesArr(curArray, indexes),\n };\n }),\n\n equals: [...equalSet].map((key) => {\n const refIndexes = refMap.get(key) || [];\n const curIndexes = curMap.get(key) || [];\n return {\n refIndexes,\n curIndexes,\n refValues: toIndexesArr(refArray, refIndexes),\n curValues: toIndexesArr(curArray, curIndexes),\n };\n }),\n };\n}\n\n/**\n * 从数组中移除指定索引的元素\n * @template T - 数组元素的类型\n * @param {T[]} array - 原始数组\n * @param {number[]} indexes - 要移除的元素索引数组\n * @returns {T[]} 移除指定索引元素后的新数组\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayRemove(arr, [1, 3]);\n * // 返回结果: [1, 3, 5]\n * ```\n */\nexport function arrayRemove<T>(array: T[], indexes: number[]) {\n return array.filter((_item, index) => !indexes.includes(index));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"array.cjs","names":[],"sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T[]}\n */\n refValues: T[];\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T[]}\n */\n refValues: T[];\n /**\n * 当前数组中的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n};\n\nexport type ArrayDiffOptions<T> = {\n getItemKey: (item: T) => unknown;\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T> {\n const { getItemKey = (item: T) => item } = options || {};\n\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用\n type Key = any;\n\n const toKeyIndexes = (map: Map<Key, number[]>, item: T) => {\n const key = getItemKey(item);\n return {\n key,\n indexes: map.get(key) || [],\n };\n };\n\n const buildMap = (arr: T[]) => {\n const map = new Map<Key, number[]>();\n\n arr.forEach((item, index) => {\n const { key, indexes } = toKeyIndexes(map, item);\n indexes.push(index);\n map.set(key, indexes);\n });\n\n return map;\n };\n\n const toIndexesArr = (arr: T[], indexes: number[]) => {\n return indexes.map((index) => arr[index]);\n };\n\n const refMap = buildMap(refArray);\n const curMap = buildMap(curArray);\n const deleteSet = new Set<Key>();\n const addSet = new Set<Key>();\n const equalSet = new Set<Key>();\n\n for (const key of refMap.keys()) {\n if (curMap.has(key)) {\n equalSet.add(key);\n } else {\n deleteSet.add(key);\n }\n }\n\n for (const key of curMap.keys()) {\n if (!refMap.has(key)) {\n addSet.add(key);\n }\n }\n\n return {\n deletes: [...deleteSet].map((key) => {\n const indexes = refMap.get(key) || [];\n return {\n refIndexes: indexes,\n refValues: toIndexesArr(refArray, indexes),\n };\n }),\n\n adds: [...addSet].map((key) => {\n const indexes = curMap.get(key) || [];\n return {\n curIndexes: indexes,\n curValues: toIndexesArr(curArray, indexes),\n };\n }),\n\n equals: [...equalSet].map((key) => {\n const refIndexes = refMap.get(key) || [];\n const curIndexes = curMap.get(key) || [];\n return {\n refIndexes,\n curIndexes,\n refValues: toIndexesArr(refArray, refIndexes),\n curValues: toIndexesArr(curArray, curIndexes),\n };\n }),\n };\n}\n\n/**\n * 从数组中移除指定索引的元素\n * @template T - 数组元素的类型\n * @param {T[]} array - 原始数组\n * @param {number[]} indexes - 要移除的元素索引数组\n * @returns {T[]} 移除指定索引元素后的新数组\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayRemove(arr, [1, 3]);\n * // 返回结果: [1, 3, 5]\n * ```\n */\nexport function arrayRemove<T>(array: T[], indexes: number[]) {\n return array.filter((_item, index) => !indexes.includes(index));\n}\n"],"mappings":"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"}
|
package/dist/array.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array.mjs","names":[],"sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T[]}\n */\n refValues: T[];\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T[]}\n */\n refValues: T[];\n /**\n * 当前数组中的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n};\n\nexport type ArrayDiffOptions<T> = {\n getItemKey: (item: T) => unknown;\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T> {\n const { getItemKey = (item: T) => item } = options || {};\n\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用\n type Key = any;\n\n const toKeyIndexes = (map: Map<Key, number[]>, item: T) => {\n const key = getItemKey(item);\n return {\n key,\n indexes: map.get(key) || [],\n };\n };\n\n const buildMap = (arr: T[]) => {\n const map = new Map<Key, number[]>();\n\n arr.forEach((item, index) => {\n const { key, indexes } = toKeyIndexes(map, item);\n indexes.push(index);\n map.set(key, indexes);\n });\n\n return map;\n };\n\n const toIndexesArr = (arr: T[], indexes: number[]) => {\n return indexes.map((index) => arr[index]);\n };\n\n const refMap = buildMap(refArray);\n const curMap = buildMap(curArray);\n const deleteSet = new Set<Key>();\n const addSet = new Set<Key>();\n const equalSet = new Set<Key>();\n\n for (const key of refMap.keys()) {\n if (curMap.has(key)) {\n equalSet.add(key);\n } else {\n deleteSet.add(key);\n }\n }\n\n for (const key of curMap.keys()) {\n if (!refMap.has(key)) {\n addSet.add(key);\n }\n }\n\n return {\n deletes: [...deleteSet].map((key) => {\n const indexes = refMap.get(key) || [];\n return {\n refIndexes: indexes,\n refValues: toIndexesArr(refArray, indexes),\n };\n }),\n\n adds: [...addSet].map((key) => {\n const indexes = curMap.get(key) || [];\n return {\n curIndexes: indexes,\n curValues: toIndexesArr(curArray, indexes),\n };\n }),\n\n equals: [...equalSet].map((key) => {\n const refIndexes = refMap.get(key) || [];\n const curIndexes = curMap.get(key) || [];\n return {\n refIndexes,\n curIndexes,\n refValues: toIndexesArr(refArray, refIndexes),\n curValues: toIndexesArr(curArray, curIndexes),\n };\n }),\n };\n}\n\n/**\n * 从数组中移除指定索引的元素\n * @template T - 数组元素的类型\n * @param {T[]} array - 原始数组\n * @param {number[]} indexes - 要移除的元素索引数组\n * @returns {T[]} 移除指定索引元素后的新数组\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayRemove(arr, [1, 3]);\n * // 返回结果: [1, 3, 5]\n * ```\n */\nexport function arrayRemove<T>(array: T[], indexes: number[]) {\n return array.filter((_item, index) => !indexes.includes(index));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"array.mjs","names":[],"sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T[]}\n */\n refValues: T[];\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T[]}\n */\n refValues: T[];\n /**\n * 当前数组中的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n};\n\nexport type ArrayDiffOptions<T> = {\n getItemKey: (item: T) => unknown;\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T> {\n const { getItemKey = (item: T) => item } = options || {};\n\n // biome-ignore lint/suspicious/noExplicitAny: 内部使用\n type Key = any;\n\n const toKeyIndexes = (map: Map<Key, number[]>, item: T) => {\n const key = getItemKey(item);\n return {\n key,\n indexes: map.get(key) || [],\n };\n };\n\n const buildMap = (arr: T[]) => {\n const map = new Map<Key, number[]>();\n\n arr.forEach((item, index) => {\n const { key, indexes } = toKeyIndexes(map, item);\n indexes.push(index);\n map.set(key, indexes);\n });\n\n return map;\n };\n\n const toIndexesArr = (arr: T[], indexes: number[]) => {\n return indexes.map((index) => arr[index]);\n };\n\n const refMap = buildMap(refArray);\n const curMap = buildMap(curArray);\n const deleteSet = new Set<Key>();\n const addSet = new Set<Key>();\n const equalSet = new Set<Key>();\n\n for (const key of refMap.keys()) {\n if (curMap.has(key)) {\n equalSet.add(key);\n } else {\n deleteSet.add(key);\n }\n }\n\n for (const key of curMap.keys()) {\n if (!refMap.has(key)) {\n addSet.add(key);\n }\n }\n\n return {\n deletes: [...deleteSet].map((key) => {\n const indexes = refMap.get(key) || [];\n return {\n refIndexes: indexes,\n refValues: toIndexesArr(refArray, indexes),\n };\n }),\n\n adds: [...addSet].map((key) => {\n const indexes = curMap.get(key) || [];\n return {\n curIndexes: indexes,\n curValues: toIndexesArr(curArray, indexes),\n };\n }),\n\n equals: [...equalSet].map((key) => {\n const refIndexes = refMap.get(key) || [];\n const curIndexes = curMap.get(key) || [];\n return {\n refIndexes,\n curIndexes,\n refValues: toIndexesArr(refArray, refIndexes),\n curValues: toIndexesArr(curArray, curIndexes),\n };\n }),\n };\n}\n\n/**\n * 从数组中移除指定索引的元素\n * @template T - 数组元素的类型\n * @param {T[]} array - 原始数组\n * @param {number[]} indexes - 要移除的元素索引数组\n * @returns {T[]} 移除指定索引元素后的新数组\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayRemove(arr, [1, 3]);\n * // 返回结果: [1, 3, 5]\n * ```\n */\nexport function arrayRemove<T>(array: T[], indexes: number[]) {\n return array.filter((_item, index) => !indexes.includes(index));\n}\n"],"mappings":"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"}
|
package/dist/async.cjs
CHANGED
package/dist/async.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async.cjs","names":["#add","#length","#tasks","#stopLength","#startPwr","#running","#run","#addAndRun","#startResolved","#startLength","#startRejected","#startResults","#stopResults","#stopResolved","#stopPwr","#stopRejected"],"sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './function';\nimport type { AnyArray } 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"async.cjs","names":["#add","#length","#tasks","#stopLength","#startPwr","#running","#run","#addAndRun","#startResolved","#startLength","#startRejected","#startResults","#stopResults","#stopResolved","#stopPwr","#stopRejected"],"sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './function';\nimport type { AnyArray } 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"],"mappings":"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"}
|
package/dist/async.mjs
CHANGED
package/dist/async.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async.mjs","names":["#add","#length","#tasks","#stopLength","#startPwr","#running","#run","#addAndRun","#startResolved","#startLength","#startRejected","#startResults","#stopResults","#stopResolved","#stopPwr","#stopRejected"],"sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './function';\nimport type { AnyArray } 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"async.mjs","names":["#add","#length","#tasks","#stopLength","#startPwr","#running","#run","#addAndRun","#startResolved","#startLength","#startRejected","#startResults","#stopResults","#stopResolved","#stopPwr","#stopRejected"],"sources":["../src/async.ts"],"sourcesContent":["import { fnNoop } from './function';\nimport type { AnyArray } 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"],"mappings":"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"}
|
package/dist/base64.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base64.cjs","names":[],"sources":["../src/base64.ts"],"sourcesContent":["/**\n * base64 转换为 Blob 实例\n * @ref http://stackoverflow.com/q/18253378\n * @param base64 {String} base64 编码\n * @returns {Blob}\n */\nexport function base64toBlob(base64: string): Blob {\n const byteString = atob(base64.split(',')[1]);\n const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];\n const ab = new ArrayBuffer(byteString.length);\n const ua = new Uint8Array(ab);\n\n for (let i = 0; i < byteString.length; i++) {\n ua[i] = byteString.charCodeAt(i);\n }\n\n return new Blob([ab], {\n type: mimeString,\n });\n}\n"],"mappings":";;;;;;;;AAMA,SAAgB,aAAa,QAAsB;CACjD,MAAM,aAAa,KAAK,OAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"base64.cjs","names":[],"sources":["../src/base64.ts"],"sourcesContent":["/**\n * base64 转换为 Blob 实例\n * @ref http://stackoverflow.com/q/18253378\n * @param base64 {String} base64 编码\n * @returns {Blob}\n */\nexport function base64toBlob(base64: string): Blob {\n const byteString = atob(base64.split(',')[1]);\n const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];\n const ab = new ArrayBuffer(byteString.length);\n const ua = new Uint8Array(ab);\n\n for (let i = 0; i < byteString.length; i++) {\n ua[i] = byteString.charCodeAt(i);\n }\n\n return new Blob([ab], {\n type: mimeString,\n });\n}\n"],"mappings":";;;;;;;;AAMA,SAAgB,aAAa,QAAsB;CACjD,MAAM,aAAa,KAAK,OAAO,MAAM,GAAG,EAAE,EAAE;CAC5C,MAAM,aAAa,OAAO,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE;CACjE,MAAM,KAAK,IAAI,YAAY,WAAW,MAAM;CAC5C,MAAM,KAAK,IAAI,WAAW,EAAE;CAE5B,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KACrC,GAAG,KAAK,WAAW,WAAW,CAAC;CAGjC,OAAO,IAAI,KAAK,CAAC,EAAE,GAAG,EACpB,MAAM,WACR,CAAC;AACH"}
|
package/dist/base64.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base64.mjs","names":[],"sources":["../src/base64.ts"],"sourcesContent":["/**\n * base64 转换为 Blob 实例\n * @ref http://stackoverflow.com/q/18253378\n * @param base64 {String} base64 编码\n * @returns {Blob}\n */\nexport function base64toBlob(base64: string): Blob {\n const byteString = atob(base64.split(',')[1]);\n const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];\n const ab = new ArrayBuffer(byteString.length);\n const ua = new Uint8Array(ab);\n\n for (let i = 0; i < byteString.length; i++) {\n ua[i] = byteString.charCodeAt(i);\n }\n\n return new Blob([ab], {\n type: mimeString,\n });\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,aAAa,QAAsB;CACjD,MAAM,aAAa,KAAK,OAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"base64.mjs","names":[],"sources":["../src/base64.ts"],"sourcesContent":["/**\n * base64 转换为 Blob 实例\n * @ref http://stackoverflow.com/q/18253378\n * @param base64 {String} base64 编码\n * @returns {Blob}\n */\nexport function base64toBlob(base64: string): Blob {\n const byteString = atob(base64.split(',')[1]);\n const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];\n const ab = new ArrayBuffer(byteString.length);\n const ua = new Uint8Array(ab);\n\n for (let i = 0; i < byteString.length; i++) {\n ua[i] = byteString.charCodeAt(i);\n }\n\n return new Blob([ab], {\n type: mimeString,\n });\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,aAAa,QAAsB;CACjD,MAAM,aAAa,KAAK,OAAO,MAAM,GAAG,EAAE,EAAE;CAC5C,MAAM,aAAa,OAAO,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE;CACjE,MAAM,KAAK,IAAI,YAAY,WAAW,MAAM;CAC5C,MAAM,KAAK,IAAI,WAAW,EAAE;CAE5B,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KACrC,GAAG,KAAK,WAAW,WAAW,CAAC;CAGjC,OAAO,IAAI,KAAK,CAAC,EAAE,GAAG,EACpB,MAAM,WACR,CAAC;AACH"}
|
package/dist/cache.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.cjs","names":[],"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"],"mappings":";;;;;;;AAsDA,IAAa,gBAAb,MAAkD;CAChD,UAAU,QAAmB;EAC3B,OAAO,OAAO,YAAY,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"cache.cjs","names":[],"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"],"mappings":";;;;;;;AAsDA,IAAa,gBAAb,MAAkD;CAChD,UAAU,QAAmB;EAC3B,OAAO,OAAO,YAAY,KAAK,KAAK,IAAI,IAAI,OAAO;CACrD;CAEA,gBAAgB,IAAY,MAAS,SAAmC;EACtE,MAAM,EAAE,YAAY,GAAG,SAAS,MAAM,WAAW,CAAC;EAClD,MAAM,MAAM,KAAK,IAAI;EACrB,OAAO;GACL;GACA;GACA,WAAW;GACX,WAAW,YAAY,aAAA,UAAU,SAAS,EAAE,QAAQ,IAAI,SAAS,IAAI,MAAM,SAAS;EACtF;CACF;;;;;;CAOA,IAAI,KAA6C;EAC/C,OAAO;CACT;;;;;;;CAQA,IAAI,KAAa,OAAU,UAA6C,CAExE;;;;;CAMA,IAAI,KAAiC,CAErC;;;;CAKA,QAA4B,CAE5B;AACF;;;;;AAMA,IAAa,cAAb,cAAoC,cAAiB;CACnD,wBAAwC,IAAI,IAAI;CAEhD,IAAI,IAAY;EACd,MAAM,SAAS,KAAK,MAAM,IAAI,EAAE;EAEhC,IAAI,CAAC,QAAQ,OAAO;EAEpB,IAAI,KAAK,UAAU,MAAM,GAAG;GAC1B,KAAK,IAAI,EAAE;GACX,OAAO;EACT;EAEA,OAAO;CACT;CAEA,IAAI,IAAY,MAAS,SAAwB;EAC/C,KAAK,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;CAC5D;CAEA,IAAI,IAAY;EACd,KAAK,MAAM,OAAO,EAAE;CACtB;CAEA,QAAQ;EACN,KAAK,MAAM,MAAM;CACnB;AACF;;;;;;AAOA,SAAgB,iBAAoB;CAClC,OAAO,IAAI,YAAe;AAC5B"}
|
package/dist/cache.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.mjs","names":[],"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"],"mappings":";;;;;;AAsDA,IAAa,gBAAb,MAAkD;CAChD,UAAU,QAAmB;EAC3B,OAAO,OAAO,YAAY,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"cache.mjs","names":[],"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"],"mappings":";;;;;;AAsDA,IAAa,gBAAb,MAAkD;CAChD,UAAU,QAAmB;EAC3B,OAAO,OAAO,YAAY,KAAK,KAAK,IAAI,IAAI,OAAO;CACrD;CAEA,gBAAgB,IAAY,MAAS,SAAmC;EACtE,MAAM,EAAE,YAAY,GAAG,SAAS,MAAM,WAAW,CAAC;EAClD,MAAM,MAAM,KAAK,IAAI;EACrB,OAAO;GACL;GACA;GACA,WAAW;GACX,WAAW,YAAY,UAAU,SAAS,EAAE,QAAQ,IAAI,SAAS,IAAI,MAAM,SAAS;EACtF;CACF;;;;;;CAOA,IAAI,KAA6C;EAC/C,OAAO;CACT;;;;;;;CAQA,IAAI,KAAa,OAAU,UAA6C,CAExE;;;;;CAMA,IAAI,KAAiC,CAErC;;;;CAKA,QAA4B,CAE5B;AACF;;;;;AAMA,IAAa,cAAb,cAAoC,cAAiB;CACnD,wBAAwC,IAAI,IAAI;CAEhD,IAAI,IAAY;EACd,MAAM,SAAS,KAAK,MAAM,IAAI,EAAE;EAEhC,IAAI,CAAC,QAAQ,OAAO;EAEpB,IAAI,KAAK,UAAU,MAAM,GAAG;GAC1B,KAAK,IAAI,EAAE;GACX,OAAO;EACT;EAEA,OAAO;CACT;CAEA,IAAI,IAAY,MAAS,SAAwB;EAC/C,KAAK,MAAM,IAAI,IAAI,KAAK,gBAAgB,IAAI,MAAM,OAAO,CAAC;CAC5D;CAEA,IAAI,IAAY;EACd,KAAK,MAAM,OAAO,EAAE;CACtB;CAEA,QAAQ;EACN,KAAK,MAAM,MAAM;CACnB;AACF;;;;;;AAOA,SAAgB,iBAAoB;CAClC,OAAO,IAAI,YAAe;AAC5B"}
|
package/dist/color.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color.cjs","names":[],"sources":["../src/color/luminance.ts","../src/color/contrast.ts","../src/color/distance.ts","../src/color/helpers.ts","../src/color/hex-rgb.ts","../src/color/rgb-hsl.ts","../src/color/hex-hsl.ts","../src/color/rgb-hsv.ts","../src/color/hex-hsv.ts","../src/color/rgb-hwb.ts","../src/color/hex-hwb.ts","../src/color/hsl-lighten.ts","../src/color/hsv-brighten.ts","../src/color/mix.ts","../src/color/rgb-xyz.ts","../src/color/xyz-lab.ts","../src/color/rgb-lab.ts","../src/color/rgb-whiter.ts"],"sourcesContent":["import type { RGB } from './types';\n\n/**\n * 计算RGB颜色的相对亮度(符合WCAG 2.1标准)\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {number} 相对亮度值(0-1之间)\n * @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance\n * @example\n * luminance({r: 255, g: 255, b: 255}) // 返回1\n */\nexport function luminance({ r, g, b }: RGB) {\n const a = [r, g, b].map((v) => {\n const vFinal = v / 255;\n return vFinal <= 0.03928 ? vFinal / 12.92 : ((vFinal + 0.055) / 1.055) ** 2.4;\n });\n return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;\n}\n","import { luminance } from './luminance';\nimport type { RGB } from './types';\n\n/**\n * 计算两个颜色之间的对比度比率(符合WCAG 2.1标准)\n * @param rgb1 第一个RGB颜色对象(分量范围0-255)\n * @param rgb2 第二个RGB颜色对象(分量范围0-255)\n * @returns {number} 对比度比率,范围1-21(1:1 到 21:1)\n * @example\n * contrast({r: 0, g: 0, b: 0}, {r: 255, g: 255, b: 255}) // 返回21\n */\nexport function contrast(rgb1: RGB, rgb2: RGB) {\n const lum1 = luminance(rgb1);\n const lum2 = luminance(rgb2);\n\n const brightest = Math.max(lum1, lum2);\n const darkest = Math.min(lum1, lum2);\n\n return (brightest + 0.05) / (darkest + 0.05);\n}\n","import type { LAB } from './types';\n\n// calculate the perceptual distance between colors in CIELAB\n// https://github.com/THEjoezack/ColorMine/blob/master/ColorMine/ColorSpaces/Comparisons/Cie94Comparison.cs\n\n/**\n * 计算两个颜色之间的距离(距离越小相似度越高),值范围 [0, 1]\n * @param {LAB} labA\n * @param {LAB} labB\n * @returns {number}\n */\nexport function distance(labA: LAB, labB: LAB) {\n const deltaL = labA.l - labB.l;\n const deltaA = labA.a - labB.a;\n const deltaB = labA.b - labB.b;\n const c1 = Math.sqrt(labA.a * labA.a + labA.b * labA.b);\n const c2 = Math.sqrt(labB.a * labB.a + labB.b * labB.b);\n const deltaC = c1 - c2;\n let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;\n deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);\n const sc = 1.0 + 0.045 * c1;\n const sh = 1.0 + 0.015 * c1;\n const deltaLKlsl = deltaL / 1.0;\n const deltaCkcsc = deltaC / sc;\n const deltaHkhsh = deltaH / sh;\n const i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;\n return (i < 0 ? 0 : Math.sqrt(i)) / 100;\n}\n","import type { RGB } from './types';\n\nconst { min, max } = Math;\n\nexport function rgbToHue({ r, g, b }: RGB): [number, number, number, number] {\n r /= 255;\n g /= 255;\n b /= 255;\n\n const rgbMax = max(r, g, b);\n const rgbMin = min(r, g, b);\n const rgbDiff = rgbMax - rgbMin;\n const h =\n rgbDiff === 0\n ? 0\n : rgbDiff && rgbMax === r\n ? (g - b) / rgbDiff\n : rgbMax === g\n ? 2 + (b - r) / rgbDiff\n : 4 + (r - g) / rgbDiff;\n\n return [60 * (h < 0 ? h + 6 : h), rgbMax, rgbMin, rgbDiff];\n}\n","import type { HEX, RGB } from './types';\n\n/**\n * 将HEX颜色字符串转换为RGB颜色对象\n * @param hex HEX颜色字符串,支持3位或6位格式(例如#f00或#ff0000)\n * @returns {RGB} 对应的RGB颜色对象\n * @throws {SyntaxError} 当颜色格式不符合规范时抛出\n * @example\n * hexToRgb('#f00') // returns {r: 255, g: 0, b: 0}\n */\nexport function hexToRgb(hex: HEX): RGB {\n const reg = hex.length === 4 ? /^#(.)(.)(.)$/ : /^#(.{2})(.{2})(.{2})$/;\n const result = reg.exec(hex);\n\n if (!result) throw new SyntaxError(`颜色(${hex})表达式有误`);\n\n const [_, r, g, b] = result;\n\n return {\n r: Number.parseInt(r.padEnd(2, r), 16),\n g: Number.parseInt(g.padEnd(2, g), 16),\n b: Number.parseInt(b.padEnd(2, b), 16),\n };\n}\n\nfunction to16(n: number) {\n return Math.round(n).toString(16).padStart(2, '0');\n}\n\n/**\n * 将RGB颜色对象转换为HEX颜色字符串\n * @param rgb RGB颜色对象\n * @returns {HEX} 6位HEX颜色字符串(带#前缀)\n * @example\n * rgbToHex({r: 255, g: 0, b: 0}) // returns '#ff0000'\n */\nexport function rgbToHex(rgb: RGB): HEX {\n return `#${to16(rgb.r)}${to16(rgb.g)}${to16(rgb.b)}`;\n}\n","// @ref https://www.w3schools.com/lib/w3color.js\nimport { rgbToHue } from './helpers';\nimport type { HSL, RGB } from './types';\n\nconst { min, max } = Math;\n\n/**\n * 将RGB颜色转换为HSL颜色空间\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {HSL} HSL颜色对象,其中:\n * h: 色相(0-360度)\n * s: 饱和度(0-100%)\n * l: 亮度(0-100%)\n * @example\n * rgbToHsl({r: 255, g: 0, b: 0}) // returns {h: 0, s: 100, l: 50}\n */\nexport function rgbToHsl(rgb: RGB): HSL {\n const [hue, max, min, diff] = rgbToHue(rgb);\n const l = (2 * max - diff) / 2;\n const s = min === max ? 0 : l < 0.5 ? (max - min) / (max + min) : (max - min) / (2 - max - min);\n\n return {\n h: hue,\n s: s * 100,\n l: l * 100,\n };\n}\n\n// @ref https://www.30secondsofcode.org/js/s/hsl-to-rgb/\n/**\n * 将HSL颜色转换回RGB颜色空间\n * @param hsl HSL颜色对象\n * @param hsl.h 色相(0-360度)\n * @param hsl.s 饱和度(0-100%)\n * @param hsl.l 亮度(0-100%)\n * @returns {RGB} RGB颜色对象(分量范围0-255)\n * @example\n * hslToRgb({h: 0, s: 100, l: 50}) // returns {r: 255, g: 0, b: 0}\n */\nexport function hslToRgb({ h, s, l }: HSL): RGB {\n s /= 100;\n l /= 100;\n\n const a = s * min(l, 1 - l);\n const k = (n: number) => (n + h / 30) % 12;\n const f = (n: number) => l - a * max(-1, min(k(n) - 3, min(9 - k(n), 1)));\n\n return {\n r: 255 * f(0),\n g: 255 * f(8),\n b: 255 * f(4),\n };\n}\n","import { hexToRgb, rgbToHex } from './hex-rgb';\nimport { hslToRgb, rgbToHsl } from './rgb-hsl';\nimport type { HEX, HSL } from './types';\n\nexport function hslToHex(hsl: HSL): HEX {\n return rgbToHex(hslToRgb(hsl));\n}\n\nexport function hexToHsl(hex: HEX): HSL {\n return rgbToHsl(hexToRgb(hex));\n}\n","import { rgbToHue } from './helpers';\nimport type { HSV, RGB } from './types';\n\nconst { min, max } = Math;\n\n// @ref https://www.30secondsofcode.org/js/s/rgb-to-hsb/\n/**\n * 将RGB颜色转换为HSV颜色空间\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {HSV} HSV颜色对象:\n * h: 色相(0-360度)\n * s: 饱和度(0-100%)\n * v: 明度(0-100%)\n * @see https://en.wikipedia.org/wiki/HSL_and_HSV\n * @example\n * rgbToHsv({r: 255, g: 0, b: 0}) // {h: 0, s: 100, v: 100}\n */\nexport function rgbToHsv(rgb: RGB): HSV {\n const [hue, max, _min, diff] = rgbToHue(rgb);\n\n return {\n h: hue,\n s: max && (diff / max) * 100,\n v: max * 100,\n };\n}\n\n// @ref https://www.30secondsofcode.org/js/s/hsb-to-rgb/\n/**\n * 将HSV颜色转换回RGB颜色空间\n * @param hsv HSV颜色对象\n * @param hsv.h 色相(0-360度)\n * @param hsv.s 饱和度(0-100%)\n * @param hsv.v 明度(0-100%)\n * @returns {RGB} RGB颜色对象(分量范围0-255)\n * @see https://www.rapidtables.com/convert/color/hsv-to-rgb.html\n * @example\n * hsvToRgb({h: 0, s: 100, v: 100}) // {r: 255, g: 0, b: 0}\n */\nexport function hsvToRgb({ h, s, v }: HSV): RGB {\n s /= 100;\n v /= 100;\n\n const k = (n: number) => (n + h / 60) % 6;\n const f = (n: number) => v * (1 - s * max(0, min(k(n), 4 - k(n), 1)));\n\n return {\n r: 255 * f(5),\n g: 255 * f(3),\n b: 255 * f(1),\n };\n}\n","import { hexToRgb, rgbToHex } from './hex-rgb';\nimport { hsvToRgb, rgbToHsv } from './rgb-hsv';\nimport type { HEX, HSV } from './types';\n\n/**\n * 将HEX颜色转换为HSV颜色空间\n * @param hex HEX颜色字符串(支持3位或6位格式)\n * @returns {HSV} HSV颜色对象,包含:\n * h: 色相(0-360度)\n * s: 饱和度(0-100%)\n * v: 明度(0-100%)\n * @example\n * hexToHsv('#ff0000') // returns {h: 0, s: 100, v: 100}\n */\nexport function hexToHsv(hex: HEX): HSV {\n return rgbToHsv(hexToRgb(hex));\n}\n\n/**\n * 将HSV颜色转换回HEX字符串\n * @param hsv HSV颜色对象\n * @returns {HEX} 6位HEX颜色字符串(带#前缀)\n * @example\n * hsvToHex({h: 0, s: 100, v: 100}) // returns '#ff0000'\n */\nexport function hsvToHex(hsv: HSV): HEX {\n return rgbToHex(hsvToRgb(hsv));\n}\n","import { rgbToHue } from './helpers';\nimport { hslToRgb } from './rgb-hsl';\nimport type { HWB, RGB } from './types';\n\n/**\n * 将RGB颜色转换为HWB颜色空间\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {HWB} HWB颜色对象:\n * h: 色相(0-360度)\n * w: 白度(0-100%)\n * b: 黑度(0-100%)\n * @see https://www.w3.org/TR/css-color-4/#hwb-to-rgb\n * @example\n * rgbToHwb({r: 255, g: 0, b: 0}) // {h: 0, w: 0, b: 0}\n */\nexport function rgbToHwb(rgb: RGB): HWB {\n const [hue, max, min, _diff] = rgbToHue(rgb);\n return {\n h: hue,\n w: min * 100,\n b: (1 - max) * 100,\n };\n}\n\n// @ref https://www.w3schools.com/lib/w3color.js\n/**\n * 将HWB颜色转换回RGB颜色空间\n * @param hwb HWB颜色对象\n * @param hwb.h 色相(0-360度)\n * @param hwb.w 白度(0-100%)\n * @param hwb.b 黑度(0-100%)\n * @returns {RGB} RGB颜色对象(分量范围0-255)\n * @see https://en.wikipedia.org/wiki/HWB_color_model\n * @example\n * hwbToRgb({h: 0, w: 0, b: 0}) // {r: 255, g: 0, b: 0}\n */\nexport function hwbToRgb({ h, w: white, b: black }: HWB) {\n white /= 100;\n black /= 100;\n\n const { r, g, b } = hslToRgb({ h, s: 100, l: 50 });\n const tot = white + black;\n\n if (tot > 1) {\n white = white / tot;\n black = black / tot;\n }\n\n const f = (n: number) => ((n / 255) * (1 - white - black) + white) * 255;\n\n return {\n r: f(r),\n g: f(g),\n b: f(b),\n };\n}\n","import { hexToRgb, rgbToHex } from './hex-rgb';\nimport { hwbToRgb, rgbToHwb } from './rgb-hwb';\nimport type { HEX, HWB } from './types';\n\n/**\n * 将HWB颜色转换为HEX字符串\n * @param hwb HWB颜色对象\n * @param hwb.h 色相(0-360度)\n * @param hwb.w 白度(0-100%)\n * @param hwb.b 黑度(0-100%)\n * @returns {HEX} 6位HEX颜色字符串(带#前缀)\n * @example\n * hwbToHex({h: 0, w: 0, b: 0}) // returns '#ff0000'\n */\nexport function hwbToHex(hwb: HWB): HEX {\n return rgbToHex(hwbToRgb(hwb));\n}\n\n/**\n * 将HEX颜色转换为HWB颜色空间\n * @param hex HEX颜色字符串(支持3位或6位格式)\n * @returns {HWB} HWB颜色对象,包含:\n * h: 色相(0-360度)\n * w: 白度(0-100%)\n * b: 黑度(0-100%)\n * @example\n * hexToHwb('#ff0000') // returns {h: 0, w: 0, b: 0}\n */\nexport function hexToHwb(hex: HEX): HWB {\n return rgbToHwb(hexToRgb(hex));\n}\n","import type { HSL } from './types';\n\n/**\n * 通过HSL颜色空间调整颜色亮度\n * @param hsl 原始 HSL 颜色\n * @param value 亮度调整系数(0-1之间,0.1表示增加10%亮度)\n * @returns {HSL} 调整后的 HSL 颜色\n * @example\n * hslLighten({h: 300, s: 33, l: 44}, 0.2) // 返回亮度增加20%后的颜色\n */\nexport function hslLighten(hsl: HSL, value: number): HSL {\n const hslFinal = { ...hsl };\n hslFinal.l = hslFinal.l * (1 + value);\n return hslFinal;\n}\n","import type { HSV } from './types';\n\n/**\n * 通过HSV颜色空间调整颜色明度\n * @param hsv 原始HSV颜色对象\n * @param value 明度调整系数(-1到1之间):\n * - 正值增加明度(如0.2表示+20%)\n * - 负值降低明度(如-0.1表示-10%)\n * @returns {HSV} 调整后的HSV颜色对象(v值范围0-100%)\n * @example\n * hsvBrighten({h: 0, s: 100, v: 50}, 0.3) // 返回{h: 0, s: 100, v: 65}\n */\nexport function hsvBrighten(hsv: HSV, value: number): HSV {\n const hsvFinal = { ...hsv };\n hsvFinal.v = hsvFinal.v * (1 + value);\n return hsvFinal;\n}\n","import type { HSL, HSV, RGB } from './types';\n\n/**\n * 颜色混合函数(支持RGB/HSL/HSV色彩模型)\n * @template T 颜色类型,支持RGB、HSL或HSV对象\n * @param {T} a 第一个颜色对象\n * @param {T} b 第二个颜色对象\n * @param {number} [weight=0.5] 混合权重(0-1之间):\n * - 0 表示完全使用第一个颜色\n * - 1 表示完全使用第二个颜色\n * @returns {T} 线性混合后的新颜色对象\n * @example\n * // RGB混合示例\n * mix({r: 255, g: 0, b: 0}, {r: 0, g: 0, b: 255}, 0.5) // 返回紫色\n *\n * // HSL混合示例\n * mix({h: 0, s: 100, l: 50}, {h: 120, s: 100, l: 50}, 0.3)\n */\nexport function mix<T extends RGB | HSV | HSL>(a: T, b: T, weight = 0.5): T {\n return Object.keys(a).reduce((acc, key) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n acc[key] = (b[key] - a[key]) * weight + a[key];\n return acc;\n }, {} as T);\n}\n","// https://stackoverflow.com/a/73998199\n\nimport type { RGB, XYZ } from './types';\n\n/**\n * 将RGB颜色转换为CIE 1931 XYZ颜色空间(D65白点,2°观察者)\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {XYZ} XYZ颜色对象:\n * x: 约0-95.047\n * y: 约0-100.0\n * z: 约0-108.883\n * @see https://en.wikipedia.org/wiki/CIE_1931_color_space\n * @example\n * rgbToXyz({r: 255, g: 255, b: 255}) // {x: 95.047, y: 100.0, z: 108.883}\n */\nexport function rgbToXyz(rgb: RGB): XYZ {\n const { r, g, b } = rgb;\n const [var_R, var_G, var_B] = [r, g, b]\n .map((x) => x / 255)\n .map((x) => (x > 0.04045 ? ((x + 0.055) / 1.055) ** 2.4 : x / 12.92))\n .map((x) => x * 100);\n\n return {\n // Observer. = 2°, Illuminant = D65\n x: var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805,\n y: var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722,\n z: var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505,\n };\n}\n\n/**\n * 将XYZ颜色转换回RGB颜色空间(可能超出常规范围)\n * @param xyz XYZ颜色对象\n * @returns {RGB} RGB颜色对象(分量可能超出0-255范围)\n * @see https://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html\n * @example\n * xyzToRgb({x: 95.047, y: 100.0, z: 108.883}) // {r: 255, g: 255, b: 255}\n */\nexport function xyzToRgb(xyz: XYZ): RGB {\n const { x, y, z } = xyz;\n\n //X, Y and Z input refer to a D65/2° standard illuminant.\n //sR, sG and sB (standard RGB) output range = 0 ÷ 255\n\n const var_X = x / 100;\n const var_Y = y / 100;\n const var_Z = z / 100;\n\n const var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;\n const var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;\n const var_B = var_X * 0.0557 + var_Y * -0.204 + var_Z * 1.057;\n\n const [r, g, b] = [var_R, var_G, var_B]\n .map((n) => (n > 0.0031308 ? 1.055 * n ** (1 / 2.4) - 0.055 : 12.92 * n))\n .map((n) => n * 255);\n\n return {\n r,\n g,\n b,\n };\n}\n","// https://stackoverflow.com/a/73998199\n\nimport type { LAB, XYZ } from './types';\n\nconst ref_X = 95.047;\nconst ref_Y = 100.0;\nconst ref_Z = 108.883;\n\n/**\n * 将XYZ颜色转换为Lab颜色空间(CIE 1976 L*a*b*,D65白点)\n * @param xyz XYZ颜色对象(参考值:D65白点X=95.047,Y=100,Z=108.883)\n * @returns {LAB} Lab颜色对象:\n * l: 明度(0-100)\n * a: 绿-红分量(典型范围-128到127)\n * b: 蓝-黄分量(典型范围-128到127)\n * @see https://en.wikipedia.org/wiki/CIELAB_color_space\n * @example\n * xyzToLab({x: 95.047, y: 100.0, z: 108.883}) // {l: 100, a: 0, b: 0}\n */\nexport function xyzToLab(xyz: XYZ): LAB {\n const { x, y, z } = xyz;\n const [var_X, var_Y, var_Z] = [x / ref_X, y / ref_Y, z / ref_Z].map((a) =>\n a > 0.008856 ? a ** (1 / 3) : 7.787 * a + 16 / 116,\n );\n\n const l = 116 * var_Y - 16;\n const a = 500 * (var_X - var_Y);\n const b = 200 * (var_Y - var_Z);\n\n return { l, a, b };\n}\n\n/**\n * 将Lab颜色转换回XYZ颜色空间\n * @param lab Lab颜色对象\n * @param lab.l 明度(0-100)\n * @param lab.a 绿-红分量(典型范围-128到127)\n * @param lab.b 蓝-黄分量(典型范围-128到127)\n * @returns {XYZ} XYZ颜色对象(基于D65白点)\n * @see https://www.easyrgb.com/en/math.php\n * @example\n * labToXyz({l: 100, a: 0, b: 0}) // {x: 95.047, y: 100.0, z: 108.883}\n */\nexport function labToXyz(lab: LAB): XYZ {\n const { l, a, b } = lab;\n\n const var_Y = (l + 16) / 116;\n const var_X = a / 500 + var_Y;\n const var_Z = var_Y - b / 200;\n\n const [X, Y, Z] = [var_X, var_Y, var_Z].map((n) => (n ** 3 > 0.008856 ? n ** 3 : (n - 16 / 116) / 7.787));\n\n return { x: X * ref_X, y: Y * ref_Y, z: Z * ref_Z };\n}\n","import { rgbToXyz, xyzToRgb } from './rgb-xyz';\nimport type { LAB, RGB } from './types';\nimport { labToXyz, xyzToLab } from './xyz-lab';\n\n/**\n * 将RGB颜色转换为Lab颜色空间(CIE 1976标准)\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {LAB} Lab颜色对象:\n * l: 明度(0-100)\n * a: 绿-红分量(-128到127)\n * b: 蓝-黄分量(-128到127)\n * @see https://en.wikipedia.org/wiki/CIELAB_color_space\n * @example\n * rgbToLab({r: 255, g: 0, b: 0}) // {l: 53.24, a: 80.09, b: 67.20}\n */\nexport function rgbToLab(rgb: RGB): LAB {\n return xyzToLab(rgbToXyz(rgb));\n}\n\n/**\n * 将Lab颜色转换回RGB颜色空间\n * @param lab Lab颜色对象\n * @param lab.l 明度(0-100)\n * @param lab.a 绿-红分量(-128到127)\n * @param lab.b 蓝-黄分量(-128到127)\n * @returns {RGB} RGB颜色对象(分量可能超出0-255范围)\n * @see https://www.easyrgb.com/en/math.php\n * @example\n * labToRgb({l: 53.24, a: 80.09, b: 67.20}) // {r: 255, g: 0, b: 0}\n */\nexport function labToRgb(lab: LAB): RGB {\n return xyzToRgb(labToXyz(lab));\n}\n","import { mix } from './mix';\nimport type { RGB } from './types';\n\nconst { abs } = Math;\n\nconst whiteRGB: RGB = { r: 0, g: 0, b: 0 };\nconst blackRGB: RGB = { r: 255, g: 255, b: 255 };\n\n/**\n * 通过混合颜色调整明暗度\n * @param rgb 原始RGB颜色对象\n * @param value 调整强度(-1到1之间):\n * - 正值时与黑色混合(增加暗度)\n * - 负值时与白色混合(增加亮度)\n * @returns {RGB} 调整后的RGB颜色对象\n * @example\n * rgbDarken({r: 100, g: 150, b: 200}, 0.2) // 变暗20%\n */\nexport function rgbWhiter(rgb: RGB, value: number): RGB {\n const rgb2: RGB = value > 0 ? whiteRGB : blackRGB;\n return mix(rgb, rgb2, abs(value));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"color.cjs","names":[],"sources":["../src/color/luminance.ts","../src/color/contrast.ts","../src/color/distance.ts","../src/color/helpers.ts","../src/color/hex-rgb.ts","../src/color/rgb-hsl.ts","../src/color/hex-hsl.ts","../src/color/rgb-hsv.ts","../src/color/hex-hsv.ts","../src/color/rgb-hwb.ts","../src/color/hex-hwb.ts","../src/color/hsl-lighten.ts","../src/color/hsv-brighten.ts","../src/color/mix.ts","../src/color/rgb-xyz.ts","../src/color/xyz-lab.ts","../src/color/rgb-lab.ts","../src/color/rgb-whiter.ts"],"sourcesContent":["import type { RGB } from './types';\n\n/**\n * 计算RGB颜色的相对亮度(符合WCAG 2.1标准)\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {number} 相对亮度值(0-1之间)\n * @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance\n * @example\n * luminance({r: 255, g: 255, b: 255}) // 返回1\n */\nexport function luminance({ r, g, b }: RGB) {\n const a = [r, g, b].map((v) => {\n const vFinal = v / 255;\n return vFinal <= 0.03928 ? vFinal / 12.92 : ((vFinal + 0.055) / 1.055) ** 2.4;\n });\n return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;\n}\n","import { luminance } from './luminance';\nimport type { RGB } from './types';\n\n/**\n * 计算两个颜色之间的对比度比率(符合WCAG 2.1标准)\n * @param rgb1 第一个RGB颜色对象(分量范围0-255)\n * @param rgb2 第二个RGB颜色对象(分量范围0-255)\n * @returns {number} 对比度比率,范围1-21(1:1 到 21:1)\n * @example\n * contrast({r: 0, g: 0, b: 0}, {r: 255, g: 255, b: 255}) // 返回21\n */\nexport function contrast(rgb1: RGB, rgb2: RGB) {\n const lum1 = luminance(rgb1);\n const lum2 = luminance(rgb2);\n\n const brightest = Math.max(lum1, lum2);\n const darkest = Math.min(lum1, lum2);\n\n return (brightest + 0.05) / (darkest + 0.05);\n}\n","import type { LAB } from './types';\n\n// calculate the perceptual distance between colors in CIELAB\n// https://github.com/THEjoezack/ColorMine/blob/master/ColorMine/ColorSpaces/Comparisons/Cie94Comparison.cs\n\n/**\n * 计算两个颜色之间的距离(距离越小相似度越高),值范围 [0, 1]\n * @param {LAB} labA\n * @param {LAB} labB\n * @returns {number}\n */\nexport function distance(labA: LAB, labB: LAB) {\n const deltaL = labA.l - labB.l;\n const deltaA = labA.a - labB.a;\n const deltaB = labA.b - labB.b;\n const c1 = Math.sqrt(labA.a * labA.a + labA.b * labA.b);\n const c2 = Math.sqrt(labB.a * labB.a + labB.b * labB.b);\n const deltaC = c1 - c2;\n let deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC;\n deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);\n const sc = 1.0 + 0.045 * c1;\n const sh = 1.0 + 0.015 * c1;\n const deltaLKlsl = deltaL / 1.0;\n const deltaCkcsc = deltaC / sc;\n const deltaHkhsh = deltaH / sh;\n const i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;\n return (i < 0 ? 0 : Math.sqrt(i)) / 100;\n}\n","import type { RGB } from './types';\n\nconst { min, max } = Math;\n\nexport function rgbToHue({ r, g, b }: RGB): [number, number, number, number] {\n r /= 255;\n g /= 255;\n b /= 255;\n\n const rgbMax = max(r, g, b);\n const rgbMin = min(r, g, b);\n const rgbDiff = rgbMax - rgbMin;\n const h =\n rgbDiff === 0\n ? 0\n : rgbDiff && rgbMax === r\n ? (g - b) / rgbDiff\n : rgbMax === g\n ? 2 + (b - r) / rgbDiff\n : 4 + (r - g) / rgbDiff;\n\n return [60 * (h < 0 ? h + 6 : h), rgbMax, rgbMin, rgbDiff];\n}\n","import type { HEX, RGB } from './types';\n\n/**\n * 将HEX颜色字符串转换为RGB颜色对象\n * @param hex HEX颜色字符串,支持3位或6位格式(例如#f00或#ff0000)\n * @returns {RGB} 对应的RGB颜色对象\n * @throws {SyntaxError} 当颜色格式不符合规范时抛出\n * @example\n * hexToRgb('#f00') // returns {r: 255, g: 0, b: 0}\n */\nexport function hexToRgb(hex: HEX): RGB {\n const reg = hex.length === 4 ? /^#(.)(.)(.)$/ : /^#(.{2})(.{2})(.{2})$/;\n const result = reg.exec(hex);\n\n if (!result) throw new SyntaxError(`颜色(${hex})表达式有误`);\n\n const [_, r, g, b] = result;\n\n return {\n r: Number.parseInt(r.padEnd(2, r), 16),\n g: Number.parseInt(g.padEnd(2, g), 16),\n b: Number.parseInt(b.padEnd(2, b), 16),\n };\n}\n\nfunction to16(n: number) {\n return Math.round(n).toString(16).padStart(2, '0');\n}\n\n/**\n * 将RGB颜色对象转换为HEX颜色字符串\n * @param rgb RGB颜色对象\n * @returns {HEX} 6位HEX颜色字符串(带#前缀)\n * @example\n * rgbToHex({r: 255, g: 0, b: 0}) // returns '#ff0000'\n */\nexport function rgbToHex(rgb: RGB): HEX {\n return `#${to16(rgb.r)}${to16(rgb.g)}${to16(rgb.b)}`;\n}\n","// @ref https://www.w3schools.com/lib/w3color.js\nimport { rgbToHue } from './helpers';\nimport type { HSL, RGB } from './types';\n\nconst { min, max } = Math;\n\n/**\n * 将RGB颜色转换为HSL颜色空间\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {HSL} HSL颜色对象,其中:\n * h: 色相(0-360度)\n * s: 饱和度(0-100%)\n * l: 亮度(0-100%)\n * @example\n * rgbToHsl({r: 255, g: 0, b: 0}) // returns {h: 0, s: 100, l: 50}\n */\nexport function rgbToHsl(rgb: RGB): HSL {\n const [hue, max, min, diff] = rgbToHue(rgb);\n const l = (2 * max - diff) / 2;\n const s = min === max ? 0 : l < 0.5 ? (max - min) / (max + min) : (max - min) / (2 - max - min);\n\n return {\n h: hue,\n s: s * 100,\n l: l * 100,\n };\n}\n\n// @ref https://www.30secondsofcode.org/js/s/hsl-to-rgb/\n/**\n * 将HSL颜色转换回RGB颜色空间\n * @param hsl HSL颜色对象\n * @param hsl.h 色相(0-360度)\n * @param hsl.s 饱和度(0-100%)\n * @param hsl.l 亮度(0-100%)\n * @returns {RGB} RGB颜色对象(分量范围0-255)\n * @example\n * hslToRgb({h: 0, s: 100, l: 50}) // returns {r: 255, g: 0, b: 0}\n */\nexport function hslToRgb({ h, s, l }: HSL): RGB {\n s /= 100;\n l /= 100;\n\n const a = s * min(l, 1 - l);\n const k = (n: number) => (n + h / 30) % 12;\n const f = (n: number) => l - a * max(-1, min(k(n) - 3, min(9 - k(n), 1)));\n\n return {\n r: 255 * f(0),\n g: 255 * f(8),\n b: 255 * f(4),\n };\n}\n","import { hexToRgb, rgbToHex } from './hex-rgb';\nimport { hslToRgb, rgbToHsl } from './rgb-hsl';\nimport type { HEX, HSL } from './types';\n\nexport function hslToHex(hsl: HSL): HEX {\n return rgbToHex(hslToRgb(hsl));\n}\n\nexport function hexToHsl(hex: HEX): HSL {\n return rgbToHsl(hexToRgb(hex));\n}\n","import { rgbToHue } from './helpers';\nimport type { HSV, RGB } from './types';\n\nconst { min, max } = Math;\n\n// @ref https://www.30secondsofcode.org/js/s/rgb-to-hsb/\n/**\n * 将RGB颜色转换为HSV颜色空间\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {HSV} HSV颜色对象:\n * h: 色相(0-360度)\n * s: 饱和度(0-100%)\n * v: 明度(0-100%)\n * @see https://en.wikipedia.org/wiki/HSL_and_HSV\n * @example\n * rgbToHsv({r: 255, g: 0, b: 0}) // {h: 0, s: 100, v: 100}\n */\nexport function rgbToHsv(rgb: RGB): HSV {\n const [hue, max, _min, diff] = rgbToHue(rgb);\n\n return {\n h: hue,\n s: max && (diff / max) * 100,\n v: max * 100,\n };\n}\n\n// @ref https://www.30secondsofcode.org/js/s/hsb-to-rgb/\n/**\n * 将HSV颜色转换回RGB颜色空间\n * @param hsv HSV颜色对象\n * @param hsv.h 色相(0-360度)\n * @param hsv.s 饱和度(0-100%)\n * @param hsv.v 明度(0-100%)\n * @returns {RGB} RGB颜色对象(分量范围0-255)\n * @see https://www.rapidtables.com/convert/color/hsv-to-rgb.html\n * @example\n * hsvToRgb({h: 0, s: 100, v: 100}) // {r: 255, g: 0, b: 0}\n */\nexport function hsvToRgb({ h, s, v }: HSV): RGB {\n s /= 100;\n v /= 100;\n\n const k = (n: number) => (n + h / 60) % 6;\n const f = (n: number) => v * (1 - s * max(0, min(k(n), 4 - k(n), 1)));\n\n return {\n r: 255 * f(5),\n g: 255 * f(3),\n b: 255 * f(1),\n };\n}\n","import { hexToRgb, rgbToHex } from './hex-rgb';\nimport { hsvToRgb, rgbToHsv } from './rgb-hsv';\nimport type { HEX, HSV } from './types';\n\n/**\n * 将HEX颜色转换为HSV颜色空间\n * @param hex HEX颜色字符串(支持3位或6位格式)\n * @returns {HSV} HSV颜色对象,包含:\n * h: 色相(0-360度)\n * s: 饱和度(0-100%)\n * v: 明度(0-100%)\n * @example\n * hexToHsv('#ff0000') // returns {h: 0, s: 100, v: 100}\n */\nexport function hexToHsv(hex: HEX): HSV {\n return rgbToHsv(hexToRgb(hex));\n}\n\n/**\n * 将HSV颜色转换回HEX字符串\n * @param hsv HSV颜色对象\n * @returns {HEX} 6位HEX颜色字符串(带#前缀)\n * @example\n * hsvToHex({h: 0, s: 100, v: 100}) // returns '#ff0000'\n */\nexport function hsvToHex(hsv: HSV): HEX {\n return rgbToHex(hsvToRgb(hsv));\n}\n","import { rgbToHue } from './helpers';\nimport { hslToRgb } from './rgb-hsl';\nimport type { HWB, RGB } from './types';\n\n/**\n * 将RGB颜色转换为HWB颜色空间\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {HWB} HWB颜色对象:\n * h: 色相(0-360度)\n * w: 白度(0-100%)\n * b: 黑度(0-100%)\n * @see https://www.w3.org/TR/css-color-4/#hwb-to-rgb\n * @example\n * rgbToHwb({r: 255, g: 0, b: 0}) // {h: 0, w: 0, b: 0}\n */\nexport function rgbToHwb(rgb: RGB): HWB {\n const [hue, max, min, _diff] = rgbToHue(rgb);\n return {\n h: hue,\n w: min * 100,\n b: (1 - max) * 100,\n };\n}\n\n// @ref https://www.w3schools.com/lib/w3color.js\n/**\n * 将HWB颜色转换回RGB颜色空间\n * @param hwb HWB颜色对象\n * @param hwb.h 色相(0-360度)\n * @param hwb.w 白度(0-100%)\n * @param hwb.b 黑度(0-100%)\n * @returns {RGB} RGB颜色对象(分量范围0-255)\n * @see https://en.wikipedia.org/wiki/HWB_color_model\n * @example\n * hwbToRgb({h: 0, w: 0, b: 0}) // {r: 255, g: 0, b: 0}\n */\nexport function hwbToRgb({ h, w: white, b: black }: HWB) {\n white /= 100;\n black /= 100;\n\n const { r, g, b } = hslToRgb({ h, s: 100, l: 50 });\n const tot = white + black;\n\n if (tot > 1) {\n white = white / tot;\n black = black / tot;\n }\n\n const f = (n: number) => ((n / 255) * (1 - white - black) + white) * 255;\n\n return {\n r: f(r),\n g: f(g),\n b: f(b),\n };\n}\n","import { hexToRgb, rgbToHex } from './hex-rgb';\nimport { hwbToRgb, rgbToHwb } from './rgb-hwb';\nimport type { HEX, HWB } from './types';\n\n/**\n * 将HWB颜色转换为HEX字符串\n * @param hwb HWB颜色对象\n * @param hwb.h 色相(0-360度)\n * @param hwb.w 白度(0-100%)\n * @param hwb.b 黑度(0-100%)\n * @returns {HEX} 6位HEX颜色字符串(带#前缀)\n * @example\n * hwbToHex({h: 0, w: 0, b: 0}) // returns '#ff0000'\n */\nexport function hwbToHex(hwb: HWB): HEX {\n return rgbToHex(hwbToRgb(hwb));\n}\n\n/**\n * 将HEX颜色转换为HWB颜色空间\n * @param hex HEX颜色字符串(支持3位或6位格式)\n * @returns {HWB} HWB颜色对象,包含:\n * h: 色相(0-360度)\n * w: 白度(0-100%)\n * b: 黑度(0-100%)\n * @example\n * hexToHwb('#ff0000') // returns {h: 0, w: 0, b: 0}\n */\nexport function hexToHwb(hex: HEX): HWB {\n return rgbToHwb(hexToRgb(hex));\n}\n","import type { HSL } from './types';\n\n/**\n * 通过HSL颜色空间调整颜色亮度\n * @param hsl 原始 HSL 颜色\n * @param value 亮度调整系数(0-1之间,0.1表示增加10%亮度)\n * @returns {HSL} 调整后的 HSL 颜色\n * @example\n * hslLighten({h: 300, s: 33, l: 44}, 0.2) // 返回亮度增加20%后的颜色\n */\nexport function hslLighten(hsl: HSL, value: number): HSL {\n const hslFinal = { ...hsl };\n hslFinal.l = hslFinal.l * (1 + value);\n return hslFinal;\n}\n","import type { HSV } from './types';\n\n/**\n * 通过HSV颜色空间调整颜色明度\n * @param hsv 原始HSV颜色对象\n * @param value 明度调整系数(-1到1之间):\n * - 正值增加明度(如0.2表示+20%)\n * - 负值降低明度(如-0.1表示-10%)\n * @returns {HSV} 调整后的HSV颜色对象(v值范围0-100%)\n * @example\n * hsvBrighten({h: 0, s: 100, v: 50}, 0.3) // 返回{h: 0, s: 100, v: 65}\n */\nexport function hsvBrighten(hsv: HSV, value: number): HSV {\n const hsvFinal = { ...hsv };\n hsvFinal.v = hsvFinal.v * (1 + value);\n return hsvFinal;\n}\n","import type { HSL, HSV, RGB } from './types';\n\n/**\n * 颜色混合函数(支持RGB/HSL/HSV色彩模型)\n * @template T 颜色类型,支持RGB、HSL或HSV对象\n * @param {T} a 第一个颜色对象\n * @param {T} b 第二个颜色对象\n * @param {number} [weight=0.5] 混合权重(0-1之间):\n * - 0 表示完全使用第一个颜色\n * - 1 表示完全使用第二个颜色\n * @returns {T} 线性混合后的新颜色对象\n * @example\n * // RGB混合示例\n * mix({r: 255, g: 0, b: 0}, {r: 0, g: 0, b: 255}, 0.5) // 返回紫色\n *\n * // HSL混合示例\n * mix({h: 0, s: 100, l: 50}, {h: 120, s: 100, l: 50}, 0.3)\n */\nexport function mix<T extends RGB | HSV | HSL>(a: T, b: T, weight = 0.5): T {\n return Object.keys(a).reduce((acc, key) => {\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-expect-error\n acc[key] = (b[key] - a[key]) * weight + a[key];\n return acc;\n }, {} as T);\n}\n","// https://stackoverflow.com/a/73998199\n\nimport type { RGB, XYZ } from './types';\n\n/**\n * 将RGB颜色转换为CIE 1931 XYZ颜色空间(D65白点,2°观察者)\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {XYZ} XYZ颜色对象:\n * x: 约0-95.047\n * y: 约0-100.0\n * z: 约0-108.883\n * @see https://en.wikipedia.org/wiki/CIE_1931_color_space\n * @example\n * rgbToXyz({r: 255, g: 255, b: 255}) // {x: 95.047, y: 100.0, z: 108.883}\n */\nexport function rgbToXyz(rgb: RGB): XYZ {\n const { r, g, b } = rgb;\n const [var_R, var_G, var_B] = [r, g, b]\n .map((x) => x / 255)\n .map((x) => (x > 0.04045 ? ((x + 0.055) / 1.055) ** 2.4 : x / 12.92))\n .map((x) => x * 100);\n\n return {\n // Observer. = 2°, Illuminant = D65\n x: var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805,\n y: var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722,\n z: var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505,\n };\n}\n\n/**\n * 将XYZ颜色转换回RGB颜色空间(可能超出常规范围)\n * @param xyz XYZ颜色对象\n * @returns {RGB} RGB颜色对象(分量可能超出0-255范围)\n * @see https://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html\n * @example\n * xyzToRgb({x: 95.047, y: 100.0, z: 108.883}) // {r: 255, g: 255, b: 255}\n */\nexport function xyzToRgb(xyz: XYZ): RGB {\n const { x, y, z } = xyz;\n\n //X, Y and Z input refer to a D65/2° standard illuminant.\n //sR, sG and sB (standard RGB) output range = 0 ÷ 255\n\n const var_X = x / 100;\n const var_Y = y / 100;\n const var_Z = z / 100;\n\n const var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;\n const var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;\n const var_B = var_X * 0.0557 + var_Y * -0.204 + var_Z * 1.057;\n\n const [r, g, b] = [var_R, var_G, var_B]\n .map((n) => (n > 0.0031308 ? 1.055 * n ** (1 / 2.4) - 0.055 : 12.92 * n))\n .map((n) => n * 255);\n\n return {\n r,\n g,\n b,\n };\n}\n","// https://stackoverflow.com/a/73998199\n\nimport type { LAB, XYZ } from './types';\n\nconst ref_X = 95.047;\nconst ref_Y = 100.0;\nconst ref_Z = 108.883;\n\n/**\n * 将XYZ颜色转换为Lab颜色空间(CIE 1976 L*a*b*,D65白点)\n * @param xyz XYZ颜色对象(参考值:D65白点X=95.047,Y=100,Z=108.883)\n * @returns {LAB} Lab颜色对象:\n * l: 明度(0-100)\n * a: 绿-红分量(典型范围-128到127)\n * b: 蓝-黄分量(典型范围-128到127)\n * @see https://en.wikipedia.org/wiki/CIELAB_color_space\n * @example\n * xyzToLab({x: 95.047, y: 100.0, z: 108.883}) // {l: 100, a: 0, b: 0}\n */\nexport function xyzToLab(xyz: XYZ): LAB {\n const { x, y, z } = xyz;\n const [var_X, var_Y, var_Z] = [x / ref_X, y / ref_Y, z / ref_Z].map((a) =>\n a > 0.008856 ? a ** (1 / 3) : 7.787 * a + 16 / 116,\n );\n\n const l = 116 * var_Y - 16;\n const a = 500 * (var_X - var_Y);\n const b = 200 * (var_Y - var_Z);\n\n return { l, a, b };\n}\n\n/**\n * 将Lab颜色转换回XYZ颜色空间\n * @param lab Lab颜色对象\n * @param lab.l 明度(0-100)\n * @param lab.a 绿-红分量(典型范围-128到127)\n * @param lab.b 蓝-黄分量(典型范围-128到127)\n * @returns {XYZ} XYZ颜色对象(基于D65白点)\n * @see https://www.easyrgb.com/en/math.php\n * @example\n * labToXyz({l: 100, a: 0, b: 0}) // {x: 95.047, y: 100.0, z: 108.883}\n */\nexport function labToXyz(lab: LAB): XYZ {\n const { l, a, b } = lab;\n\n const var_Y = (l + 16) / 116;\n const var_X = a / 500 + var_Y;\n const var_Z = var_Y - b / 200;\n\n const [X, Y, Z] = [var_X, var_Y, var_Z].map((n) => (n ** 3 > 0.008856 ? n ** 3 : (n - 16 / 116) / 7.787));\n\n return { x: X * ref_X, y: Y * ref_Y, z: Z * ref_Z };\n}\n","import { rgbToXyz, xyzToRgb } from './rgb-xyz';\nimport type { LAB, RGB } from './types';\nimport { labToXyz, xyzToLab } from './xyz-lab';\n\n/**\n * 将RGB颜色转换为Lab颜色空间(CIE 1976标准)\n * @param rgb RGB颜色对象(分量范围0-255)\n * @returns {LAB} Lab颜色对象:\n * l: 明度(0-100)\n * a: 绿-红分量(-128到127)\n * b: 蓝-黄分量(-128到127)\n * @see https://en.wikipedia.org/wiki/CIELAB_color_space\n * @example\n * rgbToLab({r: 255, g: 0, b: 0}) // {l: 53.24, a: 80.09, b: 67.20}\n */\nexport function rgbToLab(rgb: RGB): LAB {\n return xyzToLab(rgbToXyz(rgb));\n}\n\n/**\n * 将Lab颜色转换回RGB颜色空间\n * @param lab Lab颜色对象\n * @param lab.l 明度(0-100)\n * @param lab.a 绿-红分量(-128到127)\n * @param lab.b 蓝-黄分量(-128到127)\n * @returns {RGB} RGB颜色对象(分量可能超出0-255范围)\n * @see https://www.easyrgb.com/en/math.php\n * @example\n * labToRgb({l: 53.24, a: 80.09, b: 67.20}) // {r: 255, g: 0, b: 0}\n */\nexport function labToRgb(lab: LAB): RGB {\n return xyzToRgb(labToXyz(lab));\n}\n","import { mix } from './mix';\nimport type { RGB } from './types';\n\nconst { abs } = Math;\n\nconst whiteRGB: RGB = { r: 0, g: 0, b: 0 };\nconst blackRGB: RGB = { r: 255, g: 255, b: 255 };\n\n/**\n * 通过混合颜色调整明暗度\n * @param rgb 原始RGB颜色对象\n * @param value 调整强度(-1到1之间):\n * - 正值时与黑色混合(增加暗度)\n * - 负值时与白色混合(增加亮度)\n * @returns {RGB} 调整后的RGB颜色对象\n * @example\n * rgbDarken({r: 100, g: 150, b: 200}, 0.2) // 变暗20%\n */\nexport function rgbWhiter(rgb: RGB, value: number): RGB {\n const rgb2: RGB = value > 0 ? whiteRGB : blackRGB;\n return mix(rgb, rgb2, abs(value));\n}\n"],"mappings":"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"}
|