@catbee/utils 2.0.0-next.0 → 2.0.0-next.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.
Files changed (97) hide show
  1. package/README.md +52 -16
  2. package/array/index.cjs +180 -71
  3. package/array/index.d.ts +293 -1
  4. package/array/index.mjs +171 -72
  5. package/async/index.cjs +92 -36
  6. package/async/index.d.ts +275 -1
  7. package/async/index.mjs +92 -36
  8. package/cache/index.cjs +1 -1
  9. package/cache/index.d.ts +155 -1
  10. package/cache/index.mjs +2 -2
  11. package/config/index.cjs +78 -64
  12. package/config/index.d.ts +64 -2
  13. package/config/index.mjs +76 -64
  14. package/context-store/index.d.ts +192 -1
  15. package/crypto/index.d.ts +163 -1
  16. package/date/index.cjs +46 -1
  17. package/date/index.d.ts +190 -1
  18. package/date/index.mjs +45 -2
  19. package/decorators/index.cjs +1156 -18
  20. package/decorators/index.d.ts +684 -1
  21. package/decorators/index.mjs +1156 -18
  22. package/dir/index.cjs +4 -3
  23. package/dir/index.d.ts +195 -1
  24. package/dir/index.mjs +4 -3
  25. package/env/index.cjs +10 -26
  26. package/env/index.d.ts +379 -1
  27. package/env/index.mjs +10 -26
  28. package/exception/index.d.ts +232 -1
  29. package/fs/index.cjs +70 -36
  30. package/fs/index.d.ts +205 -1
  31. package/fs/index.mjs +64 -34
  32. package/http-status-codes/index.d.ts +267 -1
  33. package/id/index.d.ts +37 -1
  34. package/index.cjs +3 -3
  35. package/index.d.ts +1 -1
  36. package/index.mjs +1 -1
  37. package/logger/index.cjs +11 -11
  38. package/logger/index.d.ts +189 -1
  39. package/logger/index.mjs +12 -12
  40. package/middleware/index.d.ts +103 -1
  41. package/obj/index.cjs +150 -162
  42. package/obj/index.d.ts +136 -1
  43. package/obj/index.mjs +150 -162
  44. package/package.json +11 -11
  45. package/performance/index.cjs +2 -2
  46. package/performance/index.d.ts +138 -1
  47. package/performance/index.mjs +2 -2
  48. package/request/index.cjs +1 -1
  49. package/request/index.d.ts +241 -2
  50. package/request/index.mjs +1 -1
  51. package/response/index.d.ts +318 -2
  52. package/server/index.cjs +27 -23
  53. package/server/index.d.ts +785 -4
  54. package/server/index.mjs +28 -23
  55. package/stream/index.d.ts +90 -1
  56. package/string/index.d.ts +102 -1
  57. package/type/index.cjs +1 -1
  58. package/type/index.d.ts +107 -1
  59. package/type/index.mjs +1 -1
  60. package/types/index.d.ts +774 -4
  61. package/url/index.cjs +2 -4
  62. package/url/index.d.ts +142 -1
  63. package/url/index.mjs +2 -4
  64. package/{validate → validation}/index.cjs +89 -42
  65. package/{validate/validate.utils.d.ts → validation/index.d.ts} +32 -23
  66. package/{validate → validation}/index.mjs +85 -42
  67. package/array/array.utils.d.ts +0 -191
  68. package/async/async.utils.d.ts +0 -296
  69. package/cache/cache.utils.d.ts +0 -176
  70. package/config/config.d.ts +0 -57
  71. package/context-store/context-store.utils.d.ts +0 -212
  72. package/crypto/crypto.utils.d.ts +0 -183
  73. package/date/date.utils.d.ts +0 -190
  74. package/decorators/decorators.utils.d.ts +0 -705
  75. package/dir/dir.utils.d.ts +0 -216
  76. package/env/env.utils.d.ts +0 -400
  77. package/exception/exception.utils.d.ts +0 -253
  78. package/fs/fs.utils.d.ts +0 -196
  79. package/http-status-codes/http-status-codes.d.ts +0 -289
  80. package/id/id.utils.d.ts +0 -59
  81. package/logger/logger.utils.d.ts +0 -210
  82. package/middleware/middleware.utils.d.ts +0 -123
  83. package/obj/obj.utils.d.ts +0 -156
  84. package/performance/performance.utils.d.ts +0 -159
  85. package/request/request.utils.d.ts +0 -109
  86. package/response/response.utils.d.ts +0 -186
  87. package/server/server.builder.d.ts +0 -531
  88. package/server/server.d.ts +0 -303
  89. package/stream/stream.utils.d.ts +0 -111
  90. package/string/string.utils.d.ts +0 -124
  91. package/type/type.utils.d.ts +0 -129
  92. package/types/api-response.d.ts +0 -175
  93. package/types/common.d.ts +0 -148
  94. package/types/config.d.ts +0 -88
  95. package/types/server.d.ts +0 -291
  96. package/url/url.utils.d.ts +0 -164
  97. package/validate/index.d.ts +0 -25
