--- /dev/null
+'use strict';
+const mimicFn = require('mimic-fn');
+const isPromise = require('p-is-promise');
+const mapAgeCleaner = require('map-age-cleaner');
+
+const cacheStore = new WeakMap();
+
+const defaultCacheKey = (...arguments_) => {
+ if (arguments_.length === 0) {
+ return '__defaultKey';
+ }
+
+ if (arguments_.length === 1) {
+ const [firstArgument] = arguments_;
+ if (
+ firstArgument === null ||
+ firstArgument === undefined ||
+ (typeof firstArgument !== 'function' && typeof firstArgument !== 'object')
+ ) {
+ return firstArgument;
+ }
+ }
+
+ return JSON.stringify(arguments_);
+};
+
+const mem = (fn, options) => {
+ options = Object.assign({
+ cacheKey: defaultCacheKey,
+ cache: new Map(),
+ cachePromiseRejection: false
+ }, options);
+
+ if (typeof options.maxAge === 'number') {
+ mapAgeCleaner(options.cache);
+ }
+
+ const {cache} = options;
+ options.maxAge = options.maxAge || 0;
+
+ const setData = (key, data) => {
+ cache.set(key, {
+ data,
+ maxAge: Date.now() + options.maxAge
+ });
+ };
+
+ const memoized = function (...arguments_) {
+ const key = options.cacheKey(...arguments_);
+
+ if (cache.has(key)) {
+ return cache.get(key).data;
+ }
+
+ const cacheItem = fn.call(this, ...arguments_);
+
+ setData(key, cacheItem);
+
+ if (isPromise(cacheItem) && options.cachePromiseRejection === false) {
+ // Remove rejected promises from cache unless `cachePromiseRejection` is set to `true`
+ cacheItem.catch(() => cache.delete(key));
+ }
+
+ return cacheItem;
+ };
+
+ try {
+ // The below call will throw in some host environments
+ // See https://github.com/sindresorhus/mimic-fn/issues/10
+ mimicFn(memoized, fn);
+ } catch (_) {}
+
+ cacheStore.set(memoized, options.cache);
+
+ return memoized;
+};
+
+module.exports = mem;
+// TODO: Remove this for the next major release
+module.exports.default = mem;
+
+module.exports.clear = fn => {
+ const cache = cacheStore.get(fn);
+
+ if (cache && typeof cache.clear === 'function') {
+ cache.clear();
+ }
+};