Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
wraithgar committed Aug 21, 2024
1 parent d7e462b commit 3fd7a48
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 86 deletions.
168 changes: 134 additions & 34 deletions node_modules/lru-cache/dist/commonjs/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,26 @@ class Stack {
/**
* Default export, the thing you're using this module to get.
*
* All properties from the options object (with the exception of
* {@link OptionsBase.max} and {@link OptionsBase.maxSize}) are added as
* normal public members. (`max` and `maxBase` are read-only getters.)
* Changing any of these will alter the defaults for subsequent method calls,
* but is otherwise safe.
* The `K` and `V` types define the key and value types, respectively. The
* optional `FC` type defines the type of the `context` object passed to
* `cache.fetch()` and `cache.memo()`.
*
* Keys and values **must not** be `null` or `undefined`.
*
* All properties from the options object (with the exception of `max`,
* `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
* added as normal public members. (The listed options are read-only getters.)
*
* Changing any of these will alter the defaults for subsequent method calls.
*/
class LRUCache {
// properties coming in from the options of these, only max and maxSize
// really *need* to be protected. The rest can be modified, as they just
// set defaults for various methods.
// options that cannot be changed without disaster
#max;
#maxSize;
#dispose;
#disposeAfter;
#fetchMethod;
#memoMethod;
/**
* {@link LRUCache.OptionsBase.ttl}
*/
Expand Down Expand Up @@ -290,6 +295,9 @@ class LRUCache {
get fetchMethod() {
return this.#fetchMethod;
}
get memoMethod() {
return this.#memoMethod;
}
/**
* {@link LRUCache.OptionsBase.dispose} (read-only)
*/
Expand All @@ -303,7 +311,7 @@ class LRUCache {
return this.#disposeAfter;
}
constructor(options) {
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, } = options;
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, } = options;
if (max !== 0 && !isPosInt(max)) {
throw new TypeError('max option must be a nonnegative integer');
}
Expand All @@ -323,6 +331,11 @@ class LRUCache {
throw new TypeError('sizeCalculation set to non-function');
}
}
if (memoMethod !== undefined &&
typeof memoMethod !== 'function') {
throw new TypeError('memoMethod must be a function if defined');
}
this.#memoMethod = memoMethod;
if (fetchMethod !== undefined &&
typeof fetchMethod !== 'function') {
throw new TypeError('fetchMethod must be a function if specified');
Expand Down Expand Up @@ -401,7 +414,8 @@ class LRUCache {
}
}
/**
* Return the remaining TTL time for a given entry key
* Return the number of ms left in the item's TTL. If item is not in cache,
* returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
*/
getRemainingTTL(key) {
return this.#keyMap.has(key) ? Infinity : 0;
Expand All @@ -417,7 +431,7 @@ class LRUCache {
if (ttl !== 0 && this.ttlAutopurge) {
const t = setTimeout(() => {
if (this.#isStale(index)) {
this.delete(this.#keyList[index]);
this.#delete(this.#keyList[index], 'expire');
}
}, ttl + 1);
// unref() not supported on all platforms
Expand Down Expand Up @@ -674,13 +688,14 @@ class LRUCache {
return this.entries();
}
/**
* A String value that is used in the creation of the default string description of an object.
* Called by the built-in method Object.prototype.toString.
* A String value that is used in the creation of the default string
* description of an object. Called by the built-in method
* `Object.prototype.toString`.
*/
[Symbol.toStringTag] = 'LRUCache';
/**
* Find a value for which the supplied fn method returns a truthy value,
* similar to Array.find(). fn is called as fn(value, key, cache).
* similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
*/
find(fn, getOptions = {}) {
for (const i of this.#indexes()) {
Expand All @@ -696,10 +711,15 @@ class LRUCache {
}
}
/**
* Call the supplied function on each item in the cache, in order from
* most recently used to least recently used. fn is called as
* fn(value, key, cache). Does not update age or recenty of use.
* Does not iterate over stale values.
* Call the supplied function on each item in the cache, in order from most
* recently used to least recently used.
*
* `fn` is called as `fn(value, key, cache)`.
*
* If `thisp` is provided, function will be called in the `this`-context of
* the provided object, or the cache if no `thisp` object is provided.
*
* Does not update age or recenty of use, or iterate over stale values.
*/
forEach(fn, thisp = this) {
for (const i of this.#indexes()) {
Expand Down Expand Up @@ -735,17 +755,23 @@ class LRUCache {
let deleted = false;
for (const i of this.#rindexes({ allowStale: true })) {
if (this.#isStale(i)) {
this.delete(this.#keyList[i]);
this.#delete(this.#keyList[i], 'expire');
deleted = true;
}
}
return deleted;
}
/**
* Get the extended info about a given entry, to get its value, size, and
* TTL info simultaneously. Like {@link LRUCache#dump}, but just for a
* single key. Always returns stale values, if their info is found in the
* cache, so be sure to check for expired TTLs if relevant.
* TTL info simultaneously. Returns `undefined` if the key is not present.
*
* Unlike {@link LRUCache#dump}, which is designed to be portable and survive
* serialization, the `start` value is always the current timestamp, and the
* `ttl` is a calculated remaining time to live (negative if expired).
*
* Always returns stale values, if their info is found in the cache, so be
* sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
* if relevant.
*/
info(key) {
const i = this.#keyMap.get(key);
Expand Down Expand Up @@ -774,7 +800,16 @@ class LRUCache {
}
/**
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
* passed to cache.load()
* passed to {@link LRLUCache#load}.
*
* The `start` fields are calculated relative to a portable `Date.now()`
* timestamp, even if `performance.now()` is available.
*
* Stale entries are always included in the `dump`, even if
* {@link LRUCache.OptionsBase.allowStale} is false.
*
* Note: this returns an actual array, not a generator, so it can be more
* easily passed around.
*/
dump() {
const arr = [];
Expand Down Expand Up @@ -803,8 +838,12 @@ class LRUCache {
}
/**
* Reset the cache and load in the items in entries in the order listed.
* Note that the shape of the resulting cache may be different if the
* same options are not used in both caches.
*
* The shape of the resulting cache may be different if the same options are
* not used in both caches.
*
* The `start` fields are assumed to be calculated relative to a portable
* `Date.now()` timestamp, even if `performance.now()` is available.
*/
load(arr) {
this.clear();
Expand All @@ -827,6 +866,30 @@ class LRUCache {
*
* Note: if `undefined` is specified as a value, this is an alias for
* {@link LRUCache#delete}
*
* Fields on the {@link LRUCache.SetOptions} options param will override
* their corresponding values in the constructor options for the scope
* of this single `set()` operation.
*
* If `start` is provided, then that will set the effective start
* time for the TTL calculation. Note that this must be a previous
* value of `performance.now()` if supported, or a previous value of
* `Date.now()` if not.
*
* Options object may also include `size`, which will prevent
* calling the `sizeCalculation` function and just use the specified
* number if it is a positive integer, and `noDisposeOnSet` which
* will prevent calling a `dispose` function in the case of
* overwrites.
*
* If the `size` (or return value of `sizeCalculation`) for a given
* entry is greater than `maxEntrySize`, then the item will not be
* added to the cache.
*
* Will update the recency of the entry.
*
* If the value is `undefined`, then this is an alias for
* `cache.delete(key)`. `undefined` is never stored in the cache.
*/
set(k, v, setOptions = {}) {
if (v === undefined) {
Expand All @@ -844,7 +907,7 @@ class LRUCache {
status.maxEntrySizeExceeded = true;
}
// have to delete, in case something is there already.
this.delete(k);
this.#delete(k, 'set');
return this;
}
let index = this.#size === 0 ? undefined : this.#keyMap.get(k);
Expand Down Expand Up @@ -996,6 +1059,14 @@ class LRUCache {
* Will return false if the item is stale, even though it is technically
* in the cache.
*
* Check if a key is in the cache, without updating the recency of
* use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
* to `true` in either the options or the constructor.
*
* Will return `false` if the item is stale, even though it is technically in
* the cache. The difference can be determined (if it matters) by using a
* `status` argument, and inspecting the `has` field.
*
* Will not update item age unless
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
*/
Expand Down Expand Up @@ -1087,7 +1158,7 @@ class LRUCache {
this.#valList[index] = bf.__staleWhileFetching;
}
else {
this.delete(k);
this.#delete(k, 'fetch');
}
}
else {
Expand Down Expand Up @@ -1116,7 +1187,7 @@ class LRUCache {
// the stale value is not removed from the cache when the fetch fails.
const del = !noDelete || bf.__staleWhileFetching === undefined;
if (del) {
this.delete(k);
this.#delete(k, 'fetch');
}
else if (!allowStaleAborted) {
// still replace the *promise* with the stale value,
Expand Down Expand Up @@ -1262,6 +1333,28 @@ class LRUCache {
return staleVal ? p.__staleWhileFetching : (p.__returned = p);
}
}
async forceFetch(k, fetchOptions = {}) {
const v = await this.fetch(k, fetchOptions);
if (v === undefined)
throw new Error('fetch() returned undefined');
return v;
}
memo(k, memoOptions = {}) {
const memoMethod = this.#memoMethod;
if (!memoMethod) {
throw new Error('no memoMethod provided to constructor');
}
const { context, forceRefresh, ...options } = memoOptions;
const v = this.get(k, options);
if (!forceRefresh && v !== undefined)
return v;
const vv = memoMethod(k, v, {
options,
context,
});
this.set(k, vv, options);
return vv;
}
/**
* Return a value from the cache. Will update the recency of the cache
* entry found.
Expand All @@ -1282,7 +1375,7 @@ class LRUCache {
// delete only if not an in-flight background fetch
if (!fetching) {
if (!noDeleteOnStaleGet) {
this.delete(k);
this.#delete(k, 'expire');
}
if (status && allowStale)
status.returnedStale = true;
Expand Down Expand Up @@ -1345,16 +1438,20 @@ class LRUCache {
}
/**
* Deletes a key out of the cache.
*
* Returns true if the key was deleted, false otherwise.
*/
delete(k) {
return this.#delete(k, 'delete');
}
#delete(k, reason) {
let deleted = false;
if (this.#size !== 0) {
const index = this.#keyMap.get(k);
if (index !== undefined) {
deleted = true;
if (this.#size === 1) {
this.clear();
this.#clear(reason);
}
else {
this.#removeItemSize(index);
Expand All @@ -1364,10 +1461,10 @@ class LRUCache {
}
else if (this.#hasDispose || this.#hasDisposeAfter) {
if (this.#hasDispose) {
this.#dispose?.(v, k, 'delete');
this.#dispose?.(v, k, reason);
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([v, k, 'delete']);
this.#disposed?.push([v, k, reason]);
}
}
this.#keyMap.delete(k);
Expand Down Expand Up @@ -1403,6 +1500,9 @@ class LRUCache {
* Clear the cache entirely, throwing away all values.
*/
clear() {
return this.#clear('delete');
}
#clear(reason) {
for (const index of this.#rindexes({ allowStale: true })) {
const v = this.#valList[index];
if (this.#isBackgroundFetch(v)) {
Expand All @@ -1411,10 +1511,10 @@ class LRUCache {
else {
const k = this.#keyList[index];
if (this.#hasDispose) {
this.#dispose?.(v, k, 'delete');
this.#dispose?.(v, k, reason);
}
if (this.#hasDisposeAfter) {
this.#disposed?.push([v, k, 'delete']);
this.#disposed?.push([v, k, reason]);
}
}
}
Expand Down
Loading

0 comments on commit 3fd7a48

Please sign in to comment.