package/array/index.d.ts CHANGED
@@ -22,4 +22,296 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- export * from './array.utils';
25
+ /**
26
+ * Splits an array into chunks of the specified size.
27
+ *
28
+ * @template T The type of array elements.
29
+ * @param {T[]} array - The array to split into chunks.
30
+ * @param {number} size - The number of elements per chunk.
31
+ * @returns {T[][]} A new array containing chunked arrays.
32
+ * @throws {TypeError} If array is not an array.
33
+ * @throws {Error} If chunk size is not a positive integer.
34
+ */
35
+ declare function chunk<T>(array: readonly T[], size: number): T[][];
36
+ /**
37
+ * Removes duplicate values from an array.
38
+ * Optionally enforces uniqueness by a key function.
39
+ *
40
+ * @template T The type of array elements.
41
+ * @param {T[]} array - The input array.
42
+ * @param {(item: T) => unknown} [keyFn] - Optional function to determine uniqueness by key.
43
+ * @returns {T[]} A new array with unique values.
44
+ */
45
+ declare function unique<T>(array: readonly T[], keyFn?: (item: T) => unknown): T[];
46
+ /**
47
+ * Deeply flattens a nested array to a single-level array (iterative, stack-based).
48
+ *
49
+ * @template T The leaf type of array elements.
50
+ * @param {readonly unknown[]} array - The (possibly deeply nested) input array.
51
+ * @returns {T[]} A deeply flattened array.
52
+ */
53
+ declare function flattenDeep<T>(array: readonly unknown[]): T[];
54
+ /**
55
+ * Returns a random element from an array, or undefined if empty. Uses crypto-secure randomness
56
+ *
57
+ * @template T The type of array elements.
58
+ * @param {T[]} array - The input array.
59
+ * @returns {T | undefined} A randomly selected item, or undefined if array is empty or not an array.
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * securePick(['a','b','c']); // -> 'b'
64
+ * ```
65
+ */
66
+ declare function random<T>(array: readonly T[]): T | undefined;
67
+ /**
68
+ * Groups items in an array by a nested key or key function.
69
+ *
70
+ * @template T The type of array elements.
71
+ * @overload
72
+ * @param {T[]} array - The array to group.
73
+ * @param {keyof T} key - Property key to group by.
74
+ * @returns {Record<string, readonly T[]>}
75
+ * @overload
76
+ * @param {T[]} array - The array to group.
77
+ * @param {(item: T) => string | number | symbol} keyFn - Function to generate group key from item.
78
+ * @returns {Record<K, readonly T[]>}
79
+ * @param {T[]} array - The array to group.
80
+ * @param {keyof T | ((item: T) => string | number | symbol)} keyOrFn - Nested property key or key selector.
81
+ * @returns {Record<string | number | symbol, readonly T[]>} Grouped result object.
82
+ */
83
+ declare function groupBy<T>(array: T[], key: keyof T): Record<string, readonly T[]>;
84
+ declare function groupBy<T, K extends string | number | symbol>(array: T[], keyFn: (item: T) => K): Record<K, readonly T[]>;
85
+ /**
86
+ * Shuffles an array using the Fisher-Yates algorithm. Uses crypto-secure randomness.
87
+ *
88
+ * @template T The type of array elements.
89
+ * @param {T[]} array - The input array.
90
+ * @returns {T[]} A new shuffled array.
91
+ * @throws {TypeError} If array is not an array.
92
+ */
93
+ declare function shuffle<T>(array: readonly T[]): T[];
94
+ /**
95
+ * Returns an array of property values from an array of objects. Returns undefined for missing properties.
96
+ *
97
+ * @template T The type of array elements.
98
+ * @template K The object property to pluck.
99
+ * @param {T[]} array - The input array.
100
+ * @param {K} key - The property name to pluck.
101
+ * @returns {T[K][]} Array of property values.
102
+ */
103
+ declare function pluck<T, K extends keyof T>(array: readonly T[], key: K): T[K][];
104
+ /**
105
+ * Returns values in array A that are not in array B.
106
+ *
107
+ * @template T The type of array elements.
108
+ * @param {T[]} a - First array.
109
+ * @param {T[]} b - Second array.
110
+ * @returns {T[]} Elements in A that are not in B.
111
+ */
112
+ declare function difference<T>(a: readonly T[], b: readonly T[]): T[];
113
+ /**
114
+ * Returns common values between arrays A and B.
115
+ *
116
+ * @template T The type of array elements.
117
+ * @param {T[]} a - First array.
118
+ * @param {T[]} b - Second array.
119
+ * @returns {T[]} Elements that exist in both arrays.
120
+ */
121
+ declare function intersect<T>(a: readonly T[], b: readonly T[]): T[];
122
+ /**
123
+ * Sorts an array of objects by a nested key using Merge Sort (O(n log n)).
124
+ * Missing/undefined keys are sorted to the "end" (asc) or "start" (desc").
125
+ * Optionally accepts a custom compare function or collator.
126
+ *
127
+ * @template T The type of array elements (objects).
128
+ * @param {T[]} array - Array of objects to sort.
129
+ * @param {string | ((item: T) => any)} key - Dot-notated key (e.g., "profile.age") or function.
130
+ * @param {"asc" | "desc"} [direction="asc"] - Sort direction: 'asc' or 'desc'.
131
+ * @param {(a: T, b: T) => number} [compareFn] - Optional custom compare function.
132
+ * @returns {T[]} A new sorted array.
133
+ * @throws {TypeError} If array is not an array.
134
+ */
135
+ declare function mergeSort<T>(array: readonly T[], key: string | ((item: T) => unknown), direction?: 'asc' | 'desc', compareFn?: (a: T, b: T) => number): T[];
136
+ /**
137
+ * Combines multiple arrays into a single array of grouped elements.
138
+ * Output length equals the length of the shortest input array.
139
+ *
140
+ * This implementation ensures type safety and avoids holes in output.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * zip([1, 2], ['a', 'b']) => [[1, 'a'], [2, 'b']]
145
+ * ```
146
+ * @param {...Array<T>[]} arrays - Two or more arrays to zip together.
147
+ * @returns {Array<T[]>} Array of grouped elements.
148
+ */
149
+ declare function zip<T>(...arrays: ReadonlyArray<T>[]): T[][];
150
+ /**
151
+ * Splits an array into two arrays based on a predicate function.
152
+ * Supports type-guard narrowing via overload.
153
+ *
154
+ * @template T The type of array elements.
155
+ * @overload
156
+ * @param {readonly T[]} array - The input array.
157
+ * @param {(item: T, index: number, array: readonly T[]) => item is U} predicate - Type guard predicate.
158
+ * @returns {[U[], Exclude<T, U>[]]} A tuple of two arrays: [matched, unmatched].
159
+ * @overload
160
+ * @param {readonly T[]} array - The input array.
161
+ * @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Boolean predicate.
162
+ * @returns {[T[], T[]]} A tuple of two arrays: [matched, unmatched].
163
+ */
164
+ declare function partition<T, U extends T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => item is U): [U[], Exclude<T, U>[]];
165
+ declare function partition<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): [T[], T[]];
166
+ /**
167
+ * Generates an array of numbers within a specified range.
168
+ *
169
+ * @param {number} start - Start of range (inclusive).
170
+ * @param {number} end - End of range (exclusive).
171
+ * @param {number} [step=1] - Step between numbers.
172
+ * @returns {number[]} Array of numbers in range.
173
+ */
174
+ declare function range(start: number, end: number, step?: number): number[];
175
+ /**
176
+ * Returns the first `n` elements from an array.
177
+ *
178
+ * @template T The type of array elements.
179
+ * @param {T[]} array - The input array.
180
+ * @param {number} [n=1] - Number of elements to take.
181
+ * @returns {T[]} New array with first n elements.
182
+ */
183
+ declare function take<T>(array: readonly T[], n?: number): T[];
184
+ /**
185
+ * Takes elements from an array while predicate returns true.
186
+ *
187
+ * @template T The type of array elements.
188
+ * @param {readonly T[]} array - Input array.
189
+ * @param {(item: T, index: number) => boolean} predicate - Condition function.
190
+ * @returns {T[]} New array with taken elements.
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * takeWhile([1,2,3,4], (n) => n < 3); // -> [1,2]
195
+ * ```
196
+ */
197
+ declare function takeWhile<T>(array: readonly T[], predicate: (item: T, index: number) => boolean): T[];
198
+ /**
199
+ * Removes all falsy values from an array.
200
+ * `false`, `null`, `0`, `""`, `undefined`, and `NaN` are falsy.
201
+ *
202
+ * @template T The type of array elements.
203
+ * @param {T[]} array - The input array.
204
+ * @returns {NonNullable<T>[]} New array with falsy values removed.
205
+ */
206
+ declare function compact<T>(array: readonly T[]): NonNullable<T>[];
207
+ /**
208
+ * Counts array elements by a key function.
209
+ *
210
+ * @template T The type of array elements.
211
+ * @param {T[]} array - The input array.
212
+ * @param {(item: T) => string | number | symbol} keyFn - Function to generate count key.
213
+ * @returns {Record<string, number>} Object with counts by key.
214
+ */
215
+ declare function countBy<T>(array: readonly T[], keyFn: (item: T) => string | number | symbol): Record<string, number>;
216
+ /**
217
+ * Toggles an item in array (adds if not present, removes if present).
218
+ *
219
+ * @template T
220
+ * @param {readonly T[]} array
221
+ * @param {T} item
222
+ * @returns {T[]} New array with item toggled.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * toggle([1,2,3], 2); // -> [1,3]
227
+ * toggle([1,3], 2); // -> [1,3,2]
228
+ * ```
229
+ */
230
+ declare function toggle<T>(array: readonly T[], item: T): T[];
231
+ /**
232
+ * Returns a cryptographically secure random index for an array.
233
+ * Used internally for secure pick/shuffle operations.
234
+ *
235
+ * @param {number} max Upper bound (exclusive).
236
+ * @returns {number} A secure random integer in range `[0, max)`.
237
+ * @throws {RangeError} If `max` is not a positive number.
238
+ *
239
+ * @example
240
+ * ```ts
241
+ * secureIndex(10); // -> 3 (unpredictable)
242
+ * ```
243
+ */
244
+ declare function secureIndex(max: number): number;
245
+ /**
246
+ * Returns a secure random element from an array using Node crypto.
247
+ *
248
+ * @template T
249
+ * @param {readonly T[]} array
250
+ * @returns {T | undefined}
251
+ */
252
+ declare const secureRandom: <T>(array: readonly T[]) => T | undefined;
253
+ /**
254
+ * Returns the last element in the array that satisfies the provided testing function.
255
+ *
256
+ * @template T
257
+ * @param {readonly T[]} array - The input array.
258
+ * @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Function to test each element.
259
+ * @returns {T | undefined} The found element, or undefined if not found.
260
+ */
261
+ declare function findLast<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): T | undefined;
262
+ /**
263
+ * Returns the index of the last element in the array that satisfies the provided testing function.
264
+ *
265
+ * @template T
266
+ * @param {readonly T[]} array - The input array.
267
+ * @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Function to test each element.
268
+ * @returns {number} The index, or -1 if not found.
269
+ */
270
+ declare function findLastIndex<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): number;
271
+ /**
272
+ * Splits an array into chunks based on a predicate function.
273
+ * Each chunk starts when predicate returns true.
274
+ *
275
+ * @template T
276
+ * @param {readonly T[]} array - The input array.
277
+ * @param {(item: T, index: number, array: readonly T[]) => boolean} predicate - Function to determine chunk boundaries.
278
+ * @returns {T[][]} Array of chunked arrays.
279
+ */
280
+ declare function chunkBy<T>(array: readonly T[], predicate: (item: T, index: number, array: readonly T[]) => boolean): T[][];
281
+ /**
282
+ * Removes all occurrences of a value from an array.
283
+ *
284
+ * @template T
285
+ * @param {readonly T[]} array - The input array.
286
+ * @param {T} value - Value to remove.
287
+ * @returns {T[]} New array with value removed.
288
+ */
289
+ declare function remove<T>(array: readonly T[], value: T): T[];
290
+ /**
291
+ * Checks if an array is sorted in ascending or descending order.
292
+ *
293
+ * @template T
294
+ * @param {readonly T[]} array - The input array.
295
+ * @param {'asc' | 'desc'} [direction='asc'] - Sort direction.
296
+ * @param {(a: T, b: T) => number} [compareFn] - Optional compare function.
297
+ * @returns {boolean} True if sorted, false otherwise.
298
+ */
299
+ declare function isSorted<T>(array: readonly T[], direction?: 'asc' | 'desc', compareFn?: (a: T, b: T) => number): boolean;
300
+ /**
301
+ * Returns the first element of an array, or undefined if empty.
302
+ *
303
+ * @template T
304
+ * @param {readonly T[]} array
305
+ * @returns {T | undefined}
306
+ */
307
+ declare function headOfArr<T>(array: readonly T[]): T | undefined;
308
+ /**
309
+ * Returns the last element of an array, or undefined if empty.
310
+ *
311
+ * @template T
312
+ * @param {readonly T[]} array
313
+ * @returns {T | undefined}
314
+ */
315
+ declare function lastOfArr<T>(array: readonly T[]): T | undefined;
316
+
317
+ export { chunk, chunkBy, compact, countBy, difference, findLast, findLastIndex, flattenDeep, groupBy, headOfArr, intersect, isSorted, lastOfArr, mergeSort, partition, pluck, random, range, remove, secureIndex, secureRandom, shuffle, take, takeWhile, toggle, unique, zip };
package/array/index.mjs CHANGED
@@ -23,6 +23,7 @@
23
23
  */
