Skip to content

Commit

Permalink
Require Node.js 12.20 and move to ESM (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
Richienb authored Jul 13, 2021
1 parent a473986 commit 32c01b1
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 136 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ jobs:
fail-fast: false
matrix:
node-version:
- 16
- 14
- 12
- 10
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
- run: npm install
Expand Down
107 changes: 52 additions & 55 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
'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;

const decoratorInstanceMap = new WeakMap();

const cacheStore = new WeakMap<AnyFunction>();
const cacheStore = new WeakMap<AnyFunction, CacheStorage<any, any>>();

interface CacheStorageContent<ValueType> {
data: ValueType;
Expand All @@ -23,7 +22,7 @@ interface CacheStorage<KeyType, ValueType> {

interface Options<
FunctionToMemoize extends AnyFunction,
CacheKeyType
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,63 +95,59 @@ memoized('bar');
//=> 2
```
*/
const mem = <
export default function mem<
FunctionToMemoize extends AnyFunction,
CacheKeyType
CacheKeyType,
>(
fn: FunctionToMemoize,
{
cacheKey,
cache = new Map(),
maxAge
}: Options<FunctionToMemoize, CacheKeyType> = {}
): FunctionToMemoize => {
maxAge,
}: Options<FunctionToMemoize, CacheKeyType> = {},
): FunctionToMemoize {
if (typeof maxAge === 'number') {
// TODO: Drop after https://github.com/SamVerschueren/map-age-cleaner/issues/5
// @ts-expect-error
mapAgeCleaner(cache);
mapAgeCleaner(cache as unknown as Map<CacheKeyType, ReturnType<FunctionToMemoize>>);
}

const memoized = function (this: any, ...arguments_) {
const key = cacheKey ? cacheKey(arguments_) : arguments_[0];
const memoized = function (this: any, ...arguments_: Parameters<FunctionToMemoize>): ReturnType<FunctionToMemoize> {
const key = cacheKey ? cacheKey(arguments_) : arguments_[0] as CacheKeyType;

const cacheItem = cache.get(key);
if (cacheItem) {
return cacheItem.data;
return cacheItem.data; // eslint-disable-line @typescript-eslint/no-unsafe-return
}

const result = fn.apply(this, arguments_);
const result = fn.apply(this, arguments_) as ReturnType<FunctionToMemoize>;

cache.set(key, {
data: result,
maxAge: maxAge ? Date.now() + maxAge : Number.POSITIVE_INFINITY
maxAge: maxAge ? Date.now() + maxAge : Number.POSITIVE_INFINITY,
});

return result;
return result; // eslint-disable-line @typescript-eslint/no-unsafe-return
} as FunctionToMemoize;

mimicFn(memoized, fn, {
ignoreNonConfigurable: true
ignoreNonConfigurable: true,
});

cacheStore.set(memoized, cache);

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 +156,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
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');
}
options: Options<FunctionToMemoize, CacheKeyType> = {},
) {
return (
target: any,
propertyKey: string,
descriptor: PropertyDescriptor,
): void => {
const input = target[propertyKey]; // eslint-disable-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access

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) as FunctionToMemoize;
decoratorInstanceMap.set(this, value);
return value;
}

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

/**
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 All @@ -214,4 +211,4 @@ mem.clear = (fn: AnyFunction): void => {
}

cache.clear();
};
}
36 changes: 19 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@
"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",
"test": "xo && ava && npm run build && tsd",
"build": "del-cli dist && tsc",
"prepack": "npm run build"
},
"main": "dist",
"types": "dist/index.d.ts",
"files": [
"dist/index.js",
"dist/index.d.ts"
"dist"
],
"keywords": [
"memoize",
Expand All @@ -39,30 +39,32 @@
],
"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",
"ts-node": "^10.1.0",
"tsd": "^0.13.1",
"typescript": "^4.0.3",
"xo": "^0.38.2"
"typescript": "^4.3.5",
"xo": "^0.41.0"
},
"ava": {
"files": [
"test.ts"
],
"timeout": "1m",
"typescript": {
"rewritePaths": {
"./": "dist/"
}
}
"extensions": {
"ts": "module"
},
"nonSemVerExperiments": {
"configurableModuleFormat": true
},
"nodeArguments": [
"--loader=ts-node/esm"
]
},
"xo": {
"rules": {
Expand Down
Loading

0 comments on commit 32c01b1

Please sign in to comment.