@zairakai/js-utils 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -0
  3. package/dist/arrays.cjs +210 -0
  4. package/dist/arrays.d.cts +119 -0
  5. package/dist/arrays.d.ts +119 -0
  6. package/dist/arrays.js +32 -0
  7. package/dist/chunk-27YHP2CK.js +407 -0
  8. package/dist/chunk-3WNRYKPG.js +37 -0
  9. package/dist/chunk-42CHLXT7.js +214 -0
  10. package/dist/chunk-6F4PWJZI.js +0 -0
  11. package/dist/chunk-7SXRFZBB.js +173 -0
  12. package/dist/chunk-F6RSTW65.js +156 -0
  13. package/dist/chunk-G7ZJ23DW.js +253 -0
  14. package/dist/chunk-IPP7PA6H.js +136 -0
  15. package/dist/chunk-LDSWHSRX.js +96 -0
  16. package/dist/chunk-TY75OOIQ.js +700 -0
  17. package/dist/chunk-W6JEMFAF.js +54 -0
  18. package/dist/chunk-XEJLBAXE.js +164 -0
  19. package/dist/chunk-Z7G3SIQH.js +270 -0
  20. package/dist/chunk-ZJPKS2MQ.js +101 -0
  21. package/dist/collections.cjs +797 -0
  22. package/dist/collections.d.cts +353 -0
  23. package/dist/collections.d.ts +353 -0
  24. package/dist/collections.js +17 -0
  25. package/dist/datetime.cjs +80 -0
  26. package/dist/datetime.d.cts +75 -0
  27. package/dist/datetime.d.ts +75 -0
  28. package/dist/datetime.js +24 -0
  29. package/dist/equals.cjs +121 -0
  30. package/dist/equals.d.cts +24 -0
  31. package/dist/equals.d.ts +24 -0
  32. package/dist/equals.js +8 -0
  33. package/dist/formatters.cjs +201 -0
  34. package/dist/formatters.d.cts +180 -0
  35. package/dist/formatters.d.ts +180 -0
  36. package/dist/formatters.js +48 -0
  37. package/dist/index.cjs +2906 -0
  38. package/dist/index.d.cts +120 -0
  39. package/dist/index.d.ts +120 -0
  40. package/dist/index.js +348 -0
  41. package/dist/number.cjs +279 -0
  42. package/dist/number.d.cts +177 -0
  43. package/dist/number.d.ts +177 -0
  44. package/dist/number.js +10 -0
  45. package/dist/obj.cjs +427 -0
  46. package/dist/obj.d.cts +177 -0
  47. package/dist/obj.d.ts +177 -0
  48. package/dist/obj.js +12 -0
  49. package/dist/php-arrays.cjs +954 -0
  50. package/dist/php-arrays.d.cts +256 -0
  51. package/dist/php-arrays.d.ts +256 -0
  52. package/dist/php-arrays.js +70 -0
  53. package/dist/runtime.cjs +134 -0
  54. package/dist/runtime.d.cts +90 -0
  55. package/dist/runtime.d.ts +90 -0
  56. package/dist/runtime.js +24 -0
  57. package/dist/schemas.cjs +86 -0
  58. package/dist/schemas.d.cts +108 -0
  59. package/dist/schemas.d.ts +108 -0
  60. package/dist/schemas.js +22 -0
  61. package/dist/str.cjs +499 -0
  62. package/dist/str.d.cts +282 -0
  63. package/dist/str.d.ts +282 -0
  64. package/dist/str.js +11 -0
  65. package/dist/types.cjs +18 -0
  66. package/dist/types.d.cts +13 -0
  67. package/dist/types.d.ts +13 -0
  68. package/dist/types.js +1 -0
  69. package/dist/validator.cjs +251 -0
  70. package/dist/validator.d.cts +99 -0
  71. package/dist/validator.d.ts +99 -0
  72. package/dist/validator.js +11 -0
  73. package/dist/validators.cjs +217 -0
  74. package/dist/validators.d.cts +216 -0
  75. package/dist/validators.d.ts +216 -0
  76. package/dist/validators.js +64 -0
  77. package/package.json +180 -0
  78. package/src/arrays.ts +316 -0
  79. package/src/collections.ts +866 -0
  80. package/src/datetime.ts +103 -0
  81. package/src/equals.ts +134 -0
  82. package/src/formatters.ts +342 -0
  83. package/src/index.ts +36 -0
  84. package/src/number.ts +281 -0
  85. package/src/obj.ts +303 -0
  86. package/src/php-arrays.ts +445 -0
  87. package/src/pipe.ts +29 -0
  88. package/src/runtime.ts +194 -0
  89. package/src/schemas.ts +136 -0
  90. package/src/str.ts +438 -0
  91. package/src/types.ts +13 -0
  92. package/src/validator.ts +157 -0
  93. package/src/validators.ts +359 -0