24
24
 
25
25
  import { getValueByPath } from '@catbee/utils/obj';
26
+ import { randomBytes } from 'crypto';
26
27
 
27
28
  var __defProp = Object.defineProperty;
28
29
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -41,49 +42,64 @@ function unique(array, keyFn) {
41
42
  if (!Array.isArray(array) || array.length === 0) return [];
42
43
  if (!keyFn) return Array.from(new Set(array));
43
44
  const seen = /* @__PURE__ */ new Set();
44
- return array.filter((item) => {
45
+ const result = [];
46
+ for (const item of array) {
45
47
  const key = keyFn(item);
46
- if (seen.has(key)) return false;
47
- seen.add(key);
48
- return true;
49
- });
48
+ if (!seen.has(key)) {
49
+ seen.add(key);
50
+ result.push(item);
51
+ }
52
+ }
53
+ return result;
50
54
  }
51
55
  __name(unique, "unique");
52
56
  function flattenDeep(array) {
53
57
  if (!Array.isArray(array)) return [];
54
58
  const result = [];
55
- for (const val of array) {
59
+ const stack = [
60
+ ...array
61
+ ];
62
+ while (stack.length) {
63
+ const val = stack.pop();
56
64
  if (Array.isArray(val)) {
57
- result.push(...flattenDeep(val));
65
+ stack.push(...val);
58
66
  } else {
59
67
  result.push(val);
60
68
  }
61
69
  }
62
- return result;
70
+ return result.reverse();
63
71
  }
64
72
  __name(flattenDeep, "flattenDeep");
65
73
  function random(array) {
66
74
  if (!Array.isArray(array) || array.length === 0) return void 0;
67
- const idx = Math.floor(Math.random() * array.length);
68
- return array[idx];
75
+ return array[secureIndex(array.length)];
69
76
  }
70
77
  __name(random, "random");
71
78
  function groupBy(array, keyOrFn) {
72
79
  if (!Array.isArray(array) || array.length === 0) return {};
73
- const keyFn = typeof keyOrFn === "function" ? keyOrFn : (item) => item[keyOrFn];
74
- return array.reduce((acc, item) => {
75
- const key = keyFn(item);
76
- if (!acc[key]) acc[key] = [];
77
- acc[key].push(item);
78
- return acc;
79
- }, {});
80
+ const keyFn = typeof keyOrFn === "function" ? keyOrFn : (item) => String(getValueByPath(item, keyOrFn));
81
+ const result = {};
82
+ for (const item of array) {
83
+ const key = String(keyFn(item));
84
+ if (Object.hasOwn?.(result, key) ?? Object.prototype.hasOwnProperty.call(result, key)) {
85
+ result[key].push(item);
86
+ } else {
87
+ result[key] = [
88
+ item
89
+ ];
90
+ }
91
+ }
92
+ return Object.fromEntries(Object.entries(result).map(([k, v]) => [
93
+ k,
94
+ v
95
+ ]));
80
96
  }
81
97
  __name(groupBy, "groupBy");
82
98
  function shuffle(array) {
83
99
  if (!Array.isArray(array)) throw new TypeError("Expected an array");
84
100
  const copy = array.slice();
85
101
  for (let i = copy.length - 1; i > 0; i--) {
86
- const j = Math.floor(Math.random() * (i + 1));
102
+ const j = secureIndex(i + 1);
87
103
  [copy[i], copy[j]] = [
88
104
  copy[j],
89
105
  copy[i]
@@ -94,7 +110,7 @@ function shuffle(array) {
94
110
  __name(shuffle, "shuffle");
95
111
  function pluck(array, key) {
96
112
  if (!Array.isArray(array)) return [];
97
- return array.map((item) => item[key]);
113
+ return array.map((item) => item?.[key]);
98
114
  }
99
115
  __name(pluck, "pluck");
100
116
  function difference(a, b) {
@@ -109,35 +125,41 @@ function intersect(a, b) {
109
125
  return a.filter((item) => setB.has(item));
110
126
  }
111
127
  __name(intersect, "intersect");
112
- function mergeSort(array, key, direction = "asc") {
128
+ function mergeSort(array, key, direction = "asc", compareFn) {
113
129
  if (!Array.isArray(array)) throw new TypeError("Expected array");
114
- if (array.length <= 1) return array.slice();
130
+ const arr = array.slice();
131
+ if (arr.length <= 1) return arr;
115
132
  const keyFn = typeof key === "function" ? key : (item) => getValueByPath(item, key);
116
- const compare = /* @__PURE__ */ __name((a, b) => {
133
+ const collator = new Intl.Collator("en", {
134
+ numeric: true
135
+ });
136
+ const compare = compareFn ?? function(a, b) {
117
137
  const aVal = keyFn(a);
118
138
  const bVal = keyFn(b);
119
139
  if (aVal === bVal) return 0;
120
140
  if (aVal == null) return direction === "asc" ? 1 : -1;
121
141
  if (bVal == null) return direction === "asc" ? -1 : 1;
122
- return direction === "asc" ? aVal < bVal ? -1 : 1 : aVal > bVal ? -1 : 1;
123
- }, "compare");
142
+ return direction === "asc" ? collator.compare(String(aVal), String(bVal)) : collator.compare(String(bVal), String(aVal));
143
+ };
124
144
  const merge = /* @__PURE__ */ __name((left, right) => {
125
145
  const result = [];
126
146
  let i = 0, j = 0;
127
147
  while (i < left.length && j < right.length) {
128
- if (compare(left[i], right[j]) <= 0) result.push(left[i++]);
129
- else result.push(right[j++]);
148
+ result.push(compare(left[i], right[j]) <= 0 ? left[i++] : right[j++]);
130
149
  }
131
- return result.concat(left.slice(i)).concat(right.slice(j));
150
+ while (i < left.length) result.push(left[i++]);
151
+ while (j < right.length) result.push(right[j++]);
152
+ return result;
132
153
  }, "merge");
133
- const sort = /* @__PURE__ */ __name((arr) => {
134
- if (arr.length <= 1) return arr;
135
- const mid = Math.floor(arr.length / 2);
136
- const left = sort(arr.slice(0, mid));
137
- const right = sort(arr.slice(mid));
154
+ const sort = /* @__PURE__ */ __name((input) => {
155
+ const len = input.length;
156
+ if (len <= 1) return input;
157
+ const mid = len >> 1;
158
+ const left = sort(input.slice(0, mid));
159
+ const right = sort(input.slice(mid));
138
160
  return merge(left, right);
139
161
  }, "sort");
140
- return sort(array);
162
+ return sort(arr);
141
163
  }
142
164
  __name(mergeSort, "mergeSort");
143
165
  function zip(...arrays) {
@@ -154,28 +176,20 @@ function zip(...arrays) {
154
176
  }
155
177
  __name(zip, "zip");
156
178
  function partition(array, predicate) {
179
+ const pass = [];
180
+ const fail = [];
157
181
  if (!Array.isArray(array)) return [
158
- [],
159
- []
182
+ pass,
183
+ fail
184
+ ];
185
+ for (let i = 0; i < array.length; i++) {
186
+ const item = array[i];
187
+ (predicate(item, i, array) ? pass : fail).push(item);
188
+ }
189
+ return [
190
+ pass,
191
+ fail
160
192
  ];
161
- return array.reduce(([pass, fail], item, index) => {
162
- return predicate(item, index, array) ? [
163
- [
164
- ...pass,
165
- item
166
- ],
167
- fail
168
- ] : [
169
- pass,
170
- [
171
- ...fail,
172
- item
173
- ]
174
- ];
175
- }, [
176
- [],
177
- []
178
- ]);
179
193
  }
180
194
  __name(partition, "partition");
181
195
  function range(start, end, step = 1) {
@@ -183,46 +197,131 @@ function range(start, end, step = 1) {
183
197
  throw new TypeError("Arguments must be finite numbers");
184
198
  }
185
199
  if (step === 0) throw new Error("Step cannot be zero");
186
- const isAscending = step > 0;
187
- if (isAscending && start >= end || !isAscending && start <= end) {
188
- return [];
189
- }
190
- const length = Math.max(Math.ceil((end - start) / step), 0);
191
- const result = new Array(length);
192
- for (let i = 0, value = start; i < length; i++, value += step) {
193
- result[i] = value;
200
+ const result = [];
201
+ if (step > 0) {
202
+ for (let i = start; i < end; i += step) result.push(i);
203
+ } else {
204
+ for (let i = start; i > end; i += step) result.push(i);
194
205
  }
195
206
  return result;
196
207
  }
197
208
  __name(range, "range");
198
209
  function take(array, n = 1) {
199
210
  if (!Array.isArray(array) || n <= 0) return [];
200
- return array.slice(0, n);
211
+ return n >= array.length ? array.slice() : array.slice(0, n);
201
212
  }
202
213
  __name(take, "take");
203
214
  function takeWhile(array, predicate) {
204
- if (!Array.isArray(array)) return [];
205
215
  const result = [];
206
- for (let i = 0; i < array.length; i++) {
207
- if (!predicate(array[i], i)) break;
208
- result.push(array[i]);
216
+ if (!Array.isArray(array)) return result;
217
+ const len = array.length;
218
+ for (let i = 0; i < len; i++) {
219
+ const item = array[i];
220
+ if (!predicate(item, i)) break;
221
+ result.push(item);
209
222
  }
210
223
  return result;
211
224
  }
212
225
  __name(takeWhile, "takeWhile");
213
226
  function compact(array) {
214
227
  if (!Array.isArray(array)) return [];
215
- return array.filter(Boolean);
228
+ const result = [];
229
+ for (const v of array) {
230
+ if (v) result.push(v);
231
+ }
232
+ return result;
216
233
  }
217
234
  __name(compact, "compact");
218
235
  function countBy(array, keyFn) {
219
236
  if (!Array.isArray(array)) return {};
220
- return array.reduce((acc, item) => {
237
+ const result = {};
238
+ for (const item of array) {
221
239
  const key = String(keyFn(item));
222
- acc[key] = (acc[key] || 0) + 1;
223
- return acc;
224
- }, {});
240
+ result[key] = (result[key] ?? 0) + 1;
241
+ }
242
+ return result;
225
243
  }
226
244
  __name(countBy, "countBy");
245
+ function toggle(array, item) {
246
+ if (!Array.isArray(array)) return [
247
+ item
248
+ ];
249
+ const exists = array.includes(item);
250
+ if (exists) return array.filter((x) => x !== item);
251
+ return [
252
+ ...array,
253
+ item
254
+ ];
255
+ }
256
+ __name(toggle, "toggle");
257
+ function secureIndex(max) {
258
+ if (!Number.isInteger(max) || max <= 0) throw new RangeError("Max must be a positive integer");
259
+ const limit = 4294967295 - 4294967295 % max;
260
+ let rand;
261
+ do {
262
+ rand = randomBytes(4).readUInt32BE(0);
263
+ } while (rand >= limit);
264
+ return rand % max;
265
+ }
266
+ __name(secureIndex, "secureIndex");
267
+ var secureRandom = /* @__PURE__ */ __name((array) => {
268
+ if (!Array.isArray(array) || array.length === 0) return void 0;
269
+ const idx = secureIndex(array.length);
270
+ return array[idx];
271
+ }, "secureRandom");
272
+ function findLast(array, predicate) {
273
+ if (!Array.isArray(array)) return void 0;
274
+ for (let i = array.length - 1; i >= 0; i--) {
275
+ if (predicate(array[i], i, array)) return array[i];
276
+ }
277
+ return void 0;
278
+ }
279
+ __name(findLast, "findLast");
280
+ function findLastIndex(array, predicate) {
281
+ if (!Array.isArray(array)) return -1;
282
+ for (let i = array.length - 1; i >= 0; i--) {
283
+ if (predicate(array[i], i, array)) return i;
284
+ }
285
+ return -1;
286
+ }
287
+ __name(findLastIndex, "findLastIndex");
288
+ function chunkBy(array, predicate) {
289
+ if (!Array.isArray(array) || array.length === 0) return [];
290
+ const result = [];
291
+ let chunk2 = [];
292
+ for (let i = 0; i < array.length; i++) {
293
+ if (predicate(array[i], i, array) && chunk2.length) {
294
+ result.push(chunk2);
295
+ chunk2 = [];
296
+ }
297
+ chunk2.push(array[i]);
298
+ }
299
+ if (chunk2.length) result.push(chunk2);
300
+ return result;
301
+ }
302
+ __name(chunkBy, "chunkBy");
303
+ function remove(array, value) {
304
+ if (!Array.isArray(array)) return [];
305
+ return array.filter((item) => item !== value);
306
+ }
307
+ __name(remove, "remove");
308
+ function isSorted(array, direction = "asc", compareFn) {
309
+ if (!Array.isArray(array) || array.length <= 1) return true;
310
+ const cmp = compareFn || ((a, b) => a < b ? -1 : a > b ? 1 : 0);
311
+ for (let i = 1; i < array.length; i++) {
312
+ const res = cmp(array[i - 1], array[i]);
313
+ if (direction === "asc" && res > 0 || direction === "desc" && res < 0) return false;
314
+ }
315
+ return true;
316
+ }
317
+ __name(isSorted, "isSorted");
318
+ function headOfArr(array) {
319
+ return Array.isArray(array) && array.length > 0 ? array[0] : void 0;
320
+ }
321
+ __name(headOfArr, "headOfArr");
322
+ function lastOfArr(array) {
323
+ return Array.isArray(array) && array.length > 0 ? array.at(-1) : void 0;
324
+ }
325
+ __name(lastOfArr, "lastOfArr");
227
326
 
228
- export { chunk, compact, countBy, difference, flattenDeep, groupBy, intersect, mergeSort, partition, pluck, random, range, shuffle, take, takeWhile, unique, zip };
327
+ export { chunk, chunkBy, compact, countBy, difference, findLast, findLastIndex, flattenDeep, groupBy, headOfArr, intersect, isSorted, lastOfArr, mergeSort, partition, pluck, random, range, remove, secureIndex, secureRandom, shuffle, take, takeWhile, toggle, unique, zip };