atomic-fns 0.3.5 → 0.4.3

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 (109) hide show
  1. package/README.md +1 -12
  2. package/{core → dist}/collections/BTree.d.ts +6 -6
  3. package/{core → dist}/collections/BTree.js +17 -17
  4. package/{core → dist}/collections/Heap.d.ts +3 -3
  5. package/{core → dist}/collections/Heap.js +0 -0
  6. package/dist/collections/LRUCache.d.ts +80 -0
  7. package/dist/collections/LRUCache.js +126 -0
  8. package/{core → dist}/collections/SortedMap.d.ts +2 -2
  9. package/{core → dist}/collections/SortedMap.js +0 -0
  10. package/{core → dist}/collections/SortedSet.d.ts +3 -3
  11. package/{core → dist}/collections/SortedSet.js +1 -1
  12. package/{core → dist}/collections/SortedTree.d.ts +3 -3
  13. package/{core → dist}/collections/SortedTree.js +1 -1
  14. package/{core → dist}/collections/SplayTree.d.ts +5 -5
  15. package/{core → dist}/collections/SplayTree.js +0 -0
  16. package/{core → dist}/collections/abc.d.ts +0 -0
  17. package/{core → dist}/collections/abc.js +0 -0
  18. package/{core → dist}/collections/deque.d.ts +7 -7
  19. package/{core → dist}/collections/deque.js +6 -8
  20. package/{core → dist}/collections/frozenset.d.ts +0 -0
  21. package/{core → dist}/collections/frozenset.js +3 -6
  22. package/{core → dist}/collections/index.d.ts +207 -105
  23. package/{core → dist}/collections/index.js +179 -436
  24. package/{core → dist}/functools/index.d.ts +30 -16
  25. package/{core → dist}/functools/index.js +34 -12
  26. package/dist/globals/decimal.d.ts +142 -0
  27. package/dist/globals/decimal.js +371 -0
  28. package/{core → dist}/globals/index.d.ts +26 -25
  29. package/{core → dist}/globals/index.js +16 -37
  30. package/dist/i18n/currency.d.ts +24 -0
  31. package/dist/i18n/currency.js +85 -0
  32. package/dist/i18n/date/index.d.ts +204 -0
  33. package/dist/i18n/date/index.js +530 -0
  34. package/dist/i18n/date/utils.d.ts +65 -0
  35. package/dist/i18n/date/utils.js +290 -0
  36. package/dist/i18n/duration.d.ts +112 -0
  37. package/dist/i18n/duration.js +392 -0
  38. package/dist/i18n/format.d.ts +26 -0
  39. package/dist/i18n/format.js +495 -0
  40. package/{core → dist}/i18n/index.d.ts +2 -1
  41. package/{core → dist}/i18n/index.js +2 -1
  42. package/{core → dist}/index.d.ts +0 -0
  43. package/{core → dist}/index.js +0 -0
  44. package/{core → dist}/itertools/index.d.ts +74 -46
  45. package/{core → dist}/itertools/index.js +28 -56
  46. package/{core → dist}/math/index.d.ts +9 -10
  47. package/{core → dist}/math/index.js +3 -1
  48. package/{core → dist}/operators/index.d.ts +4 -4
  49. package/{core → dist}/operators/index.js +2 -8
  50. package/{core → dist}/random/index.d.ts +1 -1
  51. package/{core → dist}/random/index.js +5 -5
  52. package/package.json +28 -42
  53. package/.editorconfig +0 -12
  54. package/.esdoc.json +0 -27
  55. package/.eslintignore +0 -1
  56. package/.eslintrc.json +0 -35
  57. package/.firebaserc +0 -5
  58. package/.prettierrc +0 -19
  59. package/core/collections/BTree.ts +0 -1340
  60. package/core/collections/Heap.ts +0 -189
  61. package/core/collections/LRUCache.d.ts +0 -152
  62. package/core/collections/LRUCache.js +0 -409
  63. package/core/collections/LRUCache.ts +0 -486
  64. package/core/collections/SortedMap.ts +0 -146
  65. package/core/collections/SortedSet.ts +0 -110
  66. package/core/collections/SortedTree.ts +0 -160
  67. package/core/collections/SplayTree.ts +0 -354
  68. package/core/collections/abc.ts +0 -176
  69. package/core/collections/deque.ts +0 -338
  70. package/core/collections/frozenset.ts +0 -37
  71. package/core/collections/index.ts +0 -1024
  72. package/core/collections/test.html +0 -10
  73. package/core/collections/typedArrays.d.ts +0 -31
  74. package/core/collections/typedArrays.js +0 -143
  75. package/core/collections/typedArrays.ts +0 -163
  76. package/core/functools/index.ts +0 -260
  77. package/core/globals/index.ts +0 -481
  78. package/core/i18n/date/format.d.ts +0 -16
  79. package/core/i18n/date/format.js +0 -307
  80. package/core/i18n/date/format.ts +0 -343
  81. package/core/i18n/date/index.d.ts +0 -224
  82. package/core/i18n/date/index.js +0 -387
  83. package/core/i18n/date/index.ts +0 -471
  84. package/core/i18n/date/test.html +0 -67
  85. package/core/i18n/index.ts +0 -8
  86. package/core/index.ts +0 -8
  87. package/core/itertools/index.ts +0 -494
  88. package/core/math/index.ts +0 -152
  89. package/core/operators/index.ts +0 -310
  90. package/core/random/index.ts +0 -66
  91. package/firebase.json +0 -10
  92. package/jasmine.json +0 -14
  93. package/tests/BTree.spec.ts +0 -143
  94. package/tests/Cache.spec.ts +0 -161
  95. package/tests/Heap.spec.ts +0 -66
  96. package/tests/SortedMap.spec.ts +0 -144
  97. package/tests/SortedSet.spec.ts +0 -84
  98. package/tests/SortedTree.spec.ts +0 -164
  99. package/tests/SplayTree.spec.ts +0 -121
  100. package/tests/collections.spec.ts +0 -288
  101. package/tests/deque.spec.ts +0 -107
  102. package/tests/globals.spec.ts +0 -270
  103. package/tests/itertools.spec.ts +0 -266
  104. package/tests/math.spec.ts +0 -25
  105. package/tests/operators.spec.ts +0 -40
  106. package/tests/random.spec.ts +0 -46
  107. package/tsconfig.json +0 -126
  108. package/tsconfig.node.json +0 -18
  109. package/tsconfig.xo.json +0 -9
