atomic-fns 0.2.0 → 0.2.2
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/.esdoc.json +19 -1
- package/.eslintrc.json +1 -0
- package/README.md +3 -6
- package/package.json +6 -5
- package/src/collections.d.ts +4 -0
- package/src/collections.js +422 -439
- package/src/collections.ts +6 -2
- package/src/datetime.d.ts +4 -0
- package/src/datetime.js +5 -1
- package/src/datetime.ts +5 -0
- package/src/functools.d.ts +4 -0
- package/src/functools.js +45 -46
- package/src/functools.ts +4 -0
- package/src/globals.d.ts +7 -3
- package/src/globals.js +175 -195
- package/src/globals.ts +8 -4
- package/src/index.js +7 -7
- package/src/itertools.d.ts +4 -0
- package/src/itertools.js +51 -54
- package/src/itertools.ts +4 -0
- package/src/math.js +45 -42
- package/src/math.ts +4 -0
- package/src/objects.js +1 -1
- package/src/operators.js +73 -92
- package/src/operators.ts +4 -0
- package/src/random.js +26 -26
- package/src/random.ts +5 -1
- package/src/strings.js +1 -1
- package/src/util.js +1 -1
- package/tests/collections.spec.ts +81 -9
- package/tests/globals.spec.ts +40 -2
- package/tests/itertools.spec.ts +17 -10
- package/tests/operators.spec.ts +8 -5
- package/tsconfig.json +10 -2
package/src/collections.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Collections
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import {
|
|
6
|
+
call,
|
|
7
|
+
get,
|
|
8
|
+
isArray,
|
|
9
|
+
isArrayLike,
|
|
10
|
+
isBool,
|
|
11
|
+
isEmpty,
|
|
12
|
+
isFunc,
|
|
13
|
+
isNull,
|
|
14
|
+
isNumber,
|
|
15
|
+
isObject,
|
|
16
|
+
isString,
|
|
17
|
+
keys,
|
|
18
|
+
NotImplementedError,
|
|
19
|
+
set
|
|
20
|
+
} from './globals.js'
|
|
21
|
+
import { comp, eq, id } from './operators.js'
|
|
3
22
|
/**
|
|
4
23
|
* A Collection is an iterable container type.
|
|
5
24
|
* This is an abstract base class for user-defined collection types.
|
|
@@ -10,49 +29,52 @@ import { comp, eq, id } from './operators.js';
|
|
|
10
29
|
* @implements {Container}
|
|
11
30
|
*/
|
|
12
31
|
export class Collection {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Returns an iterator for the container items
|
|
34
|
+
* @return {Iterator}
|
|
35
|
+
*/
|
|
36
|
+
[Symbol.iterator]() {
|
|
37
|
+
return this
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Implements the iterator protocol and returns the next item in the iterable.
|
|
42
|
+
*/
|
|
43
|
+
next() {}
|
|
44
|
+
/**
|
|
45
|
+
* Adds a new item to the container.
|
|
46
|
+
* @param item
|
|
47
|
+
*/
|
|
48
|
+
add(item) {}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if item is present in the container.
|
|
51
|
+
* @param item
|
|
52
|
+
*/
|
|
53
|
+
contains(item) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns the total number of elements in the container.
|
|
59
|
+
*/
|
|
60
|
+
size() {
|
|
61
|
+
throw new NotImplementedError()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Remove the first item from the container where `item == x`
|
|
66
|
+
* @raises ValueError when x is not found
|
|
67
|
+
*/
|
|
68
|
+
remove(x) {}
|
|
69
|
+
/**
|
|
70
|
+
* Retrieve and remove the item at index `i`.
|
|
71
|
+
* @returns the item or undefined if not found.
|
|
72
|
+
*/
|
|
73
|
+
pop(i) {}
|
|
74
|
+
/**
|
|
75
|
+
* Remove all items from the container
|
|
76
|
+
*/
|
|
77
|
+
clear() {}
|
|
56
78
|
}
|
|
57
79
|
/**
|
|
58
80
|
* A sequence is an iterable type with efficient index-based access.
|
|
@@ -64,64 +86,69 @@ export class Collection {
|
|
|
64
86
|
* @template T
|
|
65
87
|
*/
|
|
66
88
|
export class Sequence extends Collection {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Return the item at the given key or index
|
|
91
|
+
* @param {*} key
|
|
92
|
+
* @memberof Sequence
|
|
93
|
+
*/
|
|
94
|
+
get(key) {
|
|
95
|
+
throw new NotImplementedError()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Set a new value at the given key or index
|
|
100
|
+
*
|
|
101
|
+
* @param {*} key
|
|
102
|
+
* @param {T} val
|
|
103
|
+
* @memberof Sequence
|
|
104
|
+
*/
|
|
105
|
+
set(key, val) {
|
|
106
|
+
throw new NotImplementedError()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Deletes the given key or index, and its value.
|
|
111
|
+
* Raises ValueError if not key is found.
|
|
112
|
+
*
|
|
113
|
+
* @param {*} key
|
|
114
|
+
* @memberof Sequence
|
|
115
|
+
*/
|
|
116
|
+
delete(key) {
|
|
117
|
+
throw new NotImplementedError()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Adds a new item to the end of the sequence.
|
|
122
|
+
*
|
|
123
|
+
* @param {T} x
|
|
124
|
+
* @memberof Sequence
|
|
125
|
+
*/
|
|
126
|
+
append(x) {}
|
|
127
|
+
/**
|
|
128
|
+
* Append all the items to the sequence.
|
|
129
|
+
*
|
|
130
|
+
* @param {Iterable<T>} iter
|
|
131
|
+
* @memberof Sequence
|
|
132
|
+
*/
|
|
133
|
+
extend(iter) {}
|
|
134
|
+
/**
|
|
135
|
+
* Return the index of x in the sequence, or undefined if not found.
|
|
136
|
+
*
|
|
137
|
+
* @param {T} item
|
|
138
|
+
* @return {(number | undefined)}
|
|
139
|
+
* @memberof Sequence
|
|
140
|
+
*/
|
|
141
|
+
indexOf(item) {
|
|
142
|
+
throw new NotImplementedError()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
size() {
|
|
146
|
+
return 0
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
reversed() {
|
|
150
|
+
throw new NotImplementedError()
|
|
151
|
+
}
|
|
125
152
|
}
|
|
126
153
|
/**
|
|
127
154
|
* Returns a new immutable Set object with elements from `iterable`. Its contents cannot be altered after it's created.
|
|
@@ -132,27 +159,31 @@ export class Sequence extends Collection {
|
|
|
132
159
|
* @template T
|
|
133
160
|
*/
|
|
134
161
|
export class FrozenSet extends Set {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
162
|
+
constructor(iterable) {
|
|
163
|
+
super(iterable)
|
|
164
|
+
return this.freeze()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
add() {
|
|
168
|
+
throw TypeError('FrozenSet cannot be modified.')
|
|
141
169
|
return this; // eslint-disable-line
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
delete() {
|
|
173
|
+
throw TypeError('FrozenSet cannot be modified.')
|
|
145
174
|
return false; // eslint-disable-line
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
clear() {
|
|
178
|
+
throw TypeError('FrozenSet cannot be modified.')
|
|
149
179
|
return this; // eslint-disable-line
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
freeze() {
|
|
183
|
+
return Object.freeze(this)
|
|
184
|
+
}
|
|
154
185
|
}
|
|
155
|
-
export const compact = (...arr) => arr.filter((x) => !isEmpty(x))
|
|
186
|
+
export const compact = (...arr) => arr.filter((x) => !isEmpty(x))
|
|
156
187
|
/**
|
|
157
188
|
* Creates a function that can be used to create named tuple-like objects.
|
|
158
189
|
* @example
|
|
@@ -167,198 +198,163 @@ export const compact = (...arr) => arr.filter((x) => !isEmpty(x));
|
|
|
167
198
|
* @return
|
|
168
199
|
*/
|
|
169
200
|
export function namedtuple(...fields) {
|
|
170
|
-
|
|
201
|
+
return (...args) => fields.reduce((prev, f, i) => set(prev, f, args[i], false, true), {})
|
|
171
202
|
}
|
|
172
203
|
export function filter(arr, fn = isNull) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (isObject(fn))
|
|
180
|
-
return arr.filter(matches(fn));
|
|
181
|
-
}
|
|
204
|
+
if (Array.isArray(arr)) {
|
|
205
|
+
// @ts-expect-error function is not compatible?
|
|
206
|
+
if (typeof fn === 'function') return arr.filter(fn)
|
|
207
|
+
if (typeof fn === 'string') return arr.filter((x) => get(x, fn))
|
|
208
|
+
if (isObject(fn)) return arr.filter(matches(fn))
|
|
209
|
+
}
|
|
182
210
|
}
|
|
183
211
|
export function find(arr, fn) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (isObject(fn))
|
|
190
|
-
return arr.find(matches(fn));
|
|
191
|
-
}
|
|
212
|
+
if (Array.isArray(arr)) {
|
|
213
|
+
if (typeof fn === 'function') return arr.find(fn)
|
|
214
|
+
if (typeof fn === 'string') return arr.find((x) => x?.[fn])
|
|
215
|
+
if (isObject(fn)) return arr.find(matches(fn))
|
|
216
|
+
}
|
|
192
217
|
}
|
|
193
218
|
export function findRight(arr, fn) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (matches(fn)(x))
|
|
207
|
-
return x;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
219
|
+
if (Array.isArray(arr)) {
|
|
220
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
221
|
+
const x = arr[i]
|
|
222
|
+
if (typeof fn === 'function') {
|
|
223
|
+
if (fn(x)) return x
|
|
224
|
+
} else if (typeof fn === 'string') {
|
|
225
|
+
if (x?.[fn]) return x
|
|
226
|
+
} else if (isObject(fn)) {
|
|
227
|
+
if (matches(fn)(x)) return x
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
211
231
|
}
|
|
212
232
|
export const matches = (o) => (x) => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return true;
|
|
220
|
-
};
|
|
233
|
+
if (!o || !x) return false
|
|
234
|
+
for (const key in o) {
|
|
235
|
+
if (!eq(x[key], o[key])) return false
|
|
236
|
+
}
|
|
237
|
+
return true
|
|
238
|
+
}
|
|
221
239
|
export function forEach(arr, fn) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
240
|
+
if (Array.isArray(arr)) return arr.forEach(fn)
|
|
241
|
+
if (isObject(arr)) {
|
|
242
|
+
return Object.keys(arr).forEach((key) => fn(get(arr, key), key, arr))
|
|
243
|
+
}
|
|
227
244
|
}
|
|
228
245
|
export function flatten(arr, depth = 1) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (isObject(arr))
|
|
234
|
-
return flattenObj(arr);
|
|
235
|
-
return arr;
|
|
246
|
+
if (!depth) return arr
|
|
247
|
+
if (Array.isArray(arr)) return flattenArray(arr, depth, [])
|
|
248
|
+
if (isObject(arr)) return flattenObj(arr)
|
|
249
|
+
return arr
|
|
236
250
|
}
|
|
237
251
|
export function flattenArray(arr, depth = 1, result = []) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return result;
|
|
252
|
+
for (const value of arr) {
|
|
253
|
+
if (depth && Array.isArray(value)) {
|
|
254
|
+
flattenArray(value, typeof depth === 'number' ? depth - 1 : depth, result)
|
|
255
|
+
} else {
|
|
256
|
+
result.push(value)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return result
|
|
247
260
|
}
|
|
248
261
|
export function flattenObj(o, prefix = '', result = {}, keepNull = false) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
else {
|
|
264
|
-
pref = prefix + '.' + i;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
flattenObj(o[i], pref, result, keepNull);
|
|
262
|
+
if (isString(o) || isNumber(o) || isBool(o) || (keepNull && isNull(o))) {
|
|
263
|
+
result[prefix] = o
|
|
264
|
+
return result
|
|
265
|
+
}
|
|
266
|
+
if (isArray(o) || isObject(o)) {
|
|
267
|
+
for (const i in o) {
|
|
268
|
+
let pref = prefix
|
|
269
|
+
if (isArray(o)) {
|
|
270
|
+
pref = pref + `[${i}]`
|
|
271
|
+
} else {
|
|
272
|
+
if (isEmpty(prefix)) {
|
|
273
|
+
pref = i
|
|
274
|
+
} else {
|
|
275
|
+
pref = prefix + '.' + i
|
|
268
276
|
}
|
|
269
|
-
|
|
277
|
+
}
|
|
278
|
+
flattenObj(o[i], pref, result, keepNull)
|
|
270
279
|
}
|
|
271
|
-
return result
|
|
280
|
+
return result
|
|
281
|
+
}
|
|
282
|
+
return result
|
|
272
283
|
}
|
|
273
284
|
export const map = (arr, fn) => {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
};
|
|
285
|
+
if (Array.isArray(arr)) {
|
|
286
|
+
return arr.map((x, i) => {
|
|
287
|
+
if (typeof fn === 'string') return x[fn]
|
|
288
|
+
return fn(x, i, arr)
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
if (isObject(arr)) {
|
|
292
|
+
return Object.keys(arr).map((key) => {
|
|
293
|
+
if (typeof fn === 'string') return get(arr[key], fn)
|
|
294
|
+
return fn(arr[key], key, arr)
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
}
|
|
289
298
|
export function pick(obj, paths) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (paths(value, key))
|
|
304
|
-
result[key] = value;
|
|
305
|
-
}
|
|
299
|
+
if (obj == null) {
|
|
300
|
+
return {}
|
|
301
|
+
}
|
|
302
|
+
const result = {}
|
|
303
|
+
if (Array.isArray(paths)) {
|
|
304
|
+
for (const key of paths) {
|
|
305
|
+
result[key] = obj[key]
|
|
306
|
+
}
|
|
307
|
+
return result
|
|
308
|
+
} else if (typeof paths === 'function') {
|
|
309
|
+
for (const key in obj) {
|
|
310
|
+
const value = obj[key]
|
|
311
|
+
if (paths(value, key)) result[key] = value
|
|
306
312
|
}
|
|
307
|
-
|
|
313
|
+
}
|
|
314
|
+
return result
|
|
308
315
|
}
|
|
309
316
|
export function omit(obj, paths) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
return result;
|
|
317
|
+
const result = {}
|
|
318
|
+
for (const key in obj) {
|
|
319
|
+
const value = obj[key]
|
|
320
|
+
if (Array.isArray(paths) && !paths.includes(key)) {
|
|
321
|
+
result[key] = value
|
|
322
|
+
} else if (typeof paths === 'function' && !paths(value, key)) {
|
|
323
|
+
result[key] = value
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return result
|
|
321
327
|
}
|
|
322
328
|
export function contains(arr, y) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
return indexOf(arr, y) >= 0;
|
|
329
|
+
const op = call(arr, 'contains', y)
|
|
330
|
+
if (op != null) return op
|
|
331
|
+
return indexOf(arr, y) >= 0
|
|
327
332
|
}
|
|
328
333
|
export function indexOf(obj, x, start = 0) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
if (eq(x, obj[start]))
|
|
342
|
-
return start;
|
|
343
|
-
}
|
|
344
|
-
return -1;
|
|
334
|
+
if (obj == null) return
|
|
335
|
+
const op = call(obj, 'indexOf', x, start)
|
|
336
|
+
if (op != null) return op
|
|
337
|
+
const length = obj.length
|
|
338
|
+
if (length && start < 0) {
|
|
339
|
+
start = Math.max(start + length, 0)
|
|
340
|
+
}
|
|
341
|
+
if (!length || start >= length) return -1
|
|
342
|
+
for (; start < length; start++) {
|
|
343
|
+
if (eq(x, obj[start])) return start
|
|
344
|
+
}
|
|
345
|
+
return -1
|
|
345
346
|
}
|
|
346
347
|
export function lastIndexOf(obj, x, start) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
for (; start >= 0; start--) {
|
|
358
|
-
if (eq(x, obj[start]))
|
|
359
|
-
return start;
|
|
360
|
-
}
|
|
361
|
-
return -1;
|
|
348
|
+
if (obj == null) return
|
|
349
|
+
const op = call(obj, 'lastIndexOf', x, start)
|
|
350
|
+
if (op != null) return op
|
|
351
|
+
const length = obj.length
|
|
352
|
+
if (start == null) start = length - 1
|
|
353
|
+
if (!length || start < 0) return -1
|
|
354
|
+
for (; start >= 0; start--) {
|
|
355
|
+
if (eq(x, obj[start])) return start
|
|
356
|
+
}
|
|
357
|
+
return -1
|
|
362
358
|
}
|
|
363
359
|
/**
|
|
364
360
|
* Creates a clone of the given `obj`. If `deep` is `true` it will clone it recursively.
|
|
@@ -369,118 +365,108 @@ export function lastIndexOf(obj, x, start) {
|
|
|
369
365
|
* @return The clone value
|
|
370
366
|
*/
|
|
371
367
|
export function clone(obj, deep = false) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
return obj;
|
|
368
|
+
if (ArrayBuffer.isView(obj)) {
|
|
369
|
+
return cloneTypedArray(obj, deep)
|
|
370
|
+
}
|
|
371
|
+
if (isArray(obj) || isArrayLike(obj)) {
|
|
372
|
+
return cloneArray(obj, deep)
|
|
373
|
+
}
|
|
374
|
+
if (isObject(obj)) {
|
|
375
|
+
if (isFunc(obj.clone)) {
|
|
376
|
+
return obj.clone()
|
|
377
|
+
}
|
|
378
|
+
const copy = {}
|
|
379
|
+
for (const key of keys(obj)) {
|
|
380
|
+
if (deep) {
|
|
381
|
+
copy[key] = clone(obj[key], deep)
|
|
382
|
+
} else {
|
|
383
|
+
copy[key] = obj[key]
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return copy
|
|
387
|
+
}
|
|
388
|
+
return obj
|
|
394
389
|
}
|
|
395
390
|
export function cloneArray(arr, deep = false) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
return arr.map((item) => clone(item, deep));
|
|
391
|
+
if (!deep) return Array.from(arr)
|
|
392
|
+
return arr.map((item) => clone(item, deep))
|
|
399
393
|
}
|
|
400
394
|
export function cloneArrayBuffer(arrayBuffer) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
395
|
+
const result = new arrayBuffer.constructor(arrayBuffer.byteLength)
|
|
396
|
+
new Uint8Array(result).set(new Uint8Array(arrayBuffer))
|
|
397
|
+
return result
|
|
404
398
|
}
|
|
405
399
|
export function cloneTypedArray(typedArray, isDeep) {
|
|
406
|
-
|
|
407
|
-
|
|
400
|
+
const buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer
|
|
401
|
+
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length)
|
|
408
402
|
}
|
|
409
403
|
export function uniq(arr, fn = id) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
return Array.from(keys.values());
|
|
404
|
+
const keys = new Set()
|
|
405
|
+
for (const x of arr) {
|
|
406
|
+
if (typeof fn === 'function') {
|
|
407
|
+
keys.add(fn(x))
|
|
408
|
+
} else {
|
|
409
|
+
keys.add(get(x, fn))
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return Array.from(keys.values())
|
|
420
413
|
}
|
|
421
414
|
export function sortedUniq(arr, fn = id) {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
415
|
+
const lst = uniq(arr, fn)
|
|
416
|
+
lst.sort(comp)
|
|
417
|
+
return lst
|
|
425
418
|
}
|
|
426
419
|
function baseMergeDeep(obj, source, key, stack) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
stack.set(srcValue, newValue);
|
|
464
|
-
baseMerge(newValue, srcValue, stack);
|
|
465
|
-
stack.delete(srcValue);
|
|
466
|
-
}
|
|
467
|
-
obj[key] = newValue;
|
|
420
|
+
const objValue = obj[key]
|
|
421
|
+
const srcValue = source[key]
|
|
422
|
+
const stacked = stack.get(srcValue)
|
|
423
|
+
if (stacked && (objValue !== stacked || !(key in obj))) {
|
|
424
|
+
obj[key] = stacked
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
let newValue
|
|
428
|
+
let isCommon = newValue === undefined
|
|
429
|
+
const isArray = Array.isArray(srcValue)
|
|
430
|
+
const isTyped = ArrayBuffer.isView(srcValue)
|
|
431
|
+
if (isArray || isTyped) {
|
|
432
|
+
if (Array.isArray(objValue)) {
|
|
433
|
+
newValue = objValue
|
|
434
|
+
} else if (isArrayLike(objValue)) {
|
|
435
|
+
newValue = Array.from(objValue)
|
|
436
|
+
} else if (isTyped) {
|
|
437
|
+
isCommon = false
|
|
438
|
+
newValue = cloneTypedArray(srcValue, true)
|
|
439
|
+
} else {
|
|
440
|
+
newValue = []
|
|
441
|
+
}
|
|
442
|
+
} else if (isObject(srcValue)) {
|
|
443
|
+
newValue = objValue
|
|
444
|
+
if (!isObject(objValue)) {
|
|
445
|
+
newValue = srcValue
|
|
446
|
+
}
|
|
447
|
+
} else {
|
|
448
|
+
isCommon = false
|
|
449
|
+
}
|
|
450
|
+
if (isCommon) {
|
|
451
|
+
stack.set(srcValue, newValue)
|
|
452
|
+
baseMerge(newValue, srcValue, stack)
|
|
453
|
+
stack.delete(srcValue)
|
|
454
|
+
}
|
|
455
|
+
obj[key] = newValue
|
|
468
456
|
}
|
|
469
457
|
function baseMerge(obj, source, stack) {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
}
|
|
458
|
+
if (obj === source) return obj
|
|
459
|
+
for (const key in source) {
|
|
460
|
+
const srcValue = source[key]
|
|
461
|
+
const objValue = obj[key]
|
|
462
|
+
if (typeof srcValue === 'object' && srcValue !== null) {
|
|
463
|
+
baseMergeDeep(obj, source, key, stack || new WeakMap())
|
|
464
|
+
} else {
|
|
465
|
+
if (objValue !== srcValue) {
|
|
466
|
+
obj[key] = srcValue
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
484
470
|
}
|
|
485
471
|
/**
|
|
486
472
|
* 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.
|
|
@@ -493,50 +479,48 @@ function baseMerge(obj, source, stack) {
|
|
|
493
479
|
* @return {Object} The destination object.
|
|
494
480
|
*/
|
|
495
481
|
export function merge(obj, ...sources) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
482
|
+
for (const source of sources) {
|
|
483
|
+
baseMerge(obj, source)
|
|
484
|
+
}
|
|
485
|
+
return obj
|
|
500
486
|
}
|
|
501
487
|
export function* difference(...args) {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
488
|
+
const sets = args.map((arr) => new Set(arr))
|
|
489
|
+
const setA = sets[0]
|
|
490
|
+
for (let i = 1; i < sets.length; i++) {
|
|
491
|
+
for (const x of sets[i].values()) {
|
|
492
|
+
if (!setA.delete(x)) setA.add(x)
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
for (const x of setA.values()) {
|
|
496
|
+
yield x
|
|
497
|
+
}
|
|
513
498
|
}
|
|
514
499
|
export function* intersection(...args) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
500
|
+
const sets = args.map((arr) => new Set(arr))
|
|
501
|
+
// build a counter map to find items in all
|
|
502
|
+
const results = new Map()
|
|
503
|
+
const total = sets.length
|
|
504
|
+
for (let i = 0; i < total; i++) {
|
|
505
|
+
for (const x of sets[i].values()) {
|
|
506
|
+
const count = results.get(x) || 0
|
|
507
|
+
results.set(x, count + 1)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
for (const [key, value] of results.entries()) {
|
|
511
|
+
if (value === total) yield key
|
|
512
|
+
}
|
|
529
513
|
}
|
|
530
514
|
export function* union(...args) {
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
515
|
+
const results = new Set()
|
|
516
|
+
for (const arr of args) {
|
|
517
|
+
for (const item of arr) {
|
|
518
|
+
results.add(item)
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
for (const item of results.values()) {
|
|
522
|
+
yield item
|
|
523
|
+
}
|
|
540
524
|
}
|
|
541
525
|
/**
|
|
542
526
|
* 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.
|
|
@@ -547,24 +531,23 @@ export function* union(...args) {
|
|
|
547
531
|
* @return {Object} Returns the composed aggregate object.
|
|
548
532
|
*/
|
|
549
533
|
export function groupBy(arr, func = id) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return results;
|
|
534
|
+
const results = {}
|
|
535
|
+
if (Array.isArray(arr)) {
|
|
536
|
+
for (let i = 0; i < arr.length; i++) {
|
|
537
|
+
const item = arr[i]
|
|
538
|
+
const groupKey = typeof func === 'function' ? func(item, i) : get(item, func)
|
|
539
|
+
const values = results[groupKey] || []
|
|
540
|
+
values.push(item)
|
|
541
|
+
results[groupKey] = values
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
for (const k in arr) {
|
|
545
|
+
const item = arr[k]
|
|
546
|
+
const groupKey = typeof func === 'function' ? func(item, k) : get(item, func)
|
|
547
|
+
const values = results[groupKey]
|
|
548
|
+
values.push(item)
|
|
549
|
+
results[groupKey] = values
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return results
|
|
570
553
|
}
|