@stacksjs/collections 0.65.0 → 0.68.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.
package/src/index.ts DELETED
@@ -1,2024 +0,0 @@
1
- /* eslint-disable ts/no-unsafe-function-type,eqeqeq,ts/no-use-before-define,unused-imports/no-unused-vars,no-prototype-builtins, no-console */
2
- import process from 'node:process'
3
- import { clone, deleteKeys, isArray, isFunction, isObject, nestedValue, values } from './helpers/'
4
-
5
- type IsArray<T> = T extends any[] ? true : false
6
- type CollectionAll<T> = IsArray<T> extends true ? T : { [K in keyof T]: T[K] }
7
-
8
- export function collect<T extends object | string | number | boolean>(items: T): Collection<T> {
9
- return new Collection(items)
10
- }
11
-
12
- export class Collection<T> {
13
- protected items: T[] | Record<string, T>
14
-
15
- constructor(items: T[] | Record<string | number | symbol, T> = []) {
16
- this.items = items
17
- }
18
-
19
- [Symbol.iterator] = SymbolIterator
20
-
21
- toJSON(): T[] {
22
- return this.items as T[]
23
- }
24
-
25
- all(): CollectionAll<T> {
26
- return this.items as CollectionAll<T>
27
- }
28
-
29
- average(key?: string | ((item: T) => number)): number {
30
- if (key === undefined) {
31
- return this.sum() / Number(this.items.length)
32
- }
33
-
34
- if (isFunction(key)) {
35
- return (
36
- Number(new (this.constructor as new (items: typeof this.items) => typeof this)(this.items).sum(key))
37
- / Number(this.items.length)
38
- )
39
- }
40
-
41
- return (
42
- Number(new (this.constructor as new (items: typeof this.items) => typeof this)(this.items).pluck(key).sum())
43
- / Number(this.items.length)
44
- )
45
- }
46
-
47
- avg: typeof this.average = this.average
48
-
49
- chunk(size: number): Collection<T[]> {
50
- const chunks = []
51
- const items = Array.isArray(this.items) ? this.items : Object.values(this.items)
52
-
53
- for (let i = 0; i < items.length; i += size) {
54
- chunks.push(items.slice(i, i + size))
55
- }
56
-
57
- return new Collection(chunks)
58
- }
59
-
60
- collapse(): Collection<T extends any[] ? T[number] : T> {
61
- return new (this.constructor as any)(([] as T[]).concat(...(this.items as any[])))
62
- }
63
-
64
- combine(values: any): Collection<T> {
65
- if (typeof values === 'string') {
66
- values = [values]
67
- }
68
-
69
- if (!Array.isArray(values)) {
70
- throw new TypeError('The values must be an array or a string')
71
- }
72
-
73
- const collection = {}
74
- const keys = Array.isArray(this.items) ? this.items : Object.keys(this.items)
75
-
76
- keys.forEach((key, index) => {
77
- if (values[index] !== undefined) {
78
- collection[key] = values[index]
79
- }
80
- })
81
-
82
- return new Collection(collection)
83
- }
84
-
85
- concat(collectionOrArrayOrObject: Collection<T> | T[] | object): Collection<T> {
86
- let list = collectionOrArrayOrObject
87
-
88
- if (collectionOrArrayOrObject instanceof this.constructor) {
89
- list = collectionOrArrayOrObject.all()
90
- }
91
- else if (typeof collectionOrArrayOrObject === 'object') {
92
- list = []
93
- Object.keys(collectionOrArrayOrObject).forEach((property) => {
94
- list.push(collectionOrArrayOrObject[property])
95
- })
96
- }
97
-
98
- const collection = clone(this.items)
99
-
100
- list.forEach((item) => {
101
- if (typeof item === 'object') {
102
- Object.keys(item).forEach(key => collection.push(item[key]))
103
- }
104
- else {
105
- collection.push(item)
106
- }
107
- })
108
-
109
- return new this.constructor(collection)
110
- }
111
-
112
- contains(key: T extends (infer U)[] ? U : T | string | ((item: T, index: number) => boolean), value?: any): boolean {
113
- if (typeof key === 'function') {
114
- return this.items.some(key as (item: T, index: number) => boolean)
115
- }
116
-
117
- if (Array.isArray(this.items)) {
118
- return (this.items as any[]).includes(key as any)
119
- }
120
-
121
- if (value !== undefined) {
122
- if (Array.isArray(this.items)) {
123
- return this.items.some(item => item[key as keyof T] !== undefined && item[key as keyof T] === value)
124
- }
125
-
126
- return (
127
- (key as string | number | symbol) in this.items
128
- && (this.items as Record<keyof T, any>)[key as keyof T] === value
129
- )
130
- }
131
-
132
- if (Array.isArray(this.items)) {
133
- return this.items.includes(key as T extends (infer U)[] ? U : never)
134
- }
135
-
136
- return Object.values(this.items).includes(key as T extends object ? T[keyof T] : never)
137
- }
138
-
139
- containsOneItem(): boolean {
140
- if (typeof this.items === 'string') {
141
- return true
142
- }
143
-
144
- return Object.keys(this.items).length === 1
145
- }
146
-
147
- count(predicate?: (item: T) => boolean): number {
148
- if (predicate) {
149
- return this.filter(predicate).count()
150
- }
151
-
152
- return Object.keys(this.items).length
153
- }
154
-
155
- countBy(callback?: (item: T) => string | number): Collection<number> {
156
- const counts: Record<string | number, number> = {}
157
- this.each((item) => {
158
- const key = callback ? callback(item) : item
159
- counts[key] = (counts[key] || 0) + 1
160
- })
161
- return new Collection(counts)
162
- }
163
-
164
- crossJoin(...values: T[]): Collection<T> {
165
- function join(collection: T[], constructor: new (items: T[]) => Collection<T>, args: T[]): T[] {
166
- let current = args[0]
167
-
168
- if (current instanceof Collection) {
169
- current = current.all()
170
- }
171
-
172
- const rest = args.slice(1)
173
- const last = !rest.length
174
- let result = []
175
-
176
- for (let i = 0; i < current.length; i += 1) {
177
- const collectionCopy = collection.slice()
178
- collectionCopy.push(current[i])
179
-
180
- if (last) {
181
- result.push(collectionCopy)
182
- }
183
- else {
184
- result = result.concat(join(collectionCopy, constructor, rest))
185
- }
186
- }
187
-
188
- return result
189
- }
190
-
191
- return new this.constructor(join([], this.constructor, [].concat([this.items], values)))
192
- }
193
-
194
- dd(): void {
195
- console.log(JSON.stringify(this.all(), null, 2))
196
- process.exit()
197
- }
198
-
199
- diff(values: Collection<T> | T[]): Collection<T> {
200
- let valuesToDiff
201
-
202
- if (values instanceof this.constructor) {
203
- valuesToDiff = values.all()
204
- }
205
- else {
206
- valuesToDiff = values
207
- }
208
-
209
- const collection = this.items.filter(item => !valuesToDiff.includes(item))
210
-
211
- return new this.constructor(collection)
212
- }
213
-
214
- diffAssoc(values: Collection<T> | T[]): Collection<T> {
215
- let diffValues = values
216
-
217
- if (values instanceof this.constructor) {
218
- diffValues = values.all()
219
- }
220
-
221
- const collection = {}
222
-
223
- Object.keys(this.items).forEach((key) => {
224
- if (diffValues[key] === undefined || diffValues[key] !== this.items[key]) {
225
- collection[key] = this.items[key]
226
- }
227
- })
228
-
229
- return new this.constructor(collection)
230
- }
231
-
232
- diffKeys(object: Collection<T> | T[]): Collection<T> {
233
- let objectToDiff
234
-
235
- if (object instanceof this.constructor) {
236
- objectToDiff = object.all()
237
- }
238
- else {
239
- objectToDiff = object
240
- }
241
-
242
- const objectKeys = Object.keys(objectToDiff)
243
-
244
- const remainingKeys = Object.keys(this.items).filter(item => !objectKeys.includes(item))
245
-
246
- return new this.constructor(this.items).only(remainingKeys)
247
- }
248
-
249
- diffUsing(array: any[] | null, callback: (a: any, b: any) => number): Collection<T> {
250
- console.log('Original collection:', this.items)
251
-
252
- console.log('Array to compare:', array)
253
-
254
- if (array === null) {
255
- // If the input array is null, return a copy of the original collection
256
- return new Collection(this.items)
257
- }
258
-
259
- const collection = this.items.filter((item) => {
260
- const index = array.findIndex((otherItem) => {
261
- return callback(item, otherItem) === 0
262
- })
263
-
264
- return index === -1
265
- })
266
-
267
- return new Collection(collection)
268
- }
269
-
270
- doesntContain(key: string | number | symbol | ((item: T, index: number) => boolean), value?: any): boolean {
271
- console.log('doesntContain called with:', { key, value })
272
-
273
- if (typeof key === 'function') {
274
- console.log('Function branch')
275
- return !this.contains(key)
276
- }
277
-
278
- if (value !== undefined) {
279
- console.log('Key-value pair branch')
280
- return !this.contains((item) => {
281
- console.log('Comparing:', item[key], 'with', value)
282
- return item[key] === value
283
- })
284
- }
285
-
286
- console.log('Single value branch')
287
- return !this.contains(key)
288
- }
289
-
290
- dump(): this {
291
- console.log(this.items)
292
- return this
293
- }
294
-
295
- duplicates(): Collection<T> {
296
- const occuredValues = []
297
- const duplicateValues = {}
298
-
299
- const stringifiedValue = (value: any): string => {
300
- if (Array.isArray(value) || typeof value === 'object') {
301
- return JSON.stringify(value)
302
- }
303
-
304
- return value
305
- }
306
-
307
- if (Array.isArray(this.items)) {
308
- this.items.forEach((value, index) => {
309
- const valueAsString = stringifiedValue(value)
310
-
311
- if (!occuredValues.includes(valueAsString)) {
312
- occuredValues.push(valueAsString)
313
- }
314
- else {
315
- duplicateValues[index] = value
316
- }
317
- })
318
- }
319
- else if (typeof this.items === 'object') {
320
- Object.keys(this.items).forEach((key) => {
321
- const valueAsString = stringifiedValue(this.items[key])
322
-
323
- if (!occuredValues.includes(valueAsString)) {
324
- occuredValues.push(valueAsString)
325
- }
326
- else {
327
- duplicateValues[key] = this.items[key]
328
- }
329
- })
330
- }
331
-
332
- return new this.constructor(duplicateValues)
333
- }
334
-
335
- each(fn: (item: T, index: number | string, items: T[]) => boolean | void): Collection<T> {
336
- let stop = false
337
-
338
- if (Array.isArray(this.items)) {
339
- const { length } = this.items
340
-
341
- for (let index = 0; index < length && !stop; index += 1) {
342
- stop = fn(this.items[index], index, this.items) === false
343
- }
344
- }
345
- else {
346
- const keys = Object.keys(this.items)
347
- const { length } = keys
348
-
349
- for (let index = 0; index < length && !stop; index += 1) {
350
- const key = keys[index]
351
-
352
- stop = fn(this.items[key], key, this.items) === false
353
- }
354
- }
355
-
356
- return this
357
- }
358
-
359
- eachSpread(fn: (...args: any[]) => void): Collection<T> {
360
- this.each((values: any, key: any) => {
361
- fn(...values, key)
362
- })
363
-
364
- return this
365
- }
366
-
367
- every(fn: (value: T, key: string | number, collection: T[]) => boolean): boolean {
368
- const items = values(this.items)
369
-
370
- return items.every(fn)
371
- }
372
-
373
- except(keys: string | string[]): Collection<T> {
374
- const result = { ...this.items }
375
- const keysArray = Array.isArray(keys) ? keys : [keys]
376
- keysArray.forEach(key => delete result[key])
377
- return new Collection(result)
378
- }
379
-
380
- filter(callback?: (item: T, index: number) => boolean): Collection<T> {
381
- console.log('Filter method called with callback:', callback)
382
-
383
- console.log('Current items:', this.items)
384
-
385
- if (typeof callback !== 'function') {
386
- console.log('No callback provided, removing falsy values')
387
- const filteredItems = this.items.filter((item) => {
388
- console.log('Filtering item:', item)
389
- return Boolean(item)
390
- })
391
-
392
- console.log('Filtered items:', filteredItems)
393
- return new Collection(filteredItems)
394
- }
395
-
396
- const filteredItems = this.items.filter((item, index) => {
397
- console.log('Filtering item:', item, 'at index:', index)
398
- return callback(item, index)
399
- })
400
-
401
- console.log('Filtered items:', filteredItems)
402
- return new Collection(filteredItems)
403
- }
404
-
405
- first(
406
- fn?: (value: T, key: string | number, collection?: T[]) => boolean,
407
- defaultValue?: T | (() => T),
408
- ): T | undefined {
409
- if (isFunction(fn)) {
410
- const keys = Object.keys(this.items)
411
-
412
- for (let i = 0; i < keys.length; i += 1) {
413
- const key = keys[i]
414
- const item = this.items[key]
415
-
416
- if (fn(item, key)) {
417
- return item
418
- }
419
- }
420
-
421
- if (isFunction(defaultValue)) {
422
- return defaultValue()
423
- }
424
-
425
- return defaultValue
426
- }
427
-
428
- if ((Array.isArray(this.items) && this.items.length) || Object.keys(this.items).length) {
429
- if (Array.isArray(this.items)) {
430
- return this.items[0]
431
- }
432
-
433
- const firstKey = Object.keys(this.items)[0]
434
-
435
- return this.items[firstKey]
436
- }
437
-
438
- if (isFunction(defaultValue)) {
439
- return defaultValue()
440
- }
441
-
442
- return defaultValue
443
- }
444
-
445
- firstOrFail(callback?: (item: T) => boolean): T {
446
- const found = this.items.find(callback || (() => true))
447
- if (found === undefined) {
448
- throw new Error('Item not found.')
449
- }
450
- return found
451
- }
452
-
453
- firstWhere(key: string, operator: string, value: any): T | null {
454
- return this.where(key, operator, value).first() || null
455
- }
456
-
457
- flatMap(fn: (item: T, key: string | number) => any): Collection<any> {
458
- return this.map(fn).collapse()
459
- }
460
-
461
- flatten(depth: number = Number.POSITIVE_INFINITY): Collection<T> {
462
- const flatten = (item: any, d: number): any[] => {
463
- if (!Array.isArray(item) && typeof item !== 'object') {
464
- return [item]
465
- }
466
- return d > 0
467
- ? Object.values(item).reduce(
468
- (acc, val) => acc.concat(Array.isArray(val) || typeof val === 'object' ? flatten(val, d - 1) : val),
469
- [],
470
- )
471
- : Array.isArray(item)
472
- ? [...item]
473
- : [item]
474
- }
475
-
476
- return new Collection(flatten(this.items, depth))
477
- }
478
-
479
- flip(): Collection<T> {
480
- const flipped = {}
481
- if (Array.isArray(this.items)) {
482
- this.items.forEach((value, index) => {
483
- flipped[value] = index
484
- })
485
- }
486
- else {
487
- Object.entries(this.items).forEach(([key, value]) => {
488
- flipped[value] = key
489
- })
490
- }
491
- return new this.constructor(flipped)
492
- }
493
-
494
- forPage(page: number, chunk: number): Collection<T> {
495
- let collection = {}
496
-
497
- if (Array.isArray(this.items)) {
498
- collection = this.items.slice(page * chunk - chunk, page * chunk)
499
- }
500
- else {
501
- Object.keys(this.items)
502
- .slice(page * chunk - chunk, page * chunk)
503
- .forEach((key) => {
504
- collection[key] = this.items[key]
505
- })
506
- }
507
-
508
- return new this.constructor(collection)
509
- }
510
-
511
- forget(key: string): Collection<T> {
512
- if (Array.isArray(this.items)) {
513
- this.items = this.items.filter((item, index) => index !== Number.parseInt(key, 10))
514
- }
515
- else if (typeof this.items === 'object' && this.items !== null) {
516
- delete this.items[key]
517
- }
518
-
519
- return this
520
- }
521
-
522
- get(key: string | number, defaultValue: T | null = null): T | null {
523
- if (Array.isArray(this.items)) {
524
- return this.items[key as number] ?? defaultValue
525
- }
526
-
527
- return (this.items as Record<string, T>)[key as string] ?? defaultValue
528
- }
529
-
530
- groupBy(fn: ((item: T) => any) | string): Collection<Collection<T>> {
531
- const groups = {}
532
- this.each((item, key) => {
533
- const groupKey = typeof fn === 'function' ? fn(item) : item[fn]
534
- if (!(groupKey in groups)) {
535
- groups[groupKey] = new Collection()
536
- }
537
- groups[groupKey].push(item)
538
- })
539
-
540
- return new Collection(groups)
541
- }
542
-
543
- has(key: string | number): boolean {
544
- if (Array.isArray(this.items)) {
545
- return key in this.items
546
- }
547
-
548
- return key in (this.items as Record<string, T>)
549
- }
550
-
551
- implode(key: string, glue?: string): string {
552
- if (glue === undefined) {
553
- return this.items.join(key)
554
- }
555
-
556
- return new this.constructor(this.items).pluck(key).all().join(glue)
557
- }
558
-
559
- includes(key: T | T[keyof T]): boolean {
560
- if (Array.isArray(this.items)) {
561
- return this.items.includes(key as T)
562
- }
563
-
564
- return Object.values(this.items).includes(key)
565
- }
566
-
567
- intersect(values: Collection<T> | T[]): Collection<T> {
568
- let intersectValues = values
569
-
570
- if (values instanceof this.constructor) {
571
- intersectValues = values.all()
572
- }
573
-
574
- const collection = this.items.filter(item => intersectValues.includes(item))
575
-
576
- return new this.constructor(collection)
577
- }
578
-
579
- intersectByKeys(values: Collection<T> | T[]): Collection<T> {
580
- let intersectKeys = Object.keys(values)
581
-
582
- if (values instanceof this.constructor) {
583
- intersectKeys = Object.keys(values.all())
584
- }
585
-
586
- const collection = {}
587
-
588
- Object.keys(this.items).forEach((key) => {
589
- if (intersectKeys.includes(key)) {
590
- collection[key] = this.items[key]
591
- }
592
- })
593
-
594
- return new this.constructor(collection)
595
- }
596
-
597
- isEmpty(): boolean {
598
- return this.count() === 0
599
- }
600
-
601
- isNotEmpty(): boolean {
602
- return !this.isEmpty()
603
- }
604
-
605
- join(glue: string, finalGlue?: string): string {
606
- const collection = this.values()
607
-
608
- if (finalGlue === undefined) {
609
- return collection.implode(glue)
610
- }
611
-
612
- const count = collection.count()
613
-
614
- if (count === 0) {
615
- return ''
616
- }
617
-
618
- if (count === 1) {
619
- return collection.last()
620
- }
621
-
622
- const finalItem = collection.pop()
623
-
624
- return collection.implode(glue) + finalGlue + finalItem
625
- }
626
-
627
- keyBy(key: string | ((item: T) => string)): Collection<T> {
628
- const collection = {}
629
-
630
- if (isFunction(key)) {
631
- this.items.forEach((item) => {
632
- collection[key(item)] = item
633
- })
634
- }
635
- else {
636
- this.items.forEach((item) => {
637
- const keyValue = nestedValue(item, key)
638
-
639
- collection[keyValue || ''] = item
640
- })
641
- }
642
-
643
- return new this.constructor(collection)
644
- }
645
-
646
- keys(): Collection<string> {
647
- return new Collection(Object.keys(this.items))
648
- }
649
-
650
- last(fn?: (item: T) => boolean, defaultValue?: T | (() => T)): T {
651
- let { items } = this
652
-
653
- if (isFunction(fn)) {
654
- items = this.filter(fn).all()
655
- }
656
-
657
- if ((Array.isArray(items) && !items.length) || !Object.keys(items).length) {
658
- if (isFunction(defaultValue)) {
659
- return defaultValue()
660
- }
661
-
662
- return defaultValue
663
- }
664
-
665
- if (Array.isArray(items)) {
666
- return items[items.length - 1]
667
- }
668
- const keys = Object.keys(items)
669
-
670
- return items[keys[keys.length - 1]]
671
- }
672
-
673
- macro(name: string, fn: Function): void {
674
- this.constructor.prototype[name] = fn
675
- }
676
-
677
- make(items: T[] = []): Collection<T> {
678
- return new this.constructor(items)
679
- }
680
-
681
- map(fn: (item: T, index: number) => any): Collection<any> {
682
- if (Array.isArray(this.items)) {
683
- return new this.constructor(this.items.map(fn))
684
- }
685
-
686
- const collection = {}
687
-
688
- Object.keys(this.items).forEach((key) => {
689
- collection[key] = fn(this.items[key], Number(key))
690
- })
691
-
692
- return new this.constructor(collection)
693
- }
694
-
695
- mapSpread(fn: (...args: any[]) => any): Collection<any> {
696
- return this.map((values, key) => fn(...values, key))
697
- }
698
-
699
- mapToDictionary(fn: (item: T, key: number) => [string, any]): Collection<any[]> {
700
- const collection = {}
701
-
702
- this.items.forEach((item, k) => {
703
- const [key, value] = fn(item, k)
704
-
705
- if (collection[key] === undefined) {
706
- collection[key] = [value]
707
- }
708
- else {
709
- collection[key].push(value)
710
- }
711
- })
712
-
713
- return new this.constructor(collection)
714
- }
715
-
716
- mapInto(ClassName: new (value: T, key: number | string) => any): Collection<any> {
717
- return this.map((value, key) => new ClassName(value, key))
718
- }
719
-
720
- mapToGroups(fn: (item: T, key: number) => [string, any]): Collection<any[]> {
721
- const collection = {}
722
-
723
- this.items.forEach((item, key) => {
724
- const [keyed, value] = fn(item, key)
725
-
726
- if (collection[keyed] === undefined) {
727
- collection[keyed] = [value]
728
- }
729
- else {
730
- collection[keyed].push(value)
731
- }
732
- })
733
-
734
- return new this.constructor(collection)
735
- }
736
-
737
- mapWithKeys(fn: (item: T, index: number) => [string, any]): Collection<any> {
738
- const collection = {}
739
-
740
- if (Array.isArray(this.items)) {
741
- this.items.forEach((item, index) => {
742
- const [keyed, value] = fn(item, index)
743
- collection[keyed] = value
744
- })
745
- }
746
- else {
747
- Object.keys(this.items).forEach((key) => {
748
- const [keyed, value] = fn(this.items[key], Number(key))
749
- collection[keyed] = value
750
- })
751
- }
752
-
753
- return new this.constructor(collection)
754
- }
755
-
756
- max(key?: string): number {
757
- if (typeof key === 'string') {
758
- const filtered = this.items.filter(item => item[key] !== undefined)
759
-
760
- return Math.max(...filtered.map(item => item[key]))
761
- }
762
-
763
- return Math.max(...this.items)
764
- }
765
-
766
- median(key?: string): number {
767
- const { length } = this.items
768
-
769
- if (key === undefined) {
770
- if (length % 2 === 0) {
771
- return (this.items[length / 2 - 1] + this.items[length / 2]) / 2
772
- }
773
-
774
- return this.items[Math.floor(length / 2)]
775
- }
776
-
777
- if (length % 2 === 0) {
778
- return (this.items[length / 2 - 1][key] + this.items[length / 2][key]) / 2
779
- }
780
-
781
- return this.items[Math.floor(length / 2)][key]
782
- }
783
-
784
- merge(object: object): Collection<T> {
785
- const merged = { ...this.items, ...object }
786
-
787
- return new Collection(merged)
788
- }
789
-
790
- mergeRecursive(items: T | T[] | Collection<T>): Collection<T> {
791
- const merge = (target: any, source: any): any => {
792
- const merged = {}
793
-
794
- const mergedKeys = Object.keys({ ...target, ...source })
795
-
796
- mergedKeys.forEach((key) => {
797
- if (target[key] === undefined && source[key] !== undefined) {
798
- merged[key] = source[key]
799
- }
800
- else if (target[key] !== undefined && source[key] === undefined) {
801
- merged[key] = target[key]
802
- }
803
- else if (target[key] !== undefined && source[key] !== undefined) {
804
- if (target[key] === source[key]) {
805
- merged[key] = target[key]
806
- }
807
- else if (
808
- !Array.isArray(target[key])
809
- && typeof target[key] === 'object'
810
- && !Array.isArray(source[key])
811
- && typeof source[key] === 'object'
812
- ) {
813
- merged[key] = merge(target[key], source[key])
814
- }
815
- else {
816
- merged[key] = [].concat(target[key], source[key])
817
- }
818
- }
819
- })
820
-
821
- return merged
822
- }
823
-
824
- if (!items) {
825
- return this
826
- }
827
-
828
- if (items.constructor.name === 'Collection') {
829
- return new this.constructor(merge(this.items, items.all()))
830
- }
831
-
832
- return new this.constructor(merge(this.items, items))
833
- }
834
-
835
- min(key?: string): number {
836
- if (key !== undefined) {
837
- const filtered = this.items.filter(item => item[key] !== undefined)
838
-
839
- return Math.min(...filtered.map(item => item[key]))
840
- }
841
-
842
- return Math.min(...this.items)
843
- }
844
-
845
- mode(key?: string): any[] {
846
- const values = []
847
- let highestCount = 1
848
-
849
- if (!this.items.length) {
850
- return null
851
- }
852
-
853
- this.items.forEach((item) => {
854
- const tempValues = values.filter((value) => {
855
- if (key !== undefined) {
856
- return value.key === item[key]
857
- }
858
-
859
- return value.key === item
860
- })
861
-
862
- if (!tempValues.length) {
863
- if (key !== undefined) {
864
- values.push({ key: item[key], count: 1 })
865
- }
866
- else {
867
- values.push({ key: item, count: 1 })
868
- }
869
- }
870
- else {
871
- tempValues[0].count += 1
872
- const { count } = tempValues[0]
873
-
874
- if (count > highestCount) {
875
- highestCount = count
876
- }
877
- }
878
- })
879
-
880
- return values.filter(value => value.count === highestCount).map(value => value.key)
881
- }
882
-
883
- nth(n: number, offset = 0): Collection<T> {
884
- const items = values(this.items)
885
-
886
- const collection = items.slice(offset).filter((item, index) => index % n === 0)
887
-
888
- return new this.constructor(collection)
889
- }
890
-
891
- only(keys: string[]): Collection<T> {
892
- const result = {}
893
- keys.forEach((key) => {
894
- if (key in this.items)
895
- result[key] = this.items[key]
896
- })
897
- return new Collection(result)
898
- }
899
-
900
- pad(size: number, value: T): Collection<T> {
901
- const abs = Math.abs(size)
902
- const count = this.count()
903
-
904
- if (abs <= count) {
905
- return this
906
- }
907
-
908
- let diff = abs - count
909
- const items = clone(this.items)
910
- const isArray = Array.isArray(this.items)
911
- const prepend = size < 0
912
-
913
- for (let iterator = 0; iterator < diff;) {
914
- if (!isArray) {
915
- if (items[iterator] !== undefined) {
916
- diff += 1
917
- }
918
- else {
919
- items[iterator] = value
920
- }
921
- }
922
- else if (prepend) {
923
- items.unshift(value)
924
- }
925
- else {
926
- items.push(value)
927
- }
928
-
929
- iterator += 1
930
- }
931
-
932
- return new this.constructor(items)
933
- }
934
-
935
- partition(fn: (item: T) => boolean): [Collection<T>, Collection<T>] {
936
- let arrays
937
-
938
- if (Array.isArray(this.items)) {
939
- arrays = [new this.constructor([]), new this.constructor([])]
940
-
941
- this.items.forEach((item) => {
942
- if (fn(item) === true) {
943
- arrays[0].push(item)
944
- }
945
- else {
946
- arrays[1].push(item)
947
- }
948
- })
949
- }
950
- else {
951
- arrays = [new this.constructor({}), new this.constructor({})]
952
-
953
- Object.keys(this.items).forEach((prop) => {
954
- const value = this.items[prop]
955
-
956
- if (fn(value) === true) {
957
- arrays[0].put(prop, value)
958
- }
959
- else {
960
- arrays[1].put(prop, value)
961
- }
962
- })
963
- }
964
-
965
- return new this.constructor(arrays)
966
- }
967
-
968
- pipe(fn) {
969
- return fn(this)
970
- }
971
-
972
- pluck(value: string, key?: string) {
973
- if (value.includes('*')) {
974
- const keyPathMap = buildKeyPathMap(this.items)
975
- const keyMatches = []
976
-
977
- if (key !== undefined) {
978
- const keyRegex = new RegExp(`0.${key}`, 'g')
979
- const keyNumberOfLevels = `0.${key}`.split('.').length
980
-
981
- Object.keys(keyPathMap).forEach((k) => {
982
- const matchingKey = k.match(keyRegex)
983
-
984
- if (matchingKey) {
985
- const match = matchingKey[0]
986
-
987
- if (match.split('.').length === keyNumberOfLevels) {
988
- keyMatches.push(keyPathMap[match])
989
- }
990
- }
991
- })
992
- }
993
-
994
- const valueMatches = []
995
- const valueRegex = new RegExp(`0.${value}`, 'g')
996
- const valueNumberOfLevels = `0.${value}`.split('.').length
997
-
998
- Object.keys(keyPathMap).forEach((k) => {
999
- const matchingValue = k.match(valueRegex)
1000
-
1001
- if (matchingValue) {
1002
- const match = matchingValue[0]
1003
-
1004
- if (match.split('.').length === valueNumberOfLevels) {
1005
- valueMatches.push(keyPathMap[match])
1006
- }
1007
- }
1008
- })
1009
-
1010
- if (key !== undefined) {
1011
- const collection = {}
1012
-
1013
- this.items.forEach((item, index) => {
1014
- collection[keyMatches[index] || ''] = valueMatches
1015
- })
1016
-
1017
- return new this.constructor(collection)
1018
- }
1019
-
1020
- return new this.constructor([valueMatches])
1021
- }
1022
-
1023
- if (key !== undefined) {
1024
- const collection = {}
1025
-
1026
- this.items.forEach((item) => {
1027
- if (nestedValue(item, value) !== undefined) {
1028
- collection[item[key] || ''] = nestedValue(item, value)
1029
- }
1030
- else {
1031
- collection[item[key] || ''] = null
1032
- }
1033
- })
1034
-
1035
- return new this.constructor(collection)
1036
- }
1037
-
1038
- return this.map((item) => {
1039
- if (nestedValue(item, value) !== undefined) {
1040
- return nestedValue(item, value)
1041
- }
1042
-
1043
- return null
1044
- })
1045
- }
1046
-
1047
- pop(count = 1) {
1048
- if (this.isEmpty()) {
1049
- return null
1050
- }
1051
-
1052
- if (isArray(this.items)) {
1053
- if (count === 1) {
1054
- return this.items.pop()
1055
- }
1056
-
1057
- return new this.constructor(this.items.splice(-count))
1058
- }
1059
-
1060
- if (isObject(this.items)) {
1061
- const keys = Object.keys(this.items)
1062
-
1063
- if (count === 1) {
1064
- const key = keys[keys.length - 1]
1065
- const last = this.items[key]
1066
-
1067
- deleteKeys(this.items, key)
1068
-
1069
- return last
1070
- }
1071
-
1072
- const poppedKeys = keys.slice(-count)
1073
-
1074
- const newObject = poppedKeys.reduce((acc, current) => {
1075
- acc[current] = this.items[current]
1076
-
1077
- return acc
1078
- }, {})
1079
-
1080
- deleteKeys(this.items, poppedKeys)
1081
-
1082
- return new this.constructor(newObject)
1083
- }
1084
-
1085
- return null
1086
- }
1087
-
1088
- prepend(value, key) {
1089
- if (key !== undefined) {
1090
- return this.put(key, value)
1091
- }
1092
-
1093
- this.items.unshift(value)
1094
-
1095
- return this
1096
- }
1097
-
1098
- pull(key: string | number, defaultValue: T | null = null): T | null {
1099
- if (Array.isArray(this.items)) {
1100
- const index = Number(key)
1101
- if (Number.isNaN(index))
1102
- return defaultValue
1103
- const value = this.items[index]
1104
- this.items.splice(index, 1)
1105
- return value ?? defaultValue
1106
- }
1107
-
1108
- const value = this.items[key as string]
1109
- delete this.items[key as string]
1110
- return value ?? defaultValue
1111
- }
1112
-
1113
- push(...items: T[]): Collection<T> {
1114
- this.items = [...this.items, ...items]
1115
- return this
1116
- }
1117
-
1118
- put(key: string, value: any): this {
1119
- this.items[key] = value
1120
- return this
1121
- }
1122
-
1123
- random(length = null) {
1124
- const items = values(this.items)
1125
-
1126
- const collection = new this.constructor(items).shuffle()
1127
-
1128
- // If not a length was specified
1129
- if (length !== Number.parseInt(length, 10)) {
1130
- return collection.first()
1131
- }
1132
-
1133
- return collection.take(length)
1134
- }
1135
-
1136
- reduce(fn, carry) {
1137
- let reduceCarry = null
1138
-
1139
- if (carry !== undefined) {
1140
- reduceCarry = carry
1141
- }
1142
-
1143
- if (Array.isArray(this.items)) {
1144
- this.items.forEach((item) => {
1145
- reduceCarry = fn(reduceCarry, item)
1146
- })
1147
- }
1148
- else {
1149
- Object.keys(this.items).forEach((key) => {
1150
- reduceCarry = fn(reduceCarry, this.items[key], key)
1151
- })
1152
- }
1153
-
1154
- return reduceCarry
1155
- }
1156
-
1157
- reject(fn) {
1158
- return new this.constructor(this.items).filter(item => !fn(item))
1159
- }
1160
-
1161
- replace(items) {
1162
- if (!items) {
1163
- return this
1164
- }
1165
-
1166
- if (Array.isArray(items)) {
1167
- const replaced = this.items.map((value, index) => items[index] || value)
1168
-
1169
- return new this.constructor(replaced)
1170
- }
1171
-
1172
- if (items.constructor.name === 'Collection') {
1173
- const replaced = { ...this.items, ...items.all() }
1174
-
1175
- return new this.constructor(replaced)
1176
- }
1177
-
1178
- const replaced = { ...this.items, ...items }
1179
-
1180
- return new this.constructor(replaced)
1181
- }
1182
-
1183
- replaceRecursive(items) {
1184
- const replace = (target, source) => {
1185
- const replaced = { ...target }
1186
-
1187
- const mergedKeys = Object.keys({ ...target, ...source })
1188
-
1189
- mergedKeys.forEach((key) => {
1190
- if (!Array.isArray(source[key]) && typeof source[key] === 'object') {
1191
- replaced[key] = replace(target[key], source[key])
1192
- }
1193
- else if (target[key] === undefined && source[key] !== undefined) {
1194
- if (typeof target[key] === 'object') {
1195
- replaced[key] = { ...source[key] }
1196
- }
1197
- else {
1198
- replaced[key] = source[key]
1199
- }
1200
- }
1201
- else if (target[key] !== undefined && source[key] === undefined) {
1202
- if (typeof target[key] === 'object') {
1203
- replaced[key] = { ...target[key] }
1204
- }
1205
- else {
1206
- replaced[key] = target[key]
1207
- }
1208
- }
1209
- else if (target[key] !== undefined && source[key] !== undefined) {
1210
- if (typeof source[key] === 'object') {
1211
- replaced[key] = { ...source[key] }
1212
- }
1213
- else {
1214
- replaced[key] = source[key]
1215
- }
1216
- }
1217
- })
1218
-
1219
- return replaced
1220
- }
1221
-
1222
- if (!items) {
1223
- return this
1224
- }
1225
-
1226
- if (!Array.isArray(items) && typeof items !== 'object') {
1227
- return new this.constructor(replace(this.items, [items]))
1228
- }
1229
-
1230
- if (items.constructor.name === 'Collection') {
1231
- return new this.constructor(replace(this.items, items.all()))
1232
- }
1233
-
1234
- return new this.constructor(replace(this.items, items))
1235
- }
1236
-
1237
- reverse() {
1238
- const collection = [].concat(this.items).reverse()
1239
-
1240
- return new this.constructor(collection)
1241
- }
1242
-
1243
- search(valueOrFunction, strict) {
1244
- let result
1245
-
1246
- const find = (item, key) => {
1247
- if (isFunction(valueOrFunction)) {
1248
- return valueOrFunction(this.items[key], key)
1249
- }
1250
-
1251
- if (strict) {
1252
- return this.items[key] === valueOrFunction
1253
- }
1254
-
1255
- return this.items[key] == valueOrFunction
1256
- }
1257
-
1258
- if (isArray(this.items)) {
1259
- result = this.items.findIndex(find)
1260
- }
1261
- else if (isObject(this.items)) {
1262
- result = Object.keys(this.items).find(key => find(this.items[key], key))
1263
- }
1264
-
1265
- if (result === undefined || result < 0) {
1266
- return false
1267
- }
1268
-
1269
- return result
1270
- }
1271
-
1272
- shift(count = 1): T | undefined | null {
1273
- if (this.isEmpty()) {
1274
- return null
1275
- }
1276
-
1277
- if (isArray(this.items)) {
1278
- if (count === 1) {
1279
- return this.items.shift()
1280
- }
1281
-
1282
- return new this.constructor(this.items.splice(0, count))
1283
- }
1284
-
1285
- if (isObject(this.items)) {
1286
- if (count === 1) {
1287
- const key = Object.keys(this.items)[0]
1288
- const value = this.items[key]
1289
- delete this.items[key]
1290
-
1291
- return value
1292
- }
1293
-
1294
- const keys = Object.keys(this.items)
1295
- const poppedKeys = keys.slice(0, count)
1296
-
1297
- const newObject = poppedKeys.reduce((acc, current) => {
1298
- acc[current] = this.items[current]
1299
-
1300
- return acc
1301
- }, {})
1302
-
1303
- deleteKeys(this.items, poppedKeys)
1304
-
1305
- return new this.constructor(newObject)
1306
- }
1307
-
1308
- return null
1309
- }
1310
-
1311
- shuffle(): Collection<T> {
1312
- const items = values(this.items)
1313
-
1314
- let j
1315
- let x
1316
- let i
1317
-
1318
- for (i = items.length; i; i -= 1) {
1319
- j = Math.floor(Math.random() * i)
1320
- x = items[i - 1]
1321
- items[i - 1] = items[j]
1322
- items[j] = x
1323
- }
1324
-
1325
- this.items = items
1326
-
1327
- return this
1328
- }
1329
-
1330
- skip(number: number): Collection<T> {
1331
- if (isObject(this.items)) {
1332
- return new this.constructor(
1333
- Object.keys(this.items).reduce((accumulator, key, index) => {
1334
- if (index + 1 > number) {
1335
- accumulator[key] = this.items[key]
1336
- }
1337
-
1338
- return accumulator
1339
- }, {}),
1340
- )
1341
- }
1342
-
1343
- return new this.constructor(this.items.slice(number))
1344
- }
1345
-
1346
- skipUntil(valueOrFunction: any): Collection<T> {
1347
- let previous = null
1348
- let items
1349
-
1350
- let callback = value => value === valueOrFunction
1351
- if (isFunction(valueOrFunction)) {
1352
- callback = valueOrFunction
1353
- }
1354
-
1355
- if (isArray(this.items)) {
1356
- items = this.items.filter((item) => {
1357
- if (previous !== true) {
1358
- previous = callback(item)
1359
- }
1360
-
1361
- return previous
1362
- })
1363
- }
1364
-
1365
- if (isObject(this.items)) {
1366
- items = Object.keys(this.items).reduce((acc, key) => {
1367
- if (previous !== true) {
1368
- previous = callback(this.items[key])
1369
- }
1370
-
1371
- if (previous !== false) {
1372
- acc[key] = this.items[key]
1373
- }
1374
-
1375
- return acc
1376
- }, {})
1377
- }
1378
-
1379
- return new this.constructor(items)
1380
- }
1381
-
1382
- skipWhile(valueOrFunction: any): Collection<T> {
1383
- let previous = null
1384
- let items
1385
-
1386
- let callback = value => value === valueOrFunction
1387
- if (isFunction(valueOrFunction)) {
1388
- callback = valueOrFunction
1389
- }
1390
-
1391
- if (isArray(this.items)) {
1392
- items = this.items.filter((item) => {
1393
- if (previous !== true) {
1394
- previous = !callback(item)
1395
- }
1396
-
1397
- return previous
1398
- })
1399
- }
1400
-
1401
- if (isObject(this.items)) {
1402
- items = Object.keys(this.items).reduce((acc, key) => {
1403
- if (previous !== true) {
1404
- previous = !callback(this.items[key])
1405
- }
1406
-
1407
- if (previous !== false) {
1408
- acc[key] = this.items[key]
1409
- }
1410
-
1411
- return acc
1412
- }, {})
1413
- }
1414
-
1415
- return new this.constructor(items)
1416
- }
1417
-
1418
- slice(remove: number, limit: number): Collection<T> {
1419
- let collection = this.items.slice(remove)
1420
-
1421
- if (limit !== undefined) {
1422
- collection = collection.slice(0, limit)
1423
- }
1424
-
1425
- return new this.constructor(collection)
1426
- }
1427
-
1428
- sole(): T {
1429
- if (this.items.length !== 1) {
1430
- throw new Error('Collection does not contain exactly one item.')
1431
- }
1432
- return this.items[0]
1433
- }
1434
-
1435
- some(key: string): boolean {
1436
- return this.items.some(item => item.hasOwnProperty(key))
1437
- }
1438
-
1439
- sort(fn: (a: T, b: T) => number): Collection<T> {
1440
- const collection = [].concat(this.items)
1441
-
1442
- if (fn === undefined) {
1443
- if (this.every(item => typeof item === 'number')) {
1444
- collection.sort((a, b) => a - b)
1445
- }
1446
- else {
1447
- collection.sort()
1448
- }
1449
- }
1450
- else {
1451
- collection.sort(fn)
1452
- }
1453
-
1454
- return new this.constructor(collection)
1455
- }
1456
-
1457
- sortDesc(): Collection<T> {
1458
- return this.sort().reverse()
1459
- }
1460
-
1461
- sortBy(valueOrFunction: any): Collection<T> {
1462
- const collection = [].concat(this.items)
1463
- const getValue = (item) => {
1464
- if (isFunction(valueOrFunction)) {
1465
- return valueOrFunction(item)
1466
- }
1467
-
1468
- return nestedValue(item, valueOrFunction)
1469
- }
1470
-
1471
- collection.sort((a, b) => {
1472
- const valueA = getValue(a)
1473
- const valueB = getValue(b)
1474
-
1475
- if (valueA === null || valueA === undefined) {
1476
- return 1
1477
- }
1478
- if (valueB === null || valueB === undefined) {
1479
- return -1
1480
- }
1481
-
1482
- if (valueA < valueB) {
1483
- return -1
1484
- }
1485
- if (valueA > valueB) {
1486
- return 1
1487
- }
1488
-
1489
- return 0
1490
- })
1491
-
1492
- return new this.constructor(collection)
1493
- }
1494
-
1495
- sortByDesc(valueOrFunction: any): Collection<T> {
1496
- return this.sortBy(valueOrFunction).reverse()
1497
- }
1498
-
1499
- sortKeys(): Collection<T> {
1500
- const ordered = {}
1501
-
1502
- Object.keys(this.items)
1503
- .sort()
1504
- .forEach((key) => {
1505
- ordered[key] = this.items[key]
1506
- })
1507
-
1508
- return new this.constructor(ordered)
1509
- }
1510
-
1511
- sortKeysDesc(): Collection<T> {
1512
- const ordered = {}
1513
-
1514
- Object.keys(this.items)
1515
- .sort()
1516
- .reverse()
1517
- .forEach((key) => {
1518
- ordered[key] = this.items[key]
1519
- })
1520
-
1521
- return new this.constructor(ordered)
1522
- }
1523
-
1524
- splice(index: number, limit: number, replace: any): Collection<T> {
1525
- const slicedCollection = this.slice(index, limit)
1526
-
1527
- this.items = this.diff(slicedCollection.all()).all()
1528
-
1529
- if (Array.isArray(replace)) {
1530
- for (let iterator = 0, { length } = replace; iterator < length; iterator += 1) {
1531
- this.items.splice(index + iterator, 0, replace[iterator])
1532
- }
1533
- }
1534
-
1535
- return slicedCollection
1536
- }
1537
-
1538
- split(numberOfGroups: number): Collection<T[]> {
1539
- const itemsArray = this.toArray()
1540
- const groups: T[][] = []
1541
- const size = Math.ceil(itemsArray.length / numberOfGroups)
1542
-
1543
- for (let i = 0; i < itemsArray.length; i += size) {
1544
- groups.push(itemsArray.slice(i, i + size))
1545
- }
1546
-
1547
- return new Collection(groups)
1548
- }
1549
-
1550
- sum(key?: string | ((item: T) => number)): number {
1551
- const items = values(this.items)
1552
-
1553
- let total = 0
1554
-
1555
- if (key === undefined) {
1556
- for (let i = 0, { length } = items; i < length; i += 1) {
1557
- total += Number.parseFloat(items[i])
1558
- }
1559
- }
1560
- else if (isFunction(key)) {
1561
- for (let i = 0, { length } = items; i < length; i += 1) {
1562
- total += Number.parseFloat(key(items[i]))
1563
- }
1564
- }
1565
- else {
1566
- for (let i = 0, { length } = items; i < length; i += 1) {
1567
- total += Number.parseFloat(items[i][key])
1568
- }
1569
- }
1570
-
1571
- return Number.parseFloat(total.toPrecision(12))
1572
- }
1573
-
1574
- take(length: number): Collection<T> {
1575
- if (!Array.isArray(this.items) && typeof this.items === 'object') {
1576
- const keys = Object.keys(this.items)
1577
- let slicedKeys
1578
-
1579
- if (length < 0) {
1580
- slicedKeys = keys.slice(length)
1581
- }
1582
- else {
1583
- slicedKeys = keys.slice(0, length)
1584
- }
1585
-
1586
- const collection = {}
1587
-
1588
- keys.forEach((prop) => {
1589
- if (slicedKeys.includes(prop)) {
1590
- collection[prop] = this.items[prop]
1591
- }
1592
- })
1593
-
1594
- return new this.constructor(collection)
1595
- }
1596
-
1597
- if (length < 0) {
1598
- return new this.constructor(this.items.slice(length))
1599
- }
1600
-
1601
- return new this.constructor(this.items.slice(0, length))
1602
- }
1603
-
1604
- takeUntil(valueOrFunction): Collection<T> {
1605
- let previous = null
1606
- let items
1607
-
1608
- let callback = value => value === valueOrFunction
1609
- if (isFunction(valueOrFunction)) {
1610
- callback = valueOrFunction
1611
- }
1612
-
1613
- if (isArray(this.items)) {
1614
- items = this.items.filter((item) => {
1615
- if (previous !== false) {
1616
- previous = !callback(item)
1617
- }
1618
-
1619
- return previous
1620
- })
1621
- }
1622
-
1623
- if (isObject(this.items)) {
1624
- items = Object.keys(this.items).reduce((acc, key) => {
1625
- if (previous !== false) {
1626
- previous = !callback(this.items[key])
1627
- }
1628
-
1629
- if (previous !== false) {
1630
- acc[key] = this.items[key]
1631
- }
1632
-
1633
- return acc
1634
- }, {})
1635
- }
1636
-
1637
- return new this.constructor(items)
1638
- }
1639
-
1640
- takeWhile(valueOrFunction: any): Collection<T> {
1641
- let previous = null
1642
- let items
1643
-
1644
- let callback = value => value === valueOrFunction
1645
- if (isFunction(valueOrFunction)) {
1646
- callback = valueOrFunction
1647
- }
1648
-
1649
- if (isArray(this.items)) {
1650
- items = this.items.filter((item) => {
1651
- if (previous !== false) {
1652
- previous = callback(item)
1653
- }
1654
-
1655
- return previous
1656
- })
1657
- }
1658
-
1659
- if (isObject(this.items)) {
1660
- items = Object.keys(this.items).reduce((acc, key) => {
1661
- if (previous !== false) {
1662
- previous = callback(this.items[key])
1663
- }
1664
-
1665
- if (previous !== false) {
1666
- acc[key] = this.items[key]
1667
- }
1668
-
1669
- return acc
1670
- }, {})
1671
- }
1672
-
1673
- return new this.constructor(items)
1674
- }
1675
-
1676
- tap(fn: (collection: Collection<T>) => void): Collection<T> {
1677
- fn(this)
1678
-
1679
- return this
1680
- }
1681
-
1682
- times(n: number, fn: (iterator: number) => void): Collection<T> {
1683
- for (let iterator = 1; iterator <= n; iterator += 1) {
1684
- this.items.push(fn(iterator))
1685
- }
1686
-
1687
- return this
1688
- }
1689
-
1690
- toArray(): T[] {
1691
- return Array.isArray(this.items) ? this.items : Object.values(this.items)
1692
- }
1693
-
1694
- toJson(): string {
1695
- return JSON.stringify(this.items)
1696
- }
1697
-
1698
- transform(fn: (item: T, key: string) => T): Collection<T> {
1699
- if (Array.isArray(this.items)) {
1700
- this.items = this.items.map(fn)
1701
- }
1702
- else {
1703
- const collection = {}
1704
-
1705
- Object.keys(this.items).forEach((key) => {
1706
- collection[key] = fn(this.items[key], key)
1707
- })
1708
-
1709
- this.items = collection
1710
- }
1711
-
1712
- return this
1713
- }
1714
-
1715
- undot(): Collection<T> {
1716
- if (Array.isArray(this.items)) {
1717
- return this
1718
- }
1719
-
1720
- let collection = {}
1721
-
1722
- Object.keys(this.items).forEach((key) => {
1723
- if (key.includes('.')) {
1724
- const obj = collection
1725
-
1726
- key.split('.').reduce((acc, current, index, array) => {
1727
- if (!acc[current]) {
1728
- acc[current] = {}
1729
- }
1730
-
1731
- if (index === array.length - 1) {
1732
- acc[current] = this.items[key]
1733
- }
1734
-
1735
- return acc[current]
1736
- }, obj)
1737
-
1738
- collection = { ...collection, ...obj }
1739
- }
1740
- else {
1741
- collection[key] = this.items[key]
1742
- }
1743
- })
1744
-
1745
- return new this.constructor(collection)
1746
- }
1747
-
1748
- unless<T>(value: any, fn: (collection: this) => T, defaultFn?: () => T): T | undefined {
1749
- if (!value) {
1750
- return fn(this)
1751
- }
1752
-
1753
- if (defaultFn)
1754
- return defaultFn()
1755
- return undefined
1756
- }
1757
-
1758
- unlessEmpty(callback: (collection: Collection<T>) => void): this {
1759
- if (!this.isEmpty()) {
1760
- callback(this)
1761
- }
1762
-
1763
- return this
1764
- }
1765
-
1766
- unlessNotEmpty(callback: (collection: Collection<T>) => void): Collection<T> {
1767
- if (this.isEmpty()) {
1768
- callback(this)
1769
- }
1770
-
1771
- return this
1772
- }
1773
-
1774
- union(object: Record<string, T>): Collection<T> {
1775
- const collection = JSON.parse(JSON.stringify(this.items))
1776
-
1777
- Object.keys(object).forEach((prop) => {
1778
- if (this.items[prop] === undefined) {
1779
- collection[prop] = object[prop]
1780
- }
1781
- })
1782
-
1783
- return new this.constructor(collection)
1784
- }
1785
-
1786
- unique(): Collection<T> {
1787
- const uniqueItems = Array.from(new Set(this.items))
1788
- return new this.constructor(uniqueItems)
1789
- }
1790
-
1791
- unwrap(): T[] | Record<string, T> {
1792
- return this.items
1793
- }
1794
-
1795
- values(): Collection<T> {
1796
- return new Collection(Object.values(this.items))
1797
- }
1798
-
1799
- when(
1800
- value: any,
1801
- callback: (collection: Collection<T>, value: any) => void,
1802
- defaultCallback?: () => void,
1803
- ): Collection<T> {
1804
- if (value) {
1805
- callback(this, value)
1806
- }
1807
- else if (defaultCallback) {
1808
- defaultCallback()
1809
- }
1810
- return this
1811
- }
1812
-
1813
- whenEmpty(fn, defaultFn) {
1814
- if (Array.isArray(this.items) && !this.items.length) {
1815
- return fn(this)
1816
- }
1817
- if (!Object.keys(this.items).length) {
1818
- return fn(this)
1819
- }
1820
-
1821
- if (defaultFn !== undefined) {
1822
- if (Array.isArray(this.items) && this.items.length) {
1823
- return defaultFn(this)
1824
- }
1825
- if (Object.keys(this.items).length) {
1826
- return defaultFn(this)
1827
- }
1828
- }
1829
-
1830
- return this
1831
- }
1832
-
1833
- whenNotEmpty(fn: (collection: Collection<T>) => void, defaultFn: (collection: Collection<T>) => void): Collection<T> {
1834
- if (Array.isArray(this.items) && this.items.length) {
1835
- return fn(this)
1836
- }
1837
-
1838
- if (Object.keys(this.items).length) {
1839
- return fn(this)
1840
- }
1841
-
1842
- if (defaultFn !== undefined) {
1843
- if (Array.isArray(this.items) && !this.items.length) {
1844
- return defaultFn(this)
1845
- }
1846
- if (!Object.keys(this.items).length) {
1847
- return defaultFn(this)
1848
- }
1849
- }
1850
-
1851
- return this
1852
- }
1853
-
1854
- where(key: string, operator?: any, value?: any): Collection<T> {
1855
- // If only one argument is passed, we're checking for existence
1856
- if (arguments.length === 1) {
1857
- return new Collection(this.items.filter(item => item[key] !== undefined))
1858
- }
1859
-
1860
- // If two arguments are passed, the second one is the value
1861
- if (arguments.length === 2) {
1862
- value = operator
1863
- operator = '==='
1864
- }
1865
-
1866
- const compareValues = (item: any, key: string, value: any, operator: string) => {
1867
- const itemValue = item[key]
1868
-
1869
- switch (operator) {
1870
- case '===':
1871
- return itemValue === value
1872
- case '!==':
1873
- return itemValue !== value
1874
- case '<':
1875
- return itemValue < value
1876
- case '<=':
1877
- return itemValue <= value
1878
- case '>':
1879
- return itemValue > value
1880
- case '>=':
1881
- return itemValue >= value
1882
- default:
1883
- return itemValue == value
1884
- }
1885
- }
1886
-
1887
- return new Collection(this.items.filter(item => compareValues(item, key, value, operator)))
1888
- }
1889
-
1890
- whereBetween(key: string, values: [number, number]): Collection<T> {
1891
- return this.filter((item) => {
1892
- const itemValue = typeof item === 'object' ? item[key] : item
1893
- return itemValue >= values[0] && itemValue <= values[1]
1894
- })
1895
- }
1896
-
1897
- whereIn(key: string, values: any[]): Collection<T> {
1898
- return this.filter((item) => {
1899
- const itemValue = typeof item === 'object' ? item[key] : item
1900
- return values.includes(itemValue)
1901
- })
1902
- }
1903
-
1904
- whereNotBetween(key: string, values: [number, number]): Collection<T> {
1905
- return this.filter((item) => {
1906
- const itemValue = typeof item === 'object' ? item[key] : item
1907
- return itemValue < values[0] || itemValue > values[1]
1908
- })
1909
- }
1910
-
1911
- whereNotIn(key: string, values: any[]): Collection<T> {
1912
- const filteredItems = this.items.filter((item) => {
1913
- const keys = key.split('.')
1914
- let value = item
1915
-
1916
- for (const k of keys) {
1917
- if (value[k] === undefined)
1918
- return true
1919
- value = value[k]
1920
- }
1921
-
1922
- return !values.includes(value)
1923
- })
1924
-
1925
- return new Collection(filteredItems)
1926
- }
1927
-
1928
- private getNestedValue(item: any, key: string): any {
1929
- const keys = key.split('.')
1930
- return keys.reduce((obj, k) => (obj && obj[k] !== undefined ? obj[k] : null), item)
1931
- }
1932
-
1933
- whereInstanceOf(type: any): Collection<T> {
1934
- return this.filter(item => item instanceof type)
1935
- }
1936
-
1937
- whereNotNull(key: string): Collection<T> {
1938
- return this.where(key, '!==', null)
1939
- }
1940
-
1941
- whereNull(key: string): Collection<T> {
1942
- return this.where(key, '===', null)
1943
- }
1944
-
1945
- static wrap<T>(value: T | T[] | Collection<T>): Collection<T> {
1946
- if (value instanceof Collection)
1947
- return value
1948
- return new Collection(Array.isArray(value) ? value : [value])
1949
- }
1950
-
1951
- static unwrap<T extends object>(value: T | T[] | Collection<T>): T | T[] {
1952
- if (value instanceof Collection) {
1953
- return value.all()
1954
- }
1955
-
1956
- return value
1957
- }
1958
-
1959
- wrap(value: any): Collection<T> {
1960
- if (value instanceof Collection) {
1961
- return value
1962
- }
1963
-
1964
- if (typeof value === 'object') {
1965
- return new Collection(value)
1966
- }
1967
-
1968
- return new Collection([value])
1969
- }
1970
-
1971
- zip(...arrays: any[]): Collection<any> {
1972
- const arrayOfArrays = arrays.map(arg => this.constructor.wrap(arg).all())
1973
- const zipped = this.items.map((item, index) => {
1974
- const values = [item]
1975
- arrayOfArrays.forEach((array) => {
1976
- values.push(array[index])
1977
- })
1978
- return new this.constructor(values) // Wrap each zipped item in a new Collection
1979
- })
1980
- return new this.constructor(zipped)
1981
- }
1982
- }
1983
-
1984
- const buildKeyPathMap = function buildKeyPathMap(items: any) {
1985
- const keyPaths = {}
1986
-
1987
- items.forEach((item: any, index: number) => {
1988
- function buildKeyPath(val: any, keyPath: string) {
1989
- if (isObject(val)) {
1990
- Object.keys(val).forEach((prop) => {
1991
- buildKeyPath(val[prop], `${keyPath}.${prop}`)
1992
- })
1993
- }
1994
- else if (isArray(val)) {
1995
- val.forEach((v, i) => {
1996
- buildKeyPath(v, `${keyPath}.${i}`)
1997
- })
1998
- }
1999
-
2000
- keyPaths[keyPath] = val
2001
- }
2002
-
2003
- buildKeyPath(item, index)
2004
- })
2005
-
2006
- return keyPaths
2007
- }
2008
-
2009
- function SymbolIterator() {
2010
- let index = -1
2011
-
2012
- return {
2013
- next: () => {
2014
- index += 1
2015
-
2016
- return {
2017
- value: this.items[index],
2018
- done: index >= this.items.length,
2019
- }
2020
- },
2021
- }
2022
- }
2023
-
2024
- export default collect