UNPKG

moderndash

Version:

A Typescript-First utility library inspired by Lodash. Optimized for modern browsers.

1 lines 98 kB
{"version":3,"sources":["../src/index.ts","../src/array/chunk.ts","../src/array/count.ts","../src/helpers/fastArrayFlat.ts","../src/array/difference.ts","../src/array/dropRightWhile.ts","../src/array/dropWhile.ts","../src/array/group.ts","../src/array/unique.ts","../src/array/intersection.ts","../src/array/move.ts","../src/array/range.ts","../src/array/shuffle.ts","../src/array/sort.ts","../src/array/takeRightWhile.ts","../src/array/takeWhile.ts","../src/crypto/hash.ts","../src/crypto/randomInt.ts","../src/crypto/randomElem.ts","../src/crypto/randomFloat.ts","../src/crypto/randomString.ts","../src/decorator/toDecorator.ts","../src/function/debounce.ts","../src/decorator/decDebounce.ts","../src/function/maxCalls.ts","../src/decorator/decMaxCalls.ts","../src/function/memoize.ts","../src/decorator/decMemoize.ts","../src/function/minCalls.ts","../src/decorator/decMinCalls.ts","../src/function/throttle.ts","../src/decorator/decThrottle.ts","../src/function/times.ts","../src/number/sum.ts","../src/number/average.ts","../src/number/median.ts","../src/number/round.ts","../src/validate/isPlainObject.ts","../src/object/flatKeys.ts","../src/object/merge.ts","../src/object/pick.ts","../src/object/omit.ts","../src/object/set.ts","../src/promise/queue.ts","../src/promise/races.ts","../src/promise/sleep.ts","../src/promise/retry.ts","../src/promise/timeout.ts","../src/promise/tryCatch.ts","../src/string/splitWords.ts","../src/string/capitalize.ts","../src/string/deburr.ts","../src/string/camelCase.ts","../src/string/escapeHtml.ts","../src/string/escapeRegExp.ts","../src/string/kebabCase.ts","../src/string/pascalCase.ts","../src/string/replaceLast.ts","../src/string/snakeCase.ts","../src/string/titleCase.ts","../src/string/trim.ts","../src/string/trimEnd.ts","../src/string/trimStart.ts","../src/string/truncate.ts","../src/string/unescapeHtml.ts","../src/validate/isEmpty.ts","../src/validate/isEqual.ts","../src/validate/isUrl.ts"],"sourcesContent":["/**\n * @file Automatically generated by barrelsby.\n */\n\nexport * from \"./array/index\";\nexport * from \"./crypto/index\";\nexport * from \"./decorator/index\";\nexport * from \"./function/index\";\nexport * from \"./number/index\";\nexport * from \"./object/index\";\nexport * from \"./promise/index\";\nexport * from \"./string/index\";\nexport * from \"./type/index\";\nexport * from \"./validate/index\";\n","/**\n * Creates an array of elements split into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements.\n *\n * @example\n * chunk(['a', 'b', 'c', 'd'], 2)\n * // => [['a', 'b'], ['c', 'd']]\n *\n * chunk(['a', 'b', 'c', 'd'], 3)\n * // => [['a', 'b', 'c'], ['d']]\n * @param chunkSize The length of each chunk\n * @param array The array to chunk\n * @template TElem The type of the array elements\n * @returns Returns the new array of chunks\n */\n\nexport function chunk<TElem>(array: readonly TElem[], chunkSize: number): TElem[][] {\n const intSize = Math.trunc(chunkSize);\n\n if (array.length === 0 || intSize < 1)\n return [];\n \n let index = 0;\n let resultIndex = 0;\n const result = new Array(Math.ceil(array.length / intSize)) as TElem[][];\n\n while (index < array.length) {\n result[resultIndex++] = array.slice(index, (index += intSize));\n }\n\n return result;\n}","/**\n * Creates an object with counts of occurrences of items in the array.\n *\n * @example\n * const users = [\n * { 'user': 'barney', 'active': true, age: 36 },\n * { 'user': 'betty', 'active': false, age: 36 },\n * { 'user': 'fred', 'active': true, age: 40 }\n * ]\n *\n * count(users, value => value.active ? 'active' : 'inactive');\n * // => { 'active': 2, 'inactive': 1 }\n *\n * count(users, value => value.age);\n * // => { 36: 2, 40: 1 }\n *\n * @param criteria The criteria to count by\n * @param array The array or record to iterate over\n * @template TElem The type of the array elements\n * @returns Returns the composed aggregate object\n */\n\nexport function count<TElem, TKey extends PropertyKey>(array: readonly TElem[], criteria: (value: TElem) => TKey): Record<TKey, number> {\n const result = {} as Record<TKey, number>;\n for (const value of array) {\n const key = criteria(value);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n result[key] = (result[key] ?? 0) + 1;\n }\n return result;\n}","// native Array.flat is much slower than this - node 19\nexport function fastArrayFlat<TElem>(arrays: (readonly TElem[])[]): readonly TElem[] {\n let result = arrays.shift() ?? [];\n\n for (const array of arrays) {\n result = [...result, ...array];\n }\n\n return result;\n}","import type { CompareFunction } from \"@helpers/ArrayTypeUtils.js\";\nimport type { ArrayMinLength } from \"@type/ArrayMinLength.js\";\n\nimport { fastArrayFlat } from \"@helpers/fastArrayFlat.js\";\n\n/**\n * Create a new array with values from the first array that are not present in the other arrays.\n * Optionally, use a compare function to determine the comparison of elements (default is `===`).\n * \n * **Consider using the native [Set.prototype.difference()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/difference) function instead.**\n * \n * @example\n * difference([2, 1], [2, 3], [6])\n * // => [1]\n *\n * // ---- Custom compare function ----\n * const compareByFloor = (a, b) => Math.floor(a) === Math.floor(b);\n * difference([1.2, 3.1], [1.3, 2.4], compareByFloor)\n * // => [3.1]\n *\n * // ---- Only compare by id ----\n * const arr1 = [{ id: 1, name: 'Yeet' }, { id: 3, name: 'John' }];\n * const arr2 = [{ id: 3, name: 'Carl' }, { id: 4, name: 'Max' }];\n *\n * difference(arr1, arr2, (a, b) => a.id === b.id)\n * // => [{ id: 1, name: 'Yeet' }]\n * \n * @param arraysOrCompareFn Two or more arrays with an optional compare function at the end\n * @template TElem The type of the array elements\n * @template TArrays The type of the arrays provided\n * @returns Returns a new array of filtered values\n */\nexport function difference<TElem>(...arraysOrCompareFn: ArrayMinLength<TElem[], 2>): TElem[];\nexport function difference<TArrays extends ArrayMinLength<unknown[], 2>>(...arraysOrCompareFn: [...TArrays, CompareFunction<TArrays>]): TArrays[0];\nexport function difference<TArrays extends ArrayMinLength<unknown[], 2>, TElem>(...arraysOrCompareFn: ArrayMinLength<TElem[], 2> | [...TArrays, CompareFunction<TArrays>]): TArrays[0] {\n const compareFnProvided = typeof arraysOrCompareFn.at(-1) === \"function\";\n const compareFunction = compareFnProvided && arraysOrCompareFn.pop() as CompareFunction<TArrays>;\n\n const arrays = arraysOrCompareFn as TArrays;\n const firstArray = arrays.shift()!;\n const combinedRestArray = fastArrayFlat(arrays);\n\n if (!compareFunction) {\n const restSet = new Set(combinedRestArray);\n return firstArray.filter(element => !restSet.has(element));\n }\n\n const difference: TArrays[0] = [];\n for (const element of firstArray) {\n if (combinedRestArray.every(item => !compareFunction(element, item))) {\n difference.push(element);\n }\n }\n\n return difference;\n}\n","/**\n * Creates a slice of `array` excluding elements dropped from the end. \n * Elements are dropped until `predicate` returns falsy.\n *\n * @example\n * const users = [\n * { 'user': 'barney', 'active': false },\n * { 'user': 'fred', 'active': true },\n * { 'user': 'pebbles', 'active': true }\n * ]\n *\n * dropRightWhile(users, user => user.active)\n * // => objects for ['barney']\n * @param predicate The function invoked per iteration\n * @param array The array to query\n * @template TElem The type of the array elements\n * @returns Returns the slice of `array`\n */\n\nexport function dropRightWhile<TElem>(array: readonly TElem[], predicate: (value: TElem) => boolean) {\n let i = array.length;\n while (i > 0 && predicate(array[i - 1])) {\n i--;\n }\n return array.slice(0, i);\n}\n","/**\n * Creates a slice of `array` excluding elements dropped from the beginning. \n * Elements are dropped until `predicate` returns falsy.\n *\n * @example\n * const users = [\n * { 'user': 'barney', 'active': true },\n * { 'user': 'fred', 'active': true },\n * { 'user': 'pebbles', 'active': false }\n * ]\n *\n * dropWhile(users, user => user.active)\n * // => objects for ['pebbles']\n * @param predicate The function invoked per iteration\n * @param array The array to query\n * @template TElem The type of the array elements\n * @returns Returns the slice of `array`\n */\n\nexport function dropWhile<TElem>(array: readonly TElem[], predicate: (value: TElem) => boolean): TElem[] {\n const index = array.findIndex(x => !predicate(x));\n return array.slice(index === -1 ? array.length : index);\n}\n","/**\n * Creates an object with grouped items in the array.\n * \n * @deprecated\n * **Deprecated: Use the native \"Object.groupBy()\" function instead.**\n * \n * @example\n * group([6.1, 4.2, 6.3], Math.floor)\n * // => { 4: [4.2], 6: [6.1, 6.3] }\n *\n * group([6.1, 4.2, 6.3], value => value > 5 ? '>5' : '<=5')\n * // => { '<=5': [4.2], '>5': [6.1, 6.3] }\n * \n * @param collection The array or object to iterate over\n * @param getGroupKey A function that returns the group id for each item\n * @template TElem The type of the array elements\n * @returns An object with grouped items\n */\n\nexport function group<TElem, TKey extends PropertyKey>(array: readonly TElem[], getGroupKey: (elem: TElem) => TKey): Record<TKey, TElem[]> {\n const result = {} as Record<TKey, TElem[]>;\n for (const elem of array) {\n const key = getGroupKey(elem);\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n (result[key] ??= []).push(elem);\n }\n return result;\n}","/**\n * Creates unique array retaining first occurrence of elements.\n *\n * A compare function is optional (default is `===`).\n * \n * @example\n * unique([2, 1, 2])\n * // => [2, 1]\n * \n * // compare by object values\n * const users = [\n * { id: 1, name: 'john' },\n * { id: 2, name: 'john' },\n * { id: 2, name: 'john' },\n * ]\n * \n * unique(users, isEqual)\n * // => [{ id: 1, name: 'john' }, { id: 2, name: 'john' }]\n * \n * // compare by id\n * unique(users, (a, b) => a.name === b.name)\n * // => [{ id: 1, name: 'john' }]\n *\n * @param array Array to inspect\n * @param iteratee Iteratee invoked per element\n * @template TElem Type of the array elements\n * @returns A new unique array\n */\n\nexport function unique<TElem>(array: readonly TElem[], compareFn?: (a: TElem, b: TElem) => boolean): TElem[] {\n if (!compareFn)\n return [...new Set(array)];\n\n // Custom compare function can't be optimized with Set\n const uniqueArray: TElem[] = [];\n\n for (const value of array) {\n if (!uniqueArray.some(uniqueValue => compareFn(value, uniqueValue)))\n uniqueArray.push(value);\n }\n \n return uniqueArray;\n}\n","import type { CompareFunction } from \"@helpers/ArrayTypeUtils.js\";\nimport type { ArrayMinLength } from \"@type/ArrayMinLength.js\";\n\nimport { fastArrayFlat } from \"@helpers/fastArrayFlat.js\";\n\nimport { unique } from \"./unique.js\";\n\n/**\n * Create an array with unique values that are present in all arrays. \n * The order of the values is based on the first array. \n * \n * Optionally, use a compare function for element comparison (default is `===`).\n * \n * **Consider using the native [Set.prototype.intersection()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/intersection) function instead.**\n * \n * @example\n * intersection([2, 1], [2, 3], [6, 2])\n * // => [2]\n *\n * // ---- Custom compare function ----\n * const compareFn = (a, b) => Math.floor(a) === Math.floor(b);\n * \n * intersection([1.2, 1.1], [1.3, 2.4], compareFn)\n * // => [1.2]\n *\n * // ---- Only compare by id ----\n * const arr1 = [{ id: 1, name: 'Yeet' }, { id: 3, name: 'John' }];\n * const arr2 = [{ id: 3, name: 'Carl' }, { id: 4, name: 'Max' }];\n *\n * intersection(arr1, arr2, (a, b) => a.id === b.id)\n * // => [{ id: 3, name: 'John' }]\n * \n * @param arraysOrCompareFn Two or more arrays with an optional compare function at the end\n * @template TElem Type of the array elements\n * @template TArrays Type of the arrays provided\n * @returns New array of intersecting values\n */\n\nexport function intersection<TElem>(...arraysOrCompareFn: ArrayMinLength<TElem[], 2>): TElem[];\nexport function intersection<TArrays extends ArrayMinLength<unknown[], 2>>(...arraysOrCompareFn: [...TArrays, CompareFunction<TArrays>]): TArrays[0];\nexport function intersection<TArrays extends ArrayMinLength<unknown[], 2>, TElem>(...arraysOrCompareFn: ArrayMinLength<TElem[], 2> | [...TArrays, CompareFunction<TArrays>]): TArrays[0] {\n const compareFnProvided = typeof arraysOrCompareFn.at(-1) === \"function\";\n const compareFunction = compareFnProvided && arraysOrCompareFn.pop() as CompareFunction<TArrays>;\n\n const arrays = arraysOrCompareFn as TArrays;\n const firstArray = unique(arrays.shift()!);\n const combinedRestArray = fastArrayFlat(arrays);\n\n if (!compareFunction) {\n const restSet = new Set(combinedRestArray);\n return firstArray.filter(element => restSet.has(element));\n }\n \n const intersection: TArrays[0] = [];\n\n for (const element of firstArray) {\n if (combinedRestArray.some(item => compareFunction(element, item))) {\n intersection.push(element);\n }\n }\n\n return intersection;\n}\n","/**\n * Moves an element within an array.\n * \n * @example\n * ```typescript\n * move([1, 2, 3, 4, 5], 0, 2);\n * // => [2, 3, 1, 4, 5]\n * ```\n * \n * @param array The input array\n * @param fromIndex Index of the element to move\n * @param toIndex Target index for the element\n * @throws If index is out of bounds\n * @template TArr Type of the array elements\n * @returns The modified array with the moved element\n */\nexport function move<TArr>(array: TArr[], fromIndex: number, toIndex: number): TArr[] {\n if (fromIndex < 0 || fromIndex >= array.length)\n throw new Error(`Invalid 'fromIndex': ${fromIndex}. Must be between 0 and ${array.length - 1}.`);\n\n if (toIndex < 0 || toIndex >= array.length)\n throw new Error(`Invalid 'toIndex': ${toIndex}. Must be between 0 and ${array.length - 1}.`);\n\n if (fromIndex === toIndex)\n return array;\n\n const item = array[fromIndex];\n\n if (fromIndex < toIndex)\n for (let index = fromIndex; index < toIndex; index++)\n array[index] = array[index + 1];\n else\n for (let index = fromIndex; index > toIndex; index--)\n array[index] = array[index - 1];\n\n array[toIndex] = item;\n\n return array;\n}","/**\n * Creates an array from start to end (inclusive), stepping by step. \n * If start is larger than end, the array is generated in reverse\n *\n * @example\n * for (const num of range(1, 5)) {\n * console.log(num);\n * }\n * // => 1 2 3 4 5\n * \n * // Array of even numbers between 0 and 10:\n * range(0, 10, 2);\n * // => [0, 2, 4, 6, 8, 10]\n * \n * // Descending range:\n * range(5, 0, 2);\n * // => [5, 3, 1]\n * \n * @param start Start number of sequence\n * @param end End number of sequence\n * @param step Step between numbers, default: 1\n * @throws If range is negative or step is 0\n * @returns An array of numbers\n */\nexport function range(start: number, end: number, step = 1): number[] {\n if (step <= 0)\n throw new Error(\"The step must be greater than 0.\");\n\n step = start > end ? -step : step;\n const length = Math.floor(Math.abs((end - start) / step)) + 1;\n\n const result = new Array(length) as number[];\n \n for (let i = 0; i < length; i++) {\n result[i] = start + (i * step);\n }\n\n return result;\n}","/**\n * Creates a new array of shuffled values, using the Fisher-Yates-Durstenfeld Shuffle algorithm.\n *\n * @example\n * shuffle([1, 2, 3, 4])\n * // => [4, 1, 3, 2]\n * @param array Array to shuffle\n * @template TElem The type of the array elements\n * @returns A new shuffled array\n */\n\nexport function shuffle<TElem>(array: readonly TElem[]): TElem[] {\n const shuffledArray = [...array];\n \n for (let index = shuffledArray.length - 1; index > 0; index--) {\n const randomIndex = Math.floor(Math.random() * (index + 1));\n [shuffledArray[index], shuffledArray[randomIndex]] = [shuffledArray[randomIndex], shuffledArray[index]];\n }\n \n return shuffledArray;\n}","\n/**\n * Creates new array sorted in ascending/descending order with single or multiple criteria.\n * \n * @example\n * sort([1, 2, 3, 4], { order: 'desc' })\n * // => [4, 3, 2, 1]\n * \n * // --- Sorting by multiple properties ---\n * const array = [{ a: 2, b: 1 }, { a: 1, b: 2 }, { a: 1, b: 1 }];\n * \n * sort(array,\n * { order: 'asc', by: item => item.a },\n * { order: 'desc', by: item => item.b }\n * )\n * // => [{ a: 1, b: 2 }, { a: 1, b: 1 }, { a: 2, b: 1 }]\n * \n * @param array Array to sort\n * @param criteria Criteria to sort by\n * @param criteria.order Order to sort in, either 'asc' or 'desc'\n * @param criteria.by Iteratee function to sort based on a specific property\n * @template TElem Type of the array elements\n * @returns New sorted array\n*/\nexport function sort<TElem>(array: readonly TElem[], ...criteria: { order?: \"asc\" | \"desc\", by?: (item: TElem) => number | bigint | Date | string }[]): TElem[] {\n return [...array].sort((a, b) => {\n for (const { order = \"asc\", by = (item: TElem) => item } of criteria) {\n const aValue = by(a);\n const bValue = by(b);\n if (aValue !== bValue) {\n const compare = aValue < bValue ? -1 : 1;\n return order === \"asc\" ? compare : -compare;\n }\n }\n return 0;\n });\n}\n","/**\n * Creates a slice of `array` with elements taken from the end. \n * Elements are taken until `predicate` returns falsy.\n * \n * @example\n * const users = [\n * { 'user': 'barney', 'active': false },\n * { 'user': 'fred', 'active': true },\n * { 'user': 'pebbles', 'active': true }\n * ]\n *\n * takeRightWhile(users, user => user.active)\n * // => objects for ['fred', 'pebbles']\n * @param predicate The function invoked per iteration.\n * @param array The array to query.\n * @template TElem The type of the array elements.\n * @returns Returns the slice of `array`.\n */\n\nexport function takeRightWhile<TElem>(array: readonly TElem[], predicate: (elem: TElem) => boolean): TElem[] {\n const result: TElem[] = [];\n\n for (let i = array.length - 1; i >= 0; i--) {\n if (predicate(array[i])) {\n result.unshift(array[i]);\n } else {\n break;\n }\n }\n\n return result;\n}\n","/**\n * Creates a slice of `array` with elements taken from the beginning. \n * Elements are taken until `predicate` returns falsy.\n *\n * @example\n * const users = [\n * { 'user': 'barney', 'active': true },\n * { 'user': 'fred', 'active': true },\n * { 'user': 'pebbles', 'active': false }\n * ]\n *\n * takeWhile(users, user => user.active)\n * // => objects for ['barney', 'fred']\n * @param predicate The function invoked per iteration.\n * @param array The array to query.\n * @template TElem The type of the array elements.\n * @returns A new array of taken elements.\n */\n\nexport function takeWhile<TElem>(array: readonly TElem[], predicate: (elem: TElem) => boolean): TElem[] {\n const result: TElem[] = [];\n\n for (const element of array) {\n if (predicate(element)) {\n result.push(element);\n } else {\n break;\n }\n }\n\n return result;\n}\n","import type { Jsonifiable } from \"@type/Jsonifiable.js\";\n\ntype SupportedAlgorithms = \"SHA-256\" | \"SHA-384\" | \"SHA-512\";\n\nlet textEncoder: TextEncoder | undefined;\n\n/**\n * Generates a hash of the given data using the specified algorithm.\n *\n * It uses the Web Crypto API to generate the hash.\n * \n * *Note: If you need a secure hash use a specialized library like [crypto-js](https://www.npmjs.com/package/crypto-js) instead.*\n * \n * @example\n * // Hash a string using the default algorithm (SHA-256)\n * await hash('hello world'); \n * // => \"b94d27b9934d3e08a52e52d7da7dabfac484efe37a53...\"\n *\n * // Hash an object using the SHA-512 algorithm\n * await hash({ foo: 'bar', baz: 123 }, 'SHA-512');\n * // => \"d8f3c752c6820e580977099368083f4266b569660558...\"\n * \n * @param data The data to hash, either as a string or a JSON-serializable object.\n * @param algorithm The hashing algorithm to use. Defaults to 'SHA-256'.\n * @returns A Promise that resolves to the hexadecimal representation of the hash.\n *\n * @throws {DOMException} If the specified algorithm is not supported by the Web Crypto API.\n */\n\nexport async function hash(data: Jsonifiable, algorithm: SupportedAlgorithms = \"SHA-256\"): Promise<string> {\n textEncoder ??= new TextEncoder();\n\n const dataBuffer = typeof data === \"string\"\n ? textEncoder.encode(data) \n : textEncoder.encode(JSON.stringify(data));\n \n const hashBuffer = await crypto.subtle.digest(algorithm, dataBuffer);\n const hashArray = [...new Uint8Array(hashBuffer)];\n const hexValues = hashArray.map(b => b.toString(16).padStart(2, \"0\"));\n return hexValues.join(\"\");\n}\n","\n/**\n * Generates a random integer between two given numbers, including those numbers.\n * \n * It uses `crypto.getRandomValues` to generate the random number.\n * @example\n * randomInt(1, 10) \n * // => 5\n * \n * @param min The smallest integer that can be generated.\n * @param max The largest integer that can be generated.\n * \n * @returns A random integer between `min` and `max`, including `min` and `max`.\n */\n\nexport function randomInt(min: number, max: number): number {\n // Taken from https://stackoverflow.com/a/41452318\n if (!Number.isInteger(min) || !Number.isInteger(max))\n throw new TypeError(\"min and max must be integers\");\n\n if (min >= max) \n throw new Error(\"max must be greater than min\");\n\n const range = max - min + 1;\n const randomBytes = Math.ceil(Math.log2(range) / 8);\n const maxRandNumber = Math.pow(256, randomBytes);\n const randomBuffer = new Uint8Array(randomBytes);\n\n let randomValue: number;\n do {\n crypto.getRandomValues(randomBuffer);\n randomValue = 0;\n for (let index = 0; index < randomBytes; index++) {\n // eslint-disable-next-line no-bitwise\n randomValue = (randomValue << 8) + randomBuffer[index];\n }\n // rerun if randomValue is bigger than range\n } while (randomValue >= maxRandNumber - (maxRandNumber % range));\n\n return min + (randomValue % range);\n}\n","import { randomInt } from \"./randomInt.js\";\n\n/**\n * Gets a random element an array. A single element is returned by default. \n * Specify the `multi` parameter to get an array of multiple random elements.\n *\n * If the array is empty, `undefined` is returned. \n * If `multi` is defined it returns an empty array.\n * \n * It uses `crypto.getRandomValues` to get the random element.\n * @example\n * randomElem([1, 2, 3, 4])\n * // => 2\n *\n * randomElem([1, 2, 3, 4], 2)\n * // => [3, 1]\n * @param array The array to sample.\n * @returns Returns the random element.\n */\n\nexport function randomElem<TArr>(array: TArr[]): TArr | undefined;\nexport function randomElem<TArr>(array: TArr[], multi: number): TArr[];\nexport function randomElem<TArr>(array: TArr[], multi?: number): TArr | undefined | TArr[] {\n if (multi === undefined) {\n if (array.length === 0) return undefined;\n return getSingleElement(array);\n }\n\n if (multi && array.length === 0) return [];\n\n // Multiple samples\n const result = new Array<TArr>(multi);\n for (let i = 0; i < multi; i++) {\n result[i] = getSingleElement(array);\n }\n return result;\n}\n\nfunction getSingleElement<TArr>(array: TArr[]): TArr {\n const randomIndex = randomInt(0, array.length - 1);\n return array[randomIndex];\n}","/* eslint-disable no-bitwise */\n\n/**\n * Generates a random float between two given numbers, including those numbers.\n * \n * It uses `crypto.getRandomValues` to generate the random number.\n * @example\n * randomFloat(1, 10) \n * // => 1.123456789\n * \n * @param min The smallest float that can be generated.\n * @param max The largest float that can be generated.\n * \n * @returns A random float between `min` and `max`, including `min` and `max`.\n */\nexport function randomFloat(min: number, max: number): number {\n if (min >= max) \n throw new Error(\"max must be greater than min\");\n\n // TODO: Switch to UInt64Array when safari support is better (https://caniuse.com/mdn-javascript_builtins_bigint64array)\n const randomBuffer = new Uint32Array(2);\n crypto.getRandomValues(randomBuffer);\n\n // keep all 32 bits of the the first, top 21 of the second for 53 random bits\n const randomBigInt = (BigInt(randomBuffer[0]) << 21n) | (BigInt(randomBuffer[1]) >> 11n);\n \n // fraction between 0 and 1 with full 53bit precision\n const fraction = Number(randomBigInt) / Number.MAX_SAFE_INTEGER; // (2 ** 53)\n return min + (fraction * (max - min));\n}\n","import { randomInt } from \"./randomInt.js\";\n\nconst DEFAULT_CHARSET = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n\n/**\n * Generates a random string of the specified length.\n * The default charset is alphanumeric characters.\n * \n * It uses `crypto.getRandomValues` to generate the random string.\n * \n * @example\n * randomString(8);\n * // => \"JWw1p6rD\"\n *\n * randomString(16, 'abc');\n * // => \"cbaacbabcabccabc\"\n * @param length The length of the string to generate.\n * @param charSet The set of characters to use when generating the string. Defaults to alphanumeric characters.\n * @returns A random string of the specified length.\n */\n\nexport function randomString(length: number, charSet = DEFAULT_CHARSET): string {\n if (charSet.length <= 0) return \"\";\n\n let result = \"\";\n for (let index = 0; index < length; index++) {\n const randomIndex = randomInt(0, charSet.length - 1);\n result += charSet[randomIndex];\n }\n\n return result;\n}","import type { GenericFunction } from \"@type/GenericFunction.js\";\n\ntype Tail<T extends unknown[]> = T extends [infer _Head, ...infer Tail] ? Tail : never;\n\n/**\n * Transforms a function into a decorator function.\n * \n * @example\n * ```typescript\n * function log(func: Function, message: string) {\n * return function (...args: unknown[]) {\n * console.log(message);\n * return func(...args);\n * };\n * }\n * \n * const logger = toDecorator(log);\n * \n * class TestClass {\n * @logger(\"Hello world!\")\n * testMethod() {\n * return 1; \n * }\n * }\n * \n * const instance = new TestClass();\n * instance.testMethod(); \n * // => Log \"Hello World\" and return 1\n * ```\n * @param func The function to transform.\n * @returns A decorator function that can be used to decorate a method.\n */\n// waiting for https://github.com/evanw/esbuild/issues/104\nexport function toDecorator<TFunc extends GenericFunction<TFunc>>(func: TFunc) {\n return function (...args: Tail<Parameters<TFunc>>) {\n return function (originalMethod: unknown, _context: ClassMethodDecoratorContext) {\n const funcArgs = [originalMethod, ...args] as Parameters<TFunc>;\n return func(...funcArgs);\n };\n };\n}","import type { GenericFunction } from \"@type/GenericFunction.js\";\n\n/**\n * Creates a debounced version of a function. Only calling it after a specified amount of time has passed without any new calls.\n * \n * **Methods:** \n * - `cancel()` will cancel the next invocation of the debounced function. \n * - `flush()` will immediately invoke the debounced function and cancel any pending invocations.\n * - `pending()` returns true if the debounced function is set to invoke.\n * \n * This function can be used as a decorator with {@link decDebounce}.\n * \n * @example\n * const sayHello = (name: string) => console.log(`Hello, ${name}!`);\n * const debouncedSayHello = debounce(sayHello, 200);\n * \n * debouncedSayHello(\"John\");\n * debouncedSayHello(\"Jane\");\n * // => Only the second invocation of `debouncedSayHello` is executed, after a delay of 200ms.\n * @param func The function to debounce.\n * @param wait The number of milliseconds to wait before invoking `func`.\n * @returns A debounced version of `func` with `cancel` and `flush` methods.\n */\n\nexport function debounce<TFunc extends GenericFunction<TFunc>>(func: TFunc, wait: number): TFunc & {\n cancel: () => void;\n flush: () => void;\n pending: () => boolean;\n} {\n let timeoutId: NodeJS.Timeout | undefined;\n const debounced = function (this: unknown, ...args: Parameters<TFunc>) {\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => {\n func.apply(this, args);\n timeoutId = undefined;\n }, wait);\n };\n\n debounced.cancel = function () {\n clearTimeout(timeoutId);\n timeoutId = undefined;\n };\n\n debounced.flush = function (this: unknown, ...args: Parameters<TFunc>) {\n debounced.cancel();\n func.apply(this, args);\n };\n\n debounced.pending = function () {\n return timeoutId !== undefined;\n };\n\n return debounced as TFunc & { cancel: () => void; flush: () => void; pending: () => boolean };\n}\n","import { toDecorator } from \"@decorator/toDecorator.js\";\nimport { debounce } from \"@function/debounce.js\";\n\n/**\n * Debounces the decorated function. Only calling it after a specified amount of time has passed without any new calls.\n * \n * Look at {@link debounce} for the non-decorator version.\n * \n * @example\n * ```typescript\n * class TestClass {\n * @decDebounce(100)\n * testMethod(str: string) {\n * console.log(\"Debounced:\", str);\n * }\n * }\n * \n * const instance = new TestClass();\n * instance.testMethod(\"Hello\");\n * instance.testMethod(\"World\");\n * // => Only the second invocation of `debouncedSayHello` is executed, after a delay of 1000ms.\n * ```\n * @param wait Milliseconds to wait before invoking the decorated function after the last invocation.\n */\n\nexport function decDebounce(wait: number) {\n return toDecorator(debounce)(wait);\n}\n","import type { GenericFunction } from \"@type/GenericFunction.js\";\n\n/**\n * Creates a function that invokes the given function as long as it's called `<= n` times.\n * \n * Subsequent calls to the created function return the result of the last `func` invocation.\n *\n * This function can be used as a decorator with {@link decMaxCalls}.\n * @example\n * let count = 0;\n * const addCount = () => ++count;\n *\n * // Allow addCount to be invoked twice.\n * const limitAddCount = maxCalls(addCount, 2)\n *\n * limitAddCount() // => 1\n * limitAddCount() // => 2\n * limitAddCount() // => 2\n * // => `limitAddCount` is invoked twice and the result is cached.\n * @param n The number of calls before the cached result is returned.\n * @param func The function to restrict.\n * @returns Returns the new restricted function.\n */\n\nexport function maxCalls<TFunc extends GenericFunction<TFunc>>(func: TFunc, n: number): TFunc {\n let count = 0;\n let result: ReturnType<TFunc>;\n return function (this: unknown, ...args: Parameters<TFunc>): ReturnType<TFunc> {\n if (count < n) {\n count += 1;\n result = func.apply(this, args);\n }\n return result;\n } as TFunc;\n}\n","import { toDecorator } from \"@decorator/toDecorator.js\";\nimport { maxCalls } from \"@function/maxCalls.js\";\n\n/**\n * Only invokes the decorated function as long as it's called `<= n` times. \n * Subsequent calls to the decorated function return the result of the last invocation.\n * \n * Look at {@link maxCalls} for the non-decorator version.\n * \n * @example\n * ```typescript\n * class TestClass {\n * private count = 0;\n * @decMaxCalls(2)\n * testMethod() {\n * return ++this.count;\n * }\n * }\n * const instance = new TestClass();\n * instance.testMethod(); // => 1 \n * instance.testMethod(); // => 2\n * instance.testMethod(); // => 2\n * ```\n * @param n The number of calls before the cached result is returned.\n */\n\nexport function decMaxCalls(n: number) {\n return toDecorator(maxCalls)(n);\n}","import type { GenericFunction } from \"@type/GenericFunction.js\";\n\nconst defaultResolver = (...args: unknown[]) => JSON.stringify(args);\n\n/**\n * Creates a function that memoizes the result of a given function.\n * \n * The cache key is determined by the `resolver` or by the arguments from the function call.\n *\n * **Options:**\n * - `resolver` A function that determines the cache key based on the arguments provided.\n * - `ttl` the time to live for the cache entries in milliseconds.\n * \n * **Properties:**\n * - `cache` The cache is an instance of `Map` and can be used to clear or inspect the cache. \n * It can be replaced by a custom cache that matches the `Map` interface.\n * \n * \n * This function can be used as a decorator with {@link decMemoize}.\n * \n * @example\n * ```typescript\n * function fibonacci(n: number) {\n * if (n <= 1) return n;\n * return fibonacci(n - 1) + fibonacci(n - 2);\n * }\n *\n * const memoizedFib = memoize(fibonacci, { ttl: 1000 })\n * \n * memoizedFib(40) // => 102334155\n * memoizedFib(40) // => 102334155 (cache hit)\n * setTimeout(() => memoizedFib(40), 1000) // => 102334155 (cache miss)\n * \n * // Cached values are exposed as the `cache` property.\n * memoizedFib.cache.get(\"40\") // => [value, timestamp]\n * memoizedFib.cache.set(\"40\", [1234, Date.now()])\n * memoizedFib.cache.clear()\n * \n * // This is the default way to create cache keys.\n * const defaultResolver = (...args: unknown[]) => JSON.stringify(args)\n * ```\n * @param func The function to have its output memoized.\n * @param options The options object with optional `resolver` and `ttl` parameters.\n * @param options.resolver - A function that determines the cache key for storing the result based on the arguments provided.\n * @param options.ttl - The time to live for the cache in milliseconds.\n * @template TFunc The type of the function to memoize.\n * @template Cache The type of the cache storage.\n * @returns Returns the new memoized function.\n */\n\nexport function memoize<TFunc extends GenericFunction<TFunc>, Cache extends Map<string, [ReturnType<TFunc>, number]>>(\n func: TFunc, options: { resolver?: (...args: Parameters<TFunc>) => string, ttl?: number; } = {}\n): TFunc & { cache: Cache } {\n const resolver = options.resolver ?? defaultResolver;\n const ttl = options.ttl;\n const cache = new Map() as Cache;\n\n const memoizedFunc = function (this: unknown, ...args: Parameters<TFunc>): ReturnType<TFunc> {\n const key = resolver(...args);\n if (cache.has(key)) {\n const [cacheResult, cacheTime] = cache.get(key)!;\n if (ttl === undefined || (Date.now() - cacheTime < ttl)) {\n return cacheResult;\n }\n }\n const result = func.apply(this, args);\n cache.set(key, [result, Date.now()]);\n return result;\n };\n\n memoizedFunc.cache = cache;\n return memoizedFunc as TFunc & { cache: Cache };\n} ","import { toDecorator } from \"@decorator/toDecorator.js\";\nimport { memoize } from \"@function/memoize.js\";\n\n/**\n * Memoizes the decorated function. \n * The cache key is either determined by the provided resolver or by the arguments used in the memoized function.\n * \n * **Options:**\n * - `resolver` A function that determines the cache key for storing the result based on the arguments provided.\n * - `ttl` sets the time to live for the cache in milliseconds. After `ttl` milliseconds, the next call to the memoized function will result in a cache miss.\n * \n * Look at {@link memoize} for the non-decorator version.\n * \n * @example\n * ```typescript\n * class TestClass {\n * @decMemoize({ ttl: 1000 })\n * testMethod(a: number, b: number) {\n * return a + b;\n * }\n * }\n * const instance = new TestClass();\n * instance.testMethod(1, 2); // => 3\n * instance.testMethod(1, 2); // => 3 (cached)\n * \n * // After 1 second:\n * instance.testMethod(1, 2); // => 3 (cache miss)\n * ```\n * @param options The options object.\n * @param options.resolver - A function that determines the cache key for storing the result based on the arguments provided.\n * @param options.ttl - The time to live for the cache in milliseconds.\n */\n\nexport function decMemoize(options: Parameters<typeof memoize>[1] = {}) {\n return toDecorator(memoize)(options);\n}","import type { GenericFunction } from \"@type/GenericFunction.js\";\n\n/**\n * Creates a function that invokes the given function once it's called more than `n` times. \n * Returns undefined until the minimum call count is reached.\n * \n * This function can be used as a decorator with {@link decMinCalls}.\n * @example\n * const caution = () => console.log(\"Caution!\");\n * const limitedCaution = minCalls(caution, 2);\n *\n * limitedCaution()\n * limitedCaution()\n * limitedCaution()\n * // => `caution` is invoked on the third call.\n * @param n The number of calls before the given function is invoked.\n * @param func The function to restrict.\n * @returns Returns the new restricted function.\n */\n\nexport function minCalls<TFunc extends GenericFunction<TFunc>>(func: TFunc, n: number) {\n let count = 1;\n return function (this: unknown, ...args: Parameters<TFunc>): ReturnType<TFunc> | undefined {\n if (count > n) {\n return func.apply(this, args);\n }\n count += 1;\n };\n}","import { toDecorator } from \"@decorator/toDecorator.js\";\nimport { minCalls } from \"@function/minCalls.js\";\n\n/** \n * Only invokes the decorated function after it's called more than `n` times.\n * \n * Look at {@link minCalls} for the non-decorator version.\n * \n * @example\n * ```typescript\n * class TestClass {\n * @decMinCalls(2)\n * testMethod() {\n * return 1;\n * }\n * }\n * const instance = new TestClass();\n * instance.testMethod(); // => undefined\n * instance.testMethod(); // => undefined\n * instance.testMethod(); // => 1\n * ```\n * @param n The number of calls before the decorated function is invoked.\n */\n\nexport function decMinCalls(n: number) {\n return toDecorator(minCalls)(n);\n}","import type { GenericFunction } from \"@type/GenericFunction.js\";\n\n/**\n * Generates a function that invokes the given function `func` at most once per every `wait` milliseconds. \n * The throttled function always returns the result of the last `func` invocation.\n * \n * This function can be used as a decorator with {@link decThrottle}.\n * @example\n * const throttled = throttle(() => console.log(\"Throttled!\"), 1000);\n * \n * throttled();\n * throttled();\n * // => \"Throttled!\" is logged once per second.\n * @param func The function to throttle.\n * @param wait The number of milliseconds to throttle invocations to.\n * @returns Returns the new throttled function.\n */\n\nexport function throttle<TFunc extends GenericFunction<TFunc>>(func: TFunc, wait: number): TFunc {\n let inThrottle = false;\n let lastResult: ReturnType<TFunc>;\n return function (this: unknown, ...args: Parameters<TFunc>) {\n if (!inThrottle) {\n lastResult = func.apply(this, args);\n inThrottle = true;\n setTimeout(() => (inThrottle = false), wait);\n }\n\n return lastResult;\n } as TFunc;\n}\n \n","import { toDecorator } from \"@decorator/toDecorator.js\";\nimport { throttle } from \"@function/throttle.js\";\n\n/**\n * The decorated function is invoked at most once per every `wait` milliseconds.\n * \n * Look at {@link throttle} for the non-decorator version.\n * \n * @example\n * ```typescript\n * class TestClass {\n * @decThrottle(1000)\n * testMethod() {\n * console.log(\"Throttled!\");\n * }\n * }\n * \n * const instance = new TestClass();\n * instance.testMethod(); // => \"Throttled!\" is logged once per second.\n * instance.testMethod(); // nothing happens\n * ```\n * @param wait The number of milliseconds to wait between invocations.\n */\n\nexport function decThrottle(wait: number) {\n return toDecorator(throttle)(wait);\n}","/**\n * Invokes a function `n` times, returning an array of the results of\n * each invocation.\n * \n * @example\n * times(index => console.log(\"Run\", index), 3)\n * // => \"Run 0\" | \"Run 1\" | \"Run 2\"\n * times(Math.random, 3)\n * // => [0.123, 0.456, 0.789]\n * times(() => 0, 4)\n * // => [0, 0, 0, 0]\n * @param n The number of times to invoke `func`.\n * @param func The function invoked per iteration.\n * @returns Returns an array of results.\n */\n\nexport function times<TInput>(func: (index: number) => TInput, n: number): TInput[] {\n const result: TInput[] = [];\n for (let i = 0; i < n; i++) {\n result.push(func(i));\n }\n return result;\n}","\n/**\n * Calculates the sum of an array of numbers.\n * \n * Returns `NaN` if the input array is empty.\n * @example\n * sum([1, 2, 3, 4, 5]) // => 15\n * \n * @param numbers The input array of numbers\n * @returns The sum of the input array \n */\n\nexport function sum(numbers: readonly number[]): number {\n if (numbers.length === 0)\n return NaN;\n return numbers.reduce((total, current) => total + current, 0);\n}","import { sum } from \"@number/sum.js\";\n\n/**\n * Calculates the average of an array of numbers\n * \n * Returns `NaN` if the input array is empty.\n * @example\n * average([1, 2, 3, 4, 5]) // => 3\n * \n * @param numbers The input array of numbers\n * @returns The average of the input array, or NaN if the input array is empty\n */\n\nexport function average(numbers: readonly number[]): number {\n if (numbers.length === 0)\n return NaN;\n return sum(numbers) / numbers.length;\n}","/**\n * Calculates the median of an array of numbers\n * \n * Returns `NaN` if the input array is empty.\n * @example\n * median([1, 2, 3, 4, 5]) // => 3\n * median([1, 2, 3, 4, 5, 6]) // => 3.5\n * \n * @param numbers The input array of numbers\n * @returns The median of the input array\n */\n\nexport function median(numbers: readonly number[]): number {\n if (numbers.length === 0)\n return NaN;\n const sortedArray = [...numbers].sort((a, b) => a - b);\n const mid = Math.floor(sortedArray.length / 2);\n return sortedArray.length % 2 === 0 ? ((sortedArray[mid - 1] + sortedArray[mid]) / 2) : sortedArray[mid];\n}","/**\n * Rounds a number to the given precision.\n *\n * @example\n * round(1.23456, 2); // => 1.23\n * round(1.235, 1); // => 1.2\n * round(1234.56); // => 1234.56\n * \n * @param number The number to be rounded.\n * @param precision The number of decimal places to round to. Defaults to 2.\n * @returns The rounded number.\n */\n\nexport function round(number: number, precision = 2): number {\n const factor = Math.pow(10, precision);\n return Math.round((number + Number.EPSILON) * factor) / factor;\n}","import type { PlainObject } from \"@type/PlainObject.js\";\n\n/**\n * Checks if the value is a plain object.\n * \n * Refers to the {@link PlainObject} type.\n * @example\n * isPlainObject({}) // => true\n * isPlainObject({ a: 1 }) // => true\n * isPlainObject(null) // => false\n * isPlainObject('1') // => false\n * isPlainObject([]) // => false\n * isPlainObject(new Function()) // => false\n * isPlainObject(new Date()) // => false\n * @param value The value to check\n * @returns Boolean indicating if the value is a plain object\n */\n\nexport function isPlainObject(value: unknown): value is PlainObject {\n return value?.constructor === Object;\n}","import type { GenericObject } from \"@type/GenericObject\";\nimport type { Paths } from \"type-fest\";\n\nimport { isPlainObject } from \"@validate/isPlainObject.js\";\n\ntype StringIfNever<Type> = [Type] extends [never] ? string : Type;\ntype PathOrString<TObj> = StringIfNever<Paths<TObj, { bracketNotation: true, maxRecursionDepth: 20 }>>;\n\n/**\n * Flattens an object into a single level object.\n * \n * @example\n * const obj = { a: { b: 2, c: [{ d: 3 }, { d: 4 }] } };\n * flatKeys(obj);\n * // => { 'a.b': 2, 'a.c[0].d': 3, 'a.c[1].d': 4 }\n * \n * @param obj The object to flatten.\n * @template TObj The type of the object to flatten.\n * @returns A new object with flattened keys.\n */\n\nexport function flatKeys<TObj extends GenericObject>(obj: TObj): Record<PathOrString<TObj>, unknown> {\n const flatObject: Record<string, unknown> = {};\n \n for (const [key, value] of Object.entries(obj)) {\n addToResult(key, value, flatObject);\n }\n \n return flatObject;\n}\n\nfunction addToResult(prefix: string, value: unknown, flatObject: Record<string, unknown>) {\n if (isPlainObject(value)) {\n const flatObj = flatKeys(value);\n for (const [flatKey, flatValue] of Object.entries(flatObj)) {\n flatObject[`${prefix}.${flatKey}`] = flatValue;\n }\n } else if (Array.isArray(value)) {\n for (const [index, element] of value.entries()) {\n addToResult(`${prefix}[${index}]`, element, flatObject);\n }\n\n } else {\n flatObject[prefix] = value;\n }\n}","import type { ArrayMinLength } from \"@type/ArrayMinLength.js\";\nimport type { GenericObject } from \"@type/GenericObject\";\nimport type { PlainObject } from \"@type/PlainObject.js\";\n\nimport { isPlainObject } from \"@validate/isPlainObject.js\";\n\n/**\n * This function combines two or more objects into a single new object. Arrays and other types are overwritten.\n * \n * @example\n * // ---- Nested objects are merged ----\n * merge({ a: 1 }, { b: 2 }, { c: 3, d: { e: 4 } }) \n * // => { a: 1, b: 2, c: 3, d: { e: 4 } }\n *\n * // ---- Other types are overwritten ----\n * merge({ a: [1, 2] }, { a: [3, 4] })\n * // => { a: [3, 4] }\n * \n * merge({ a: 1 }, { a: \"Yes\" })\n * // => { a: \"Yes\" }\n * @param target The target object\n * @param sources The source objects\n * @template TTarget The type of the target object\n * @template TSources The type of the source objects\n * @returns A new merged object\n */\n\nexport function merge<TTarget extends GenericObject, TSources extends ArrayMinLength<GenericObject, 1>>(target: TTarget, ...sources: TSources): MergeDeepObjects<[TTarget, ...TSources]> {\n const targetCopy = { ...target };\n for (const source of sources) {\n for (const [key, value] of Object.entries(source)) {\n (targetCopy as PlainObject)[key] = isPlainObject(value) && isPlainObject(targetCopy[key]) \n ? merge(targetCopy[key], value) \n : value;\n }\n }\n return targetCopy as MergeDeepObjects<[TTarget, ...TSources]>; \n}\n\ntype OptionalPropertyNames<T> =\n { [K in keyof T]-?: (PlainObject extends { [P in K]: T[K] } ? K : never) }[keyof T];\n\ntype SpreadProperties<L, R, K extends keyof L & keyof R> =\n { [P in K]: L[P] | Exclude<R[P], undefined> };\n\ntype Id<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;\n\ntype SpreadTwo<L, R> = Id<\n& Pick<L, Exclude<keyof L, keyof R>>\n& Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>>\n& Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>>\n& SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>\n>;\n\ntype MergeDeepObjects<A extends readonly [...unknown[]]> = A extends [infer L, ...infer R] ?\n SpreadTwo<L, MergeDeepObjects<R>> : unknown;\n","import type { GenericObject } from \"@type/GenericObject\";\n\n/**\n * Creates an object composed of the picked `object` properties.\n *\n * @example\n * const object = { 'a': 1, 'b': '2', 'c': 3 }\n *\n * pick(object, ['a', 'c'])\n * // => { 'a': 1, 'c': 3 }\n * @param object The source object.\n * @param keysToPick The property paths to pick.\n * @template TObj The type of the object.\n * @returns Returns the new object.\n */\n\nexport function pick<TObj extends GenericObject, Key extends keyof TObj>(object: TObj, keysToPick: Key[]): Pick<TObj, Key> {\n const result = {} as Pick<TObj, Key>;\n for (const key of keysToPick) {\n result[key] = object[key];\n }\n return result;\n}\n","import type { GenericObject } from \"@type/GenericObject\";\n\nimport { difference } from \"@array/difference.js\";\nimport { pick } from \"@object/pick.js\";\n\n/**\n * Omit specified keys from an object\n *\n * @example\n * const obj = {a: 1, b: 2, c: 3};\n * omit(obj, ['a', 'b']);\n * // => {c: 3}\n *\n * @param object The object to filter\n * @param keysToOmit The keys to exclude from the returned object\n * @template TObj The type of the object\n * @returns - An object without the specified keys\n */\n\nexport function omit<TObj extends GenericObject, Key extends keyof TObj>(object: TObj, keysToOmit: Key[]): Omit<TObj, Key> {\n const allKeys = Object.keys(object);\n const filteredKeys = difference(allKeys, keysToOmit as string[]) as Exclude<keyof TObj, Key>[];\n\n return pick(object, filteredKeys);\n}","import type { GenericObject } from \"@type/GenericObject\";\nimport type { PlainObject } from \"@type/PlainObject.js\";\nimport type { Call, Objects } from \"hotscript\";\n\nimport { isPlainObject } from \"@validate/isPlainObject.js\";\n\nconst va