@common.js/p-memoize 7.1.0 → 8.0.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.
package/README.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  The [p-memoize](https://www.npmjs.com/package/p-memoize) package exported as CommonJS modules.
4
4
 
5
- Exported from [p-memoize@7.1.0](https://www.npmjs.com/package/p-memoize/v/7.1.0) using https://github.com/etienne-martin/common.js.
5
+ Exported from [p-memoize@8.0.0](https://www.npmjs.com/package/p-memoize/v/8.0.0) using https://github.com/etienne-martin/common.js.
package/dist/index.d.ts CHANGED
@@ -1,15 +1,22 @@
1
1
  import type { AsyncReturnType } from 'type-fest';
2
- export declare type AnyAsyncFunction = (...arguments_: readonly any[]) => Promise<unknown | void>;
3
- export interface CacheStorage<KeyType, ValueType> {
2
+ export type AnyAsyncFunction = (...arguments_: readonly any[]) => Promise<unknown | void>;
3
+ export type CacheStorage<KeyType, ValueType> = {
4
4
  has: (key: KeyType) => Promise<boolean> | boolean;
5
5
  get: (key: KeyType) => Promise<ValueType | undefined> | ValueType | undefined;
6
6
  set: (key: KeyType, value: ValueType) => Promise<unknown> | unknown;
7
7
  delete: (key: KeyType) => unknown;
8
8
  clear?: () => unknown;
9
- }
10
- export interface Options<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType> {
9
+ };
10
+ /**
11
+ Controls whether a fulfilled value should be written to the cache.
12
+ */
13
+ export type ShouldCache<KeyType, ValueType, ArgumentsList extends readonly unknown[] = readonly unknown[]> = (value: ValueType, context: {
14
+ key: KeyType;
15
+ argumentsList: ArgumentsList;
16
+ }) => boolean | Promise<boolean>;
17
+ export type Options<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType> = {
11
18
  /**
12
- Determines the cache key for storing the result based on the function arguments. By default, __only the first argument is considered__ and it only works with [primitives](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
19
+ Determines the cache key for storing the result based on the function arguments. By default, __only the first argument is considered__ and it only works with [primitives](https://developer.mozilla.org/docs/Glossary/Primitive).
13
20
 
14
21
  A `cacheKey` function can return any type supported by `Map` (or whatever structure you use in the `cache` option).
15
22
 
@@ -41,7 +48,34 @@ export interface Options<FunctionToMemoize extends AnyAsyncFunction, CacheKeyTyp
41
48
  @example new WeakMap()
42
49
  */
43
50
  readonly cache?: CacheStorage<CacheKeyType, AsyncReturnType<FunctionToMemoize>> | false;
44
- }
51
+ /**
52
+ Controls whether a fulfilled value should be written to the cache.
53
+
54
+ It runs after the function fulfills and before `cache.set`.
55
+
56
+ - Omit to keep current behavior (always write).
57
+ - Return `false` to skip writing to the cache (in-flight de-duplication is still cleared).
58
+ - Throw or reject to propagate the error and skip caching.
59
+
60
+ @example
61
+ ```
62
+ import pMemoize from 'p-memoize';
63
+
64
+ // Only cache defined values
65
+ const getMaybe = pMemoize(async key => db.get(key), {
66
+ shouldCache: value => value !== undefined,
67
+ });
68
+
69
+ // Only cache non-empty arrays
70
+ const search = pMemoize(async query => fetchResults(query), {
71
+ shouldCache: value => Array.isArray(value) && value.length > 0,
72
+ });
73
+ ```
74
+
75
+ Note: This only affects writes; reads from the cache are unchanged.
76
+ */
77
+ readonly shouldCache?: ShouldCache<CacheKeyType, AsyncReturnType<FunctionToMemoize>, Parameters<FunctionToMemoize>>;
78
+ };
45
79
  /**
46
80
  [Memoize](https://en.wikipedia.org/wiki/Memoization) functions - An optimization used to speed up consecutive function calls by caching the result of calls with identical input.
47
81
 
@@ -66,13 +100,14 @@ await delay(2000);
66
100
  await memoizedGot('https://sindresorhus.com');
67
101
  ```
68
102
  */
69
- export default function pMemoize<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType>(fn: FunctionToMemoize, { cacheKey, cache, }?: Options<FunctionToMemoize, CacheKeyType>): FunctionToMemoize;
103
+ export default function pMemoize<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType = Parameters<FunctionToMemoize>[0], OptionsType = Options<FunctionToMemoize, CacheKeyType>>(fn: FunctionToMemoize, options?: OptionsType & Options<FunctionToMemoize, CacheKeyType>): FunctionToMemoize;
70
104
  /**
71
- - Only class methods and getters/setters can be memoized, not regular functions (they aren't part of the proposal);
72
- - Only [TypeScript’s decorators](https://www.typescriptlang.org/docs/handbook/decorators.html#parameter-decorators) are supported, not [Babel’s](https://babeljs.io/docs/en/babel-plugin-proposal-decorators), which use a different version of the proposal;
73
- - Being an experimental feature, they need to be enabled with `--experimentalDecorators`; follow TypeScript’s docs.
105
+ - Only class methods are supported; regular functions are not part of the decorators proposals.
106
+ - Uses the new ECMAScript decorators (TypeScript 5.0+). Legacy `experimentalDecorators` are not supported.
107
+ - Babel’s legacy decorators are not supported.
108
+ - Private methods are not supported.
74
109
 
75
- @returns A [decorator](https://github.com/tc39/proposal-decorators) to memoize class methods or static class methods.
110
+ @returns A decorator to memoize class methods or static class methods.
76
111
 
77
112
  @example
78
113
  ```
@@ -97,7 +132,7 @@ class ExampleWithOptions {
97
132
  }
98
133
  ```
99
134
  */
100
- export declare function pMemoizeDecorator<FunctionToMemoize extends AnyAsyncFunction, CacheKeyType>(options?: Options<FunctionToMemoize, CacheKeyType>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
135
+ export declare function pMemoizeDecorator<FunctionToMemoize extends AnyAsyncFunction = AnyAsyncFunction, CacheKeyType = Parameters<FunctionToMemoize>[0]>(options?: Options<NoInfer<FunctionToMemoize>, NoInfer<CacheKeyType>>): <This, Value extends FunctionToMemoize>(value: Value, context: ClassMethodDecoratorContext<This, Value>) => void;
101
136
  /**
102
137
  Clear all cached data of a memoized function.
103
138
 
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ await memoizedGot('https://sindresorhus.com');
42
42
  return pMemoizeClear;
43
43
  }
44
44
  });
45
- var _mimicFn = /*#__PURE__*/ _interopRequireDefault(require("mimic-fn"));
45
+ var _mimicFunction = /*#__PURE__*/ _interopRequireDefault(require("mimic-function"));
46
46
  function _arrayLikeToArray(arr, len) {
47
47
  if (len == null || len > arr.length) len = arr.length;
48
48
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
@@ -219,11 +219,12 @@ var __generator = (void 0) && (void 0).__generator || function(thisArg, body) {
219
219
  }
220
220
  };
221
221
  var cacheStore = new WeakMap();
222
- function pMemoize(fn) {
223
- var ref = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}, _cacheKey = ref.cacheKey, cacheKey = _cacheKey === void 0 ? function(param) {
222
+ function pMemoize(fn, options) {
223
+ var defaultCacheKey = function(param) {
224
224
  var _param = _slicedToArray(param, 1), firstArgument = _param[0];
225
225
  return firstArgument;
226
- } : _cacheKey, _cache = ref.cache, cache = _cache === void 0 ? new Map() : _cache;
226
+ };
227
+ var ref = options !== null && options !== void 0 ? options : {}, _cacheKey = ref.cacheKey, cacheKey = _cacheKey === void 0 ? defaultCacheKey : _cacheKey, _cache = ref.cache, cache = _cache === void 0 ? new Map() : _cache;
227
228
  // Promise objects can't be serialized so we keep track of them internally and only provide their resolved values to `cache`
228
229
  // `Promise<AsyncReturnType<FunctionToMemoize>>` is used instead of `ReturnType<FunctionToMemoize>` because promise properties are not kept
229
230
  var promiseCache = new Map();
@@ -237,15 +238,15 @@ function pMemoize(fn) {
237
238
  }
238
239
  var _this = this;
239
240
  var promise = _asyncToGenerator(function() {
240
- var _tmp, promise, result;
241
+ var _tmp, promise, result, allow, _tmp1;
241
242
  return __generator(this, function(_state) {
242
243
  switch(_state.label){
243
244
  case 0:
244
245
  _state.trys.push([
245
246
  0,
246
247
  ,
247
- 11,
248
- 12
248
+ 14,
249
+ 15
249
250
  ]);
250
251
  _tmp = cache;
251
252
  if (!_tmp) return [
@@ -287,7 +288,7 @@ function pMemoize(fn) {
287
288
  6,
288
289
  ,
289
290
  7,
290
- 10
291
+ 13
291
292
  ]);
292
293
  return [
293
294
  2,
@@ -295,31 +296,57 @@ function pMemoize(fn) {
295
296
  ];
296
297
  case 7:
297
298
  if (!cache) return [
299
+ 3,
300
+ 12
301
+ ];
302
+ if (!(options === null || options === void 0 ? void 0 : options.shouldCache)) return [
298
303
  3,
299
304
  9
300
305
  ];
301
306
  return [
302
307
  4,
303
- cache.set(key, result)
308
+ options.shouldCache(result, {
309
+ key: key,
310
+ argumentsList: arguments_
311
+ })
304
312
  ];
305
313
  case 8:
306
- _state.sent();
307
- _state.label = 9;
308
- case 9:
314
+ _tmp1 = _state.sent();
309
315
  return [
310
- 7
316
+ 3,
317
+ 10
311
318
  ];
319
+ case 9:
320
+ _tmp1 = true;
321
+ _state.label = 10;
312
322
  case 10:
313
- return [
323
+ allow = _tmp1;
324
+ if (!allow) return [
314
325
  3,
315
326
  12
316
327
  ];
328
+ return [
329
+ 4,
330
+ cache.set(key, result)
331
+ ];
317
332
  case 11:
333
+ _state.sent();
334
+ _state.label = 12;
335
+ case 12:
336
+ return [
337
+ 7
338
+ ];
339
+ case 13:
340
+ return [
341
+ 3,
342
+ 15
343
+ ];
344
+ case 14:
318
345
  promiseCache.delete(key);
319
346
  return [
320
347
  7
321
348
  ];
322
- case 12:
349
+ case 15:
323
350
  return [
324
351
  2
325
352
  ];
@@ -329,7 +356,7 @@ function pMemoize(fn) {
329
356
  promiseCache.set(key, promise);
330
357
  return promise;
331
358
  };
332
- (0, _mimicFn.default)(memoized, fn, {
359
+ (0, _mimicFunction.default)(memoized, fn, {
333
360
  ignoreNonConfigurable: true
334
361
  });
335
362
  cacheStore.set(memoized, cache);
@@ -337,22 +364,22 @@ function pMemoize(fn) {
337
364
  }
338
365
  function pMemoizeDecorator() {
339
366
  var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
340
- var instanceMap = new WeakMap();
341
- return function(target, propertyKey, descriptor) {
342
- var input = target[propertyKey]; // eslint-disable-line @typescript-eslint/no-unsafe-assignment
343
- if (typeof input !== "function") {
344
- throw new TypeError("The decorated value must be a function");
367
+ return function(value, context) {
368
+ if (context.kind !== "method") {
369
+ throw new TypeError("pMemoizeDecorator can only decorate methods");
345
370
  }
346
- delete descriptor.value;
347
- delete descriptor.writable;
348
- descriptor.get = function() {
349
- if (!instanceMap.has(this)) {
350
- var value = pMemoize(input, options);
351
- instanceMap.set(this, value);
352
- return value;
353
- }
354
- return instanceMap.get(this);
355
- };
371
+ if (context.private) {
372
+ throw new TypeError("pMemoizeDecorator cannot decorate private methods");
373
+ }
374
+ context.addInitializer(function() {
375
+ var memoizedMethod = pMemoize(value, options);
376
+ Object.defineProperty(this, context.name, {
377
+ configurable: true,
378
+ writable: true,
379
+ enumerable: false,
380
+ value: memoizedMethod
381
+ });
382
+ });
356
383
  };
357
384
  }
358
385
  function pMemoizeClear(fn) {
package/package.json CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "name": "@common.js/p-memoize",
3
- "version": "7.1.0",
4
- "description": "Memoize promise-returning & async functions",
3
+ "version": "8.0.0",
4
+ "description": "p-memoize package exported as CommonJS modules",
5
5
  "license": "MIT",
6
6
  "repository": "etienne-martin/common.js",
7
7
  "funding": "https://github.com/sindresorhus/p-memoize?sponsor=1",
8
8
  "type": "commonjs",
9
- "types": "dist/index.d.ts",
9
+ "types": "./dist/index.d.ts",
10
+ "sideEffects": false,
10
11
  "engines": {
11
- "node": ">=14.16"
12
+ "node": ">=20"
12
13
  },
13
14
  "scripts": {
14
15
  "test": "xo && ava && npm run build && tsd",
@@ -18,27 +19,31 @@
18
19
  "dist"
19
20
  ],
20
21
  "dependencies": {
21
- "@common.js/mimic-fn": "^4.0.0"
22
+ "@common.js/mimic-function": "^5.0.1",
23
+ "type-fest": "^4.41.0"
22
24
  },
23
25
  "devDependencies": {
24
- "@sindresorhus/tsconfig": "^3.0.1",
25
- "@types/serialize-javascript": "^5.0.2",
26
- "ava": "^4.3.0",
27
- "del-cli": "^4.0.1",
28
- "delay": "^5.0.0",
29
- "p-defer": "^4.0.0",
30
- "p-state": "^1.0.0",
31
- "serialize-javascript": "^6.0.0",
32
- "ts-node": "^10.8.2",
33
- "tsd": "^0.22.0",
34
- "xo": "^0.50.0"
26
+ "@sindresorhus/tsconfig": "^8.0.1",
27
+ "@types/serialize-javascript": "^5.0.4",
28
+ "ava": "^6.4.1",
29
+ "del-cli": "^6.0.0",
30
+ "delay": "^6.0.0",
31
+ "p-defer": "^4.0.1",
32
+ "p-state": "^2.0.1",
33
+ "serialize-javascript": "^6.0.2",
34
+ "tsd": "^0.33.0",
35
+ "tsimp": "^2.0.12",
36
+ "xo": "^1.2.1"
35
37
  },
36
38
  "ava": {
39
+ "environmentVariables": {
40
+ "TSIMP_DIAG": "ignore"
41
+ },
37
42
  "extensions": {
38
43
  "ts": "module"
39
44
  },
40
45
  "nodeArguments": [
41
- "--loader=ts-node/esm"
46
+ "--import=tsimp/import"
42
47
  ]
43
48
  },
44
49
  "xo": {
package/readme.md DELETED
@@ -1,154 +0,0 @@
1
- # p-memoize
2
-
3
- > [Memoize](https://en.wikipedia.org/wiki/Memoization) promise-returning & async functions
4
-
5
- Useful for speeding up consecutive function calls by caching the result of calls with identical input.
6
-
7
- <!-- Please keep this section in sync with https://github.com/sindresorhus/mem/blob/main/readme.md -->
8
-
9
- By default, **only the memoized function's first argument is considered** via strict equality comparison. If you need to cache multiple arguments or cache `object`s *by value*, have a look at alternative [caching strategies](#caching-strategy) below.
10
-
11
- This package is similar to [mem](https://github.com/sindresorhus/mem) but with async-specific enhancements; in particular, it allows for asynchronous caches and does not cache rejected promises.
12
-
13
- ## Install
14
-
15
- ```sh
16
- npm install p-memoize
17
- ```
18
-
19
- ## Usage
20
-
21
- ```js
22
- import pMemoize from 'p-memoize';
23
- import got from 'got';
24
-
25
- const memoizedGot = pMemoize(got);
26
-
27
- await memoizedGot('https://sindresorhus.com');
28
-
29
- // This call is cached
30
- await memoizedGot('https://sindresorhus.com');
31
- ```
32
-
33
- ### Caching strategy
34
-
35
- Similar to the [caching strategy for `mem`](https://github.com/sindresorhus/mem#options) with the following exceptions:
36
-
37
- - Promises returned from a memoized function are locally cached until resolving, when their value is added to `cache`. Special properties assigned to a returned promise will not be kept after resolution and every promise may need to resolve with a serializable object if caching results in a database.
38
- - `.get()`, `.has()` and `.set()` methods on `cache` can run asynchronously by returning a promise.
39
- - Instead of `.set()` being provided an object with the properties `value` and `maxAge`, it will only be provided `value` as the first argument. If you want to implement time-based expiry, consider [doing so in `cache`](#time-based-cache-expiration).
40
-
41
- ## API
42
-
43
- ### pMemoize(fn, options?)
44
-
45
- Returns a memoized version of the given function.
46
-
47
- #### fn
48
-
49
- Type: `Function`
50
-
51
- Promise-returning or async function to be memoized.
52
-
53
- #### options
54
-
55
- Type: `object`
56
-
57
- See the [`mem` options](https://github.com/sindresorhus/mem#options) in addition to the below option.
58
-
59
- ##### cacheKey
60
-
61
- Type: `Function`\
62
- Default: `arguments_ => arguments_[0]`\
63
- Example: `arguments_ => JSON.stringify(arguments_)`
64
-
65
- Determines the cache key for storing the result based on the function arguments. By default, **only the first argument is considered**.
66
-
67
- A `cacheKey` function can return any type supported by `Map` (or whatever structure you use in the `cache` option).
68
-
69
- See the [caching strategy](#caching-strategy) section for more information.
70
-
71
- ##### cache
72
-
73
- Type: `object | false`\
74
- Default: `new Map()`
75
-
76
- Use a different cache storage. Must implement the following methods: `.has(key)`, `.get(key)`, `.set(key, value)`, `.delete(key)`, and optionally `.clear()`. You could for example use a `WeakMap` instead or [`quick-lru`](https://github.com/sindresorhus/quick-lru) for a LRU cache. To disable caching so that only concurrent executions resolve with the same value, pass `false`.
77
-
78
- See the [caching strategy](https://github.com/sindresorhus/mem#caching-strategy) section in the `mem` package for more information.
79
-
80
- ### pMemoizeDecorator(options)
81
-
82
- Returns a [decorator](https://github.com/tc39/proposal-decorators) to memoize class methods or static class methods.
83
-
84
- Notes:
85
-
86
- - Only class methods and getters/setters can be memoized, not regular functions (they aren't part of the proposal);
87
- - Only [TypeScript’s decorators](https://www.typescriptlang.org/docs/handbook/decorators.html#parameter-decorators) are supported, not [Babel’s](https://babeljs.io/docs/en/babel-plugin-proposal-decorators), which use a different version of the proposal;
88
- - Being an experimental feature, they need to be enabled with `--experimentalDecorators`; follow TypeScript’s docs.
89
-
90
- #### options
91
-
92
- Type: `object`
93
-
94
- Same as options for `pMemoize()`.
95
-
96
- ```ts
97
- import {pMemoizeDecorator} from 'p-memoize';
98
-
99
- class Example {
100
- index = 0
101
-
102
- @pMemoizeDecorator()
103
- async counter() {
104
- return ++this.index;
105
- }
106
- }
107
-
108
- class ExampleWithOptions {
109
- index = 0
110
-
111
- @pMemoizeDecorator()
112
- async counter() {
113
- return ++this.index;
114
- }
115
- }
116
- ```
117
-
118
- ### pMemoizeClear(memoized)
119
-
120
- Clear all cached data of a memoized function.
121
-
122
- It will throw when given a non-memoized function.
123
-
124
- ## Tips
125
-
126
- ### Time-based cache expiration
127
-
128
- ```js
129
- import pMemoize from 'p-memoize';
130
- import ExpiryMap from 'expiry-map';
131
- import got from 'got';
132
-
133
- const cache = new ExpiryMap(10000); // Cached values expire after 10 seconds
134
-
135
- const memoizedGot = pMemoize(got, {cache});
136
- ```
137
-
138
- ### Caching promise rejections
139
-
140
- ```js
141
- import pMemoize from 'p-memoize';
142
- import pReflect from 'p-reflect';
143
-
144
- const memoizedGot = pMemoize(async (url, options) => pReflect(got(url, options)));
145
-
146
- await memoizedGot('https://example.com');
147
- // {isFulfilled: true, isRejected: false, value: '...'}
148
- ```
149
-
150
- ## Related
151
-
152
- - [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
153
- - [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
154
- - [More…](https://github.com/sindresorhus/promise-fun)