atomic-fns 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintignore +1 -0
  3. package/.eslintrc.json +34 -0
  4. package/.prettierrc +19 -0
  5. package/LICENSE +201 -0
  6. package/README.md +1 -0
  7. package/build/collections.d.ts +204 -0
  8. package/build/collections.js +545 -0
  9. package/build/datetime.d.ts +1 -0
  10. package/build/datetime.js +1 -0
  11. package/build/functools.d.ts +36 -0
  12. package/build/functools.js +79 -0
  13. package/build/globals.d.ts +175 -0
  14. package/build/globals.js +332 -0
  15. package/build/index.d.ts +7 -0
  16. package/build/index.js +7 -0
  17. package/build/itertools.d.ts +16 -0
  18. package/build/itertools.js +102 -0
  19. package/build/math.d.ts +16 -0
  20. package/build/math.js +67 -0
  21. package/build/objects.d.ts +0 -0
  22. package/build/objects.js +1 -0
  23. package/build/operators.d.ts +29 -0
  24. package/build/operators.js +128 -0
  25. package/build/random.d.ts +5 -0
  26. package/build/random.js +28 -0
  27. package/build/strings.d.ts +0 -0
  28. package/build/strings.js +1 -0
  29. package/build/util.d.ts +0 -0
  30. package/build/util.js +1 -0
  31. package/jasmine.json +14 -0
  32. package/package.json +71 -0
  33. package/src/collections.ts +614 -0
  34. package/src/datetime.ts +1 -0
  35. package/src/functools.ts +89 -0
  36. package/src/globals.d.ts +5 -0
  37. package/src/globals.ts +377 -0
  38. package/src/index.ts +7 -0
  39. package/src/itertools.ts +113 -0
  40. package/src/math.ts +73 -0
  41. package/src/objects.ts +0 -0
  42. package/src/operators.ts +126 -0
  43. package/src/random.ts +29 -0
  44. package/src/strings.ts +0 -0
  45. package/src/util.ts +0 -0
  46. package/tests/collections.spec.ts +199 -0
  47. package/tests/globals.spec.ts +232 -0
  48. package/tests/itertools.spec.ts +87 -0
  49. package/tests/operators.spec.ts +62 -0
  50. package/tsconfig.json +103 -0
  51. package/tsconfig.node.json +18 -0
  52. package/tsconfig.xo.json +9 -0
