UNPKG

@boost/decorators

Version:

Experimental decorators for common patterns.

87 lines (81 loc) 4.25 kB
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import { isMethod } from './helpers/isMethod.mjs'; function hasher(...args) { return JSON.stringify(args); } function createMemoizer(method, rootCache, options) { // Must be a normal function as we require `this` return function memoizer(...args) { // Extract the cache for this specific instance let cache = rootCache.get(this); if (!cache) { cache = options.cache ? new Map(options.cache) : new Map(); rootCache.set(this, cache); } // Hash the key and check the cache const key = options.hasher(...args); const item = cache.get(key); if (item && (!item.time || typeof item.time === 'number' && item.time > Date.now())) { return item.value; } // No cache so execute and cache the result const value = method.apply(this, args); const time = options.expires > 0 ? Date.now() + options.expires : null; cache.set(key, { time, value }); // Only cache if successful if (value instanceof Promise) { // eslint-disable-next-line promise/prefer-await-to-then value.catch(() => cache?.delete(key)); } return value; }; } /** * A method decorator that caches the return value of a class method or * getter to consistently and efficiently return the same value. */ function Memoize(options = {}) { // eslint-disable-next-line complexity return (target, property, descriptor) => { if (process.env.NODE_ENV !== "production" && (!isMethod(target, property, descriptor) || !('value' in descriptor && typeof descriptor.value === 'function') && !('get' in descriptor && typeof descriptor.get === 'function'))) { throw new TypeError(`\`@Memoize\` may only be applied to class methods or getters.`); } const config = _objectSpread({ cache: null, expires: 0, hasher }, typeof options === 'function' ? { hasher: options } : options); if (process.env.NODE_ENV !== "production") { if (config.cache && !(config.cache instanceof Map)) { throw new Error('`cache` must be an instance of `Map`.'); } if (typeof config.expires !== 'number' || config.expires < 0) { throw new Error('`expires` must be a number greater than or equal to 0.'); } if (typeof config.hasher !== 'function') { throw new TypeError('`hasher` must be a function.'); } } // We must use a map as all class instances would share the // same cache otherwise. Probability of collision is high. const rootCache = new WeakMap(); if (descriptor.get) { // @ts-expect-error Override generic descriptor.get = createMemoizer(descriptor.get, rootCache, config); } else if (descriptor.value) { // @ts-expect-error Override generic descriptor.value = createMemoizer(descriptor.value, rootCache, config); } }; } export { Memoize }; //# sourceMappingURL=Memoize.mjs.map