hexo/node_modules/moize/dist/moize.esm.js

1476 lines
39 KiB
JavaScript
Raw Normal View History

2023-09-25 15:58:56 +08:00
import memoize from 'micro-memoize';
import { deepEqual, shallowEqual, sameValueZeroEqual } from 'fast-equals';
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
/**
* @private
*
* @constant DEFAULT_OPTIONS
*/
var DEFAULT_OPTIONS = {
isDeepEqual: false,
isPromise: false,
isReact: false,
isSerialized: false,
isShallowEqual: false,
matchesArg: undefined,
matchesKey: undefined,
maxAge: undefined,
maxArgs: undefined,
maxSize: 1,
onExpire: undefined,
profileName: undefined,
serializer: undefined,
updateCacheForKey: undefined,
transformArgs: undefined,
updateExpire: false
};
/**
* @private
*
* @description
* method to combine functions and return a single function that fires them all
*
* @param functions the functions to compose
* @returns the composed function
*/
function combine() {
for (var _len = arguments.length, functions = new Array(_len), _key = 0; _key < _len; _key++) {
functions[_key] = arguments[_key];
}
return functions.reduce(function (f, g) {
if (typeof f === 'function') {
return typeof g === 'function' ? function () {
f.apply(this, arguments);
g.apply(this, arguments);
} : f;
}
if (typeof g === 'function') {
return g;
}
});
}
/**
* @private
*
* @description
* method to compose functions and return a single function
*
* @param functions the functions to compose
* @returns the composed function
*/
function compose() {
for (var _len2 = arguments.length, functions = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
functions[_key2] = arguments[_key2];
}
return functions.reduce(function (f, g) {
if (typeof f === 'function') {
return typeof g === 'function' ? function () {
return f(g.apply(this, arguments));
} : f;
}
if (typeof g === 'function') {
return g;
}
});
}
/**
* @private
*
* @description
* find the index of the expiration based on the key
*
* @param expirations the list of expirations
* @param key the key to match
* @returns the index of the expiration
*/
function findExpirationIndex(expirations, key) {
for (var index = 0; index < expirations.length; index++) {
if (expirations[index].key === key) {
return index;
}
}
return -1;
}
/**
* @private
*
* @description
* create function that finds the index of the key in the list of cache keys
*
* @param isEqual the function to test individual argument equality
* @param isMatchingKey the function to test full key equality
* @returns the function that finds the index of the key
*/
function createFindKeyIndex(isEqual, isMatchingKey) {
var areKeysEqual = typeof isMatchingKey === 'function' ? isMatchingKey : function (cacheKey, key) {
for (var index = 0; index < key.length; index++) {
if (!isEqual(cacheKey[index], key[index])) {
return false;
}
}
return true;
};
return function (keys, key) {
for (var keysIndex = 0; keysIndex < keys.length; keysIndex++) {
if (keys[keysIndex].length === key.length && areKeysEqual(keys[keysIndex], key)) {
return keysIndex;
}
}
return -1;
};
}
/**
* @private
*
* @description
* merge two options objects, combining or composing functions as necessary
*
* @param originalOptions the options that already exist on the method
* @param newOptions the new options to merge
* @returns the merged options
*/
function mergeOptions(originalOptions, newOptions) {
if (!newOptions || newOptions === DEFAULT_OPTIONS) {
return originalOptions;
}
return _extends({}, originalOptions, newOptions, {
onCacheAdd: combine(originalOptions.onCacheAdd, newOptions.onCacheAdd),
onCacheChange: combine(originalOptions.onCacheChange, newOptions.onCacheChange),
onCacheHit: combine(originalOptions.onCacheHit, newOptions.onCacheHit),
transformArgs: compose(originalOptions.transformArgs, newOptions.transformArgs)
});
}
function isMoized(fn) {
return typeof fn === 'function' && fn.isMoized;
}
function setName(fn, originalFunctionName, profileName) {
try {
var name = profileName || originalFunctionName || 'anonymous';
Object.defineProperty(fn, 'name', {
configurable: true,
enumerable: false,
value: "moized(" + name + ")",
writable: true
});
} catch (_unused) {
// For engines where `function.name` is not configurable, do nothing.
}
}
/**
* @private
*
* @description
* clear an active expiration and remove it from the list if applicable
*
* @param expirations the list of expirations
* @param key the key to clear
* @param shouldRemove should the expiration be removed from the list
*/
function clearExpiration(expirations, key, shouldRemove) {
var expirationIndex = findExpirationIndex(expirations, key);
if (expirationIndex !== -1) {
clearTimeout(expirations[expirationIndex].timeoutId);
if (shouldRemove) {
expirations.splice(expirationIndex, 1);
}
}
}
/**
* @private
*
* @description
* Create the timeout for the given expiration method. If the ability to `unref`
* exists, then apply it to avoid process locks in NodeJS.
*
* @param expirationMethod the method to fire upon expiration
* @param maxAge the time to expire after
* @returns the timeout ID
*/
function createTimeout(expirationMethod, maxAge) {
var timeoutId = setTimeout(expirationMethod, maxAge);
if (typeof timeoutId.unref === 'function') {
timeoutId.unref();
}
return timeoutId;
}
/**
* @private
*
* @description
* create a function that, when an item is added to the cache, adds an expiration for it
*
* @param expirations the mutable expirations array
* @param options the options passed on initialization
* @param isEqual the function to check argument equality
* @param isMatchingKey the function to check complete key equality
* @returns the onCacheAdd function to handle expirations
*/
function createOnCacheAddSetExpiration(expirations, options, isEqual, isMatchingKey) {
var maxAge = options.maxAge;
return function onCacheAdd(cache, moizedOptions, moized) {
var key = cache.keys[0];
if (findExpirationIndex(expirations, key) === -1) {
var expirationMethod = function expirationMethod() {
var findKeyIndex = createFindKeyIndex(isEqual, isMatchingKey);
var keyIndex = findKeyIndex(cache.keys, key);
var value = cache.values[keyIndex];
if (~keyIndex) {
cache.keys.splice(keyIndex, 1);
cache.values.splice(keyIndex, 1);
if (typeof options.onCacheChange === 'function') {
options.onCacheChange(cache, moizedOptions, moized);
}
}
clearExpiration(expirations, key, true);
if (typeof options.onExpire === 'function' && options.onExpire(key) === false) {
cache.keys.unshift(key);
cache.values.unshift(value);
onCacheAdd(cache, moizedOptions, moized);
if (typeof options.onCacheChange === 'function') {
options.onCacheChange(cache, moizedOptions, moized);
}
}
};
expirations.push({
expirationMethod: expirationMethod,
key: key,
timeoutId: createTimeout(expirationMethod, maxAge)
});
}
};
}
/**
* @private
*
* @description
* creates a function that, when a cache item is hit, reset the expiration
*
* @param expirations the mutable expirations array
* @param options the options passed on initialization
* @returns the onCacheAdd function to handle expirations
*/
function createOnCacheHitResetExpiration(expirations, options) {
return function onCacheHit(cache) {
var key = cache.keys[0];
var expirationIndex = findExpirationIndex(expirations, key);
if (~expirationIndex) {
clearExpiration(expirations, key, false);
expirations[expirationIndex].timeoutId = createTimeout(expirations[expirationIndex].expirationMethod, options.maxAge);
}
};
}
/**
* @private
*
* @description
* get the micro-memoize options specific to the maxAge option
*
* @param expirations the expirations for the memoized function
* @param options the options passed to the moizer
* @param isEqual the function to test equality of the key on a per-argument basis
* @param isMatchingKey the function to test equality of the whole key
* @returns the object of options based on the entries passed
*/
function getMaxAgeOptions(expirations, options, isEqual, isMatchingKey) {
var onCacheAdd = typeof options.maxAge === 'number' && isFinite(options.maxAge) ? createOnCacheAddSetExpiration(expirations, options, isEqual, isMatchingKey) : undefined;
return {
onCacheAdd: onCacheAdd,
onCacheHit: onCacheAdd && options.updateExpire ? createOnCacheHitResetExpiration(expirations, options) : undefined
};
}
var statsCache = {
anonymousProfileNameCounter: 1,
isCollectingStats: false,
profiles: {}
};
var hasWarningDisplayed = false;
function clearStats(profileName) {
if (profileName) {
delete statsCache.profiles[profileName];
} else {
statsCache.profiles = {};
}
}
/**
* @private
*
* @description
* activate stats collection
*
* @param isCollectingStats should stats be collected
*/
function collectStats(isCollectingStats) {
if (isCollectingStats === void 0) {
isCollectingStats = true;
}
statsCache.isCollectingStats = isCollectingStats;
}
/**
* @private
*
* @description
* create a function that increments the number of calls for the specific profile
*/
function createOnCacheAddIncrementCalls(options) {
var profileName = options.profileName;
return function () {
if (profileName && !statsCache.profiles[profileName]) {
statsCache.profiles[profileName] = {
calls: 0,
hits: 0
};
}
statsCache.profiles[profileName].calls++;
};
}
/**
* @private
*
* @description
* create a function that increments the number of calls and cache hits for the specific profile
*/
function createOnCacheHitIncrementCallsAndHits(options) {
return function () {
var profiles = statsCache.profiles;
var profileName = options.profileName;
if (!profiles[profileName]) {
profiles[profileName] = {
calls: 0,
hits: 0
};
}
profiles[profileName].calls++;
profiles[profileName].hits++;
};
}
/**
* @private
*
* @description
* get the profileName for the function when one is not provided
*
* @param fn the function to be memoized
* @returns the derived profileName for the function
*/
function getDefaultProfileName(fn) {
return fn.displayName || fn.name || "Anonymous " + statsCache.anonymousProfileNameCounter++;
}
/**
* @private
*
* @description
* get the usage percentage based on the number of hits and total calls
*
* @param calls the number of calls made
* @param hits the number of cache hits when called
* @returns the usage as a percentage string
*/
function getUsagePercentage(calls, hits) {
return calls ? (hits / calls * 100).toFixed(4) + "%" : '0.0000%';
}
/**
* @private
*
* @description
* get the statistics for a given method or all methods
*
* @param [profileName] the profileName to get the statistics for (get all when not provided)
* @returns the object with stats information
*/
function getStats(profileName) {
if (!statsCache.isCollectingStats && !hasWarningDisplayed) {
console.warn('Stats are not currently being collected, please run "collectStats" to enable them.'); // eslint-disable-line no-console
hasWarningDisplayed = true;
}
var profiles = statsCache.profiles;
if (profileName) {
if (!profiles[profileName]) {
return {
calls: 0,
hits: 0,
usage: '0.0000%'
};
}
var profile = profiles[profileName];
return _extends({}, profile, {
usage: getUsagePercentage(profile.calls, profile.hits)
});
}
var completeStats = Object.keys(statsCache.profiles).reduce(function (completeProfiles, profileName) {
completeProfiles.calls += profiles[profileName].calls;
completeProfiles.hits += profiles[profileName].hits;
return completeProfiles;
}, {
calls: 0,
hits: 0
});
return _extends({}, completeStats, {
profiles: Object.keys(profiles).reduce(function (computedProfiles, profileName) {
computedProfiles[profileName] = getStats(profileName);
return computedProfiles;
}, {}),
usage: getUsagePercentage(completeStats.calls, completeStats.hits)
});
}
/**
* @private
*
* @function getStatsOptions
*
* @description
* get the options specific to storing statistics
*
* @param {Options} options the options passed to the moizer
* @returns {Object} the options specific to keeping stats
*/
function getStatsOptions(options) {
return statsCache.isCollectingStats ? {
onCacheAdd: createOnCacheAddIncrementCalls(options),
onCacheHit: createOnCacheHitIncrementCallsAndHits(options)
} : {};
}
var ALWAYS_SKIPPED_PROPERTIES = {
arguments: true,
callee: true,
caller: true,
constructor: true,
length: true,
name: true,
prototype: true
};
/**
* @private
*
* @description
* copy the static properties from the original function to the moized
* function
*
* @param originalFn the function copying from
* @param newFn the function copying to
* @param skippedProperties the list of skipped properties, if any
*/
function copyStaticProperties(originalFn, newFn, skippedProperties) {
if (skippedProperties === void 0) {
skippedProperties = [];
}
Object.getOwnPropertyNames(originalFn).forEach(function (property) {
if (!ALWAYS_SKIPPED_PROPERTIES[property] && skippedProperties.indexOf(property) === -1) {
var descriptor = Object.getOwnPropertyDescriptor(originalFn, property);
if (descriptor.get || descriptor.set) {
Object.defineProperty(newFn, property, descriptor);
} else {
// @ts-expect-error - properites may not align
newFn[property] = originalFn[property];
}
}
});
}
/**
* @private
*
* @description
* add methods to the moized fuction object that allow extra features
*
* @param memoized the memoized function from micro-memoize
*/
function addInstanceMethods(memoized, _ref) {
var expirations = _ref.expirations;
var options = memoized.options;
var findKeyIndex = createFindKeyIndex(options.isEqual, options.isMatchingKey);
var moized = memoized;
moized.clear = function () {
var onCacheChange = moized._microMemoizeOptions.onCacheChange,
cache = moized.cache;
cache.keys.length = 0;
cache.values.length = 0;
if (onCacheChange) {
onCacheChange(cache, moized.options, moized);
}
return true;
};
moized.clearStats = function () {
clearStats(moized.options.profileName);
};
moized.get = function (key) {
var transformKey = moized._microMemoizeOptions.transformKey,
cache = moized.cache;
var cacheKey = transformKey ? transformKey(key) : key;
var keyIndex = findKeyIndex(cache.keys, cacheKey);
return keyIndex !== -1 ? moized.apply(this, key) : undefined;
};
moized.getStats = function () {
return getStats(moized.options.profileName);
};
moized.has = function (key) {
var transformKey = moized._microMemoizeOptions.transformKey;
var cacheKey = transformKey ? transformKey(key) : key;
return findKeyIndex(moized.cache.keys, cacheKey) !== -1;
};
moized.keys = function () {
return moized.cacheSnapshot.keys;
};
moized.remove = function (key) {
var _moized$_microMemoize = moized._microMemoizeOptions,
onCacheChange = _moized$_microMemoize.onCacheChange,
transformKey = _moized$_microMemoize.transformKey,
cache = moized.cache;
var keyIndex = findKeyIndex(cache.keys, transformKey ? transformKey(key) : key);
if (keyIndex === -1) {
return false;
}
var existingKey = cache.keys[keyIndex];
cache.keys.splice(keyIndex, 1);
cache.values.splice(keyIndex, 1);
if (onCacheChange) {
onCacheChange(cache, moized.options, moized);
}
clearExpiration(expirations, existingKey, true);
return true;
};
moized.set = function (key, value) {
var _microMemoizeOptions = moized._microMemoizeOptions,
cache = moized.cache,
options = moized.options;
var onCacheAdd = _microMemoizeOptions.onCacheAdd,
onCacheChange = _microMemoizeOptions.onCacheChange,
transformKey = _microMemoizeOptions.transformKey;
var cacheKey = transformKey ? transformKey(key) : key;
var keyIndex = findKeyIndex(cache.keys, cacheKey);
if (keyIndex === -1) {
var cutoff = options.maxSize - 1;
if (cache.size > cutoff) {
cache.keys.length = cutoff;
cache.values.length = cutoff;
}
cache.keys.unshift(cacheKey);
cache.values.unshift(value);
if (options.isPromise) {
cache.updateAsyncCache(moized);
}
if (onCacheAdd) {
onCacheAdd(cache, options, moized);
}
if (onCacheChange) {
onCacheChange(cache, options, moized);
}
} else {
var existingKey = cache.keys[keyIndex];
cache.values[keyIndex] = value;
if (keyIndex > 0) {
cache.orderByLru(existingKey, value, keyIndex);
}
if (options.isPromise) {
cache.updateAsyncCache(moized);
}
if (typeof onCacheChange === 'function') {
onCacheChange(cache, options, moized);
}
}
};
moized.values = function () {
return moized.cacheSnapshot.values;
};
}
/**
* @private
*
* @description
* add propeties to the moized fuction object that surfaces extra information
*
* @param memoized the memoized function
* @param expirations the list of expirations for cache items
* @param options the options passed to the moizer
* @param originalFunction the function that is being memoized
*/
function addInstanceProperties(memoized, _ref2) {
var expirations = _ref2.expirations,
moizeOptions = _ref2.options,
originalFunction = _ref2.originalFunction;
var microMemoizeOptions = memoized.options;
Object.defineProperties(memoized, {
_microMemoizeOptions: {
configurable: true,
get: function get() {
return microMemoizeOptions;
}
},
cacheSnapshot: {
configurable: true,
get: function get() {
var currentCache = memoized.cache;
return {
keys: currentCache.keys.slice(0),
size: currentCache.size,
values: currentCache.values.slice(0)
};
}
},
expirations: {
configurable: true,
get: function get() {
return expirations;
}
},
expirationsSnapshot: {
configurable: true,
get: function get() {
return expirations.slice(0);
}
},
isMoized: {
configurable: true,
get: function get() {
return true;
}
},
options: {
configurable: true,
get: function get() {
return moizeOptions;
}
},
originalFunction: {
configurable: true,
get: function get() {
return originalFunction;
}
}
});
var moized = memoized;
copyStaticProperties(originalFunction, moized);
}
/**
* @private
*
* @description
* add methods and properties to the memoized function for more features
*
* @param memoized the memoized function
* @param configuration the configuration object for the instance
* @returns the memoized function passed
*/
function createMoizeInstance(memoized, configuration) {
addInstanceMethods(memoized, configuration);
addInstanceProperties(memoized, configuration);
return memoized;
}
// This was stolen from React internals, which allows us to create React elements without needing
// a dependency on the React library itself.
var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol.for ? Symbol.for('react.element') : 0xeac7;
/**
* @private
*
* @description
* Create a component that memoizes based on `props` and legacy `context`
* on a per-instance basis. This requires creating a component class to
* store the memoized function. The cost is quite low, and avoids the
* need to have access to the React dependency by basically re-creating
* the basic essentials for a component class and the results of the
* `createElement` function.
*
* @param moizer the top-level moize method
* @param fn the component to memoize
* @param options the memoization options
* @returns the memoized component
*/
function createMoizedComponent(moizer, fn, options) {
/**
* This is a hack override setting the necessary options
* for a React component to be memoized. In the main `moize`
* method, if the `isReact` option is set it is short-circuited
* to call this function, and these overrides allow the
* necessary transformKey method to be derived.
*
* The order is based on:
* 1) Set the necessary aspects of transformKey for React components.
* 2) Allow setting of other options and overrides of those aspects
* if desired (for example, `isDeepEqual` will use deep equality).
* 3) Always set `isReact` to false to prevent infinite loop.
*/
var reactMoizer = moizer(_extends({
maxArgs: 2,
isShallowEqual: true
}, options, {
isReact: false
}));
if (!fn.displayName) {
// @ts-ignore - allow setting of displayName
fn.displayName = fn.name || 'Component';
}
function Moized(props, context, updater) {
this.props = props;
this.context = context;
this.updater = updater;
this.MoizedComponent = reactMoizer(fn);
}
Moized.prototype.isReactComponent = {};
Moized.prototype.render = function () {
return {
$$typeof: REACT_ELEMENT_TYPE,
type: this.MoizedComponent,
props: this.props,
ref: null,
key: null,
_owner: null
};
};
copyStaticProperties(fn, Moized, ['contextType', 'contextTypes']);
Moized.displayName = "Moized(" + (fn.displayName || fn.name || 'Component') + ")";
setName(Moized, fn.name, options.profileName);
return Moized;
}
function createGetInitialArgs(size) {
/**
* @private
*
* @description
* take the first N number of items from the array (faster than slice)
*
* @param args the args to take from
* @returns the shortened list of args as an array
*/
return function (args) {
if (size >= args.length) {
return args;
}
if (size === 0) {
return [];
}
if (size === 1) {
return [args[0]];
}
if (size === 2) {
return [args[0], args[1]];
}
if (size === 3) {
return [args[0], args[1], args[2]];
}
var clone = [];
for (var index = 0; index < size; index++) {
clone[index] = args[index];
}
return clone;
};
}
/**
* @function getCutoff
*
* @description
* faster `Array.prototype.indexOf` implementation build for slicing / splicing
*
* @param array the array to match the value in
* @param value the value to match
* @returns the matching index, or -1
*/
function getCutoff(array, value) {
var length = array.length;
for (var index = 0; index < length; ++index) {
if (array[index] === value) {
return index + 1;
}
}
return 0;
}
/**
* @private
*
* @description
* custom replacer for the stringify function
*
* @returns if function then toString of it, else the value itself
*/
function createDefaultReplacer() {
var cache = [];
var keys = [];
return function defaultReplacer(key, value) {
var type = typeof value;
if (type === 'function' || type === 'symbol') {
return value.toString();
}
if (typeof value === 'object') {
if (cache.length) {
var thisCutoff = getCutoff(cache, this);
if (thisCutoff === 0) {
cache[cache.length] = this;
} else {
cache.splice(thisCutoff);
keys.splice(thisCutoff);
}
keys[keys.length] = key;
var valueCutoff = getCutoff(cache, value);
if (valueCutoff !== 0) {
return "[ref=" + (keys.slice(0, valueCutoff).join('.') || '.') + "]";
}
} else {
cache[0] = value;
keys[0] = key;
}
return value;
}
return '' + value;
};
}
/**
* @private
*
* @description
* get the stringified version of the argument passed
*
* @param arg argument to stringify
* @returns the stringified argument
*/
function getStringifiedArgument(arg) {
var typeOfArg = typeof arg;
return arg && (typeOfArg === 'object' || typeOfArg === 'function') ? JSON.stringify(arg, createDefaultReplacer()) : arg;
}
/**
* @private
*
* @description
* serialize the arguments passed
*
* @param options the options passed to the moizer
* @param options.maxArgs the cap on the number of arguments used in serialization
* @returns argument serialization method
*/
function defaultArgumentSerializer(args) {
var key = '|';
for (var index = 0; index < args.length; index++) {
key += getStringifiedArgument(args[index]) + '|';
}
return [key];
}
/**
* @private
*
* @description
* based on the options passed, either use the serializer passed or generate the internal one
*
* @param options the options passed to the moized function
* @returns the function to use in serializing the arguments
*/
function getSerializerFunction(options) {
return typeof options.serializer === 'function' ? options.serializer : defaultArgumentSerializer;
}
/**
* @private
*
* @description
* are the serialized keys equal to one another
*
* @param cacheKey the cache key to compare
* @param key the key to test
* @returns are the keys equal
*/
function getIsSerializedKeyEqual(cacheKey, key) {
return cacheKey[0] === key[0];
}
function createOnCacheOperation(fn) {
if (typeof fn === 'function') {
return function (_cacheIgnored, _microMemoizeOptionsIgnored, memoized) {
return fn(memoized.cache, memoized.options, memoized);
};
}
}
/**
* @private
*
* @description
* get the isEqual method passed to micro-memoize
*
* @param options the options passed to the moizer
* @returns the isEqual method to apply
*/
function getIsEqual(options) {
return options.matchesArg || options.isDeepEqual && deepEqual || options.isShallowEqual && shallowEqual || sameValueZeroEqual;
}
/**
* @private
*
* @description
* get the isEqual method passed to micro-memoize
*
* @param options the options passed to the moizer
* @returns the isEqual method to apply
*/
function getIsMatchingKey(options) {
return options.matchesKey || options.isSerialized && getIsSerializedKeyEqual || undefined;
}
/**
* @private
*
* @description
* get the function that will transform the key based on the arguments passed
*
* @param options the options passed to the moizer
* @returns the function to transform the key with
*/
function getTransformKey(options) {
return compose(options.isSerialized && getSerializerFunction(options), typeof options.transformArgs === 'function' && options.transformArgs, typeof options.maxArgs === 'number' && createGetInitialArgs(options.maxArgs));
}
function createRefreshableMoized(moized) {
var updateCacheForKey = moized.options.updateCacheForKey;
/**
* @private
*
* @description
* Wrapper around already-`moize`d function which will intercept the memoization
* and call the underlying function directly with the purpose of updating the cache
* for the given key.
*
* Promise values use a tweak of the logic that exists at cache.updateAsyncCache, which
* reverts to the original value if the promise is rejected and there was already a cached
* value.
*/
var refreshableMoized = function refreshableMoized() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (!updateCacheForKey(args)) {
return moized.apply(this, args);
}
var result = moized.fn.apply(this, args);
moized.set(args, result);
return result;
};
copyStaticProperties(moized, refreshableMoized);
return refreshableMoized;
}
var _excluded = ["matchesArg", "isDeepEqual", "isPromise", "isReact", "isSerialized", "isShallowEqual", "matchesKey", "maxAge", "maxArgs", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "onExpire", "profileName", "serializer", "updateCacheForKey", "transformArgs", "updateExpire"];
/**
* @module moize
*/
/**
* @description
* memoize a function based its arguments passed, potentially improving runtime performance
*
* @example
* import moize from 'moize';
*
* // standard implementation
* const fn = (foo, bar) => `${foo} ${bar}`;
* const memoizedFn = moize(fn);
*
* // implementation with options
* const fn = async (id) => get(`http://foo.com/${id}`);
* const memoizedFn = moize(fn, {isPromise: true, maxSize: 5});
*
* // implementation with convenience methods
* const Foo = ({foo}) => <div>{foo}</div>;
* const MemoizedFoo = moize.react(Foo);
*
* @param fn the function to memoized, or a list of options when currying
* @param [options=DEFAULT_OPTIONS] the options to apply
* @returns the memoized function
*/
var moize = function moize(fn, passedOptions) {
var options = passedOptions || DEFAULT_OPTIONS;
if (isMoized(fn)) {
var moizeable = fn.originalFunction;
var mergedOptions = mergeOptions(fn.options, options);
return moize(moizeable, mergedOptions);
}
if (typeof fn === 'object') {
return function (curriedFn, curriedOptions) {
if (typeof curriedFn === 'function') {
var _mergedOptions = mergeOptions(fn, curriedOptions);
return moize(curriedFn, _mergedOptions);
}
var mergedOptions = mergeOptions(fn, curriedFn);
return moize(mergedOptions);
};
}
if (options.isReact) {
return createMoizedComponent(moize, fn, options);
}
var coalescedOptions = _extends({}, DEFAULT_OPTIONS, options, {
maxAge: typeof options.maxAge === 'number' && options.maxAge >= 0 ? options.maxAge : DEFAULT_OPTIONS.maxAge,
maxArgs: typeof options.maxArgs === 'number' && options.maxArgs >= 0 ? options.maxArgs : DEFAULT_OPTIONS.maxArgs,
maxSize: typeof options.maxSize === 'number' && options.maxSize >= 0 ? options.maxSize : DEFAULT_OPTIONS.maxSize,
profileName: options.profileName || getDefaultProfileName(fn)
});
var expirations = [];
coalescedOptions.matchesArg;
coalescedOptions.isDeepEqual;
var isPromise = coalescedOptions.isPromise;
coalescedOptions.isReact;
coalescedOptions.isSerialized;
coalescedOptions.isShallowEqual;
coalescedOptions.matchesKey;
coalescedOptions.maxAge;
coalescedOptions.maxArgs;
var maxSize = coalescedOptions.maxSize,
onCacheAdd = coalescedOptions.onCacheAdd,
onCacheChange = coalescedOptions.onCacheChange,
onCacheHit = coalescedOptions.onCacheHit;
coalescedOptions.onExpire;
coalescedOptions.profileName;
coalescedOptions.serializer;
var updateCacheForKey = coalescedOptions.updateCacheForKey;
coalescedOptions.transformArgs;
coalescedOptions.updateExpire;
var customOptions = _objectWithoutPropertiesLoose(coalescedOptions, _excluded);
var isEqual = getIsEqual(coalescedOptions);
var isMatchingKey = getIsMatchingKey(coalescedOptions);
var maxAgeOptions = getMaxAgeOptions(expirations, coalescedOptions, isEqual, isMatchingKey);
var statsOptions = getStatsOptions(coalescedOptions);
var transformKey = getTransformKey(coalescedOptions);
var microMemoizeOptions = _extends({}, customOptions, {
isEqual: isEqual,
isMatchingKey: isMatchingKey,
isPromise: isPromise,
maxSize: maxSize,
onCacheAdd: createOnCacheOperation(combine(onCacheAdd, maxAgeOptions.onCacheAdd, statsOptions.onCacheAdd)),
onCacheChange: createOnCacheOperation(onCacheChange),
onCacheHit: createOnCacheOperation(combine(onCacheHit, maxAgeOptions.onCacheHit, statsOptions.onCacheHit)),
transformKey: transformKey
});
var memoized = memoize(fn, microMemoizeOptions);
var moized = createMoizeInstance(memoized, {
expirations: expirations,
options: coalescedOptions,
originalFunction: fn
});
if (updateCacheForKey) {
moized = createRefreshableMoized(moized);
}
setName(moized, fn.name, options.profileName);
return moized;
};
/**
* @function
* @name clearStats
* @memberof module:moize
* @alias moize.clearStats
*
* @description
* clear all existing stats stored
*/
moize.clearStats = clearStats;
/**
* @function
* @name collectStats
* @memberof module:moize
* @alias moize.collectStats
*
* @description
* start collecting statistics
*/
moize.collectStats = collectStats;
/**
* @function
* @name compose
* @memberof module:moize
* @alias moize.compose
*
* @description
* method to compose moized methods and return a single moized function
*
* @param moized the functions to compose
* @returns the composed function
*/
moize.compose = function () {
return compose.apply(void 0, arguments) || moize;
};
/**
* @function
* @name deep
* @memberof module:moize
* @alias moize.deep
*
* @description
* should deep equality check be used
*
* @returns the moizer function
*/
moize.deep = moize({
isDeepEqual: true
});
/**
* @function
* @name getStats
* @memberof module:moize
* @alias moize.getStats
*
* @description
* get the statistics of a given profile, or overall usage
*
* @returns statistics for a given profile or overall usage
*/
moize.getStats = getStats;
/**
* @function
* @name infinite
* @memberof module:moize
* @alias moize.infinite
*
* @description
* a moized method that will remove all limits from the cache size
*
* @returns the moizer function
*/
moize.infinite = moize({
maxSize: Infinity
});
/**
* @function
* @name isCollectingStats
* @memberof module:moize
* @alias moize.isCollectingStats
*
* @description
* are stats being collected
*
* @returns are stats being collected
*/
moize.isCollectingStats = function isCollectingStats() {
return statsCache.isCollectingStats;
};
/**
* @function
* @name isMoized
* @memberof module:moize
* @alias moize.isMoized
*
* @description
* is the fn passed a moized function
*
* @param fn the object to test
* @returns is fn a moized function
*/
moize.isMoized = function isMoized(fn) {
return typeof fn === 'function' && !!fn.isMoized;
};
/**
* @function
* @name matchesArg
* @memberof module:moize
* @alias moize.matchesArg
*
* @description
* a moized method where the arg matching method is the custom one passed
*
* @param keyMatcher the method to compare against those in cache
* @returns the moizer function
*/
moize.matchesArg = function (argMatcher) {
return moize({
matchesArg: argMatcher
});
};
/**
* @function
* @name matchesKey
* @memberof module:moize
* @alias moize.matchesKey
*
* @description
* a moized method where the key matching method is the custom one passed
*
* @param keyMatcher the method to compare against those in cache
* @returns the moizer function
*/
moize.matchesKey = function (keyMatcher) {
return moize({
matchesKey: keyMatcher
});
};
function maxAge(maxAge, expireOptions) {
if (expireOptions === true) {
return moize({
maxAge: maxAge,
updateExpire: expireOptions
});
}
if (typeof expireOptions === 'object') {
var onExpire = expireOptions.onExpire,
updateExpire = expireOptions.updateExpire;
return moize({
maxAge: maxAge,
onExpire: onExpire,
updateExpire: updateExpire
});
}
if (typeof expireOptions === 'function') {
return moize({
maxAge: maxAge,
onExpire: expireOptions,
updateExpire: true
});
}
return moize({
maxAge: maxAge
});
}
/**
* @function
* @name maxAge
* @memberof module:moize
* @alias moize.maxAge
*
* @description
* a moized method where the age of the cache is limited to the number of milliseconds passed
*
* @param maxAge the TTL of the value in cache
* @returns the moizer function
*/
moize.maxAge = maxAge;
/**
* @function
* @name maxArgs
* @memberof module:moize
* @alias moize.maxArgs
*
* @description
* a moized method where the number of arguments used for determining cache is limited to the value passed
*
* @param maxArgs the number of args to base the key on
* @returns the moizer function
*/
moize.maxArgs = function maxArgs(maxArgs) {
return moize({
maxArgs: maxArgs
});
};
/**
* @function
* @name maxSize
* @memberof module:moize
* @alias moize.maxSize
*
* @description
* a moized method where the total size of the cache is limited to the value passed
*
* @param maxSize the maximum size of the cache
* @returns the moizer function
*/
moize.maxSize = function maxSize(maxSize) {
return moize({
maxSize: maxSize
});
};
/**
* @function
* @name profile
* @memberof module:moize
* @alias moize.profile
*
* @description
* a moized method with a profile name
*
* @returns the moizer function
*/
moize.profile = function (profileName) {
return moize({
profileName: profileName
});
};
/**
* @function
* @name promise
* @memberof module:moize
* @alias moize.promise
*
* @description
* a moized method specific to caching resolved promise / async values
*
* @returns the moizer function
*/
moize.promise = moize({
isPromise: true,
updateExpire: true
});
/**
* @function
* @name react
* @memberof module:moize
* @alias moize.react
*
* @description
* a moized method specific to caching React element values
*
* @returns the moizer function
*/
moize.react = moize({
isReact: true
});
/**
* @function
* @name serialize
* @memberof module:moize
* @alias moize.serialize
*
* @description
* a moized method that will serialize the arguments passed to use as the cache key
*
* @returns the moizer function
*/
moize.serialize = moize({
isSerialized: true
});
/**
* @function
* @name serializeWith
* @memberof module:moize
* @alias moize.serializeWith
*
* @description
* a moized method that will serialize the arguments passed to use as the cache key
* based on the serializer passed
*
* @returns the moizer function
*/
moize.serializeWith = function (serializer) {
return moize({
isSerialized: true,
serializer: serializer
});
};
/**
* @function
* @name shallow
* @memberof module:moize
* @alias moize.shallow
*
* @description
* should shallow equality check be used
*
* @returns the moizer function
*/
moize.shallow = moize({
isShallowEqual: true
});
/**
* @function
* @name transformArgs
* @memberof module:moize
* @alias moize.transformArgs
*
* @description
* transform the args to allow for specific cache key comparison
*
* @param transformArgs the args transformer
* @returns the moizer function
*/
moize.transformArgs = function (transformArgs) {
return moize({
transformArgs: transformArgs
});
};
/**
* @function
* @name updateCacheForKey
* @memberof module:moize
* @alias moize.updateCacheForKey
*
* @description
* update the cache for a given key when the method passed returns truthy
*
* @param updateCacheForKey the method to determine when to update cache
* @returns the moizer function
*/
moize.updateCacheForKey = function (updateCacheForKey) {
return moize({
updateCacheForKey: updateCacheForKey
});
};
// Add self-referring `default` property for edge-case cross-compatibility of mixed ESM/CommonJS usage.
// This property is frozen and non-enumerable to avoid visibility on iteration or accidental overrides.
Object.defineProperty(moize, 'default', {
configurable: false,
enumerable: false,
value: moize,
writable: false
});
export { moize as default };
//# sourceMappingURL=moize.esm.js.map