@@ -0,0 +1,614 @@
1
+ /// <reference path='globals.d.ts'/>
2
+ import {
3
+ call,
4
+ Function,
5
+ get,
6
+ isArray,
7
+ isArrayLike,
8
+ isBool,
9
+ isEmpty,
10
+ isFunc,
11
+ isNull,
12
+ isNumber,
13
+ isObject,
14
+ isString,
15
+ Iteratee,
16
+ keys,
17
+ NotImplementedError
18
+ } from './globals.js'
19
+ import { comp, eq, id } from './operators.js'
20
+
21
+ /**
22
+ * A container type that provides contains().
23
+ *
24
+ * @export
25
+ * @interface Container
26
+ */
27
+ export interface Container {
28
+ contains: (x) => boolean
29
+ }
30
+
31
+ /**
32
+ * These are the "rich comparison" methods, as in Python.
33
+ *
34
+ * @export
35
+ * @interface Comparable
36
+ */
37
+ export interface Comparable {
38
+ /** x < y: calls this.lt(other) reflection. */
39
+ lt?: (other) => boolean
40
+ /** x ≤ y: calls this.le(other) reflection. */
41
+ le?: (other) => boolean
42
+ /** x == y: calls this.eq(other) reflection. */
43
+ eq: (other) => boolean
44
+ /** x != y: calls this.ne(other) reflection. */
45
+ ne: (other) => boolean
46
+ /** x > y: calls this.gt(other) reflection. */
47
+ gt?: (other) => boolean
48
+ /** x ≥ y: calls this.ge(other) reflection. */
49
+ ge?: (other) => boolean
50
+ }
51
+
52
+ /**
53
+ * A Collection is an iterable container type.
54
+ * This is an abstract base class for user-defined collection types.
55
+ *
56
+ * @export
57
+ * @abstract
58
+ * @class Collection
59
+ * @implements {Container}
60
+ */
61
+ export abstract class Collection implements Container {
62
+ /**
63
+ * Returns an iterator for the container items
64
+ * @return {Iterator}
65
+ */
66
+ [Symbol.iterator]() {
67
+ return this
68
+ }
69
+
70
+ /**
71
+ * Implements the iterator protocol and returns the next item in the iterable.
72
+ */
73
+ next() {}
74
+
75
+ /**
76
+ * Adds a new item to the container.
77
+ * @param item
78
+ */
79
+ add(item) {}
80
+
81
+ /**
82
+ * Checks if item is present in the container.
83
+ * @param item
84
+ */
85
+ contains(item) {
86
+ return false
87
+ }
88
+
89
+ /**
90
+ * Returns the total number of elements in the container.
91
+ */
92
+ size(): number {
93
+ throw new NotImplementedError()
94
+ }
95
+
96
+ /**
97
+ * Remove the first item from the container where `item == x`
98
+ * @raises ValueError when x is not found
99
+ */
100
+ remove(x) {}
101
+
102
+ /**
103
+ * Retrieve and remove the item at index `i`.
104
+ * @returns the item or undefined if not found.
105
+ */
106
+ pop(i) {}
107
+
108
+ /**
109
+ * Remove all items from the container
110
+ */
111
+ clear() {}
112
+ }
113
+
114
+ /**
115
+ * Implements an iterable that allows backward iteration.
116
+ * @interface Reversible
117
+ */
118
+ export interface Reversible<T = unknown> {
119
+ reversed: () => Iterator<T>
120
+ }
121
+
122
+ /**
123
+ * A sequence is an iterable type with efficient index-based access.
124
+ *
125
+ * @export
126
+ * @abstract
127
+ * @class Sequence
128
+ * @extends {Collection}
129
+ * @template T
130
+ */
131
+ export abstract class Sequence<T> extends Collection implements Reversible<T> {
132
+ /**
133
+ * Return the item at the given key or index
134
+ * @param {*} key
135
+ * @memberof Sequence
136
+ */
137
+ get(key): T | undefined {
138
+ throw new NotImplementedError()
139
+ }
140
+
141
+ /**
142
+ * Set a new value at the given key or index
143
+ *
144
+ * @param {*} key
145
+ * @param {T} val
146
+ * @memberof Sequence
147
+ */
148
+ set(key, val: T) {
149
+ throw new NotImplementedError()
150
+ }
151
+
152
+ /**
153
+ * Deletes the given key or index, and its value.
154
+ * Raises ValueError if not key is found.
155
+ *
156
+ * @param {*} key
157
+ * @memberof Sequence
158
+ */
159
+ delete(key) {
160
+ throw new NotImplementedError()
161
+ }
162
+
163
+ /**
164
+ * Adds a new item to the end of the sequence.
165
+ *
166
+ * @param {T} x
167
+ * @memberof Sequence
168
+ */
169
+ append(x: T) {}
170
+
171
+ /**
172
+ * Append all the items to the sequence.
173
+ *
174
+ * @param {Iterable<T>} iter
175
+ * @memberof Sequence
176
+ */
177
+ extend(iter: Iterable<T>) {}
178
+
179
+ /**
180
+ * Return the index of x in the sequence, or undefined if not found.
181
+ *
182
+ * @param {T} item
183
+ * @return {(number | undefined)}
184
+ * @memberof Sequence
185
+ */
186
+ indexOf(item: T): number | undefined {
187
+ throw new NotImplementedError()
188
+ }
189
+
190
+ size() {
191
+ return 0
192
+ }
193
+
194
+ reversed(): Iterator<T> {
195
+ throw new NotImplementedError()
196
+ }
197
+ }
198
+
199
+ export class FrozenSet<T = any> extends Set<T> {
200
+ constructor(iterable: Iterable<T>) {
201
+ super(iterable)
202
+ return this.freeze()
203
+ }
204
+
205
+ add() {
206
+ throw TypeError('FrozenSet cannot be modified.')
207
+ return this // eslint-disable-line
208
+ }
209
+
210
+ delete() {
211
+ throw TypeError('FrozenSet cannot be modified.')
212
+ return false // eslint-disable-line
213
+ }
214
+
215
+ clear() {
216
+ throw TypeError('FrozenSet cannot be modified.')
217
+ return this // eslint-disable-line
218
+ }
219
+
220
+ freeze() {
221
+ return Object.freeze(this)
222
+ }
223
+ }
224
+
225
+ export const compact = (...arr) => arr.filter((x) => !isEmpty(x))
226
+
227
+ export function namedtuple(...fields: string[]) {
228
+ return (...args) => fields.map((f, i) => [f, args[i]])
229
+ }
230
+
231
+ export function filter(arr, fn: Iteratee | PropertyKey | Object = isNull) {
232
+ if (Array.isArray(arr)) {
233
+ // @ts-expect-error function is not compatible?
234
+ if (typeof fn === 'function') return arr.filter(fn)
235
+ if (typeof fn === 'string') return arr.filter((x) => x?.[fn])
236
+ if (isObject(fn)) return arr.filter(matches(fn))
237
+ }
238
+ }
239
+
240
+ export function find(arr, fn: Iteratee | PropertyKey | Object) {
241
+ if (Array.isArray(arr)) {
242
+ // @ts-expect-error function is not compatible?
243
+ if (typeof fn === 'function') return arr.find(fn)
244
+ if (typeof fn === 'string') return arr.find((x) => x?.[fn])
245
+ if (isObject(fn)) return arr.find(matches(fn))
246
+ }
247
+ }
248
+
249
+ export function findRight(arr, fn: Iteratee | PropertyKey | Object) {
250
+ if (Array.isArray(arr)) {
251
+ for (let i = arr.length - 1; i >= 0; i--) {
252
+ const x = arr[i]
253
+ if (typeof fn === 'function') {
254
+ if (fn(x)) return x
255
+ } else if (typeof fn === 'string') {
256
+ if (x?.[fn]) return x
257
+ } else if (isObject(fn)) {
258
+ if (matches(fn)(x)) return x
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ export const matches = (o) => (x) => {
265
+ for (const key in o) {
266
+ if (!eq(x?.[key], o[key])) return false
267
+ }
268
+ return true
269
+ }
270
+
271
+ export function forEach(arr: any[], fn: Iteratee)
272
+ export function forEach(arr: Object, fn: Iteratee)
273
+ export function forEach(arr: any, fn: any) {
274
+ if (Array.isArray(arr)) return arr.forEach(fn)
275
+ if (isObject(arr)) {
276
+ return Object.keys(arr).forEach((key) => fn(get(arr, key), key, arr))
277
+ }
278
+ }
279
+
280
+ export function flatten(arr, depth: boolean | number = 1) {
281
+ if (!depth) return arr
282
+ if (Array.isArray(arr)) return flattenArray(arr, depth, [])
283
+ if (isObject(arr)) return flattenObj(arr)
284
+ return arr
285
+ }
286
+
287
+ export function flattenArray(arr: any[], depth: boolean | number = 1, result: any[] = []) {
288
+ for (const value of arr) {
289
+ if (depth && Array.isArray(value)) {
290
+ flattenArray(value, typeof depth === 'number' ? depth - 1 : depth, result)
291
+ } else {
292
+ result.push(value)
293
+ }
294
+ }
295
+ return result
296
+ }
297
+
298
+ export function flattenObj(o: any, prefix = '', result = {}, keepNull = false) {
299
+ if (isString(o) || isNumber(o) || isBool(o) || (keepNull && isNull(o))) {
300
+ result[prefix] = o
301
+ return result
302
+ }
303
+
304
+ if (isArray(o) || isObject(o)) {
305
+ for (const i in o) {
306
+ let pref = prefix
307
+ if (isArray(o)) {
308
+ pref = pref + `[${i}]`
309
+ } else {
310
+ if (isEmpty(prefix)) {
311
+ pref = i
312
+ } else {
313
+ pref = prefix + '.' + i
314
+ }
315
+ }
316
+ flattenObj(o[i], pref, result, keepNull)
317
+ }
318
+ return result
319
+ }
320
+ return result
321
+ }
322
+
323
+ export const map = (arr, fn: Function | string) => {
324
+ if (Array.isArray(arr)) {
325
+ return arr.map((x, i) => {
326
+ if (typeof fn === 'string') return x[fn]
327
+ return fn(x, i, arr)
328
+ })
329
+ }
330
+ if (isObject(arr)) {
331
+ return Object.keys(arr).map((key) => {
332
+ if (typeof fn === 'string') return arr[key]?.[fn]
333
+ return fn(arr[key], key, arr)
334
+ })
335
+ }
336
+ }
337
+
338
+ export function pick(obj, paths: Iteratee | string[]) {
339
+ if (obj == null) {
340
+ return {}
341
+ }
342
+ const result = {}
343
+ if (Array.isArray(paths)) {
344
+ for (const key of paths) {
345
+ result[key] = obj[key]
346
+ }
347
+ return result
348
+ } else if (typeof paths === 'function') {
349
+ for (const key in obj) {
350
+ const value = obj[key]
351
+ if (paths(value, key)) result[key] = value
352
+ }
353
+ }
354
+ return result
355
+ }
356
+
357
+ export function omit(obj, paths: Iteratee | string[]) {
358
+ const result = {}
359
+ for (const key in obj) {
360
+ const value = obj[key]
361
+ if (Array.isArray(paths) && !paths.includes(key)) {
362
+ result[key] = value
363
+ } else if (typeof paths === 'function' && !paths(value, key)) {
364
+ result[key] = value
365
+ }
366
+ }
367
+ return result
368
+ }
369
+
370
+ export function contains(arr, y) {
371
+ const op = call(arr, 'contains', y)
372
+ if (op != null) return op
373
+ return indexOf(arr, y) >= 0
374
+ }
375
+
376
+ export function indexOf(obj, x, start = 0) {
377
+ const op = call(obj, 'indexOf', x, start)
378
+ if (op != null) return op
379
+ const length = obj?.length
380
+ if (!length || start >= length) return -1
381
+ if (length && start < 0) {
382
+ start = Math.max(start + length, 0)
383
+ }
384
+ for (; start < length; start++) {
385
+ if (eq(x, obj[start])) return start
386
+ }
387
+ return -1
388
+ }
389
+
390
+ export function lastIndexOf(obj, x, start?) {
391
+ const op = call(obj, 'lastIndexOf', x, start)
392
+ if (op != null) return op
393
+ const length = obj?.length
394
+ if (!length) return -1
395
+ if (start == null) start = length - 1
396
+ for (; start >= 0; start--) {
397
+ if (eq(x, obj[start])) return start
398
+ }
399
+ return -1
400
+ }
401
+
402
+ /**
403
+ * Creates a clone of the given `obj`. If `deep` is `true` it will clone it recursively.
404
+ *
405
+ * @export
406
+ * @param {*} obj
407
+ * @param {boolean} [deep=false]
408
+ * @return The clone value
409
+ */
410
+ export function clone(obj, deep = false) {
411
+ if (ArrayBuffer.isView(obj)) {
412
+ return cloneTypedArray(obj, deep)
413
+ }
414
+ if (isArray(obj) || isArrayLike(obj)) {
415
+ return cloneArray(obj, deep)
416
+ }
417
+ if (isObject(obj)) {
418
+ if (isFunc(obj.clone)) {
419
+ return obj.clone()
420
+ }
421
+ const copy = {}
422
+ for (const key of keys(obj)) {
423
+ if (deep) {
424
+ copy[key] = clone(obj[key], deep)
425
+ } else {
426
+ copy[key] = obj[key]
427
+ }
428
+ }
429
+ return copy
430
+ }
431
+ return obj
432
+ }
433
+
434
+ export function cloneArray(arr, deep = false) {
435
+ if (!deep) return Array.from(arr)
436
+ return arr.map((item) => clone(item, deep))
437
+ }
438
+
439
+ export function cloneArrayBuffer(arrayBuffer) {
440
+ const result = new arrayBuffer.constructor(arrayBuffer.byteLength)
441
+ new Uint8Array(result).set(new Uint8Array(arrayBuffer))
442
+ return result
443
+ }
444
+
445
+ export function cloneTypedArray(typedArray, isDeep) {
446
+ const buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer
447
+ return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length)
448
+ }
449
+
450
+ export function uniq<T = any>(arr: T[], fn: string | Iteratee = id) {
451
+ const keys = new Set<T>()
452
+ for (const x of arr) {
453
+ if (typeof fn === 'function') {
454
+ keys.add(fn(x))
455
+ } else {
456
+ keys.add(get(x, fn))
457
+ }
458
+ }
459
+ return Array.from(keys.values())
460
+ }
461
+
462
+ export function sortedUniq(arr, fn: string | Iteratee = id) {
463
+ const lst = uniq(arr, fn)
464
+ lst.sort(comp)
465
+ return lst
466
+ }
467
+
468
+ function baseMergeDeep(obj, source, key, stack) {
469
+ const objValue = obj[key]
470
+ const srcValue = source[key]
471
+ const stacked = stack.get(srcValue)
472
+ if (stacked && (objValue !== stacked || !(key in obj))) {
473
+ obj[key] = stacked
474
+ return
475
+ }
476
+
477
+ let newValue: any
478
+ let isCommon = newValue === undefined
479
+ const isArray = Array.isArray(srcValue)
480
+ const isTyped = ArrayBuffer.isView(srcValue)
481
+
482
+ if (isArray || isTyped) {
483
+ if (Array.isArray(objValue)) {
484
+ newValue = objValue
485
+ } else if (isArrayLike(objValue)) {
486
+ newValue = Array.from(objValue)
487
+ } else if (isTyped) {
488
+ isCommon = false
489
+ newValue = cloneTypedArray(srcValue, true)
490
+ } else {
491
+ newValue = []
492
+ }
493
+ } else if (isObject(srcValue)) {
494
+ newValue = objValue
495
+ if (!isObject(objValue)) {
496
+ newValue = srcValue
497
+ }
498
+ } else {
499
+ isCommon = false
500
+ }
501
+ if (isCommon) {
502
+ stack.set(srcValue, newValue)
503
+ baseMerge(newValue, srcValue, stack)
504
+ stack.delete(srcValue)
505
+ }
506
+ obj[key] = newValue
507
+ }
508
+
509
+ function baseMerge(obj, source, stack?) {
510
+ if (obj === source) return obj
511
+ for (const key in source) {
512
+ const srcValue = source[key]
513
+ const objValue = obj[key]
514
+ if (typeof srcValue === 'object' && srcValue !== null) {
515
+ baseMergeDeep(obj, source, key, stack ?? new WeakMap())
516
+ } else {
517
+ if (objValue !== srcValue) {
518
+ obj[key] = srcValue
519
+ }
520
+ }
521
+ }
522
+ }
523
+
524
+ /**
525
+ * 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.
526
+ *
527
+ * Note: this method mutates `obj`
528
+ *
529
+ * @export
530
+ * @param {Object} obj
531
+ * @param {...Object} sources
532
+ * @return {Object} The destination object.
533
+ */
534
+ export function merge(obj, ...sources): Object {
535
+ for (const source of sources) {
536
+ baseMerge(obj, source)
537
+ }
538
+ return obj
539
+ }
540
+
541
+ export function* difference(...args) {
542
+ const sets = args.map((arr) => new Set(arr))
543
+ const setA = sets[0]
544
+
545
+ for (let i = 1; i < sets.length; i++) {
546
+ for (const x of sets[i].values()) {
547
+ if (!setA.delete(x)) setA.add(x)
548
+ }
549
+ }
550
+
551
+ for (const x of setA.values()) {
552
+ yield x
553
+ }
554
+ }
555
+
556
+ export function* intersection(...args) {
557
+ const sets = args.map((arr) => new Set(arr))
558
+ // build a counter map to find items in all
559
+ const results = new Map()
560
+ const total = sets.length
561
+
562
+ for (let i = 0; i < total; i++) {
563
+ for (const x of sets[i].values()) {
564
+ const count = results.get(x) || 0
565
+ results.set(x, count + 1)
566
+ }
567
+ }
568
+
569
+ for (const [key, value] of results.entries()) {
570
+ if (value === total) yield key
571
+ }
572
+ }
573
+
574
+ export function* union(...args) {
575
+ const results = new Set()
576
+ for (const arr of args) {
577
+ for (const item of arr) {
578
+ results.add(item)
579
+ }
580
+ }
581
+ for (const item of results.values()) {
582
+ yield item
583
+ }
584
+ }
585
+
586
+ /**
587
+ * 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.
588
+ *
589
+ * @export
590
+ * @param {(any[] | Object)} arr The collection to iterate over.
591
+ * @param {(Iteratee | PropertyKey)} [func=id] The iteratee to transform keys.
592
+ * @return {Object} Returns the composed aggregate object.
593
+ */
594
+ export function groupBy(arr: any[] | Object, func: Iteratee | PropertyKey = id): Object {
595
+ const results = {}
596
+ if (Array.isArray(arr)) {
597
+ for (let i = 0; i < arr.length; i++) {
598
+ const item = arr[i]
599
+ const groupKey = typeof func === 'function' ? func(item, i) : get(item, func)
600
+ const values = results[groupKey] || []
601
+ values.push(item)
602
+ results[groupKey] = values
603
+ }
604
+ } else {
605
+ for (const k in arr) {
606
+ const item = arr[k]
607
+ const groupKey = typeof func === 'function' ? func(item, k) : get(item, func)
608
+ const values = results[groupKey]
609
+ values.push(item)
610
+ results[groupKey] = values
611
+ }
612
+ }
613
+ return results
614
+ }
@@ -0,0 +1 @@
1
+ export const now = new Date().getTime()
@@ -0,0 +1,89 @@
1
+ import { Function } from './globals.js'
2
+
3
+ export const bind = (fn, self, ...args) => fn.bind(self, ...args)
4
+
5
+ export const partial = (fn, ...args) => bind(fn, {}, ...args)
6
+
7
+ export const flow =
8
+ (...args) =>
9
+ (x: any) => {
10
+ for (const fn of args) {
11
+ x = fn(x)
12
+ }
13
+ return x
14
+ }
15
+
16
+ export const pipe = flow
17
+
18
+ export const compose = (...args) => flow(args.reverse())
19
+
20
+ /**
21
+ * Creates a function that memoizes the result of `func`. If `resolver` is provided, it determines the cache key for storing the result based on the arguments provided to the memoized function. By default, the first argument provided to the memoized function is used as the map cache key.
22
+ *
23
+ * @export
24
+ * @param {Function} func The function to have its output memoized.
25
+ * @param {Function} [resolver] The function to resolve the cache key.
26
+ * @return {Function} Returns the new memoized function.
27
+ */
28
+ export function memoize(func: Function, resolver?: Function): Function {
29
+ const cache = new Map()
30
+ return (...args) => {
31
+ const key = resolver ? resolver(...args) : args[0]
32
+ const prev = cache.get(key)
33
+ if (prev !== undefined) return prev
34
+ const value = func(...args)
35
+ cache.set(key, value)
36
+ return value
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Creates a debounced function that delays invoking `func` until after `wait` milliseconds have elapsed since the last time the debounced function was invoked. Subsequent calls to the debounced function return the result of the last successful invocation. Provide options to set the `maxWait` milliseconds, regardless of when the function was last invoked.
42
+ *
43
+ * @export
44
+ * @param {Function} func The function to debounce.
45
+ * @param {number} wait The number of milliseconds to delay.
46
+ * @param {{ maxWait: number }} { maxWait } The maximum time `func` is allowed to be delayed before it's invoked.
47
+ * @return {Function} Returns the new debounced function.
48
+ */
49
+ export function debounce(func: Function, wait: number, { maxWait }: { maxWait: number }): Function {
50
+ let timer, maxTimer, lastResult
51
+ return (...args) => {
52
+ if (timer) clearTimeout(timer)
53
+ timer = setTimeout(() => {
54
+ clearTimeout(maxTimer)
55
+ maxTimer = null
56
+ lastResult = func(...args)
57
+ }, wait)
58
+
59
+ if (maxWait && !maxTimer) {
60
+ maxTimer = setTimeout(() => {
61
+ clearTimeout(timer)
62
+ maxTimer = null
63
+ lastResult = func(...args)
64
+ }, maxWait)
65
+ }
66
+
67
+ return lastResult
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Creates a throttled function that only invokes `func` at most once per every `wait` milliseconds. Subsequent calls to the throttled function return the result of the last successful invocation.
73
+ *
74
+ * @export
75
+ * @param {Function} func The function to throttle.
76
+ * @param {number} time The number of milliseconds to throttle invocations to.
77
+ * @return {Function} Returns the new throttled function.
78
+ */
79
+ export function throttle(func: Function, time: number): Function {
80
+ let pending = false
81
+ return (...args) => {
82
+ if (pending) return
83
+ func(...args)
84
+ pending = true
85
+ setTimeout(() => {
86
+ pending = false
87
+ }, time)
88
+ }
89
+ }
@@ -0,0 +1,5 @@
1
+ interface ErrorConstructor {
2
+ /** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */
3
+ // eslint-disable-next-line @typescript-eslint/ban-types
4
+ captureStackTrace(error: Object, constructor?: Function): void
5
+ }