@@ -0,0 +1,700 @@
1
+ import {
2
+ isEqual
3
+ } from "./chunk-LDSWHSRX.js";
4
+
5
+ // src/collections.ts
6
+ var EnhancedArray = class _EnhancedArray extends Array {
7
+ /**
8
+ * Create a new EnhancedArray instance.
9
+ *
10
+ * @param {...T[]} items The items to initialize the collection with
11
+ */
12
+ constructor(...items) {
13
+ super(...items);
14
+ Object.setPrototypeOf(this, _EnhancedArray.prototype);
15
+ this.originalItems = structuredClone(items);
16
+ }
17
+ /**
18
+ * Determine if the collection has been modified since initialization or last sync.
19
+ *
20
+ * @returns {boolean} True if modified, false otherwise
21
+ */
22
+ isDirty() {
23
+ return !isEqual(this.originalItems, Array.from(this));
24
+ }
25
+ /**
26
+ * Determine if the collection is clean (not modified).
27
+ *
28
+ * @returns {boolean} True if not modified, false otherwise
29
+ */
30
+ isClean() {
31
+ return !this.isDirty();
32
+ }
33
+ /**
34
+ * Sync the original items with current items to mark the collection as clean.
35
+ *
36
+ * @returns {this} The collection instance
37
+ */
38
+ syncOriginal() {
39
+ this.originalItems = structuredClone(Array.from(this));
40
+ return this;
41
+ }
42
+ /**
43
+ * Compare with another array or collection for equality.
44
+ *
45
+ * @param {T[] | EnhancedArray<T>} other The array or collection to compare with
46
+ * @returns {boolean} True if equivalent, false otherwise
47
+ */
48
+ isEquivalent(other) {
49
+ return isEqual(Array.from(this), Array.from(other));
50
+ }
51
+ /**
52
+ * Create an EnhancedArray from an iterable or array-like object.
53
+ *
54
+ * @param {Iterable<T> | ArrayLike<T>} items The items to convert
55
+ * @returns {EnhancedArray<T>} A new EnhancedArray instance
56
+ */
57
+ static from(items) {
58
+ return new _EnhancedArray(...Array.from(items));
59
+ }
60
+ /**
61
+ * Create an EnhancedArray from a variable number of arguments.
62
+ *
63
+ * @param {...T[]} items The items to include
64
+ * @returns {EnhancedArray<T>} A new EnhancedArray instance
65
+ */
66
+ static of(...items) {
67
+ return new _EnhancedArray(...items);
68
+ }
69
+ // Laravel Collection inspired methods
70
+ /**
71
+ * Create a new collection instance from the current items.
72
+ *
73
+ * @returns {EnhancedArray<T>} A new EnhancedArray instance
74
+ */
75
+ collect() {
76
+ return new _EnhancedArray(...this);
77
+ }
78
+ /**
79
+ * Pluck an array of values from an array of objects.
80
+ *
81
+ * @param {K} key The key to pluck
82
+ * @returns {EnhancedArray<T[K]>} A new collection of plucked values
83
+ */
84
+ pluck(key) {
85
+ return new _EnhancedArray(
86
+ ...this.map((item) => item && "object" === typeof item ? item[key] : void 0).filter(
87
+ (val) => val !== void 0
88
+ )
89
+ );
90
+ }
91
+ /**
92
+ * Group the collection's items by a given key or callback.
93
+ *
94
+ * @param {K | Callback<T, string | number>} key The key or callback to group by
95
+ * @returns {Record<string, EnhancedArray<T>>} A record of grouped collections
96
+ */
97
+ groupBy(key) {
98
+ const groups = {};
99
+ for (let i = 0; i < this.length; i++) {
100
+ const item = this[i];
101
+ const groupKey = "function" === typeof key ? String(key(item, i)) : String(item && "object" === typeof item ? item[key] : item);
102
+ if (!groups[groupKey]) {
103
+ groups[groupKey] = new _EnhancedArray();
104
+ }
105
+ groups[groupKey].push(item);
106
+ }
107
+ return groups;
108
+ }
109
+ /**
110
+ * Return only unique items from the collection.
111
+ *
112
+ * @param {K} [key] Optional key to determine uniqueness for objects
113
+ * @returns {EnhancedArray<T>} A new collection of unique items
114
+ */
115
+ unique(key) {
116
+ if (!key) {
117
+ return new _EnhancedArray(...new Set(this));
118
+ }
119
+ const seen = /* @__PURE__ */ new Set();
120
+ return new _EnhancedArray(
121
+ ...this.filter((item) => {
122
+ const value = item && "object" === typeof item ? item[key] : item;
123
+ if (seen.has(value)) {
124
+ return false;
125
+ }
126
+ seen.add(value);
127
+ return true;
128
+ })
129
+ );
130
+ }
131
+ /**
132
+ * Chunk the collection into smaller collections of a given size.
133
+ *
134
+ * @param {number} size The size of each chunk
135
+ * @returns {EnhancedArray<EnhancedArray<T>>} A collection of chunked collections
136
+ */
137
+ chunk(size) {
138
+ const chunks = new _EnhancedArray();
139
+ for (let i = 0; i < this.length; i += size) {
140
+ chunks.push(new _EnhancedArray(...this.slice(i, i + size)));
141
+ }
142
+ return chunks;
143
+ }
144
+ // Advanced manipulation methods
145
+ /**
146
+ * Flatten a multi-dimensional collection into a single level.
147
+ *
148
+ * @param {number} [depth=Infinity] The depth to flatten to
149
+ * @returns {EnhancedArray<unknown>} A new flattened collection
150
+ */
151
+ deepFlatten(depth = Infinity) {
152
+ const flatten = (arr, currentDepth) => {
153
+ const result = [];
154
+ for (const item of arr) {
155
+ if (Array.isArray(item) && 0 < currentDepth) {
156
+ result.push(...flatten(item, currentDepth - 1));
157
+ } else {
158
+ result.push(item);
159
+ }
160
+ }
161
+ return result;
162
+ };
163
+ return new _EnhancedArray(...flatten(this, depth));
164
+ }
165
+ /**
166
+ * Rotate the collection by a given number of positions.
167
+ *
168
+ * @param {number} [positions=1] The number of positions to rotate
169
+ * @returns {EnhancedArray<T>} A new rotated collection
170
+ */
171
+ rotate(positions = 1) {
172
+ if (0 === this.length) {
173
+ return new _EnhancedArray();
174
+ }
175
+ const count = this.length;
176
+ positions = positions % count;
177
+ if (0 === positions) {
178
+ return this.collect();
179
+ }
180
+ if (0 > positions) {
181
+ positions = count + positions;
182
+ }
183
+ return new _EnhancedArray(...this.slice(positions), ...this.slice(0, positions));
184
+ }
185
+ /**
186
+ * Chunk the collection as long as the given predicate returns true.
187
+ *
188
+ * @param {Predicate<T>} predicate The predicate to check
189
+ * @returns {EnhancedArray<EnhancedArray<T>>} A collection of chunked collections
190
+ */
191
+ chunkWhile(predicate) {
192
+ const chunks = new _EnhancedArray();
193
+ let currentChunk = new _EnhancedArray();
194
+ for (let i = 0; i < this.length; i++) {
195
+ const item = this[i];
196
+ if (0 < currentChunk.length && !predicate(item, i)) {
197
+ chunks.push(currentChunk);
198
+ currentChunk = new _EnhancedArray();
199
+ }
200
+ currentChunk.push(item);
201
+ }
202
+ if (0 < currentChunk.length) {
203
+ chunks.push(currentChunk);
204
+ }
205
+ return chunks;
206
+ }
207
+ /**
208
+ * Transpose the collection (swap rows and columns).
209
+ *
210
+ * @returns {EnhancedArray<EnhancedArray<unknown>>} A new transposed collection
211
+ */
212
+ transpose() {
213
+ if (0 === this.length) {
214
+ return new _EnhancedArray();
215
+ }
216
+ const maxLength = Math.max(...this.map((row) => Array.isArray(row) ? row.length : 1));
217
+ const result = new _EnhancedArray();
218
+ for (let i = 0; i < maxLength; i++) {
219
+ const column = new _EnhancedArray(
220
+ ...this.map((row) => {
221
+ if (Array.isArray(row)) {
222
+ return row[i] ?? null;
223
+ }
224
+ return 0 === i ? row : null;
225
+ })
226
+ );
227
+ result.push(column);
228
+ }
229
+ return result;
230
+ }
231
+ // Validation methods
232
+ /**
233
+ * Check if the collection is sorted.
234
+ *
235
+ * @param {Function} [compareFn] Optional comparison function
236
+ * @returns {boolean} True if sorted, false otherwise
237
+ */
238
+ isSorted(compareFn) {
239
+ if (1 >= this.length) {
240
+ return true;
241
+ }
242
+ for (let i = 1; i < this.length; i++) {
243
+ const prev = this[i - 1];
244
+ const current = this[i];
245
+ if (compareFn) {
246
+ if (0 < compareFn(prev, current)) {
247
+ return false;
248
+ }
249
+ } else {
250
+ if (prev > current) {
251
+ return false;
252
+ }
253
+ }
254
+ }
255
+ return true;
256
+ }
257
+ /**
258
+ * Check if the collection contains duplicate items.
259
+ *
260
+ * @param {K} [key] Optional key to check for uniqueness in objects
261
+ * @returns {boolean} True if duplicates found, false otherwise
262
+ */
263
+ hasDuplicates(key) {
264
+ if (key) {
265
+ const seen = /* @__PURE__ */ new Set();
266
+ for (const item of this) {
267
+ const value = item && "object" === typeof item ? item[key] : item;
268
+ if (seen.has(value)) {
269
+ return true;
270
+ }
271
+ seen.add(value);
272
+ }
273
+ return false;
274
+ }
275
+ return this.length !== new Set(this).size;
276
+ }
277
+ // Statistical methods
278
+ /**
279
+ * Calculate the median value of the collection.
280
+ *
281
+ * @param {Callback<T, number>} [accessor] Optional accessor for non-numeric items
282
+ * @returns {number | null} The median value or null if collection is empty
283
+ */
284
+ median(accessor) {
285
+ if (0 === this.length) {
286
+ return null;
287
+ }
288
+ const values = accessor ? this.map(accessor) : this;
289
+ const sorted = [...values].sort((a, b) => a - b);
290
+ const count = sorted.length;
291
+ if (0 === count % 2) {
292
+ return (sorted[count / 2 - 1] + sorted[count / 2]) / 2;
293
+ }
294
+ return sorted[Math.floor(count / 2)];
295
+ }
296
+ /**
297
+ * Calculate the mode (most frequent values) of the collection.
298
+ *
299
+ * @param {Callback<T, unknown>} [accessor] Optional accessor for the values
300
+ * @returns {EnhancedArray<unknown>} A collection of mode values
301
+ */
302
+ mode(accessor) {
303
+ if (0 === this.length) {
304
+ return new _EnhancedArray();
305
+ }
306
+ const frequencies = this.frequencies(accessor);
307
+ const maxFrequency = Math.max(...Object.values(frequencies));
308
+ return new _EnhancedArray(...Object.keys(frequencies).filter((key) => frequencies[key] === maxFrequency));
309
+ }
310
+ /**
311
+ * Calculate the standard deviation of the collection.
312
+ *
313
+ * @param {Callback<T, number>} [accessor] Optional accessor for non-numeric items
314
+ * @returns {number} The standard deviation
315
+ */
316
+ standardDeviation(accessor) {
317
+ if (0 === this.length) {
318
+ return 0;
319
+ }
320
+ const values = accessor ? this.map(accessor) : this;
321
+ const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
322
+ const sumSquaredDifferences = values.reduce(
323
+ (sum, val) => sum + Math.pow(val - mean, 2),
324
+ 0
325
+ );
326
+ return Math.sqrt(sumSquaredDifferences / values.length);
327
+ }
328
+ /**
329
+ * Calculate a specific percentile of the collection.
330
+ *
331
+ * @param {number} percentile The percentile to calculate (0-100)
332
+ * @param {Callback<T, number>} [accessor] Optional accessor for non-numeric items
333
+ * @returns {number | null} The percentile value or null if collection is empty
334
+ */
335
+ percentile(percentile, accessor) {
336
+ if (0 === this.length) {
337
+ return null;
338
+ }
339
+ const values = accessor ? this.map(accessor) : this;
340
+ const sorted = [...values].sort((a, b) => a - b);
341
+ const index = percentile / 100 * (sorted.length - 1);
342
+ const lower = Math.floor(index);
343
+ const upper = Math.ceil(index);
344
+ if (lower === upper) {
345
+ return sorted[lower];
346
+ }
347
+ const weight = index - lower;
348
+ return sorted[lower] * (1 - weight) + sorted[upper] * weight;
349
+ }
350
+ /**
351
+ * Calculate the frequencies of items in the collection.
352
+ *
353
+ * @param {Callback<T, unknown>} [accessor] Optional accessor for the values
354
+ * @returns {Record<string, number>} A record of values and their frequencies
355
+ */
356
+ frequencies(accessor) {
357
+ const frequencies = {};
358
+ for (let i = 0; i < this.length; i++) {
359
+ const item = this[i];
360
+ const key = accessor ? String(accessor(item, i)) : String(item);
361
+ frequencies[key] = (frequencies[key] || 0) + 1;
362
+ }
363
+ return frequencies;
364
+ }
365
+ // Advanced operations
366
+ /**
367
+ * Calculate the Cartesian product of the collection and other arrays.
368
+ *
369
+ * @param {...U[][]} arrays The arrays to calculate the product with
370
+ * @returns {EnhancedArray<[T, ...U[]]>} A collection of product combinations
371
+ */
372
+ cartesian(...arrays) {
373
+ const result = new _EnhancedArray();
374
+ const allArrays = [this, ...arrays];
375
+ function* cartesianProduct(arrays2, index = 0, current = []) {
376
+ if (index === arrays2.length) {
377
+ yield [...current];
378
+ return;
379
+ }
380
+ for (const item of arrays2[index]) {
381
+ yield* cartesianProduct(arrays2, index + 1, [...current, item]);
382
+ }
383
+ }
384
+ for (const combination of cartesianProduct(allArrays)) {
385
+ result.push(combination);
386
+ }
387
+ return result;
388
+ }
389
+ /**
390
+ * Interleave the collection with other arrays.
391
+ *
392
+ * @param {...U[][]} arrays The arrays to interleave with
393
+ * @returns {EnhancedArray<T | U>} A new interleaved collection
394
+ */
395
+ interleave(...arrays) {
396
+ const result = new _EnhancedArray();
397
+ const allArrays = [this, ...arrays];
398
+ const maxLength = Math.max(...allArrays.map((arr) => arr.length));
399
+ for (let i = 0; i < maxLength; i++) {
400
+ for (const array of allArrays) {
401
+ if (i < array.length) {
402
+ result.push(array[i]);
403
+ }
404
+ }
405
+ }
406
+ return result;
407
+ }
408
+ /**
409
+ * Get a sliding window of items from the collection.
410
+ *
411
+ * @param {number} [size=2] The size of the window
412
+ * @param {number} [step=1] The step between windows
413
+ * @returns {EnhancedArray<EnhancedArray<T>>} A collection of window collections
414
+ */
415
+ sliding(size = 2, step = 1) {
416
+ if (0 >= size || 0 >= step) {
417
+ return new _EnhancedArray();
418
+ }
419
+ const windows = new _EnhancedArray();
420
+ for (let i = 0; i <= this.length - size; i += step) {
421
+ windows.push(new _EnhancedArray(...this.slice(i, i + size)));
422
+ }
423
+ return windows;
424
+ }
425
+ // Navigation macros
426
+ /**
427
+ * Get the item at the given index.
428
+ *
429
+ * @param {number} index The index to retrieve
430
+ * @returns {T | undefined} The item at the index or undefined
431
+ */
432
+ at(index) {
433
+ return this[index];
434
+ }
435
+ /**
436
+ * Get the item before the given item.
437
+ *
438
+ * @param {T} item The item to search for
439
+ * @returns {T | undefined} The item before or undefined
440
+ */
441
+ before(item) {
442
+ const index = this.indexOf(item);
443
+ return 0 < index ? this[index - 1] : void 0;
444
+ }
445
+ /**
446
+ * Get the item after the given item.
447
+ *
448
+ * @param {T} item The item to search for
449
+ * @returns {T | undefined} The item after or undefined
450
+ */
451
+ after(item) {
452
+ const index = this.indexOf(item);
453
+ return 0 <= index && index < this.length - 1 ? this[index + 1] : void 0;
454
+ }
455
+ // Transformation macros
456
+ /**
457
+ * Chunk the collection by a given key or callback when its value changes.
458
+ *
459
+ * @param {K | Callback<T, unknown>} key The key or callback to chunk by
460
+ * @returns {EnhancedArray<EnhancedArray<T>>} A collection of chunked collections
461
+ */
462
+ chunkBy(key) {
463
+ if (0 === this.length) {
464
+ return new _EnhancedArray();
465
+ }
466
+ const chunks = new _EnhancedArray();
467
+ let currentChunk = new _EnhancedArray();
468
+ let lastValue = null;
469
+ for (let i = 0; i < this.length; i++) {
470
+ const item = this[i];
471
+ const currentValue = "function" === typeof key ? key(item, i) : item && "object" === typeof item ? item[key] : item;
472
+ if (0 === i || currentValue === lastValue) {
473
+ currentChunk.push(item);
474
+ } else {
475
+ chunks.push(currentChunk);
476
+ currentChunk = new _EnhancedArray(item);
477
+ }
478
+ lastValue = currentValue;
479
+ }
480
+ if (0 < currentChunk.length) {
481
+ chunks.push(currentChunk);
482
+ }
483
+ return chunks;
484
+ }
485
+ /**
486
+ * Map and filter the collection simultaneously.
487
+ * Items for which the callback returns null or undefined are removed.
488
+ *
489
+ * @param {Function} callback The callback to map items
490
+ * @returns {EnhancedArray<U>} A new mapped and filtered collection
491
+ */
492
+ filterMap(callback) {
493
+ const result = new _EnhancedArray();
494
+ for (let i = 0; i < this.length; i++) {
495
+ const mapped = callback(this[i], i);
496
+ if (null !== mapped && mapped !== void 0) {
497
+ result.push(mapped);
498
+ }
499
+ }
500
+ return result;
501
+ }
502
+ /**
503
+ * Extract a subset of properties from each item in the collection.
504
+ *
505
+ * @param {K[]} keys The keys to extract
506
+ * @returns {EnhancedArray<Partial<T>>} A new collection of partial items
507
+ */
508
+ extract(keys) {
509
+ return new _EnhancedArray(
510
+ ...this.map((item) => {
511
+ if (!item || "object" !== typeof item) {
512
+ return {};
513
+ }
514
+ const extracted = {};
515
+ for (const key of keys) {
516
+ if (key in item) {
517
+ extracted[key] = item[key];
518
+ }
519
+ }
520
+ return extracted;
521
+ })
522
+ );
523
+ }
524
+ // Utility macros
525
+ /**
526
+ * Get the first item or push a default item if the collection is empty.
527
+ *
528
+ * @param {T} item The default item to push if empty
529
+ * @returns {T} The first item or the pushed item
530
+ */
531
+ firstOrPush(item) {
532
+ if (0 === this.length) {
533
+ this.push(item);
534
+ return item;
535
+ }
536
+ return this[0];
537
+ }
538
+ /**
539
+ * Get every n-th item from the collection.
540
+ *
541
+ * @param {number} n The step size
542
+ * @returns {EnhancedArray<T>} A new collection of every n-th item
543
+ */
544
+ getNth(n) {
545
+ const result = new _EnhancedArray();
546
+ for (let i = n - 1; i < this.length; i += n) {
547
+ result.push(this[i]);
548
+ }
549
+ return result;
550
+ }
551
+ /**
552
+ * Get a random item from the collection based on weights.
553
+ *
554
+ * @param {number[]} [weights] Optional weights for each item
555
+ * @returns {T | undefined} A random item or undefined if collection is empty
556
+ */
557
+ weightedRandom(weights) {
558
+ if (0 === this.length) {
559
+ return void 0;
560
+ }
561
+ const effectiveWeights = weights ?? new Array(this.length).fill(1);
562
+ if (effectiveWeights.length !== this.length) {
563
+ throw new Error("Weights array must have same length as collection");
564
+ }
565
+ const totalWeight = effectiveWeights.reduce((sum, weight) => sum + weight, 0);
566
+ const random = Math.random() * totalWeight;
567
+ let currentWeight = 0;
568
+ for (let i = 0; i < this.length; i++) {
569
+ currentWeight += effectiveWeights[i];
570
+ if (random <= currentWeight) {
571
+ return this[i];
572
+ }
573
+ }
574
+ return this[this.length - 1];
575
+ }
576
+ /**
577
+ * Paginate the collection items.
578
+ *
579
+ * @param {number} perPage Items per page
580
+ * @param {number} [page=1] Current page number
581
+ * @returns {Object} Pagination results
582
+ */
583
+ paginate(perPage, page = 1) {
584
+ const total = this.length;
585
+ const lastPage = Math.ceil(total / perPage);
586
+ const currentPage = Math.max(1, Math.min(page, lastPage));
587
+ const from = (currentPage - 1) * perPage;
588
+ const to = Math.min(from + perPage, total);
589
+ return {
590
+ data: new _EnhancedArray(...this.slice(from, to)),
591
+ total,
592
+ perPage,
593
+ currentPage,
594
+ lastPage,
595
+ from: from + 1,
596
+ to
597
+ };
598
+ }
599
+ /**
600
+ * Recursively convert all nested arrays to EnhancedArray instances.
601
+ *
602
+ * @returns {EnhancedArray<unknown>} A new collection with recursive EnhancedArrays
603
+ */
604
+ recursive() {
605
+ const convert = (item) => {
606
+ if (Array.isArray(item)) {
607
+ return new _EnhancedArray(...item.map(convert));
608
+ }
609
+ if (item && "object" === typeof item && item.constructor === Object) {
610
+ const converted = {};
611
+ for (const [key, value] of Object.entries(item)) {
612
+ converted[key] = convert(value);
613
+ }
614
+ return converted;
615
+ }
616
+ return item;
617
+ };
618
+ return new _EnhancedArray(...this.map(convert));
619
+ }
620
+ };
621
+ var objectToMap = (obj) => {
622
+ return new Map(Object.entries(obj));
623
+ };
624
+ var mapToObject = (map) => {
625
+ return Object.fromEntries(map);
626
+ };
627
+ var EnhancedMap = class _EnhancedMap extends Map {
628
+ /**
629
+ * Create an EnhancedMap from a plain object.
630
+ *
631
+ * @param {Record<string, V>} obj The object to convert
632
+ * @returns {EnhancedMap<string, V>} A new EnhancedMap instance
633
+ */
634
+ static fromObject(obj) {
635
+ return new _EnhancedMap(Object.entries(obj));
636
+ }
637
+ /**
638
+ * Pluck a property from each value in the map.
639
+ *
640
+ * @param {P} key The key to pluck
641
+ * @returns {EnhancedArray<V[P]>} A new collection of plucked values
642
+ */
643
+ pluck(key) {
644
+ return new EnhancedArray(
645
+ ...Array.from(this.values()).map((value) => value && "object" === typeof value ? value[key] : void 0).filter((val) => val !== void 0)
646
+ );
647
+ }
648
+ /**
649
+ * Group the map's entries by a given accessor.
650
+ *
651
+ * @param {Function} accessor The accessor to group by
652
+ * @returns {Record<string, EnhancedArray<[K, V]>>} A record of grouped entries
653
+ */
654
+ groupBy(accessor) {
655
+ const groups = {};
656
+ for (const [key, value] of this) {
657
+ const groupKey = String(accessor(value, key));
658
+ if (!groups[groupKey]) {
659
+ groups[groupKey] = new EnhancedArray();
660
+ }
661
+ groups[groupKey].push([key, value]);
662
+ }
663
+ return groups;
664
+ }
665
+ /**
666
+ * Convert the map to an array of entries.
667
+ *
668
+ * @returns {EnhancedArray<[K, V]>} A collection of entries
669
+ */
670
+ toArray() {
671
+ return new EnhancedArray(...this.entries());
672
+ }
673
+ /**
674
+ * Convert the map to a plain object.
675
+ *
676
+ * @returns {Record<string, V>} A plain object representation of the map
677
+ */
678
+ toObject() {
679
+ const obj = {};
680
+ for (const [key, value] of this) {
681
+ obj[String(key)] = value;
682
+ }
683
+ return obj;
684
+ }
685
+ };
686
+ var collect = (items) => {
687
+ return new EnhancedArray(...items);
688
+ };
689
+ var collectMap = (entries) => {
690
+ return new EnhancedMap(entries);
691
+ };
692
+
693
+ export {
694
+ EnhancedArray,
695
+ objectToMap,
696
+ mapToObject,
697
+ EnhancedMap,
698
+ collect,
699
+ collectMap
700
+ };