Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require Node.js 12.20 and move to ESM #76

Merged
merged 6 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ jobs:
fail-fast: false
matrix:
node-version:
- 16
- 14
- 12
- 10
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
Richienb marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
73 changes: 36 additions & 37 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict';
import mimicFn = require('mimic-fn');
import mapAgeCleaner = require('map-age-cleaner');
import mimicFn from 'mimic-fn';
import mapAgeCleaner from 'map-age-cleaner';

type AnyFunction = (...arguments_: any) => any;

Expand All @@ -24,7 +23,7 @@ interface CacheStorage<KeyType, ValueType> {
interface Options<
FunctionToMemoize extends AnyFunction,
CacheKeyType
> {
> {
/**
Milliseconds until the cache expires.

Expand All @@ -40,16 +39,16 @@ interface Options<
You can have it cache **all** the arguments by value with `JSON.stringify`, if they are compatible:

```
import mem = require('mem');
import mem from 'mem';

mem(function_, {cacheKey: JSON.stringify});
```

Or you can use a more full-featured serializer like [serialize-javascript](https://github.com/yahoo/serialize-javascript) to add support for `RegExp`, `Date` and so on.

```
import mem = require('mem');
import serializeJavascript = require('serialize-javascript');
import mem from 'mem';
import serializeJavascript from 'serialize-javascript';

mem(function_, {cacheKey: serializeJavascript});
```
Expand All @@ -75,7 +74,7 @@ interface Options<

@example
```
import mem = require('mem');
import mem from 'mem';

let i = 0;
const counter = () => ++i;
Expand All @@ -96,7 +95,7 @@ memoized('bar');
//=> 2
```
*/
const mem = <
export default function mem<
FunctionToMemoize extends AnyFunction,
CacheKeyType
>(
Expand All @@ -106,7 +105,7 @@ const mem = <
cache = new Map(),
maxAge
}: Options<FunctionToMemoize, CacheKeyType> = {}
): FunctionToMemoize => {
): FunctionToMemoize {
if (typeof maxAge === 'number') {
// TODO: Drop after https://github.com/SamVerschueren/map-age-cleaner/issues/5
// @ts-expect-error
Expand Down Expand Up @@ -140,19 +139,17 @@ const mem = <
return memoized;
};

export = mem;

/**
@returns A [decorator](https://github.com/tc39/proposal-decorators) to memoize class methods or static class methods.

@example
```
import mem = require('mem');
import {memDecorator} from 'mem';

class Example {
index = 0

@mem.decorator()
@memDecorator()
counter() {
return ++this.index;
}
Expand All @@ -161,49 +158,51 @@ class Example {
class ExampleWithOptions {
index = 0

@mem.decorator({maxAge: 1000})
@memDecorator({maxAge: 1000})
counter() {
return ++this.index;
}
}
```
*/
mem.decorator = <
export function memDecorator<
FunctionToMemoize extends AnyFunction,
CacheKeyType
>(
options: Options<FunctionToMemoize, CacheKeyType> = {}
) => (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
): void => {
const input = target[propertyKey];

if (typeof input !== 'function') {
throw new TypeError('The decorated value must be a function');
}
) {
return (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
): void => {
const input = target[propertyKey];

if (typeof input !== 'function') {
throw new TypeError('The decorated value must be a function');
}

delete descriptor.value;
delete descriptor.writable;
delete descriptor.value;
delete descriptor.writable;

descriptor.get = function () {
if (!decoratorInstanceMap.has(this)) {
const value = mem(input, options);
decoratorInstanceMap.set(this, value);
return value;
}
descriptor.get = function () {
if (!decoratorInstanceMap.has(this)) {
const value = mem(input, options);
decoratorInstanceMap.set(this, value);
return value;
}

return decoratorInstanceMap.get(this);
return decoratorInstanceMap.get(this);
};
};
};
}

/**
Clear all cached data of a memoized function.

@param fn - Memoized function.
*/
mem.clear = (fn: AnyFunction): void => {
export function memClear(fn: AnyFunction): void {
const cache = cacheStore.get(fn);
if (!cache) {
throw new TypeError('Can\'t clear a function that was not memoized!');
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@
"email": "sindresorhus@gmail.com",
"url": "https://sindresorhus.com"
},
"type": "module",
"exports": "./dist/index.js",
"engines": {
"node": ">=10"
"node": ">=12.20"
},
"scripts": {
"test": "xo && npm run build && tsd && ava",
"build": "del-cli dist && tsc",
"prepack": "npm run build"
},
"main": "dist",
"types": "dist/index.d.ts",
"files": [
"dist/index.js",
Expand All @@ -39,19 +40,19 @@
],
"dependencies": {
"map-age-cleaner": "^0.1.3",
"mimic-fn": "^3.1.0"
"mimic-fn": "^4.0.0"
},
"devDependencies": {
"@ava/typescript": "^1.1.1",
"@sindresorhus/tsconfig": "^0.7.0",
"@sindresorhus/tsconfig": "^1.0.2",
"@types/serialize-javascript": "^4.0.0",
"ava": "^3.15.0",
"del-cli": "^3.0.1",
"delay": "^4.4.0",
"serialize-javascript": "^5.0.1",
"tsd": "^0.13.1",
"typescript": "^4.0.3",
"xo": "^0.38.2"
"xo": "^0.41.0"
},
"ava": {
"files": [
Expand Down
66 changes: 30 additions & 36 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $ npm install mem
## Usage

```js
const mem = require('mem');
import mem from 'mem';

let i = 0;
const counter = () => ++i;
Expand Down Expand Up @@ -43,40 +43,36 @@ memoized('bar', 'foo');
##### Works fine with promise returning functions

```js
const mem = require('mem');
import mem from 'mem';

let i = 0;
const counter = async () => ++i;
const memoized = mem(counter);

(async () => {
console.log(await memoized());
//=> 1
console.log(await memoized());
//=> 1

// The return value didn't increase as it's cached
console.log(await memoized());
//=> 1
})();
// The return value didn't increase as it's cached
console.log(await memoized());
//=> 1
```

```js
const mem = require('mem');
const got = require('got');
const delay = require('delay');
import mem from 'mem';
import got from 'got';
import delay from 'delay';

const memGot = mem(got, {maxAge: 1000});

(async () => {
await memGot('https://sindresorhus.com');
await memGot('https://sindresorhus.com');

// This call is cached
await memGot('https://sindresorhus.com');
// This call is cached
await memGot('https://sindresorhus.com');

await delay(2000);
await delay(2000);

// This call is not cached as the cache has expired
await memGot('https://sindresorhus.com');
})();
// This call is not cached as the cache has expired
await memGot('https://sindresorhus.com');
```

### Caching strategy
Expand Down Expand Up @@ -138,7 +134,7 @@ heavyMemoizedOperation('hello', {full: true}); // Retrieved from cache
If your function accepts multiple arguments that aren't supported by `JSON.stringify` (e.g. DOM elements and functions), you can instead extend the initial exact equality (`===`) to work on multiple arguments using [`many-keys-map`](https://github.com/fregante/many-keys-map):

```js
const ManyKeysMap = require('many-keys-map');
import ManyKeysMap from 'many-keys-map';

const addListener = (emitter, eventName, listener) => emitter.on(eventName, listener);

Expand Down Expand Up @@ -196,7 +192,7 @@ Use a different cache storage. Must implement the following methods: `.has(key)`

Refer to the [caching strategies](#caching-strategy) section for more information.

### mem.decorator(options)
### memDecorator(options)

Returns a [decorator](https://github.com/tc39/proposal-decorators) to memoize class methods or static class methods.

Expand All @@ -213,12 +209,12 @@ Type: `object`
Same as options for `mem()`.

```ts
import mem = require('mem');
import {memDecorator} from 'mem';

class Example {
index = 0

@mem.decorator()
@memDecorator()
counter() {
return ++this.index;
}
Expand All @@ -227,14 +223,14 @@ class Example {
class ExampleWithOptions {
index = 0

@mem.decorator({maxAge: 1000})
@memDecorator({maxAge: 1000})
counter() {
return ++this.index;
}
}
```

### mem.clear(fn)
### memClear(fn)

Clear all cached data of a memoized function.

Expand All @@ -253,21 +249,19 @@ If you want to know how many times your cache had a hit or a miss, you can make
#### Example

```js
const mem = require('mem');
const StatsMap = require('stats-map');
const got = require('got');
import mem from 'mem';
import StatsMap from 'stats-map';
import got from 'got';

const cache = new StatsMap();
const memGot = mem(got, {cache});

(async () => {
await memGot('https://sindresorhus.com');
await memGot('https://sindresorhus.com');
await memGot('https://sindresorhus.com');
await memGot('https://sindresorhus.com');
await memGot('https://sindresorhus.com');
await memGot('https://sindresorhus.com');

console.log(cache.stats);
//=> {hits: 2, misses: 1}
})();
console.log(cache.stats);
//=> {hits: 2, misses: 1}
```

## Related
Expand Down
4 changes: 2 additions & 2 deletions test-d/index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectType} from 'tsd';
import mem = require('..');
import mem, {memClear} from '..';

const fn = (text: string) => Boolean(text);

Expand Down Expand Up @@ -29,7 +29,7 @@ expectType<typeof overloadedFn>(mem(overloadedFn));
expectType<true>(mem(overloadedFn)(true));
expectType<false>(mem(overloadedFn)(false));

mem.clear(fn);
memClear(fn);

// `cacheKey` tests.
// The argument should match the memoized function’s parameters
Expand Down
Loading