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