@thi.ng/memoize 3.3.13 → 4.0.1

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2024-10-05T12:12:32Z
3
+ - **Last updated**: 2024-11-03T16:41:34Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,20 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ # [4.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/memoize@4.0.0) (2024-10-31)
13
+
14
+ #### 🛑 Breaking changes
15
+
16
+ - add async versions of all memoize functions ([#493](https://github.com/thi-ng/umbrella/issues/493)) ([e31543c](https://github.com/thi-ng/umbrella/commit/e31543c))
17
+ - BREAKING CHANGE: remove obsolete arity overrides (i.e. 2/3/4 suffixed versions)
18
+ - add memoizeAsync()
19
+ - add memoizeAsync1()
20
+ - add memoizeAsyncJ()
21
+ - add memoizeAsyncO()
22
+ - refactor memoize fns to be variadic
23
+ - remove obsolete fixed arity versions (e.g. `memoize2O`, 3O, 4O etc.)
24
+ - update tests
25
+
12
26
  ### [3.3.5](https://github.com/thi-ng/umbrella/tree/@thi.ng/memoize@3.3.5) (2024-06-21)
13
27
 
14
28
  #### ♻️ Refactoring
package/README.md CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  ## About
32
32
 
33
- Function memoization with configurable caching.
33
+ Function memoization with configurable caching and support for async functions.
34
34
 
35
35
  This package provides different function memoization implementations for
36
36
  functions with arbitrary arguments and custom result caching using ES6
@@ -48,10 +48,10 @@ based on different strategies. See doc strings for further details.
48
48
  - [defOnce()](https://docs.thi.ng/umbrella/memoize/functions/defOnce.html)
49
49
  - [delay()](https://docs.thi.ng/umbrella/memoize/functions/delay.html)
50
50
  - [doOnce()](https://docs.thi.ng/umbrella/memoize/functions/doOnce.html)
51
- - [memoize()](https://docs.thi.ng/umbrella/memoize/functions/memoize.html)
52
- - [memoize1()](https://docs.thi.ng/umbrella/memoize/functions/memoize1.html)
53
- - [memoizeJ()](https://docs.thi.ng/umbrella/memoize/functions/memoizeJ.html)
54
- - [memoizeO()](https://docs.thi.ng/umbrella/memoize/functions/memoizeO.html)
51
+ - [memoize()](https://docs.thi.ng/umbrella/memoize/functions/memoize.html) / [memoizeAsync()](https://docs.thi.ng/umbrella/memoize/functions/memoizeAsync.html)
52
+ - [memoize1()](https://docs.thi.ng/umbrella/memoize/functions/memoize1.html) / [memoizeAsync1()](https://docs.thi.ng/umbrella/memoize/functions/memoizeAsync1.html)
53
+ - [memoizeJ()](https://docs.thi.ng/umbrella/memoize/functions/memoizeJ.html) / [memoizeAsyncJ()](https://docs.thi.ng/umbrella/memoize/functions/memoizeAsyncJ.html)
54
+ - [memoizeO()](https://docs.thi.ng/umbrella/memoize/functions/memoizeO.html) / [memoizeAsyncO()](https://docs.thi.ng/umbrella/memoize/functions/memoizeAsyncO.html)
55
55
 
56
56
  ## Status
57
57
 
@@ -89,7 +89,7 @@ For Node.js REPL:
89
89
  const mem = await import("@thi.ng/memoize");
90
90
  ```
91
91
 
92
- Package sizes (brotli'd, pre-treeshake): ESM: 506 bytes
92
+ Package sizes (brotli'd, pre-treeshake): ESM: 507 bytes
93
93
 
94
94
  ## Dependencies
95
95
 
@@ -126,7 +126,10 @@ import { LRUCache } from "@thi.ng/cache";
126
126
  ```ts
127
127
  import { memoize1 } from "@thi.ng/memoize";
128
128
 
129
- foo = memoize1((x) => (console.log("exec"), x * 10));
129
+ foo = memoize1((x: number) => {
130
+ console.log("exec");
131
+ return x * 10;
132
+ });
130
133
 
131
134
  foo(1);
132
135
  // exec
@@ -138,7 +141,7 @@ import { EquivMap } from "@thi.ng/associative";
138
141
 
139
142
  // with custom cache
140
143
  foo = memoize1(
141
- (x) => (console.log("exec"), x[0] * 10),
144
+ (x: number[]) => (console.log("exec"), x[0] * 10),
142
145
  // custom ES6 Map impl which compares by value, not by reference
143
146
  new EquivMap()
144
147
  );
@@ -148,6 +151,7 @@ foo([1]);
148
151
  // 10
149
152
 
150
153
  // would be a cache miss w/ native ES6 Map
154
+ // due to lack of value equality semantics
151
155
  foo([1]);
152
156
  // 10
153
157
 
@@ -155,7 +159,7 @@ import { LRUCache } from "@thi.ng/cache";
155
159
 
156
160
  // use LRU cache to limit cache size
157
161
  foo = memoize1(
158
- (x) => (console.log("exec"), x[0] * 10),
162
+ (x: number[]) => (console.log("exec"), x[0] * 10),
159
163
  new LRUCache(null, { maxlen: 3 })
160
164
  );
161
165
  ```
@@ -167,7 +171,10 @@ import { memoize } from "@thi.ng/memoize";
167
171
  import { EquivMap } from "@thi.ng/associative";
168
172
 
169
173
  const dotProduct = memoize(
170
- (x, y) => (console.log("exec"), x[0] * y[0] + x[1] * y[1]),
174
+ (x: number[], y: number[]) => {
175
+ console.log("exec");
176
+ return x[0] * y[0] + x[1] * y[1];
177
+ },
171
178
  new EquivMap()
172
179
  );
173
180
 
@@ -184,11 +191,16 @@ dotProduct([1,2], [3,4]);
184
191
  import { memoizeJ } from "@thi.ng/memoize";
185
192
 
186
193
  const dotProduct = memoizeJ(
187
- (x, y) => (console.log("exec"), x[0] * y[0] + x[1] * y[1])
194
+ (x: number[], y: number[]) => {
195
+ console.log("exec");
196
+ return x[0] * y[0] + x[1] * y[1];
197
+ }
188
198
  );
199
+
189
200
  dotProduct([1, 2], [3, 4]);
190
201
  // exec
191
202
  // 11
203
+
192
204
  dotProduct([1, 2], [3, 4]);
193
205
  // 11
194
206
  ```
package/memoize.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Fn, Fn2, Fn3, Fn4 } from "@thi.ng/api";
1
+ import type { FnAny } from "@thi.ng/api";
2
2
  import type { MapLike } from "./api.js";
3
3
  /**
4
4
  * Function memoization for arbitrary argument counts. Returns augmented
@@ -17,8 +17,12 @@ import type { MapLike } from "./api.js";
17
17
  * @param fn -
18
18
  * @param cache -
19
19
  */
20
- export declare function memoize<A, B>(fn: Fn<A, B>, cache: MapLike<A, B>): Fn<A, B>;
21
- export declare function memoize<A, B, C>(fn: Fn2<A, B, C>, cache: MapLike<[A, B], C>): Fn2<A, B, C>;
22
- export declare function memoize<A, B, C, D>(fn: Fn3<A, B, C, D>, cache: MapLike<[A, B, C], D>): Fn3<A, B, C, D>;
23
- export declare function memoize<A, B, C, D, E>(fn: Fn4<A, B, C, D, E>, cache: MapLike<[A, B, C, D], E>): Fn4<A, B, C, D, E>;
20
+ export declare function memoize<T extends FnAny<any>>(fn: T, cache: MapLike<any, any>): T;
21
+ /**
22
+ * Async version of {@link memoize}.
23
+ *
24
+ * @param fn
25
+ * @param cache
26
+ */
27
+ export declare function memoizeAsync<T extends FnAny<any>>(fn: T, cache: MapLike<any, any>): (...xs: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
24
28
  //# sourceMappingURL=memoize.d.ts.map
package/memoize.js CHANGED
@@ -4,6 +4,13 @@ function memoize(fn, cache) {
4
4
  return cache.has(args) ? cache.get(args) : (cache.set(args, res = fn.apply(null, args)), res);
5
5
  };
6
6
  }
7
+ function memoizeAsync(fn, cache) {
8
+ return async (...args) => {
9
+ let res;
10
+ return cache.has(args) ? cache.get(args) : (cache.set(args, res = await fn.apply(null, args)), res);
11
+ };
12
+ }
7
13
  export {
8
- memoize
14
+ memoize,
15
+ memoizeAsync
9
16
  };
package/memoize1.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Fn } from "@thi.ng/api";
1
+ import type { Fn, MaybePromise } from "@thi.ng/api";
2
2
  import type { MapLike } from "./api.js";
3
3
  /**
4
4
  * Optimized memoization for single arg functions.
@@ -16,4 +16,11 @@ import type { MapLike } from "./api.js";
16
16
  * @param cache -
17
17
  */
18
18
  export declare const memoize1: <A, B>(fn: Fn<A, B>, cache?: MapLike<A, B>) => (x: A) => B;
19
+ /**
20
+ * Async version of {@link memoize1}.
21
+ *
22
+ * @param fn
23
+ * @param cache
24
+ */
25
+ export declare const memoizeAsync1: <A, B>(fn: Fn<A, MaybePromise<B>>, cache?: MapLike<A, B>) => (x: A) => Promise<B>;
19
26
  //# sourceMappingURL=memoize1.d.ts.map
package/memoize1.js CHANGED
@@ -2,6 +2,11 @@ const memoize1 = (fn, cache = /* @__PURE__ */ new Map()) => (x) => {
2
2
  let res;
3
3
  return cache.has(x) ? cache.get(x) : (cache.set(x, res = fn(x)), res);
4
4
  };
5
+ const memoizeAsync1 = (fn, cache = /* @__PURE__ */ new Map()) => async (x) => {
6
+ let res;
7
+ return cache.has(x) ? cache.get(x) : (cache.set(x, res = await fn(x)), res);
8
+ };
5
9
  export {
6
- memoize1
10
+ memoize1,
11
+ memoizeAsync1
7
12
  };
package/memoizej.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Fn, Fn2, Fn3, Fn4, IObjectOf } from "@thi.ng/api";
1
+ import type { FnAny, IObjectOf } from "@thi.ng/api";
2
2
  /**
3
3
  * Function memoization for arbitrary argument counts. Returns augmented
4
4
  * function, which uses `JSON.stringify()` to obtain (and store)
@@ -14,8 +14,12 @@ import type { Fn, Fn2, Fn3, Fn4, IObjectOf } from "@thi.ng/api";
14
14
  * @param fn -
15
15
  * @param cache -
16
16
  */
17
- export declare function memoizeJ<A, B>(fn: Fn<A, B>, cache?: IObjectOf<B>): Fn<A, B>;
18
- export declare function memoizeJ<A, B, C>(fn: Fn2<A, B, C>, cache?: IObjectOf<C>): Fn2<A, B, C>;
19
- export declare function memoizeJ<A, B, C, D>(fn: Fn3<A, B, C, D>, cache?: IObjectOf<D>): Fn3<A, B, C, D>;
20
- export declare function memoizeJ<A, B, C, D, E>(fn: Fn4<A, B, C, D, E>, cache?: IObjectOf<E>): Fn4<A, B, C, D, E>;
17
+ export declare function memoizeJ<T extends FnAny<any>>(fn: T, cache?: IObjectOf<any>): T;
18
+ /**
19
+ * Async version of {@link memoizeJ}.
20
+ *
21
+ * @param fn
22
+ * @param cache
23
+ */
24
+ export declare function memoizeAsyncJ<T extends FnAny<any>>(fn: T, cache?: IObjectOf<any>): (...xs: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
21
25
  //# sourceMappingURL=memoizej.d.ts.map
package/memoizej.js CHANGED
@@ -7,6 +7,16 @@ function memoizeJ(fn, cache = /* @__PURE__ */ Object.create(null)) {
7
7
  return fn.apply(null, args);
8
8
  };
9
9
  }
10
+ function memoizeAsyncJ(fn, cache = /* @__PURE__ */ Object.create(null)) {
11
+ return async (...args) => {
12
+ const key = JSON.stringify(args);
13
+ if (key !== void 0) {
14
+ return key in cache ? cache[key] : cache[key] = await fn.apply(null, args);
15
+ }
16
+ return await fn.apply(null, args);
17
+ };
18
+ }
10
19
  export {
20
+ memoizeAsyncJ,
11
21
  memoizeJ
12
22
  };
package/memoizeo.d.ts CHANGED
@@ -1,11 +1,15 @@
1
- import type { Fn, Fn2, Fn3, Fn4, NumOrString } from "@thi.ng/api";
1
+ import type { Fn, Fn2, Fn3, Fn4, IObjectOf, MaybePromise, NumOrString } from "@thi.ng/api";
2
2
  /**
3
- * The most minimalistic & fastest memoization function of this package. Similar
4
- * to {@link memoize1}, but only supports numbers or strings as keys and uses a
5
- * vanilla JS object as cache.
3
+ * The most minimalistic memoization function of this package, but only supports
4
+ * numbers or strings as arguments (max. 4) and uses a vanilla JS object as
5
+ * cache.
6
6
  *
7
7
  * @remarks
8
- * Also see {@link memoize1}, {@link memoizeJ}, {@link memoize}.
8
+ * If `fn` throws an error, no result value will be cached and no memoization
9
+ * happens for this invocation using the given arguments.
10
+ *
11
+ * Use {@link memoizeAsyncO} for async functions or other functions returning
12
+ * promises.
9
13
  *
10
14
  * @example
11
15
  * ```ts tangle:../export/memoizeo.ts
@@ -28,26 +32,22 @@ import type { Fn, Fn2, Fn3, Fn4, NumOrString } from "@thi.ng/api";
28
32
  * @param fn
29
33
  * @param cache
30
34
  */
31
- export declare const memoizeO: <A extends NumOrString, B>(fn: Fn<A, B>, cache?: Record<NumOrString, B>) => (x: A) => B;
32
- /**
33
- * Like {@link memoizeO}, but for functions with 2 arguments.
34
- *
35
- * @param fn
36
- * @param cache
37
- */
38
- export declare const memoize2O: <A extends NumOrString, B extends NumOrString, C>(fn: Fn2<A, B, C>, cache?: Record<string, C>) => (a: A, b: B) => C;
35
+ export declare function memoizeO<A extends NumOrString, B>(fn: Fn<A, B>, cache?: IObjectOf<B>): Fn<A, B>;
36
+ export declare function memoizeO<A extends NumOrString, B extends NumOrString, C>(fn: Fn2<A, B, C>, cache?: IObjectOf<C>): Fn2<A, B, C>;
37
+ export declare function memoizeO<A extends NumOrString, B extends NumOrString, C extends NumOrString, D>(fn: Fn3<A, B, C, D>, cache?: IObjectOf<D>): Fn3<A, B, C, D>;
38
+ export declare function memoizeO<A extends NumOrString, B extends NumOrString, C extends NumOrString, D extends NumOrString, E>(fn: Fn4<A, B, C, D, E>, cache?: IObjectOf<E>): Fn4<A, B, C, D, E>;
39
39
  /**
40
- * Like {@link memoizeO}, but for functions with 3 arguments.
40
+ * Async version of {@link memoizeO}.
41
41
  *
42
- * @param fn
43
- * @param cache
44
- */
45
- export declare const memoize3O: <A extends NumOrString, B extends NumOrString, C extends NumOrString, D>(fn: Fn3<A, B, C, D>, cache?: Record<string, D>) => (a: A, b: B, c: C) => D;
46
- /**
47
- * Like {@link memoizeO}, but for functions with 4 arguments.
42
+ * @remarks
43
+ * If `fn` throws an error, no result value will be cached and no memoization
44
+ * happens for this invocation using the given arguments.
48
45
  *
49
46
  * @param fn
50
47
  * @param cache
51
48
  */
52
- export declare const memoize4O: <A extends NumOrString, B extends NumOrString, C extends NumOrString, D extends NumOrString, E>(fn: Fn4<A, B, C, D, E>, cache?: Record<string, E>) => (a: A, b: B, c: C, d: D) => E;
49
+ export declare function memoizeAsyncO<A extends NumOrString, B>(fn: Fn<A, MaybePromise<B>>, cache?: IObjectOf<B>): Fn<A, Promise<B>>;
50
+ export declare function memoizeAsyncO<A extends NumOrString, B extends NumOrString, C>(fn: Fn2<A, B, MaybePromise<C>>, cache?: IObjectOf<C>): Fn2<A, B, Promise<C>>;
51
+ export declare function memoizeAsyncO<A extends NumOrString, B extends NumOrString, C extends NumOrString, D>(fn: Fn3<A, B, C, MaybePromise<D>>, cache?: IObjectOf<D>): Fn3<A, B, C, Promise<D>>;
52
+ export declare function memoizeAsyncO<A extends NumOrString, B extends NumOrString, C extends NumOrString, D extends NumOrString, E>(fn: Fn4<A, B, C, D, MaybePromise<E>>, cache?: IObjectOf<E>): Fn4<A, B, C, D, Promise<E>>;
53
53
  //# sourceMappingURL=memoizeo.d.ts.map
package/memoizeo.js CHANGED
@@ -1,19 +1,16 @@
1
- const memoizeO = (fn, cache = /* @__PURE__ */ Object.create(null)) => (x) => x in cache ? cache[x] : cache[x] = fn(x);
2
- const memoize2O = (fn, cache = /* @__PURE__ */ Object.create(null)) => (a, b) => {
3
- const key = a + "-" + b;
4
- return key in cache ? cache[key] : cache[key] = fn(a, b);
5
- };
6
- const memoize3O = (fn, cache = /* @__PURE__ */ Object.create(null)) => (a, b, c) => {
7
- const key = a + "-" + b + "-" + c;
8
- return key in cache ? cache[key] : cache[key] = fn(a, b, c);
9
- };
10
- const memoize4O = (fn, cache = /* @__PURE__ */ Object.create(null)) => (a, b, c, d) => {
11
- const key = a + "-" + b + "-" + c + "-" + d;
12
- return key in cache ? cache[key] : cache[key] = fn(a, b, c, d);
13
- };
1
+ function memoizeO(fn, cache = /* @__PURE__ */ Object.create(null)) {
2
+ return (...xs) => {
3
+ const key = xs.join("-");
4
+ return key in cache ? cache[key] : cache[key] = fn(...xs);
5
+ };
6
+ }
7
+ function memoizeAsyncO(fn, cache = /* @__PURE__ */ Object.create(null)) {
8
+ return async (...xs) => {
9
+ const key = xs.join("-");
10
+ return key in cache ? cache[key] : cache[key] = await fn(...xs);
11
+ };
12
+ }
14
13
  export {
15
- memoize2O,
16
- memoize3O,
17
- memoize4O,
14
+ memoizeAsyncO,
18
15
  memoizeO
19
16
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@thi.ng/memoize",
3
- "version": "3.3.13",
4
- "description": "Function memoization with configurable caching",
3
+ "version": "4.0.1",
4
+ "description": "Function memoization with configurable caching and support for async functions",
5
5
  "type": "module",
6
6
  "module": "./index.js",
7
7
  "typings": "./index.d.ts",
@@ -45,6 +45,7 @@
45
45
  "typescript": "^5.6.2"
46
46
  },
47
47
  "keywords": [
48
+ "async",
48
49
  "cache",
49
50
  "functional",
50
51
  "memoization",
@@ -95,5 +96,5 @@
95
96
  ],
96
97
  "year": 2018
97
98
  },
98
- "gitHead": "11ae480076e61a2263f5730ffb37dfddbf01c7d1\n"
99
+ "gitHead": "1148f3130b867c65141957b4b7617021d7ac7fc9\n"
99
100
  }