atomic-fns 0.2.2 → 0.3.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 (70) hide show
  1. package/.firebaserc +5 -0
  2. package/README.md +9 -4
  3. package/firebase.json +10 -0
  4. package/package.json +9 -9
  5. package/src/collections/index.d.ts +672 -0
  6. package/src/collections/index.js +1091 -0
  7. package/src/collections/index.ts +1186 -0
  8. package/src/datetime/index.d.ts +6 -0
  9. package/src/datetime/index.js +6 -0
  10. package/src/datetime/index.ts +7 -0
  11. package/src/functools/index.d.ts +107 -0
  12. package/src/functools/index.js +219 -0
  13. package/src/functools/index.ts +255 -0
  14. package/src/globals/index.d.ts +286 -0
  15. package/src/globals/index.js +388 -0
  16. package/src/globals/index.ts +451 -0
  17. package/src/index.d.ts +8 -7
  18. package/src/index.js +8 -7
  19. package/src/index.ts +8 -7
  20. package/src/itertools/index.d.ts +225 -0
  21. package/src/itertools/index.js +449 -0
  22. package/src/itertools/index.ts +471 -0
  23. package/src/math/index.d.ts +97 -0
  24. package/src/math/index.js +92 -0
  25. package/src/math/index.ts +152 -0
  26. package/src/{operators.d.ts → operators/index.d.ts} +11 -9
  27. package/src/operators/index.js +171 -0
  28. package/src/operators/index.ts +175 -0
  29. package/src/random/index.d.ts +42 -0
  30. package/src/random/index.js +65 -0
  31. package/src/random/index.ts +66 -0
  32. package/tests/collections.spec.ts +42 -25
  33. package/tests/globals.spec.ts +56 -60
  34. package/tests/itertools.spec.ts +176 -4
  35. package/tests/math.spec.ts +25 -0
  36. package/tests/operators.spec.ts +1 -26
  37. package/tests/random.spec.ts +46 -0
  38. package/tsconfig.json +12 -4
  39. package/src/collections.d.ts +0 -228
  40. package/src/collections.js +0 -553
  41. package/src/collections.ts +0 -641
  42. package/src/datetime.d.ts +0 -5
  43. package/src/datetime.js +0 -5
  44. package/src/datetime.ts +0 -6
  45. package/src/functools.d.ts +0 -40
  46. package/src/functools.js +0 -78
  47. package/src/functools.ts +0 -93
  48. package/src/globals.d.ts +0 -179
  49. package/src/globals.js +0 -309
  50. package/src/globals.ts +0 -377
  51. package/src/itertools.d.ts +0 -20
  52. package/src/itertools.js +0 -98
  53. package/src/itertools.ts +0 -116
  54. package/src/math.d.ts +0 -16
  55. package/src/math.js +0 -70
  56. package/src/math.ts +0 -77
  57. package/src/objects.d.ts +0 -0
  58. package/src/objects.js +0 -1
  59. package/src/objects.ts +0 -0
  60. package/src/operators.js +0 -109
  61. package/src/operators.ts +0 -130
  62. package/src/random.d.ts +0 -22
  63. package/src/random.js +0 -48
  64. package/src/random.ts +0 -53
  65. package/src/strings.d.ts +0 -0
  66. package/src/strings.js +0 -1
  67. package/src/strings.ts +0 -0
  68. package/src/util.d.ts +0 -0
  69. package/src/util.js +0 -1
  70. package/src/util.ts +0 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * This module includes classes and functions to work with Date types.
