Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@swarmy/lru-cache

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@swarmy/lru-cache - npm Package Compare versions

Comparing version 3.0.0 to 3.1.1

2

build/lru-cache.js

@@ -1,1 +0,1 @@

module.exports=function(t){var r={};function u(e){if(r[e])return r[e].exports;var n=r[e]={i:e,l:!1,exports:{}};return t[e].call(n.exports,n,n.exports,u),n.l=!0,n.exports}return u.m=t,u.c=r,u.d=function(e,n,t){u.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},u.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},u.t=function(n,e){if(1&e&&(n=u(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var t=Object.create(null);if(u.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var r in n)u.d(t,r,function(e){return n[e]}.bind(null,r));return t},u.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return u.d(n,"a",n),n},u.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},u.p="",u(u.s=0)}([function(e,n,t){"use strict";t.r(n);var l=function(e,n){null===n.newest?(n.newest=e,n.oldest=e):((n.newest.next=e).prev=n.newest,n.newest=e)},i=function(e,n){e!==n.newest&&(null===(n.newest.next=e).prev?(e.prev=n.newest,e.next.prev=null,n.oldest=e.next):(e.prev.next=e.next,e.next.prev=e.prev,e.prev=n.newest),e.next=null,n.newest=e)},r=function(e,n,t){null===e.next?n.newest=e.prev:e.next.prev=e.prev,null===e.prev?n.oldest=e.next:e.prev.next=e.next,t.delete(e.key)},c=function(e,n,t){var r,u,o,a=[];if(null===e)return a;for(;t.size>e;)a.push((u=t,void 0,o=(r=n).oldest,u.delete(r.oldest.key),r.oldest=r.oldest.next,r.oldest.prev=null,{key:o.key,value:o.value}));return a};function f(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=this instanceof f?this:Object.create(f.prototype),u=e;0===u&&(u=null);var o=new Map,a={newest:null,oldest:null};return n.setMaxSize=function(e){return(u=e)<1&&(u=null),c(u,a,o)},n.getMaxSize=function(){return u},n.getSize=function(){return o.size},n.set=function(e,n){var t=o.get(e);if(void 0!==t)return t.value=n,i(t,a),null;t={key:e,value:n,next:null,prev:null},o.set(e,t),l(t,a);var r=c(u,a,o);return 1===r.length?r[0]:null},n.get=function(e){var n=o.get(e);return void 0===n?n:(i(n,a),n.value)},n.getWithoutLruChange=function(e){var n=o.get(e);return void 0===n?n:n.value},n.delete=function(e){var n=o.get(e);return void 0!==n&&(r(n,a,o),!0)},n.forEach=function(e){for(var n=a.oldest;null!==n;)e(n.value,n.key),n=n.next},n.map=function(e){for(var n=a.oldest,t=[];null!==n;)t.push(e(n.value,n.key)),n=n.next;return t},n.clear=function(){var e=n.map(function(e,n){return{key:n,value:e}});return o.clear(),a.newest=null,a.oldest=null,e},n}function y(e){return function(e){if(Array.isArray(e)){for(var n=0,t=new Array(e.length);n<e.length;n++)t[n]=e[n];return t}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function a(n){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},r=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.forEach(function(e){s(n,e,t[e])})}return n}function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}t.d(n,"registerCacheChangedHandler",function(){return w}),t.d(n,"cacheTransaction",function(){return S}),t.d(n,"getCache",function(){return L}),t.d(n,"clearAllCaches",function(){return _});var v=500,u=0,d=new Map,h=new Map,p=new Set,o=function(t,e){null===e||Array.isArray(e)&&0===e.length?p.add(t):(Array.isArray(e)?e:[e]).forEach(function(e){var n=h.get(e);void 0===n&&(n=new Set,h.set(e,n)),n.add(t)})},g=function(n,e){null===e||Array.isArray(e)&&0===e.length?p.delete(n):(Array.isArray(e)?e:[e]).forEach(function(e){h.get(e).delete(n)})},w=function(e){var n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,t=u;u+=1;var r={changedHandler:e,valueTypes:n,isActive:!0,unregister:function(){d.delete(t),g(t,n)},activate:function(){r.isActive=!0,o(t,n)},deactivate:function(){r.isActive=!1,g(t,n)},isRegistered:function(){return d.has(t)}};return d.set(t,r),o(t,n),r},m=function(t){var e,n,r,u=(e=t.valueTypes,n="string"==typeof e?[e]:e,r=new Set,n.forEach(function(e){var n=h.get(e);void 0!==n&&n.forEach(function(e){r.add(e)})}),p.forEach(function(e){r.add(e)}),r),o=[],a=0;if(u.forEach(function(e){var n=d.get(e);try{n.changedHandler(t)}catch(e){o.push(e)}finally{a+=1}}),0<o.length){var l="handleTransactionChangeObject: "+String(o.length)+" of "+String(a)+" handlers threw an error: ";o.forEach(function(e){l+=e.message+", "});var i=new Error(l);throw i.errors=o,i}},b=null,A=0,x=0,S=function(e){if(null===b&&(b={valueTypes:new Set}),x+=1,"function"==typeof e.finally)e.finally(function(){if(0===(x-=1))try{m(b)}finally{b=null,A=0}});else try{e()}finally{if(0===(x-=1))try{m(b)}finally{b=null,A=0}}},E=function(n,e,t,r){var u=b,o=null!==u;null===u&&(u={valueTypes:new Set}),u.valueTypes.has(n)?u[n][t].push(a({},e,{order:A++})):(u.valueTypes.add(n),u[n]=s({},t,[a({},e,{order:A++})]),r.forEach(function(e){u[n][e]=[]})),o||m(u)},O=!0,j=function(e,n){O&&E(e,n,"clearRemoves",["inserts","lruRemoves","deleteRemoves"])},k=function(e,n){O&&E(e,n,"lruRemoves",["clearRemoves","inserts","deleteRemoves"])},M=function(e,n){O&&E(e,n,"deleteRemoves",["clearRemoves","lruRemoves","inserts"])},R=function(u){return function(){for(var e=arguments.length,r=new Array(e),n=0;n<e;n++)r[n]=arguments[n];return new Promise(function(n,t){setTimeout(function(){try{var e=u.apply(void 0,r);n(e)}catch(e){t(e)}},0)})}},z=function(e,n){if(function(e){if(0<p.size)return!0;var n=h.get(e);return void 0!==n&&0<n.size}(e))S(n);else try{O=!1,n()}finally{O=!0}},C=function(c,f,s,e,v){if(!Array.isArray(e))throw new Error("LruCache::setAll: keyValueAlternateKeysArray must be an array");z(c,function(){e.forEach(function(e){var n=e.key,t=e.value,r=e.alternateKeys,u=f.getWithoutLruChange(n),o=Array.isArray(r)?r:[];0===o.length&&"string"==typeof r&&(o=[r]),o.forEach(function(e){if(s.has(e)&&s.get(e)!==n)throw new Error("LruCache::setAll: alternate key '"+e+"' is given for key '"+n+"' and value type '"+c+"' but is already used for key '"+s.get(e)+"'")}),o=new Set(o),void 0===u?u={key:n,value:t,alternateKeys:o}:(u.value=t,u.alternateKeys=new Set(y(u.alternateKeys).concat(y(o))));var a,l,i=f.set(n,u);o.forEach(function(e){s.set(e,n)}),a=c,l=u,O&&E(a,l,"inserts",["clearRemoves","lruRemoves","deleteRemoves"]),null!==i&&(i.value.alternateKeys.forEach(function(e){s.delete(e)}),v&&k(c,i.value))})})},T=function(e,n,t){var r=t(e);return void 0===r&&n.has(e)&&(r=t(n.get(e))),r};function P(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:v,n=this instanceof P?this:Object.create(P.prototype),r=f(e),u=new Map,o=!1,a=!1;return n.dispatchLruRemoves=function(e){o=e},n.dispatchClearRemoves=function(e){a=e},n.setAll=function(e){C(t,r,u,e,o)},n.setAllAsync=R(n.setAll),n.set=function(e){n.setAll([e])},n.setAsync=R(n.set),n.get=function(e){var n=T(e,u,r.get);return void 0===n?n:n.value},n.getWithoutLruChange=function(e){var n=T(e,u,r.getWithoutLruChange);return void 0===n?n:n.value},n.delete=function(e){var n=T(e,u,r.getWithoutLruChange);return void 0===n?(z(t,function(){M(t,{key:e})}),!1):(r.delete(n.key),n.alternateKeys.forEach(function(e){u.delete(e)}),z(t,function(){M(t,{key:e})}),!0)},n.forEach=r.forEach,n.getEntries=function(){return r.map(function(e){return e})},n.clear=function(){var e=r.clear();u.clear(),a&&z(t,function(){e.forEach(function(e){j(t,e.value)})})},n.getSize=r.getSize,n.getValueType=function(){return t},n.getMaxSize=r.getMaxSize,n.setMaxSize=function(e){var n=r.setMaxSize(e);z(t,function(){n.forEach(function(e){e.value.alternateKeys.forEach(function(e){u.delete(e)}),o&&k(t,e.value)})})},n}var K=new Map,L=function(e){var n=K.get(e);return void 0===n&&(n=P(e),K.set(e,n)),n},_=function(){S(function(){K.forEach(function(e){e.clear()})})}}]);
module.exports=function(t){var r={};function u(e){if(r[e])return r[e].exports;var n=r[e]={i:e,l:!1,exports:{}};return t[e].call(n.exports,n,n.exports,u),n.l=!0,n.exports}return u.m=t,u.c=r,u.d=function(e,n,t){u.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},u.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},u.t=function(n,e){if(1&e&&(n=u(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var t=Object.create(null);if(u.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var r in n)u.d(t,r,function(e){return n[e]}.bind(null,r));return t},u.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return u.d(n,"a",n),n},u.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},u.p="",u(u.s=0)}([function(e,n,t){"use strict";t.r(n);var l=function(e,n){null===n.newest?(n.newest=e,n.oldest=e):((n.newest.next=e).prev=n.newest,n.newest=e)},i=function(e,n){e!==n.newest&&(null===(n.newest.next=e).prev?(e.prev=n.newest,e.next.prev=null,n.oldest=e.next):(e.prev.next=e.next,e.next.prev=e.prev,e.prev=n.newest),e.next=null,n.newest=e)},r=function(e,n,t){null===e.next?n.newest=e.prev:e.next.prev=e.prev,null===e.prev?n.oldest=e.next:e.prev.next=e.next,t.delete(e.key)},c=function(e,n,t){var r,u,o,a=[];if(null===e)return a;for(;t.size>e;)a.push((u=t,void 0,o=(r=n).oldest,u.delete(r.oldest.key),r.oldest=r.oldest.next,r.oldest.prev=null,{key:o.key,value:o.value}));return a};function f(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=this instanceof f?this:Object.create(f.prototype),u=e;0===u&&(u=null);var o=new Map,a={newest:null,oldest:null};return n.setMaxSize=function(e){return(u=e)<1&&(u=null),c(u,a,o)},n.getMaxSize=function(){return u},n.getSize=function(){return o.size},n.set=function(e,n){var t=o.get(e);if(void 0!==t)return t.value=n,i(t,a),null;t={key:e,value:n,next:null,prev:null},o.set(e,t),l(t,a);var r=c(u,a,o);return 1===r.length?r[0]:null},n.get=function(e){var n=o.get(e);return void 0===n?n:(i(n,a),n.value)},n.getWithoutLruChange=function(e){var n=o.get(e);return void 0===n?n:n.value},n.has=function(e){return o.has(e)},n.delete=function(e){var n=o.get(e);return void 0!==n&&(r(n,a,o),!0)},n.forEach=function(e){for(var n=a.oldest;null!==n;)e(n.value,n.key),n=n.next},n.map=function(e){for(var n=a.oldest,t=[];null!==n;)t.push(e(n.value,n.key)),n=n.next;return t},n.clear=function(){var e=n.map(function(e,n){return{key:n,value:e}});return o.clear(),a.newest=null,a.oldest=null,e},n}function y(e){return function(e){if(Array.isArray(e)){for(var n=0,t=new Array(e.length);n<e.length;n++)t[n]=e[n];return t}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function a(n){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},r=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.forEach(function(e){s(n,e,t[e])})}return n}function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}t.d(n,"registerCacheChangedHandler",function(){return w}),t.d(n,"cacheTransaction",function(){return E}),t.d(n,"getCache",function(){return K}),t.d(n,"clearAllCaches",function(){return L});var v=500,u=0,d=new Map,h=new Map,p=new Set,o=function(t,e){null===e||Array.isArray(e)&&0===e.length?p.add(t):(Array.isArray(e)?e:[e]).forEach(function(e){var n=h.get(e);void 0===n&&(n=new Set,h.set(e,n)),n.add(t)})},g=function(n,e){null===e||Array.isArray(e)&&0===e.length?p.delete(n):(Array.isArray(e)?e:[e]).forEach(function(e){h.get(e).delete(n)})},w=function(e){var n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,t=u;u+=1;var r={changedHandler:e,valueTypes:n,isActive:!0,unregister:function(){d.delete(t),g(t,n)},activate:function(){r.isActive=!0,o(t,n)},deactivate:function(){r.isActive=!1,g(t,n)},isRegistered:function(){return d.has(t)}};return d.set(t,r),o(t,n),r},m=function(t){var e,n,r,u=(e=t.valueTypes,n="string"==typeof e?[e]:e,r=new Set,n.forEach(function(e){var n=h.get(e);void 0!==n&&n.forEach(function(e){r.add(e)})}),p.forEach(function(e){r.add(e)}),r),o=[],a=0;if(u.forEach(function(e){var n=d.get(e);try{n.changedHandler(t)}catch(e){o.push(e)}finally{a+=1}}),0<o.length){var l="handleTransactionChangeObject: "+String(o.length)+" of "+String(a)+" handlers threw an error: ";o.forEach(function(e){l+=e.message+", "});var i=new Error(l);throw i.errors=o,i}},b=null,A=0,x=0,E=function(e){if(null===b&&(b={valueTypes:new Set}),x+=1,"function"==typeof e.finally)e.finally(function(){if(0===(x-=1))try{m(b)}finally{b=null,A=0}});else try{e()}finally{if(0===(x-=1))try{m(b)}finally{b=null,A=0}}},S=function(n,e,t,r){var u=b,o=null!==u;null===u&&(u={valueTypes:new Set}),u.valueTypes.has(n)?u[n][t].push(a({},e,{order:A++})):(u.valueTypes.add(n),u[n]=s({},t,[a({},e,{order:A++})]),r.forEach(function(e){u[n][e]=[]})),o||m(u)},O=!0,j=function(e,n){O&&S(e,n,"clearRemoves",["inserts","lruRemoves","deleteRemoves"])},k=function(e,n){O&&S(e,n,"lruRemoves",["clearRemoves","inserts","deleteRemoves"])},M=function(e,n){O&&S(e,n,"deleteRemoves",["clearRemoves","lruRemoves","inserts"])},R=function(u){return function(){for(var e=arguments.length,r=new Array(e),n=0;n<e;n++)r[n]=arguments[n];return new Promise(function(n,t){setTimeout(function(){try{var e=u.apply(void 0,r);n(e)}catch(e){t(e)}},0)})}},z=function(e,n){if(function(e){if(0<p.size)return!0;var n=h.get(e);return void 0!==n&&0<n.size}(e))E(n);else try{O=!1,n()}finally{O=!0}},C=function(c,f,s,e,v){if(!Array.isArray(e))throw new Error("LruCache::setAll: keyValueAlternateKeysArray must be an array");z(c,function(){e.forEach(function(e){var n=e.key,t=e.value,r=e.alternateKeys,u=f.getWithoutLruChange(n),o=Array.isArray(r)?r:[];0===o.length&&"string"==typeof r&&(o=[r]),o.forEach(function(e){if(s.has(e)&&s.get(e)!==n)throw new Error("LruCache::setAll: alternate key '"+e+"' is given for key '"+n+"' and value type '"+c+"' but is already used for key '"+s.get(e)+"'")}),o=new Set(o),void 0===u?u={key:n,value:t,alternateKeys:o}:(u.value=t,u.alternateKeys=new Set(y(u.alternateKeys).concat(y(o))));var a,l,i=f.set(n,u);o.forEach(function(e){s.set(e,n)}),a=c,l=u,O&&S(a,l,"inserts",["clearRemoves","lruRemoves","deleteRemoves"]),null!==i&&(i.value.alternateKeys.forEach(function(e){s.delete(e)}),v&&k(c,i.value))})})};function T(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:v,a=this instanceof T?this:Object.create(T.prototype),r=f(e),l=new Map,u=!1,n=!1;a.dispatchLruRemoves=function(e){u=e},a.dispatchClearRemoves=function(e){n=e},a.setAll=function(e){C(t,r,l,e,u)},a.setAllAsync=R(a.setAll),a.set=function(e){a.setAll([e])},a.setAsync=R(a.set);var i=null,c=new Map,o=function(n,e){var t=2<arguments.length&&void 0!==arguments[2]&&arguments[2],r=e(n);if(void 0===r&&l.has(n))r=e(l.get(n));else if(void 0===r){if(t&&null!==i){if(c.has(n))return c.get(n);var u=i(n);if(!u)return r;if("function"!=typeof u.then)return a.set(u),u.value;var o=u.then(function(e){return e?(c.has(n)&&a.set(e),e.value):e}).finally(function(){c.delete(n)});return c.set(n,o),o}return r}return r.value};return a.setEntryGetter=function(e){i=e},a.get=function(e){return o(e,r.get,!0)},a.getWithoutLruChange=function(e){return o(e,r.getWithoutLruChange,!0)},a.has=function(e){return!!r.has(e)||l.has(e)},a.delete=function(e){var n=r.getWithoutLruChange(e);return void 0===n?(z(t,function(){M(t,{key:e})}),!1):(r.delete(n.key),n.alternateKeys.forEach(function(e){l.delete(e)}),z(t,function(){M(t,{key:e})}),!0)},a.forEach=r.forEach,a.getEntries=function(){return r.map(function(e){return e})},a.clear=function(){var e=r.clear();l.clear(),n&&z(t,function(){e.forEach(function(e){j(t,e.value)})})},a.getSize=r.getSize,a.getValueType=function(){return t},a.getMaxSize=r.getMaxSize,a.setMaxSize=function(e){var n=r.setMaxSize(e);z(t,function(){n.forEach(function(e){e.value.alternateKeys.forEach(function(e){l.delete(e)}),u&&k(t,e.value)})})},a}var P=new Map,K=function(e){var n=P.get(e);return void 0===n&&(n=T(e),P.set(e,n)),n},L=function(){E(function(){P.forEach(function(e){e.clear()})})}}]);
{
"name": "@swarmy/lru-cache",
"version": "3.0.0",
"version": "3.1.1",
"description": "LRU cache with event registry to handle cache changes",

@@ -5,0 +5,0 @@ "author": "Gerd Neudert",

@@ -5,2 +5,3 @@ # lru-cache

* Alternate keys
* Value getter for cache fails
* Singleton caches per value type

@@ -11,13 +12,28 @@ * Event registry for cache change events

## Table of Contents
1. [Installation](#section-installation)
2. [Motivation](#section-motivation)
3. [Basic Usage](#section-basic-usage)
4. [Quality](#section-quality)
5. [Develop](#section-develop)
6. [Detailed Usage](#section-detailed-usage)
7. [Performance](#section-performance)
8. [Questions](#section-questions)
9. [Roadmap](#section-roadmap)
1. [What's New](#section-news)
2. [Installation](#section-installation)
3. [Motivation](#section-motivation)
4. [Basic Usage](#section-basic-usage)
5. [Quality](#section-quality)
6. [Develop](#section-develop)
7. [Detailed Usage](#section-detailed-usage)
8. [Performance](#section-performance)
9. [Questions](#section-questions)
10. [Roadmap](#section-roadmap)
## What's New <a name="section-news"></a>
### Version 3.1.0
* New LruCache method `setEntryGetter`
* Use it to set a function that provides a key-value-alternateKeys object (as expected by `set`)
* If in a call to `get` or `getWithoutLruChange`, the given key is not in the cache and an entryGetter is set, then the entry getter will be called
* In case of a synchronous entry getter, the returned entry will be inserted into the cache and the value is returned to the caller of the get method
* In case of an asynchronous entry getter, a Promise will be returned to the caller of the get method
* Subsequent calls to `get` or `getWithoutLruChange` will return the same Promise, until it is resolved
* The Promise resolves to the `entry.value` returned by the entry getter
* After the Promise resolved, the entry will be in the cache
* New LruCache method `has`
* To test if a key or alternate key is in the cache
* Prior to 3.1.0, `getWithoutLruChange` could be used in all cases to test if a value is already cached. However, now the `has` method might be mandatory to do so in case an entry getter was set.
## Installation <a name="section-installation"></a>

@@ -58,3 +74,3 @@ ```javascript

* [Detailed Usage](#caching-detail)
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/docs/index.html)
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/docs/index.html)

@@ -72,8 +88,8 @@ ### Cache Events

* [Detailed Usage](#cache-events-detail)
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/docs/index.html)
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/docs/index.html)
## Quality <a name="section-quality"></a>
* [Test results](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/test-report.html)
* [Test coverage](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/coverage/index.html)
* [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/performance-report.html)
* [Test results](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/test-report.html)
* [Test coverage](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/coverage/index.html)
* [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/performance-report.html)

@@ -109,7 +125,7 @@ ## Develop <a name="section-develop"></a>

`clear` | none | undefined | Invalidate the cache. If dispatchClearRemoves is set true for the cache, then a single event will be dispatched for the clear.
`delete` | keyOrAlternateKey: string | wasInCache: boolean | Remove an entry from the cache. A corresponding cache event will be dispatched.
`delete` | key: string | wasInCache: boolean | Remove an entry from the cache. A corresponding cache event will be dispatched. Here, no alternate key is allowed!
`dispatchClearRemoves` | newValue: boolean | undefined | Set whether a cache clear should dispatch a cache event (default: false).
`dispatchLruRemoves` | newValue: boolean | undefined | Set whether a LRU-remove (entry being removed due to exceeded cache size) should dispatch a cache event (default: false).
`forEach` | callback: function | undefined | Iterate over the cache from olodest to newest value. Callback receives cache entry as argument, being an object with `key`, `value` and `alternateKeys`.
`get` | keyOrAlternateKey: string | value | get cached value or undefined. The returned value will be made the newest value in the cache.
`get` | keyOrAlternateKey: string | value | Get cached value or undefined. The returned value will be made the newest value in the cache. If an entry getter is set (see `setEntryGetter`), this getter will be used in case of a cache miss. If the entry getter is an async function, then a Promise will be returned that resolves to the value (Subsequent calls to get will return the same Promise until resolved, so the entry getter is called only once).
`getEntries` | none | Array | Returns an array with all cache entries, order from oldest to newest.

@@ -120,7 +136,9 @@ `getMaxSize` | none | Int | Returns the current max size of the cache.

`getWithoutLruChange` | keyOrAlternateKey: string | value | Like `get`, but without making the entry the newest in the cache.
`has` | keyOrAlternateKey: string | isInCache: boolean | True, if the key or alternate key is in the cache.
`set` | keyValueAlternateKeys: object | undefined | Insert or update a value in the cache. The argument must be an object with `key` and `value`. Optionally it can also have `alternateKeys`, being string or array of strings. After set, the value will be the newest in the cache. Dispatches a corresponding cache event. If an insert exceeds the max cache size and dispatchLruRemoves is set true, it will be included in the event.
`setAll` | Array\[keyValueAlternateKeys\] | undefined | Like `set`, but for an array of cache entries. Leading to a single cache event.
`setAllAsync` | Array\[keyValueAlternateKeys\] | Promise | Like `setAll`, but performing insert and event dispatch in another event loop, resolving the returned promise afterwards.
`set` | keyValueAlternateKeys: object | Promise | Like `set`, but performing insert and event dispatch in another event loop, resolving the returned promise afterwards.
`setMaxSize` | newMaxSize | undefined | Change the max size of the cache (default: 500). If the new maxSize is less than the old and this leads to LRU-removes and dispatchLruRemoves is set true, then a single cache event will be dispatched.
`setAsync` | keyValueAlternateKeys: object | Promise | Like `set`, but performing insert and event dispatch in another event loop, resolving the returned promise afterwards.
`setEntryGetter` | entryGetter: function | undefined | Set a getter that can be used to retrieve a cache entry (keyValueAlternateKeys-object) by key in case it is not yet in the cache. For values that might be called by alternate key, the getter should also be able to handle this.
`setMaxSize` | newMaxSize: int | undefined | Change the max size of the cache (default: 500). If the new maxSize is less than the old and this leads to LRU-removes and dispatchLruRemoves is set true, then a single cache event will be dispatched.

@@ -162,6 +180,6 @@

* Also compared to LRU maps that do not support alternate keys, there is a performance impact on get in case of cache misses.
* See [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/performance-report.html)
* See [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/performance-report.html)
* However, get, set and delete are still O(1). (setMaxSize has O(size-newMaxSize), if size>newMaxSize)
* Compared to a LRU cache without cache events, there is additional performance impact on get, set and delete.
* Again see [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/performance-report.html)
* Again see [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/0eca7d9be9c3901371f27ca08fd2c9c00adde925/performance-report.html)
* However, if you are caching for performance, then because the fetching of values is significantly more time consuming. So whether you save 400ms or only 399ms hardly makes a difference here.

@@ -183,3 +201,3 @@ * If you are not caching for performance reasons, but to have the change events, well than again it's just the price to pay for the event handling.

### 3.0.x
### 3.1.x
* Fix issues that might occur

@@ -190,6 +208,6 @@ * Improve README

### 3.1.0
### 3.2.0
* Add option to use LruMap instead of LruCache (the LruMap is a currently not exported pure LRU cache, while the LruCache is a wrapper adding the event handling)
### 3.2.0
### 3.3.0
* Make shape and content of change events configurable (with the current shape being used as default).

@@ -324,10 +324,2 @@ import {LruMap} from "./LruMap";

const entryGetter = (key, alternateKeyToKey, getter) => {
let entry = getter(key);
if (typeof entry === "undefined" && alternateKeyToKey.has(key)) {
entry = getter(alternateKeyToKey.get(key));
}
return entry;
};
/** Cannot be instantiated directly! Use 'getCache' to get a cache instance.

@@ -410,4 +402,67 @@ * By default, cache events are dispatched only for inserts/updates and deletes.

let entryGetter = null;
const keyToPromise = new Map();
const internalGetter = (key, getter, useEntryGetter = false) => {
let entry = getter(key);
if (typeof entry === "undefined" && alternateKeyToKey.has(key)) {
entry = getter(alternateKeyToKey.get(key));
}
else if (typeof entry === "undefined") {
if (useEntryGetter && entryGetter !== null) {
if (keyToPromise.has(key)) {
return keyToPromise.get(key);
}
const keyValueAlternateKeys = entryGetter(key);
if (!keyValueAlternateKeys) {
return entry;
}
if (typeof keyValueAlternateKeys.then === "function") {
const promise = keyValueAlternateKeys.then(keyValueAlternateKeysResolved => {
if (!keyValueAlternateKeysResolved) {
return keyValueAlternateKeysResolved;
}
if (keyToPromise.has(key)) {
// The condition is necessary, because meanwhile there might have been a self.delete(key)
self.set(keyValueAlternateKeysResolved);
}
return keyValueAlternateKeysResolved.value;
}).finally(() => {
keyToPromise.delete(key); // important to use key and not keyValueAlternateKeysResolved.key, because key could also be an alternate key!
});
keyToPromise.set(key, promise);
return promise;
}
else {
self.set(keyValueAlternateKeys);
return keyValueAlternateKeys.value;
}
}
else {
return entry;
}
}
return entry.value;
};
/** Set a getter that can be used to retrieve a cache entry (keyValueAlternateKeys-object) by key in
* case it is not yet in the cache.
* For values that might be called by alternate key, the getter should also be able to handle this.
* @memberof LruCache
* @function
* @param {function} newEntryGetter - function that takes a key as argument and returns corresponding entry or promise
* @returns {undefined} void
*/
self.setEntryGetter = newEntryGetter => {
entryGetter = newEntryGetter;
};
/** Get value from cache by either its key or one of its alternate keys (if exists).
* Returns undefined, if not in cache.
* If the value is not found in the cache and an entry-getter was set via setEntryGetter, then:
* - If the entry getter returns a Promise, a Promise resolving to the value will be returned.
* When the Promise resolves, the entry will be set to the cache. Until the Promise is not resolved,
* subsequent calls to get will return the same Promise.
* - If the entry getter returns a cache entry (keyValueAlternateKeys-object), this will be set to the cache
* and the value will be returned.
* - If the entry getter returns null or undefined, undefined will be returned.
* If the key is not in the cache and no entry getter is set, undefined will be returned.
* Makes the corresponding entry the most recently used (use 'getWithoutLruChange' to avoid this).

@@ -417,18 +472,29 @@ * @memberof LruCache

* @param {string} keyOrAlternateKey - The key or alternate key of the value
* @returns {object | undefined} object, if the key is in cache, else undefined
* @returns {value | Promise | undefined} value, promised value or undefined
*/
self.get = keyOrAlternateKey => {
const entry = entryGetter(keyOrAlternateKey, alternateKeyToKey, lruMap.get);
return typeof entry === "undefined" ? entry : entry.value;
};
self.get = keyOrAlternateKey => internalGetter(keyOrAlternateKey, lruMap.get, true);
/** Like 'get', but not making the corresponding entry the most recently used.
* If the value is retrieved via entry getter, it will of course still become the
* most recently used.
* @memberof LruCache
* @function
* @param {string} keyOrAlternateKey - The key or alternate key of the value
* @returns {object | undefined} object, if the key is in cache, else undefined
* @returns {value | Promise | undefined} value, promised value or undefined
*/
self.getWithoutLruChange = keyOrAlternateKey => {
const entry = entryGetter(keyOrAlternateKey, alternateKeyToKey, lruMap.getWithoutLruChange);
return typeof entry === "undefined" ? entry : entry.value;
self.getWithoutLruChange = keyOrAlternateKey => internalGetter(keyOrAlternateKey, lruMap.getWithoutLruChange, true);
/** Return whether the cache contains an entry for the given key or alternate key
* @memberof LruCache
* @function
* @param {string} keyOrAlternateKey - The entry key or alternate key
* @return {boolean} true, if the given key or alternate key is in the cache
*/
self.has = keyOrAlternateKey => {
if (lruMap.has(keyOrAlternateKey)) {
return true;
}
else {
return alternateKeyToKey.has(keyOrAlternateKey);
}
};

@@ -445,3 +511,3 @@

self.delete = key => {
const entry = entryGetter(key, alternateKeyToKey, lruMap.getWithoutLruChange);
const entry = lruMap.getWithoutLruChange(key);
if (typeof entry === "undefined") {

@@ -448,0 +514,0 @@ wrapInTransaction(valueType, () => {

@@ -169,2 +169,8 @@

/** Return whether the LruMap contains key
* @param {string} key - The entry key
* @return {boolean} true, if the given key is in the LruMap
*/
self.has = key => keyToEntry.has(key);
/** Remove the entry with the given key from the map. Returns false, in case the key was not in the map

@@ -171,0 +177,0 @@ * @param {string} key - The entry key

@@ -7,2 +7,3 @@ /* eslint-disable no-magic-number, max-lines */

registerCacheChangedHandler,
clearAllCaches,
} from "../LruCache";

@@ -12,2 +13,3 @@

const VALUE_TYPE_2 = "valueType2";
const VALUE_TYPE_3 = "valueType3";
const DEFAULT_CACHE_SIZE = 500;

@@ -46,3 +48,3 @@

it("should allow to pass an array of alternate keys to 'set' method. 'get' must also work with the alternate key", () => {
it("should allow to pass an array of alternate keys to 'set' method. 'get' and 'has' must also work with the alternate key", () => {
const cache1 = getCache(VALUE_TYPE_1);

@@ -58,2 +60,5 @@

expect(typeof cache1.get("myAltKey3")).toEqual("undefined");
expect(cache1.has("key1")).toBeTruthy();
expect(cache1.has("myAltKey2")).toBeTruthy();
expect(cache1.has("myAltKey3")).toBeFalsy();

@@ -216,3 +221,3 @@ cache1.clear();

it("should provide a 'delete' method that works with key or alternate key", () => {
it("should provide a 'delete' method that works with key, but not with alternate key", () => {
const cache1 = getCache(VALUE_TYPE_1);

@@ -239,4 +244,4 @@

expect(deleteResult2).toBeFalsy();
expect(deleteResult3).toBeTruthy();
expect(deleteResult4).toBeFalsy();
expect(deleteResult3).toBeFalsy();
expect(deleteResult4).toBeTruthy();
expect(cache1.getSize()).toEqual(0);

@@ -304,2 +309,76 @@

it("should provide a method to define an entry getter that is used in case of a cache miss", () => {
const type3GetterSync = key => ({
key,
value: key + "_value",
alternateKeys: [key + "_alternate"],
});
const cache = getCache(VALUE_TYPE_3);
cache.setEntryGetter(type3GetterSync);
cache.set({
key: "key1",
value: "value1",
});
expect(cache.get("key1")).toEqual("value1");
expect(cache.get("key2")).toEqual("key2_value");
expect(cache.get("key2_alternate")).toEqual("key2_value");
cache.setEntryGetter(null);
cache.clear();
});
it("should provide a method to define an entry async getter that is used in case of a cache miss", async () => {
let nCalls = 0;
const type3GetterAsync = key => new Promise(resolve => {
nCalls += 1;
setTimeout(() => {
resolve({
key,
value: key + "_value",
alternateKeys: [key + "_alternate"],
});
}, 200)
});
const cache = getCache(VALUE_TYPE_3);
cache.setEntryGetter(type3GetterAsync);
expect(typeof cache.get("key1") === "object").toBeTruthy();
expect(typeof cache.get("key1").then === "function").toBeTruthy();
const val = await cache.get("key1");
expect(val).toEqual("key1_value");
expect(cache.get("key1")).toEqual("key1_value");
// We must also ensure that the getter was called only once:
expect(nCalls).toEqual(1);
cache.setEntryGetter(null);
cache.clear();
});
it("should handle the case where a getter returns undefined", async () => {
let nCalls = 0;
const type3GetterAsync = () => new Promise(resolve => {
nCalls += 1;
setTimeout(() => {
resolve(undefined); // eslint-disable-line no-undefined
}, 200)
});
const cache = getCache(VALUE_TYPE_3);
cache.setEntryGetter(type3GetterAsync);
expect(typeof cache.get("key1") === "object").toBeTruthy();
expect(typeof cache.get("key1").then === "function").toBeTruthy();
const val = await cache.get("key1");
expect(typeof val).toEqual("undefined");
expect(typeof cache.get("key1")).toEqual("object");
// We must also ensure that the getter was called only once:
expect(nCalls).toEqual(2);
cache.setEntryGetter(null);
cache.clear();
});
});

@@ -334,2 +413,41 @@

describe("clearAllCaches", () => {
it("should clear all caches", () => {
const cache1 = getCache(VALUE_TYPE_1);
const cache2 = getCache(VALUE_TYPE_2);
cache1.setAll([
{
key: "key1",
value: "value1 of type 1",
alternateKeys: ["myAltKey1"],
},
{
key: "key2",
value: "value2 of type 1",
alternateKeys: "myAltKey2",
},
]);
cache2.setAll([
{
key: "key1",
value: "value1 of type 2",
alternateKeys: ["myAltKey1"],
},
{
key: "key2",
value: "value2 of type 2",
alternateKeys: "myAltKey2",
},
]);
expect(cache1.get("key1")).toEqual("value1 of type 1");
expect(cache2.get("key1")).toEqual("value1 of type 2");
clearAllCaches();
expect(typeof cache1.get("key1")).toEqual("undefined");
expect(typeof cache2.get("key1")).toEqual("undefined");
});
});
describe("registerCacheChangedHandler", () => {

@@ -439,2 +557,31 @@

it("should throw an error in case of throwing change handlers, but still keep the cache consistent", () => {
const cache1 = getCache(VALUE_TYPE_1);
const handlerHandle = registerCacheChangedHandler(() => {
throw new Error("this is a test");
});
expect(() => {
cache1.setAll([
{
key: "key1",
value: "value1 of type 1",
alternateKeys: "myAltKey1",
},
{
key: "key2",
value: "value2 of type 1",
alternateKeys: "myAltKey2",
},
])
}).toThrow("handleTransactionChangeObject: 1 of 1 handlers threw an error: this is a test, ");
expect(cache1.get("key1")).toEqual("value1 of type 1");
expect(cache1.get("key2")).toEqual("value2 of type 1");
expect(cache1.get("myAltKey1")).toEqual("value1 of type 1");
handlerHandle.unregister();
cache1.clear();
});
it("should create correct change events for delete", () => {

@@ -441,0 +588,0 @@ const cache1 = getCache(VALUE_TYPE_1);

@@ -13,3 +13,3 @@ /* eslint-disable no-magic-number */

it("should provide set and get methods like a Map", () => {
it("should provide set, get and has methods like a Map", () => {
const lruMap = LruMap();

@@ -21,2 +21,4 @@ lruMap.set("key1", "value1");

expect(typeof lruMap.get("key2")).toEqual("undefined");
expect(lruMap.has("key1")).toBeTruthy();
expect(lruMap.has("key2")).toBeFalsy();
});

@@ -23,0 +25,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc