@eklabdev/blingts4
Version:
A comprehensive TypeScript decorators library implementing Stage 2 decorators for TS 4.9+
80 lines (79 loc) • 2.92 kB
JavaScript
const cache = new Map();
/**
* Caches method results with optional expiration
* @param options Cache configuration options
*/
export function Cached(options = {}) {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
const { expiryTime, key } = options;
const methodName = propertyKey;
const capitalizedName = methodName.charAt(0).toUpperCase() + methodName.slice(1);
const invalidateMethodName = `invalidate${capitalizedName}`;
// List of keys related to this method for invalidation
const methodCacheKeys = new Set();
// Add invalidation method to the prototype
const prototype = target.constructor.prototype;
prototype[invalidateMethodName] = function () {
methodCacheKeys.forEach(cacheKey => {
cache.delete(cacheKey);
});
methodCacheKeys.clear();
};
descriptor.value = function (...args) {
const cacheKey = typeof key === 'function'
? key(...args)
: `${this.constructor.name}:${methodName}:${JSON.stringify(args)}`;
methodCacheKeys.add(cacheKey);
const cached = cache.get(cacheKey);
if (cached) {
if (!cached.expiry || cached.expiry > Date.now()) {
return cached.value;
}
cache.delete(cacheKey);
}
const result = originalMethod.apply(this, args);
if (result instanceof Promise) {
return result.then(value => {
cache.set(cacheKey, {
value,
expiry: expiryTime ? Date.now() + expiryTime : undefined,
});
return value;
});
}
cache.set(cacheKey, {
value: result,
expiry: expiryTime ? Date.now() + expiryTime : undefined,
});
return result;
};
return descriptor;
};
}
/**
* Permanently caches method results
*/
export function Memoize() {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
const memoized = new Map();
const methodName = propertyKey;
descriptor.value = function (...args) {
const key = `${methodName}:${JSON.stringify(args)}`;
if (memoized.has(key)) {
return memoized.get(key);
}
const result = originalMethod.apply(this, args);
if (result instanceof Promise) {
return result.then(value => {
memoized.set(key, value);
return value;
});
}
memoized.set(key, result);
return result;
};
return descriptor;
};
}