3
+ *
4
+ * @module Date
5
+ */
6
+ export declare const now: number;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * This module includes classes and functions to work with Date types.
3
+ *
4
+ * @module Date
5
+ */
6
+ export const now = new Date().getTime();
@@ -0,0 +1,7 @@
1
+ /**
2
+ * This module includes classes and functions to work with Date types.
3
+ *
4
+ * @module Date
5
+ */
6
+
7
+ export const now = new Date().getTime()
@@ -0,0 +1,107 @@
1
+ /**
2
+ * This module includes functions that promote a more functional programming style.
3
+ *
4
+ * @module Functions
5
+ */
6
+ import { Function } from '../globals/index.js';
7
+ /**
8
+ * Creates a function that invokes `fn` with the this binding of `thisArg` and `partials` as partially applied arguments.
9
+ * @param {Function} fn The function to bind.
10
+ * @param {*} thisArg The `this` value of `fn`.
11
+ * @param {...*} [partials] The arguments to prepend to `fn`.
12
+ * @returns {Function} Returns the new bound function.
13
+ * @see {@link partial}
14
+ */
15
+ export declare const bind: (fn: Function, thisArg: any, ...partials: any[]) => (...args: any[]) => any;
16
+ /**
17
+ * Creates a function that accepts arguments of `func` and either invokes `func` returning its result, if at least arity number of arguments have been provided, or returns a function that accepts the remaining `func` arguments, and so on. The arity of `func` may be specified if `func.length` is not sufficient.
18
+ * @param {Function} func The function to curry.
19
+ * @param {number} [arity=func.length]
20
+ * @returns Returns the new curried function.
21
+ */
22
+ export declare const curry: (func: Function, arity?: number) => Function<any>;
23
+ /**
24
+ * Creates a function that invokes `fn` with partials prepended to the arguments it receives.
25
+ * **Note:** The given function will have `this` bound to `undefined`. If using `this` inside `fn`, consider {@link bind} instead.
26
+ * @param {Function} fn The function to bind.
27
+ * @param {...*} [args] The arguments to apply to `fn`.
28
+ * @returns {Function} Returns the new partially applied function
29
+ */
30
+ export declare const partial: (fn: any, ...args: any[]) => (...args: any[]) => any;
31
+ /**
32
+ * Creates a function composition from a given set of functions that will be each applied on the result of the previous one from left to right.
33
+ * @param {...*} [args] The set of functions to apply.
34
+ * @returns {Function} A new function that applies each given function on the result of the previous one.
35
+ */
36
+ export declare const flow: (...args: any[]) => (x: any) => any;
37
+ /**
38
+ * This is just an alias for the {@link flow} function.
39
+ * @see {@link flow}
40
+ */
41
+ export declare const pipe: (...args: any[]) => (x: any) => any;
42
+ export declare const compose: (...args: any[]) => (x: any) => any;
43
+ /**
44
+ * 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.
45
+ *
46
+ * @param {Function} func The function to have its output memoized.
47
+ * @param {Function} [resolver] The function to resolve the cache key.
48
+ * @return {Function} Returns the new memoized function.
49
+ */
50
+ export declare function memoize(func: Function, resolver?: Function): Function;
51
+ export declare function cache(target: any, name: any, descriptor: any): any;
52
+ /**
53
+ * 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.
54
+ *
55
+ * @param {Function} func The function to debounce.
56
+ * @param {number} wait The number of milliseconds to delay.
57
+ * @param {{ maxWait: number }} [opts] The maximum time `func` is allowed to be delayed before it's invoked.
58
+ * @returns Returns the new debounced function.
59
+ */
60
+ export declare function debounce(func: Function, wait: number, { maxWait }?: {
61
+ maxWait?: number;
62
+ }): Function;
63
+ /**
64
+ * 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.
65
+ *
66
+ * @param {Function} func The function to throttle.
67
+ * @param {number} wait The number of milliseconds to throttle invocations to.
68
+ * @return {Function} Returns the new throttled function.
69
+ */
70
+ export declare function throttle(func: Function, wait: number): Function;
71
+ /**
72
+ * Creates a function that is restricted to invoking `func` once. Repeat calls to the function return the value of the first invocation. The `func` is invoked with the arguments of the created function.
73
+ *
74
+ * @param {Function} func The function to restrict
75
+ * @returns {Function} Returns the new restricted function.
76
+ * @example
77
+ ```js
78
+ let func = x => x
79
+ let single = once(func)
80
+ single(1) // => 1
81
+ single(2) // => 1
82
+ single(3) // => 1
83
+ // ...
84
+ // => `func` is invoked only once.
85
+ ```
86
+ */
87
+ export declare function once(func: Function): (...args: any[]) => any;
88
+ export declare type Maybe<T> = T | undefined;
89
+ export declare type Result<T, E = any> = [Maybe<T>, Maybe<E>];
90
+ /**
91
+ * Wraps a function to catch any exceptions inside and return a `go` style error-return type.
92
+ *
93
+ * @param {Function} fun The function to wrap and catch if it throws.
94
+ * @param {?function(err: E, res: T): *} [onFinally] Optional callback that will be called on the `finally` clause if given.
95
+ * @returns {Function} A new function that wraps `fun`.
96
+ * @template T,E
97
+ */
98
+ export declare function result<T = any, E = unknown>(fun: Function<T>, onFinally?: (err: E, res: T) => any): (...args: any[]) => Result<T, E>;
99
+ /**
100
+ * Wraps a function or promise to catch any exceptions inside and return a `go` style error-return type. This is like {@link result} but it deals with async functions or promises.
101
+ *
102
+ * @param {Function|Promise} awaitable The function or promise to await.
103
+ * @param {?function(err: E, res: T): *} [onFinally] Optional callback that will be called on the `finally` clause if given.
104
+ * @returns {Function} A new function that awaits the `awaitable` param and returns a return type.
105
+ * @template T,E
106
+ */
107
+ export declare function resultAsync<T = any, E = unknown>(awaitable: Promise<T> | Function<Promise<T>>, onFinally?: (err: E, res: T) => any): (...args: any[]) => Promise<Result<T, E>>;
@@ -0,0 +1,219 @@
1
+ /**
2
+ * This module includes functions that promote a more functional programming style.
3
+ *
4
+ * @module Functions
5
+ */
6
+ import { isPromise } from '../globals/index.js';
7
+ /**
8
+ * Creates a function that invokes `fn` with the this binding of `thisArg` and `partials` as partially applied arguments.
9
+ * @param {Function} fn The function to bind.
10
+ * @param {*} thisArg The `this` value of `fn`.
11
+ * @param {...*} [partials] The arguments to prepend to `fn`.
12
+ * @returns {Function} Returns the new bound function.
13
+ * @see {@link partial}
14
+ */
15
+ export const bind = (fn, thisArg, ...partials) => fn.bind(thisArg, ...partials);
16
+ /**
17
+ * Creates a function that accepts arguments of `func` and either invokes `func` returning its result, if at least arity number of arguments have been provided, or returns a function that accepts the remaining `func` arguments, and so on. The arity of `func` may be specified if `func.length` is not sufficient.
18
+ * @param {Function} func The function to curry.
19
+ * @param {number} [arity=func.length]
20
+ * @returns Returns the new curried function.
21
+ */
22
+ export const curry = (func, arity) => {
23
+ if (typeof func !== 'function' || func.length < 2)
24
+ return func;
25
+ if (typeof arity !== 'number')
26
+ arity = func.length;
27
+ switch (arity) {
28
+ case 2:
29
+ return (arg0) => (arg1) => func(arg0, arg1);
30
+ case 3:
31
+ return (arg0) => (arg1) => (arg2) => func(arg0, arg1, arg2);
32
+ case 4:
33
+ return (arg0) => (arg1) => (arg2) => (arg3) => func(arg0, arg1, arg2, arg3);
34
+ case 5:
35
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => func(arg0, arg1, arg2, arg3, arg4);
36
+ case 6:
37
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => func(arg0, arg1, arg2, arg3, arg4, arg5);
38
+ case 7:
39
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => func(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
40
+ case 8:
41
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => (arg7) => func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
42
+ case 9:
43
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => (arg7) => (arg8) => func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
44
+ default:
45
+ throw Error('The specified function uses too many arguments. Consider refactoring it.');
46
+ }
47
+ };
48
+ /**
49
+ * Creates a function that invokes `fn` with partials prepended to the arguments it receives.
50
+ * **Note:** The given function will have `this` bound to `undefined`. If using `this` inside `fn`, consider {@link bind} instead.
51
+ * @param {Function} fn The function to bind.
52
+ * @param {...*} [args] The arguments to apply to `fn`.
53
+ * @returns {Function} Returns the new partially applied function
54
+ */
55
+ export const partial = (fn, ...args) => bind(fn, undefined, ...args);
56
+ /**
57
+ * Creates a function composition from a given set of functions that will be each applied on the result of the previous one from left to right.
58
+ * @param {...*} [args] The set of functions to apply.
59
+ * @returns {Function} A new function that applies each given function on the result of the previous one.
60
+ */
61
+ export const flow = (...args) => (x) => {
62
+ for (const fn of args) {
63
+ x = fn(x);
64
+ }
65
+ return x;
66
+ };
67
+ /**
68
+ * This is just an alias for the {@link flow} function.
69
+ * @see {@link flow}
70
+ */
71
+ export const pipe = flow;
72
+ export const compose = (...args) => flow(args.reverse());
73
+ /**
74
+ * 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.
75
+ *
76
+ * @param {Function} func The function to have its output memoized.
77
+ * @param {Function} [resolver] The function to resolve the cache key.
78
+ * @return {Function} Returns the new memoized function.
79
+ */
80
+ export function memoize(func, resolver) {
81
+ const cache = new Map();
82
+ return (...args) => {
83
+ const key = resolver ? resolver(...args) : args[0];
84
+ const prev = cache.get(key);
85
+ if (prev !== undefined)
86
+ return prev;
87
+ const value = func(...args);
88
+ cache.set(key, value);
89
+ return value;
90
+ };
91
+ }
92
+ // TODO: also sized lru_cache
93
+ export function cache(target, name, descriptor) {
94
+ const original = descriptor.value;
95
+ if (typeof original === 'function') {
96
+ descriptor.value = memoize(original);
97
+ }
98
+ return descriptor;
99
+ }
100
+ /**
101
+ * 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.
102
+ *
103
+ * @param {Function} func The function to debounce.
104
+ * @param {number} wait The number of milliseconds to delay.
105
+ * @param {{ maxWait: number }} [opts] The maximum time `func` is allowed to be delayed before it's invoked.
106
+ * @returns Returns the new debounced function.
107
+ */
108
+ export function debounce(func, wait, { maxWait } = {}) {
109
+ let timer, maxTimer, lastResult;
110
+ return (...args) => {
111
+ if (timer)
112
+ clearTimeout(timer);
113
+ timer = setTimeout(() => {
114
+ clearTimeout(maxTimer);
115
+ maxTimer = null;
116
+ lastResult = func(...args);
117
+ }, wait);
118
+ if (maxWait && !maxTimer) {
119
+ maxTimer = setTimeout(() => {
120
+ clearTimeout(timer);
121
+ maxTimer = null;
122
+ lastResult = func(...args);
123
+ }, maxWait);
124
+ }
125
+ return lastResult;
126
+ };
127
+ }
128
+ /**
129
+ * 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.
130
+ *
131
+ * @param {Function} func The function to throttle.
132
+ * @param {number} wait The number of milliseconds to throttle invocations to.
133
+ * @return {Function} Returns the new throttled function.
134
+ */
135
+ export function throttle(func, wait) {
136
+ let pending = false;
137
+ return (...args) => {
138
+ if (pending)
139
+ return;
140
+ func(...args);
141
+ pending = true;
142
+ setTimeout(() => {
143
+ pending = false;
144
+ }, wait);
145
+ };
146
+ }
147
+ /**
148
+ * Creates a function that is restricted to invoking `func` once. Repeat calls to the function return the value of the first invocation. The `func` is invoked with the arguments of the created function.
149
+ *
150
+ * @param {Function} func The function to restrict
151
+ * @returns {Function} Returns the new restricted function.
152
+ * @example
153
+ ```js
154
+ let func = x => x
155
+ let single = once(func)
156
+ single(1) // => 1
157
+ single(2) // => 1
158
+ single(3) // => 1
159
+ // ...
160
+ // => `func` is invoked only once.
161
+ ```
162
+ */
163
+ export function once(func) {
164
+ let result, isCalled;
165
+ return (...args) => {
166
+ if (!isCalled) {
167
+ result = func(...args);
168
+ isCalled = true;
169
+ }
170
+ return result;
171
+ };
172
+ }
173
+ /**
174
+ * Wraps a function to catch any exceptions inside and return a `go` style error-return type.
175
+ *
176
+ * @param {Function} fun The function to wrap and catch if it throws.
177
+ * @param {?function(err: E, res: T): *} [onFinally] Optional callback that will be called on the `finally` clause if given.
178
+ * @returns {Function} A new function that wraps `fun`.
179
+ * @template T,E
180
+ */
181
+ export function result(fun, onFinally) {
182
+ return (...args) => {
183
+ let value, err;
184
+ try {
185
+ value = fun(...args);
186
+ }
187
+ catch (error) {
188
+ err = error;
189
+ }
190
+ finally {
191
+ onFinally?.(err, value);
192
+ }
193
+ return [value, err];
194
+ };
195
+ }
196
+ /**
197
+ * Wraps a function or promise to catch any exceptions inside and return a `go` style error-return type. This is like {@link result} but it deals with async functions or promises.
198
+ *
199
+ * @param {Function|Promise} awaitable The function or promise to await.
200
+ * @param {?function(err: E, res: T): *} [onFinally] Optional callback that will be called on the `finally` clause if given.
201
+ * @returns {Function} A new function that awaits the `awaitable` param and returns a return type.
202
+ * @template T,E
203
+ */
204
+ export function resultAsync(awaitable, onFinally) {
205
+ return async (...args) => {
206
+ let value, err;
207
+ try {
208
+ const promise = isPromise(awaitable) ? awaitable : awaitable(...args);
209
+ value = await promise;
210
+ }
211
+ catch (error) {
212
+ err = error;
213
+ }
214
+ finally {
215
+ onFinally?.(err, value);
216
+ }
217
+ return [value, err];
218
+ };
219
+ }
@@ -0,0 +1,255 @@
1
+ /**
2
+ * This module includes functions that promote a more functional programming style.
3
+ *
4
+ * @module Functions
5
+ */
6
+
7
+ import { Function, isPromise } from '../globals/index.js'
8
+
9
+ /**
10
+ * Creates a function that invokes `fn` with the this binding of `thisArg` and `partials` as partially applied arguments.
11
+ * @param {Function} fn The function to bind.
12
+ * @param {*} thisArg The `this` value of `fn`.
13
+ * @param {...*} [partials] The arguments to prepend to `fn`.
14
+ * @returns {Function} Returns the new bound function.
15
+ * @see {@link partial}
16
+ */
17
+ export const bind = (fn: Function, thisArg, ...partials) => fn.bind(thisArg, ...partials)
18
+
19
+ /**
20
+ * Creates a function that accepts arguments of `func` and either invokes `func` returning its result, if at least arity number of arguments have been provided, or returns a function that accepts the remaining `func` arguments, and so on. The arity of `func` may be specified if `func.length` is not sufficient.
21
+ * @param {Function} func The function to curry.
22
+ * @param {number} [arity=func.length]
23
+ * @returns Returns the new curried function.
24
+ */
25
+ export const curry = (func: Function, arity?: number) => {
26
+ if (typeof func !== 'function' || func.length < 2) return func
27
+ if (typeof arity !== 'number') arity = func.length
28
+ switch (arity) {
29
+ case 2:
30
+ return (arg0) => (arg1) => func(arg0, arg1)
31
+ case 3:
32
+ return (arg0) => (arg1) => (arg2) => func(arg0, arg1, arg2)
33
+ case 4:
34
+ return (arg0) => (arg1) => (arg2) => (arg3) => func(arg0, arg1, arg2, arg3)
35
+ case 5:
36
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => func(arg0, arg1, arg2, arg3, arg4)
37
+ case 6:
38
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) =>
39
+ func(arg0, arg1, arg2, arg3, arg4, arg5)
40
+ case 7:
41
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) =>
42
+ func(arg0, arg1, arg2, arg3, arg4, arg5, arg6)
43
+ case 8:
44
+ return (arg0) => (arg1) => (arg2) => (arg3) => (arg4) => (arg5) => (arg6) => (arg7) =>
45
+ func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
46
+ case 9:
47
+ return (arg0) =>
48
+ (arg1) =>
49
+ (arg2) =>
50
+ (arg3) =>
51
+ (arg4) =>
52
+ (arg5) =>
53
+ (arg6) =>
54
+ (arg7) =>
55
+ (arg8) =>
56
+ func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
57
+
58
+ default:
59
+ throw Error('The specified function uses too many arguments. Consider refactoring it.')
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Creates a function that invokes `fn` with partials prepended to the arguments it receives.
65
+ * **Note:** The given function will have `this` bound to `undefined`. If using `this` inside `fn`, consider {@link bind} instead.
66
+ * @param {Function} fn The function to bind.
67
+ * @param {...*} [args] The arguments to apply to `fn`.
68
+ * @returns {Function} Returns the new partially applied function
69
+ */
70
+ export const partial = (fn, ...args) => bind(fn, undefined, ...args)
71
+
72
+ /**
73
+ * Creates a function composition from a given set of functions that will be each applied on the result of the previous one from left to right.
74
+ * @param {...*} [args] The set of functions to apply.
75
+ * @returns {Function} A new function that applies each given function on the result of the previous one.
76
+ */
77
+ export const flow =
78
+ (...args) =>
79
+ (x) => {
80
+ for (const fn of args) {
81
+ x = fn(x)
82
+ }
83
+ return x
84
+ }
85
+
86
+ /**
87
+ * This is just an alias for the {@link flow} function.
88
+ * @see {@link flow}
89
+ */
90
+ export const pipe = flow
91
+
92
+ export const compose = (...args) => flow(args.reverse())
93
+
94
+ /**
95
+ * 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.
96
+ *
97
+ * @param {Function} func The function to have its output memoized.
98
+ * @param {Function} [resolver] The function to resolve the cache key.
99
+ * @return {Function} Returns the new memoized function.
100
+ */
101
+ export function memoize(func: Function, resolver?: Function): Function {
102
+ const cache = new Map()
103
+ return (...args) => {
104
+ const key = resolver ? resolver(...args) : args[0]
105
+ const prev = cache.get(key)
106
+ if (prev !== undefined) return prev
107
+ const value = func(...args)
108
+ cache.set(key, value)
109
+ return value
110
+ }
111
+ }
112
+
113
+ // TODO: also sized lru_cache
114
+ export function cache(target, name, descriptor) {
115
+ const original = descriptor.value
116
+ if (typeof original === 'function') {
117
+ descriptor.value = memoize(original)
118
+ }
119
+ return descriptor
120
+ }
121
+
122
+ /**
123
+ * 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.
124
+ *
125
+ * @param {Function} func The function to debounce.
126
+ * @param {number} wait The number of milliseconds to delay.
127
+ * @param {{ maxWait: number }} [opts] The maximum time `func` is allowed to be delayed before it's invoked.
128
+ * @returns Returns the new debounced function.
129
+ */
130
+ export function debounce(
131
+ func: Function,
132
+ wait: number,
133
+ { maxWait }: { maxWait?: number } = {}
134
+ ): Function {
135
+ let timer, maxTimer, lastResult
136
+ return (...args) => {
137
+ if (timer) clearTimeout(timer)
138
+ timer = setTimeout(() => {
139
+ clearTimeout(maxTimer)
140
+ maxTimer = null
141
+ lastResult = func(...args)
142
+ }, wait)
143
+
144
+ if (maxWait && !maxTimer) {
145
+ maxTimer = setTimeout(() => {
146
+ clearTimeout(timer)
147
+ maxTimer = null
148
+ lastResult = func(...args)
149
+ }, maxWait)
150
+ }
151
+
152
+ return lastResult
153
+ }
154
+ }
155
+
156
+ /**
157
+ * 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.
158
+ *
159
+ * @param {Function} func The function to throttle.
160
+ * @param {number} wait The number of milliseconds to throttle invocations to.
161
+ * @return {Function} Returns the new throttled function.
162
+ */
163
+ export function throttle(func: Function, wait: number): Function {
164
+ let pending = false
165
+ return (...args) => {
166
+ if (pending) return
167
+ func(...args)
168
+ pending = true
169
+ setTimeout(() => {
170
+ pending = false
171
+ }, wait)
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Creates a function that is restricted to invoking `func` once. Repeat calls to the function return the value of the first invocation. The `func` is invoked with the arguments of the created function.
177
+ *
178
+ * @param {Function} func The function to restrict
179
+ * @returns {Function} Returns the new restricted function.
180
+ * @example
181
+ ```js
182
+ let func = x => x
183
+ let single = once(func)
184
+ single(1) // => 1
185
+ single(2) // => 1
186
+ single(3) // => 1
187
+ // ...
188
+ // => `func` is invoked only once.
189
+ ```
190
+ */
191
+ export function once(func: Function) {
192
+ let result, isCalled
193
+ return (...args) => {
194
+ if (!isCalled) {
195
+ result = func(...args)
196
+ isCalled = true
197
+ }
198
+ return result
199
+ }
200
+ }
201
+
202
+ export type Maybe<T> = T | undefined
203
+
204
+ export type Result<T, E = any> = [Maybe<T>, Maybe<E>]
205
+
206
+ /**
207
+ * Wraps a function to catch any exceptions inside and return a `go` style error-return type.
208
+ *
209
+ * @param {Function} fun The function to wrap and catch if it throws.
210
+ * @param {?function(err: E, res: T): *} [onFinally] Optional callback that will be called on the `finally` clause if given.
211
+ * @returns {Function} A new function that wraps `fun`.
212
+ * @template T,E
213
+ */
214
+ export function result<T = any, E = unknown>(
215
+ fun: Function<T>,
216
+ onFinally?: (err: E, res: T) => any
217
+ ) {
218
+ return (...args): Result<T, E> => {
219
+ let value, err
220
+ try {
221
+ value = fun(...args)
222
+ } catch (error) {
223
+ err = error
224
+ } finally {
225
+ onFinally?.(err, value)
226
+ }
227
+ return [value as T, err]
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Wraps a function or promise to catch any exceptions inside and return a `go` style error-return type. This is like {@link result} but it deals with async functions or promises.
233
+ *
234
+ * @param {Function|Promise} awaitable The function or promise to await.
235
+ * @param {?function(err: E, res: T): *} [onFinally] Optional callback that will be called on the `finally` clause if given.
236
+ * @returns {Function} A new function that awaits the `awaitable` param and returns a return type.
237
+ * @template T,E
238
+ */
239
+ export function resultAsync<T = any, E = unknown>(
240
+ awaitable: Promise<T> | Function<Promise<T>>,
241
+ onFinally?: (err: E, res: T) => any
242
+ ) {
243
+ return async (...args): Promise<Result<T, E>> => {
244
+ let value, err
245
+ try {
246
+ const promise = isPromise(awaitable) ? awaitable : awaitable(...args)
247
+ value = await promise
248
+ } catch (error) {
249
+ err = error
250
+ } finally {
251
+ onFinally?.(err, value)
252
+ }
253
+ return [value as T, err]
254
+ }
255
+ }