@@ -1,1024 +0,0 @@
1
- /**
2
- * This module includes classes and functions to work with Container types.
3
- *
4
- * @module Collections
5
- */
6
-
7
- import { partial } from '../functools/index.js'
8
- import {
9
- call,
10
- get,
11
- isArray,
12
- isArrayLike,
13
- isBool,
14
- isEmpty,
15
- isFunction,
16
- isIterable,
17
- isNull,
18
- isNumber,
19
- isObject,
20
- isString,
21
- isSymbol,
22
- Iteratee,
23
- keys,
24
- set
25
- } from '../globals/index.js'
26
- import { enumerate } from '../itertools/index.js'
27
- import { compare, eq, id } from '../operators/index.js'
28
-
29
- export * from './abc.js'
30
- export * from './BTree.js'
31
- export * from './deque.js'
32
- export * from './frozenset.js'
33
- export * from './Heap.js'
34
- export * from './LRUCache.js'
35
- export * from './SortedSet.js'
36
- export * from './SortedMap.js'
37
- export * from './SortedTree.js'
38
- export * from './SplayTree.js'
39
-
40
- /**
41
- * Creates a new array with all falsy and empty values removed.
42
- * @param arr The array to compact
43
- * @returns A new array with the filtered values.
44
- * @example
45
- ```js
46
- compact([0, 1, false, 2, '', 3])
47
- // => [1, 2, 3]
48
- ```
49
- */
50
- export function compact(arr: any[])
51
- export function compact(arr: Object)
52
- export function compact(arr) {
53
- if (arr == null) return
54
- if (Array.isArray(arr)) return arr.filter((x) => !isEmpty(x))
55
- const result = {}
56
- for (const key of Object.keys(arr)) {
57
- if (!isEmpty(arr[key])) {
58
- result[key] = arr[key]
59
- }
60
- }
61
- return result
62
- }
63
-
64
- export function count<T>(iterable: Iterable<T> | Object, func: Iteratee<T>) {
65
- const counters = {}
66
- forEach(iterable, (value: T, key) => {
67
- const result = func(value, key)
68
- counters[result] = get(result, counters, 0) + 1
69
- })
70
- return counters
71
- }
72
-
73
- /**
74
- * Creates a function that can be used to create named tuple-like objects.
75
- * @example
76
- ```js
77
- * let Point = namedtuple('x', 'y', 'z')
78
- * let userObj = User(0, 0, 0)
79
- * // => {x: 0, y: 0, z: 0}
80
- ```
81
- * @param fields - A list of field names
82
- * @returns A function that can be called with the field values
83
- */
84
- export function namedtuple(...fields: string[]) {
85
- return (...args) => fields.reduce((prev, f, i) => set(f, prev, args[i], false, true), {})
86
- }
87
-
88
- /**
89
- * Iterates over elements of collection, returning an array of all elements where predicate returns truthy value.
90
- *
91
- * The predicate is invoked with three arguments: `(value, index|key, arr)`.
92
- *
93
- * @example
94
- ```js
95
- * let users = [
96
- { 'user': 'barney', 'age': 36, 'active': true },
97
- { 'user': 'fred', 'age': 40, 'active': false }
98
- ]
99
-
100
- filter(users, o => !o.active)
101
- // => objects for ['fred']
102
-
103
- // The shape iteratee shorthand.
104
- filter(users, { age: 36, active: true })
105
- // => objects for ['barney']
106
-
107
- // The property iteratee shorthand.
108
- filter(users, 'active')
109
- // => objects for ['barney']
110
- ```
111
- * @param {Array} arr The collection to iterate over
112
- * @param {Function} fn The predicate function invoked for each item
113
- * @returns {Array} The new filtered array
114
- */
115
- export function filter(arr, fn: Iteratee | PropertyKey | Object = isNull) {
116
- if (Array.isArray(arr)) {
117
- if (isFunction(fn)) return arr.filter(fn)
118
- if (isNumber(fn) || isString(fn) || isSymbol(fn)) return arr.filter((x) => get(fn, x))
119
- if (isObject(fn)) return arr.filter(matches(fn))
120
- }
121
- }
122
-
123
- /**
124
- * Iterates over elements of collection, returning the first element where predicate returns truthy value. The predicate is invoked with three arguments: `(value, index|key, collection)`.
125
- * @example
126
- ```js
127
- let users = [
128
- { 'user': 'barney', 'age': 36, 'active': true },
129
- { 'user': 'fred', 'age': 40, 'active': false },
130
- { 'user': 'pebbles', 'age': 1, 'active': true }
131
- ]
132
-
133
- find(users, (o) => o.age < 40)
134
- // => object for 'barney'
135
-
136
- // The shape iteratee shorthand.
137
- find(users, { 'age': 1, 'active': true })
138
- // => object for 'pebbles'
139
-
140
- // The `property` iteratee shorthand.
141
- find(users, 'active')
142
- // => object for 'barney'
143
- ```
144
- * @param {Array} arr The collection to iterate over.
145
- * @param {Function} fn The function invoked per iteration.
146
- * @returns {*} The matched element, else `undefined`.
147
- * @see {@link findRight}
148
- */
149
- export function find(arr, fn: Iteratee | PropertyKey | Object) {
150
- if (Array.isArray(arr)) {
151
- if (isFunction(fn)) return arr.find(fn)
152
- if (isNumber(fn) || isString(fn) || isSymbol(fn)) return arr.find((x) => x?.[fn])
153
- if (isObject(fn)) return arr.find(matches(fn))
154
- }
155
- }
156
- /**
157
- * This method is like {@link find} except that it iterates from right to left.
158
- * @example
159
- ```js
160
- findRight([1, 2, 3, 4], (n) => n % 2 === 1)
161
- // => 3
162
- ```
163
- * @param {Array} arr The collection to iterate over.
164
- * @param {Function} fn The function invoked per iteration.
165
- * @returns {*} The matched element, else `undefined`.
166
- * @see {@link find}
167
- */
168
- export function findRight(arr, fn: Iteratee | PropertyKey | Object) {
169
- if (Array.isArray(arr)) {
170
- for (let i = arr.length - 1; i >= 0; i--) {
171
- const x = arr[i]
172
- if (typeof fn === 'function') {
173
- if (fn(x)) return x
174
- } else if (typeof fn === 'string') {
175
- if (x?.[fn]) return x
176
- } else if (isObject(fn)) {
177
- if (matches(fn)(x)) return x
178
- }
179
- }
180
- }
181
- }
182
-
183
- /**
184
- * Performs an efficient array insert operation in the given array. If the index or the array is invalid, it just returns the given array.
185
- *
186
- * **Note:** Uses the same behavior as `Array.splice`.
187
- *
188
- * @param {Array<*>} arr The given array to insert into
189
- * @param {number} index The index of the array insert operation.
190
- * @param {*} value The value to insert in the array at the given `index`.
191
- * @returns {Array<*>} The given array.
192
- */
193
- export function insert(arr: any[], index: number, value) {
194
- if (!arr || arr.length <= index || index < 0) return arr
195
- arr.splice(index, 0, value)
196
- return arr
197
- }
198
-
199
- /**
200
- * Creates a function that performs a partial deep comparison between a given object and `shape`, returning `true` if the given object has equivalent property values, else `false`.
201
- * @example
202
- ```js
203
- let objects = [
204
- { a: 1, b: 2, c: 3 },
205
- { a: 4, b: 5, c: 6 }
206
- ]
207
-
208
- filter(objects, matches({ a: 4, c: 6 }))
209
- // => [{ a: 4, b: 5, c: 6 }]
210
- ```
211
- * @param shape
212
- * @returns
213
- */
214
- export const matches = (shape) => (obj) => {
215
- if (!shape || !obj) return false
216
- for (const key in shape) {
217
- if (obj[key] !== shape[key]) return false
218
- }
219
- return true
220
- }
221
-
222
- /**
223
- * Iterates over elements of collection and invokes `iteratee` for each element. The iteratee is invoked with three arguments: `(value, index|key, collection)`. Iteratee functions may exit iteration early by explicitly returning `false`.
224
- * @example
225
- ```js
226
- forEach([1, 2], (value) => {
227
- console.log(value)
228
- })
229
- // => Logs `1` then `2`.
230
-
231
- forEach({ 'a': 1, 'b': 2 }, (value, key) => {
232
- console.log(key)
233
- })
234
- // => Logs 'a' then 'b' (iteration order is not guaranteed).
235
- ```
236
- * @param {Array|Object} collection The collection to iterate over.
237
- * @param {Iteratee} fn The function invoked per iteration.
238
- * @returns {*} Returns `collection`.
239
- * @see {@link forEachRight}
240
- * @see {@link filter}
241
- * @see {@link map}
242
- */
243
- export function forEach<T>(collection: T[], fn: Iteratee<T>)
244
- export function forEach<T>(collection: Iterable<T>, fn: Iteratee<T>)
245
- export function forEach<T>(collection: Object, fn: Iteratee<T>)
246
- export function forEach<T>(collection, fn: Iteratee<T>) {
247
- if (Array.isArray(collection)) {
248
- for (let i = 0; i < collection.length; i++) {
249
- const res = fn(collection[i], i, collection)
250
- if (res === false) return collection
251
- }
252
- } else if (isIterable(collection)) {
253
- for (const [index, value] of enumerate(collection)) {
254
- const res = fn(value as T, index, collection)
255
- if (res === false) return collection
256
- }
257
- } else {
258
- for (const key of keys(collection)) {
259
- const res = fn(collection[key], key, collection)
260
- if (res === false) return collection
261
- }
262
- }
263
- }
264
-
265
- /**
266
- * This method is like {@link forEach} except that it iterates over the collection from right to left.
267
-
268
- * @example
269
- ```js
270
- forEachRight([1, 2], (value) => {
271
- console.log(value)
272
- })
273
- // => Logs `2` then `1`.
274
- ```
275
- * @param {Array|Object} collection The collection to iterate over.
276
- * @param {Iteratee} fn The function invoked per iteration.
277
- * @returns {*} Returns `collection`.
278
- * @see {@link forEach}
279
- * @see {@link filter}
280
- * @see {@link map}
281
- */
282
- export function forEachRight(collection: any[] | Object, fn: Iteratee) {
283
- if (Array.isArray(collection)) {
284
- for (let i = collection.length - 1; i >= 0; i--) {
285
- const value = collection[i]
286
- const res = fn(value, i, collection)
287
- if (res === false) return collection
288
- }
289
- } else if (isObject(collection)) {
290
- const keys = Object.keys(collection)
291
- for (let i = keys.length - 1; i >= 0; i--) {
292
- const key = keys[i]
293
- const value = collection[key]
294
- const res = fn(value, i, collection)
295
- if (res === false) return collection
296
- }
297
- }
298
- return collection
299
- }
300
-
301
- /**
302
- * Flattens an array or object. Arrays will be flattened recursively up to `depth` times. Objects will be flattened recursively.
303
- * @example
304
- ```js
305
- flatten([1, [2, [3, [4]], 5]])
306
- // => [1, 2, [3, [4]], 5]
307
-
308
- flatten({
309
- dates: {
310
- expiry_date: '30 sep 2018',
311
- available: '30 sep 2017',
312
- min_contract_period: [
313
- {
314
- id: 1,
315
- name: '1 month'
316
- }
317
- ]
318
- },
319
- price: {
320
- currency: 'RM',
321
- value: 1500
322
- }
323
- })
324
- // => {
325
- 'dates.expiry_date': '30 sep 2018',
326
- 'dates.available': '30 sep 2017',
327
- 'dates.min_contract_period[0].id': 1,
328
- 'dates.min_contract_period[0].name': '1 month',
329
- 'price.currency': 'RM',
330
- 'price.value': 1500
331
- }
332
- ```
333
- * @param {Array|Object} arr The array or object to flatten.
334
- * @param {number} [depth=1] The max recursion depth.
335
- * @returns {*} The new flattened array or object.
336
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat Array.flat()}
337
- */
338
- export function flatten(arr: any[] | Object, depth: boolean | number = 1) {
339
- if (!depth) return arr
340
- if (Array.isArray(arr)) return flattenArray(arr, depth, [])
341
- if (isObject(arr)) return flattenObj(arr)
342
- return arr
343
- }
344
-
345
- function flattenArray(arr: any[], depth: boolean | number = 1, result: any[] = []) {
346
- for (const value of arr) {
347
- if (depth && Array.isArray(value)) {
348
- flattenArray(value, typeof depth === 'number' ? depth - 1 : depth, result)
349
- } else {
350
- result.push(value)
351
- }
352
- }
353
- return result
354
- }
355
-
356
- function flattenObj(obj, prefix = '', result = {}, keepNull = false) {
357
- if (isString(obj) || isNumber(obj) || isBool(obj) || (keepNull && isNull(obj))) {
358
- result[prefix] = obj
359
- return result
360
- }
361
-
362
- if (isArray(obj) || isObject(obj)) {
363
- for (const i of Object.keys(obj)) {
364
- let pref = prefix
365
- if (isArray(obj)) {
366
- pref = `${pref}[${i}]`
367
- } else {
368
- if (prefix) {
369
- pref = `${prefix}.${i}`
370
- } else {
371
- pref = i
372
- }
373
- }
374
- flattenObj(obj[i], pref, result, keepNull)
375
- }
376
- return result
377
- }
378
-
379
- return result
380
- }
381
-
382
- /**
383
- * Creates an array of values by running each element in collection thru iteratee. The iteratee is invoked with three arguments: `(value, index|key, collection)`.
384
- * @example
385
- ```js
386
- function square(n) {
387
- return n * n
388
- }
389
-
390
- map([4, 8], square)
391
- // => [16, 64]
392
-
393
- map({ a: 4, b: 8 }, square)
394
- // => [16, 64] (iteration order is not guaranteed)
395
-
396
- let users = [
397
- { user: 'barney' },
398
- { user: 'fred' }
399
- ]
400
-
401
- // The `property` iteratee shorthand.
402
- map(users, 'user')
403
- // => ['barney', 'fred']
404
- ```
405
- * @param {Array|Object} arr The collection to iterate over.
406
- * @param {Iteratee|PropertyKey} fn The function invoked per iteration.
407
- * @returns Returns the new mapped array.
408
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map Array.map()}
409
- */
410
- export function map(arr, fn: Iteratee | PropertyKey) {
411
- if (Array.isArray(arr)) {
412
- return arr.map((x, i) => {
413
- if (typeof fn === 'function') return fn(x, i, arr)
414
- return x?.[fn]
415
- })
416
- }
417
- if (isObject(arr)) {
418
- return Object.keys(arr).map((key) => {
419
- if (typeof fn === 'function') return fn(arr[key], key, arr)
420
- return get(fn, arr[key])
421
- })
422
- }
423
- }
424
-
425
- /**
426
- * Creates an object composed of the picked object properties.
427
- * @param {Object} obj The source object.
428
- * @param {Iteratee|PropertyKey[]} paths The properties to pick. If `paths` is a function, it will be invoked per property with two values `(value, key)`.
429
- * @returns A new object with the properties.
430
- * @example
431
- ```js
432
- let object = { a: 1, b: '2', c: 3 }
433
-
434
- pick(object, ['a', 'c'])
435
- // => { a: 1, c: 3 }
436
-
437
- pick(object, (x) => isNumber(x))
438
- // => { a: 1, c: 3 }
439
- ```
440
- *
441
- * @see {@link omit}
442
- */
443
- export function pick(obj: Object, paths: Iteratee | PropertyKey[]) {
444
- if (!obj) return {}
445
-
446
- const result = {}
447
-
448
- if (typeof paths === 'function') {
449
- for (const key of Object.keys(obj)) {
450
- if (paths(obj[key], key)) {
451
- result[key] = obj[key]
452
- }
453
- }
454
- return result
455
- }
456
-
457
- for (const key of paths) {
458
- result[key] = get(key, obj)
459
- }
460
- return result
461
- }
462
-
463
- /**
464
- * The opposite of {@link pick} - this method creates an object composed of the own and inherited enumerable property paths of `object` that are not omitted.
465
- * @example
466
- ```js
467
- let object = { 'a': 1, 'b': '2', 'c': 3 }
468
-
469
- omit(object, ['a', 'c'])
470
- // => { 'b': '2' }
471
-
472
- omit(object, (x) => isNumber(x))
473
- // => { 'b': '2' }
474
- ```
475
- * @param {Object} obj The source object.
476
- * @param {Iteratee|PropertyKey[]} paths The property paths to omit.
477
- * @returns {Object} Returns the new object.
478
- * @see {@link pick}
479
- */
480
- export function omit(obj: Object, paths: Iteratee | PropertyKey[]) {
481
- if (!obj) return {}
482
-
483
- const result = {}
484
-
485
- if (typeof paths === 'function') {
486
- for (const key of Object.keys(obj)) {
487
- if (!paths(obj[key], key)) {
488
- result[key] = obj[key]
489
- }
490
- }
491
- return result
492
- }
493
-
494
- Object.assign(result, obj)
495
- for (const key of paths) {
496
- delete result[key]
497
- }
498
- return result
499
- }
500
-
501
- /**
502
- * This method is like {@link find} except that it returns the index of the first element `predicate` returns truthy for instead of the element itself.
503
- * @param {Array} obj The array to inspect.
504
- * @param {string|Object|Iteratee} fn The predicate function
505
- * @param {number} [start=0] The index to search from.
506
- * @returns {number} The index of the found value, else -1
507
- * @example
508
- ```js
509
- let users = [
510
- { 'user': 'barney', 'active': false },
511
- { 'user': 'fred', 'active': false },
512
- { 'user': 'pebbles', 'active': true }
513
- ]
514
-
515
- index(users, (o) => o.user == 'barney')
516
- // => 0
517
-
518
- // The `shape` iteratee shorthand.
519
- index(users, { 'user': 'fred', 'active': false })
520
- // => 1
521
-
522
- // The `property` iteratee shorthand.
523
- index(users, 'active')
524
- // => 2
525
- ```
526
- * @see {@link indexOf}
527
- * @see {@link lastIndex}
528
- *
529
- */
530
- export function index(obj, fn: Iteratee | string | Object, start = 0) {
531
- if (obj == null) return
532
- const length = obj.length
533
- if (length && start < 0) {
534
- start = Math.max(start + length, 0)
535
- }
536
- if (!length || start >= length) return -1
537
- if (isObject(fn)) {
538
- fn = matches(fn)
539
- }
540
- for (; start < length; start++) {
541
- if (typeof fn === 'function') {
542
- if (fn(obj[start], start, obj)) return start
543
- } else {
544
- if (obj[start]?.[fn as PropertyKey]) return start
545
- }
546
- }
547
- return -1
548
- }
549
-
550
- /**
551
- * This method is like {@link index} except that it searches for a given value directly, instead of using a predicate function.
552
- * @param {Array} obj The array to inspect.
553
- * @param {*} value The value to find
554
- * @param {number} [start=0] The index to search from.
555
- * @returns {number} The index of the found value, else -1
556
- * @example
557
- ```js
558
- indexOf([1, 2, 1, 2], 2)
559
- // => 1
560
-
561
- // Search from a `start` index.
562
- indexOf([1, 2, 1, 2], 2, 2)
563
- // => 3
564
- ```
565
- * @see {@link index}
566
- * @see {@link lastIndexOf}
567
- */
568
- export function indexOf(obj, value, start = 0) {
569
- if (obj == null) return
570
- const op = call(obj, 'indexOf', value, start)
571
- if (op != null) return op
572
- const length = obj.length
573
- if (length && start < 0) {
574
- start = Math.max(start + length, 0)
575
- }
576
- if (!length || start >= length) return -1
577
- for (; start < length; start++) {
578
- if (eq(value, obj[start])) return start
579
- }
580
- return -1
581
- }
582
-
583
- /**
584
- * This method is like {@link index} except that it iterates the collection from right to left.
585
- * @param {Array} obj The array to inspect.
586
- * @param {string|Iteratee|Object} fn The function invoked per iteration.
587
- * @param {number} [start] The index to search from.
588
- * @returns {number} The index of the found value, else -1
589
- * @example
590
- ```js
591
- let users = [
592
- { 'user': 'barney', 'active': true },
593
- { 'user': 'fred', 'active': false },
594
- { 'user': 'pebbles', 'active': false }
595
- ]
596
-
597
- findLastIndex(users, (o) => o.user == 'pebbles')
598
- // => 2
599
-
600
- // The `shape` iteratee shorthand.
601
- findLastIndex(users, { 'user': 'barney', 'active': true })
602
- // => 0
603
-
604
- // The `property` iteratee shorthand.
605
- findLastIndex(users, 'active')
606
- // => 0
607
- ```
608
- * @see {@link index}
609
- * @see {@link lastIndexOf}
610
- */
611
- export function lastIndex(obj: any[], fn: string | Iteratee | Object, start?) {
612
- if (obj == null) return
613
- const length = obj.length
614
- if (start == null) start = length - 1
615
- if (!length || start < 0) return -1
616
- if (isObject(fn)) {
617
- fn = matches(fn)
618
- }
619
- for (; start >= 0; start--) {
620
- if (typeof fn === 'function') {
621
- if (fn(obj[start])) return start
622
- } else {
623
- if (obj[start]?.[fn as PropertyKey]) return start
624
- }
625
- }
626
- return -1
627
- }
628
- /**
629
- * This method is like {@link indexOf} except that it iterates the collection from right to left.
630
- * @param {Array} obj The array to inspect.
631
- * @param {*} value The value to find
632
- * @param {number} [start] The index to search from.
633
- * @returns {number} The index of the found value, else -1
634
- * @example
635
- ```js
636
- lastIndexOf([1, 2, 1, 2], 2)
637
- // => 3
638
-
639
- // Search from the `fromIndex`.
640
- lastIndexOf([1, 2, 1, 2], 2, 2)
641
- // => 1
642
- ```
643
- * @see {@link lastIndex}
644
- * @see {@link indexOf}
645
- */
646
- export function lastIndexOf(obj: any[], value, start?) {
647
- if (obj == null) return
648
- const op = call(obj, 'lastIndexOf', value, start)
649
- if (op != null) return op
650
- const length = obj.length
651
- if (start == null) start = length - 1
652
- if (!length || start < 0) return -1
653
- for (; start >= 0; start--) {
654
- if (eq(value, obj[start])) return start
655
- }
656
- return -1
657
- }
658
-
659
- /**
660
- * Creates a shallow clone of `value`. If `deep` is `true` it will clone it recursively.
661
- * @param {*} value
662
- * @param {boolean} [deep=false]
663
- * @return The clone value
664
- * @see {@link cloneArray}
665
- * @see {@link cloneTypedArray}
666
- */
667
- export function clone(value, deep = false) {
668
- if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
669
- return cloneTypedArray(value, deep)
670
- }
671
- if (isArray(value) || isArrayLike(value)) {
672
- return cloneArray(value, deep)
673
- }
674
- if (isObject(value)) {
675
- if (isFunction(value.clone)) {
676
- return value.clone()
677
- }
678
- const copy = {}
679
- for (const key in value) {
680
- if (deep) {
681
- copy[key] = clone(value[key], deep)
682
- } else {
683
- copy[key] = value[key]
684
- }
685
- }
686
- return copy
687
- }
688
- return value
689
- }
690
-
691
- /**
692
- * Clones an array. If `deep` is `false` (default) the clone will be shallow. Otherwise {@link https://developer.mozilla.org/en-US/docs/Web/API/structuredClone structuredClone} is used.
693
- * @param arr The array to clone
694
- * @param [deep=false] Creates a deep clone using `structuredClone` if true.
695
- * @returns The new array
696
- * @see {@link clone}
697
- */
698
- export function cloneArray(arr, deep = false) {
699
- if (!deep) return Array.from(arr)
700
- return structuredClone(arr)
701
- }
702
-
703
- /**
704
- * Clones a typed array. If `deep` is `false` (default) the clone will be shallow. Otherwise {@link https://developer.mozilla.org/en-US/docs/Web/API/structuredClone structuredClone} is used.
705
- * @param arr The array to clone
706
- * @param [deep=false] Creates a deep clone using `structuredClone` if true.
707
- * @returns The new array
708
- * @see {@link clone}
709
- */
710
- export function cloneTypedArray(typedArray, isDeep) {
711
- const buffer = isDeep ? structuredClone(typedArray) : typedArray.buffer
712
- return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length)
713
- }
714
-
715
- /**
716
- * Creates a duplicate-free version of an array, using a `Set` for equality comparisons, in which only the first occurrence of each element is kept. The order of result values is not guaranteed.
717
- * @param arr The array containing duplicated elements
718
- * @param fn The iteratee invoked per element.
719
- * @returns Returns the new duplicate free array.
720
- * @example
721
- ```js
722
- uniq([2, 1, 2])
723
- // => [2, 1]
724
-
725
- uniq([2.1, 1.2, 2.3], Math.floor)
726
- // => [2.1, 1.2]
727
- ```
728
- *
729
- * @see {@link sortedUniq}
730
- */
731
- export function uniq<T = any>(arr: T[], fn: PropertyKey | Iteratee = id) {
732
- const keys = new Set<T>()
733
- const mapper = typeof fn === 'function' ? fn : (x) => x?.[fn]
734
- for (const x of arr) {
735
- keys.add(mapper(x))
736
- }
737
- return Array.from(keys.values())
738
- }
739
-
740
- /**
741
- * This method is like {@link uniq} except that it sorts the results in ascending order
742
- * @param arr The array containing duplicated elements
743
- * @param fn The iteratee invoked per element.
744
- * @returns Returns the new duplicate free array
745
- * @example
746
- ```js
747
- uniq([2, 1, 2])
748
- // => [1, 2]
749
- ```
750
- * @see {@link uniq}
751
- */
752
- export function sortedUniq(arr, fn: string | Iteratee = id) {
753
- const values = uniq(arr, fn)
754
- values.sort(compare)
755
- return values
756
- }
757
-
758
- function baseMergeDeep(obj, source, key, stack) {
759
- const objValue = obj[key]
760
- const srcValue = source[key]
761
- const stacked = stack.get(srcValue)
762
- if (stacked && (objValue !== stacked || !(key in obj))) {
763
- obj[key] = stacked
764
- return
765
- }
766
-
767
- let newValue: any
768
- let isCommon = newValue === undefined
769
- const isArray = Array.isArray(srcValue)
770
- const isTyped = ArrayBuffer.isView(srcValue)
771
-
772
- if (isArray || isTyped) {
773
- if (Array.isArray(objValue)) {
774
- newValue = objValue
775
- } else if (isArrayLike(objValue)) {
776
- newValue = Array.from(objValue)
777
- } else if (isTyped) {
778
- isCommon = false
779
- newValue = cloneTypedArray(srcValue, true)
780
- } else {
781
- newValue = []
782
- }
783
- } else if (isObject(srcValue)) {
784
- newValue = objValue
785
- if (!isObject(objValue)) {
786
- newValue = srcValue
787
- }
788
- } else {
789
- isCommon = false
790
- }
791
- if (isCommon) {
792
- stack.set(srcValue, newValue)
793
- baseMerge(newValue, srcValue, stack)
794
- stack.delete(srcValue)
795
- }
796
- obj[key] = newValue
797
- }
798
-
799
- function baseMerge(obj, source, stack?) {
800
- if (obj === source) return obj
801
- for (const key of Object.keys(source)) {
802
- const srcValue = source[key]
803
- const objValue = obj[key]
804
- if (typeof srcValue === 'object' && srcValue !== null) {
805
- baseMergeDeep(obj, source, key, stack || new WeakMap())
806
- } else {
807
- if (objValue !== srcValue) {
808
- obj[key] = srcValue
809
- }
810
- }
811
- }
812
- }
813
-
814
- /**
815
- * Recursively merges own and inherited enumerable string keyed properties of source objects into the destination object. Source properties that resolve to `undefined` are skipped if a destination value exists. Array and plain object properties are merged recursively. Other objects and value types are overridden by assignment. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
816
- *
817
- * Note: this method mutates `object`
818
- *
819
- *
820
- * @param {Object} object The destination object.
821
- * @param {...Object} sources The source objects.
822
- * @returns Returns `object`.
823
- *
824
- * @example
825
- ```js
826
- let object = {
827
- 'a': [{ 'b': 2 }, { 'd': 4 }]
828
- }
829
-
830
- let other = {
831
- 'a': [{ 'c': 3 }, { 'e': 5 }]
832
- }
833
-
834
- merge(object, other)
835
- // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
836
- ```
837
- */
838
- export function merge(object, ...sources): Object {
839
- for (const source of sources) {
840
- baseMerge(object, source)
841
- }
842
- return object
843
- }
844
-
845
- /**
846
- * Assigns own and inherited enumerable string keyed properties of source objects to the destination object for all destination properties that resolve to `undefined`. Source objects are applied from left to right. Once a property is set, additional values of the same property are ignored.
847
- * **Note:** This method mutates `object`.
848
-
849
- * @param {Object} object The destination object.
850
- * @param {...Object} [sources] The source objects.
851
- * @returns Returns `object`.
852
- * @example
853
- ```js
854
- defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 })
855
- // => { 'a': 1, 'b': 2 }
856
- ```
857
- */
858
- export function defaults(object: Object, ...sources: Object[]) {
859
- for (const source of sources) {
860
- for (const key in source) {
861
- if (object[key] === undefined) {
862
- object[key] = source[key]
863
- }
864
- }
865
- }
866
- return object
867
- }
868
-
869
- /**
870
- * Returns a generator of array values not included in the other given arrays using a `Set` for equality comparisons. The order and references of result values are not guaranteed.
871
- * @param args The initial arrays
872
- * @example
873
- ```js
874
- [...difference([2, 1], [2, 3])]
875
- // => [1]
876
- ```
877
- * @see {@link union}
878
- * @see {@link intersection}
879
- */
880
- export function* difference(...args: Array<Iterable<any>>) {
881
- const sets = args.map((arr) => new Set(arr))
882
- const setA = sets[0]
883
-
884
- for (let i = 1; i < sets.length; i++) {
885
- for (const x of sets[i].values()) {
886
- if (!setA.delete(x)) setA.add(x)
887
- }
888
- }
889
-
890
- for (const x of setA.values()) {
891
- yield x
892
- }
893
- }
894
-
895
- /**
896
- * Creates a generator of unique values that are included in all given arrays.
897
- * @param args The arrays to inspect
898
- * @example
899
- ```js
900
- [...intersection([2, 1], [2, 3])]
901
- // => [2]
902
- ```
903
- * @see {@link difference}
904
- * @see {@link union}
905
- */
906
- export function* intersection(...args: Array<Iterable<any>>) {
907
- const sets = args.map((arr) => new Set(arr))
908
- // build a counter map to find items in all
909
- const results = new Map()
910
- const total = sets.length
911
-
912
- for (let i = 0; i < total; i++) {
913
- for (const x of sets[i].values()) {
914
- const count = results.get(x) || 0
915
- results.set(x, count + 1)
916
- }
917
- }
918
-
919
- for (const [key, value] of results.entries()) {
920
- if (value === total) yield key
921
- }
922
- }
923
-
924
- /**
925
- * Creates a generator of unique values from all given arrays using `Set` for equality comparisons.
926
- * @param args The arrays to perform union on.
927
- * @example
928
- ```js
929
- [...union([2], [1, 2])]
930
- // => [2, 1]
931
- ```
932
- * @see {@link difference}
933
- * @see {@link intersection}
934
- */
935
- export function* union(...args: Array<Iterable<any>>) {
936
- const results = new Set()
937
- for (const arr of args) {
938
- for (const item of arr) {
939
- results.add(item)
940
- }
941
- }
942
- for (const item of results.values()) {
943
- yield item
944
- }
945
- }
946
-
947
- /**
948
- * Creates an object composed of keys generated from the results of running each element of `arr` thru `func`. The order of grouped values is determined by the order they occur in `arr`. The corresponding value of each key is an array of elements responsible for generating the key.
949
- *
950
- * @param arr The collection to iterate over.
951
- * @param [func=id] The iteratee to transform keys.
952
- * @returns Returns the aggregated object.
953
- *
954
- * @example
955
- ```js
956
- groupBy([6.1, 4.2, 6.3], Math.floor)
957
- // => { '4': [4.2], '6': [6.1, 6.3] }
958
-
959
- // The `property` iteratee shorthand.
960
- groupBy(['one', 'two', 'three'], 'length')
961
- // => { '3': ['one', 'two'], '5': ['three'] }
962
- ```
963
- */
964
- export function groupBy(arr: Iterable<any> | Object, func: Iteratee | PropertyKey = id): Object {
965
- const results = {}
966
- const useKey = typeof func === 'function' ? func : partial(get, func)
967
- forEach(arr, (value) => {
968
- const groupKey = useKey(value)
969
- const values = results[groupKey] || []
970
- values.push(value)
971
- results[groupKey] = values
972
- })
973
- return results
974
- }
975
-
976
- /**
977
- * Similar to {@link groupBy} but it returns a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map Map} object with the results.
978
- *
979
- * @param arr The collection to iterate over.
980
- * @param {Function | PropertyKey} [func=id] The iteratee to transform keys.
981
- * @returns {Map} Returns the aggregated map object.
982
- * @template K, V
983
- *
984
- * @example
985
- ```js
986
- groupByMap([6.1, 4.2, 6.3], Math.floor)
987
- // => Map { 4: [4.2], 6: [6.1, 6.3] }
988
-
989
- // The `property` iteratee shorthand.
990
- groupByMap(['one', 'two', 'three'], 'length')
991
- // => Map { 3: ['one', 'two'], 5: ['three'] }
992
- ```
993
- */
994
- export function groupByMap<K = any, V = any>(
995
- arr: Iterable<any> | Object,
996
- func: Iteratee | PropertyKey = id
997
- ): Map<K, V[]> {
998
- const results = new Map<K, V[]>()
999
- const useKey = typeof func === 'function' ? func : partial(get, func)
1000
- forEach(arr, (value: V) => {
1001
- const groupKey = useKey(value)
1002
- const values = results.get(groupKey) || []
1003
- values.push(value)
1004
- results.set(groupKey, values)
1005
- })
1006
- return results
1007
- }
1008
-
1009
- /**
1010
- * Removes all elements from array that `func` returns truthy for and returns an array of the removed elements.
1011
- * @param arr The array to remove from.
1012
- * @param func The function invoked per iteration or value(s) or value to remove.
1013
- * @returns
1014
- */
1015
- export function remove<T>(arr: T[], func: any) {
1016
- return arr.filter((x, i) => {
1017
- if (isArray(func)) return !func.includes(x)
1018
- else if (isFunction(func)) return !func(x, i, arr)
1019
- return x !== func
1020
- })
1021
- }
1022
-
1023
- // TODO: binary search utils
1024
- // TODO: Counter