Socket
Socket
Sign inDemoInstall

quick-lru

Package Overview
Dependencies
0
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 5.1.1 to 6.0.0

68

index.d.ts

@@ -1,19 +0,28 @@

declare namespace QuickLRU {
interface Options<KeyType, ValueType> {
/**
The maximum number of items before evicting the least recently used items.
*/
readonly maxSize: number;
export interface Options<KeyType, ValueType> {
/**
The maximum number of milliseconds an item should remain in the cache.
/**
Called right before an item is evicted from the cache.
@default Infinity
Useful for side effects or for items like object URLs that need explicit cleanup (`revokeObjectURL`).
*/
onEviction?: (key: KeyType, value: ValueType) => void;
}
By default, `maxAge` will be `Infinity`, which means that items will never expire.
Lazy expiration upon the next write or read call.
Individual expiration of an item can be specified by the `set(key, value, maxAge)` method.
*/
readonly maxAge?: number;
/**
The maximum number of items before evicting the least recently used items.
*/
readonly maxSize: number;
/**
Called right before an item is evicted from the cache.
Useful for side effects or for items like object URLs that need explicit cleanup (`revokeObjectURL`).
*/
onEviction?: (key: KeyType, value: ValueType) => void;
}
declare class QuickLRU<KeyType, ValueType>
implements Iterable<[KeyType, ValueType]> {
export default class QuickLRU<KeyType, ValueType> implements Iterable<[KeyType, ValueType]> {
/**

@@ -27,7 +36,7 @@ The stored item count.

The instance is [`iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
The instance is an [`Iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) of `[key, value]` pairs so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
@example
```
import QuickLRU = require('quick-lru');
import QuickLRU from 'quick-lru';

@@ -45,3 +54,3 @@ const lru = new QuickLRU({maxSize: 1000});

*/
constructor(options: QuickLRU.Options<KeyType, ValueType>);
constructor(options: Options<KeyType, ValueType>);

@@ -51,7 +60,9 @@ [Symbol.iterator](): IterableIterator<[KeyType, ValueType]>;

/**
Set an item.
Set an item. Returns the instance.
Individual expiration of an item can be specified with the `maxAge` option. If not specified, the global `maxAge` value will be used in case it is specified in the constructor, otherwise the item will never expire.
@returns The list instance.
*/
set(key: KeyType, value: ValueType): this;
set(key: KeyType, value: ValueType, options?: {maxAge?: number}): this;

@@ -90,2 +101,9 @@ /**

/**
Update the `maxSize` in-place, discarding items as necessary. Insertion order is mostly preserved, though this is not a strong guarantee.
Useful for on-the-fly tuning of cache sizes in live systems.
*/
resize(maxSize: number): void;
/**
Iterable for all the keys.

@@ -99,4 +117,12 @@ */

values(): IterableIterator<ValueType>;
/**
Iterable for all entries, starting with the oldest (ascending in recency).
*/
entriesAscending(): IterableIterator<[KeyType, ValueType]>;
/**
Iterable for all entries, starting with the newest (descending in recency).
*/
entriesDescending(): IterableIterator<[KeyType, ValueType]>;
}
export = QuickLRU;

@@ -1,4 +0,2 @@

'use strict';
class QuickLRU {
export default class QuickLRU {
constructor(options = {}) {

@@ -9,3 +7,9 @@ if (!(options.maxSize && options.maxSize > 0)) {

if (typeof options.maxAge === 'number' && options.maxAge === 0) {
throw new TypeError('`maxAge` must be a number greater than 0');
}
// TODO: Use private class fields when ESLint supports them.
this.maxSize = options.maxSize;
this.maxAge = options.maxAge || Number.POSITIVE_INFINITY;
this.onEviction = options.onEviction;

@@ -17,2 +21,42 @@ this.cache = new Map();

// TODO: Use private class methods when targeting Node.js 16.
_emitEvictions(cache) {
if (typeof this.onEviction !== 'function') {
return;
}
for (const [key, item] of cache) {
this.onEviction(key, item.value);
}
}
_deleteIfExpired(key, item) {
if (typeof item.expiry === 'number' && item.expiry <= Date.now()) {
if (typeof this.onEviction === 'function') {
this.onEviction(key, item.value);
}
return this.delete(key);
}
return false;
}
_getOrDeleteIfExpired(key, item) {
const deleted = this._deleteIfExpired(key, item);
if (deleted === false) {
return item.value;
}
}
_getItemValue(key, item) {
return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value;
}
_peek(key, cache) {
const item = cache.get(key);
return this._getItemValue(key, item);
}
_set(key, value) {

@@ -24,11 +68,30 @@ this.cache.set(key, value);

this._size = 0;
this._emitEvictions(this.oldCache);
this.oldCache = this.cache;
this.cache = new Map();
}
}
if (typeof this.onEviction === 'function') {
for (const [key, value] of this.oldCache.entries()) {
this.onEviction(key, value);
_moveToRecent(key, item) {
this.oldCache.delete(key);
this._set(key, item);
}
* _entriesAscending() {
for (const item of this.oldCache) {
const [key, value] = item;
if (!this.cache.has(key)) {
const deleted = this._deleteIfExpired(key, value);
if (deleted === false) {
yield item;
}
}
}
this.oldCache = this.cache;
this.cache = new Map();
for (const item of this.cache) {
const [key, value] = item;
const deleted = this._deleteIfExpired(key, value);
if (deleted === false) {
yield item;
}
}

@@ -39,25 +102,37 @@ }

if (this.cache.has(key)) {
return this.cache.get(key);
const item = this.cache.get(key);
return this._getItemValue(key, item);
}
if (this.oldCache.has(key)) {
const value = this.oldCache.get(key);
this.oldCache.delete(key);
this._set(key, value);
return value;
const item = this.oldCache.get(key);
if (this._deleteIfExpired(key, item) === false) {
this._moveToRecent(key, item);
return item.value;
}
}
}
set(key, value) {
set(key, value, {maxAge = this.maxAge === Number.POSITIVE_INFINITY ? undefined : Date.now() + this.maxAge} = {}) {
if (this.cache.has(key)) {
this.cache.set(key, value);
this.cache.set(key, {
value,
maxAge
});
} else {
this._set(key, value);
this._set(key, {value, expiry: maxAge});
}
return this;
}
has(key) {
return this.cache.has(key) || this.oldCache.has(key);
if (this.cache.has(key)) {
return !this._deleteIfExpired(key, this.cache.get(key));
}
if (this.oldCache.has(key)) {
return !this._deleteIfExpired(key, this.oldCache.get(key));
}
return false;
}

@@ -67,7 +142,7 @@

if (this.cache.has(key)) {
return this.cache.get(key);
return this._peek(key, this.cache);
}
if (this.oldCache.has(key)) {
return this.oldCache.get(key);
return this._peek(key, this.oldCache);
}

@@ -91,2 +166,26 @@ }

resize(newSize) {
if (!(newSize && newSize > 0)) {
throw new TypeError('`maxSize` must be a number greater than 0');
}
const items = [...this._entriesAscending()];
const removeCount = items.length - newSize;
if (removeCount < 0) {
this.cache = new Map(items);
this.oldCache = new Map();
this._size = items.length;
} else {
if (removeCount > 0) {
this._emitEvictions(items.slice(0, removeCount));
}
this.oldCache = new Map(items.slice(removeCount));
this.cache = new Map();
this._size = 0;
}
this.maxSize = newSize;
}
* keys() {

@@ -106,9 +205,16 @@ for (const [key] of this) {

for (const item of this.cache) {
yield item;
const [key, value] = item;
const deleted = this._deleteIfExpired(key, value);
if (deleted === false) {
yield [key, value.value];
}
}
for (const item of this.oldCache) {
const [key] = item;
const [key, value] = item;
if (!this.cache.has(key)) {
yield item;
const deleted = this._deleteIfExpired(key, value);
if (deleted === false) {
yield [key, value.value];
}
}

@@ -118,3 +224,37 @@ }

* entriesDescending() {
let items = [...this.cache];
for (let i = items.length - 1; i >= 0; --i) {
const item = items[i];
const [key, value] = item;
const deleted = this._deleteIfExpired(key, value);
if (deleted === false) {
yield [key, value.value];
}
}
items = [...this.oldCache];
for (let i = items.length - 1; i >= 0; --i) {
const item = items[i];
const [key, value] = item;
if (!this.cache.has(key)) {
const deleted = this._deleteIfExpired(key, value);
if (deleted === false) {
yield [key, value.value];
}
}
}
}
* entriesAscending() {
for (const [key, value] of this._entriesAscending()) {
yield [key, value.value];
}
}
get size() {
if (!this._size) {
return this.oldCache.size;
}
let oldCacheSize = 0;

@@ -130,3 +270,1 @@ for (const key of this.oldCache.keys()) {

}
module.exports = QuickLRU;
{
"name": "quick-lru",
"version": "5.1.1",
"version": "6.0.0",
"description": "Simple “Least Recently Used” (LRU) cache",

@@ -13,7 +13,10 @@ "license": "MIT",

},
"type": "module",
"exports": "./index.js",
"engines": {
"node": ">=10"
"node": ">=12"
},
"scripts": {
"test": "xo && nyc ava && tsd"
"//test": "xo && nyc ava && tsd",
"test": "xo && ava && tsd"
},

@@ -38,8 +41,13 @@ "files": [

"devDependencies": {
"ava": "^2.0.0",
"coveralls": "^3.0.3",
"nyc": "^15.0.0",
"tsd": "^0.11.0",
"xo": "^0.26.0"
"ava": "^3.15.0",
"nyc": "^15.1.0",
"tsd": "^0.14.0",
"xo": "^0.37.1"
},
"nyc": {
"reporter": [
"text",
"lcov"
]
}
}

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

# quick-lru [![Build Status](https://travis-ci.org/sindresorhus/quick-lru.svg?branch=master)](https://travis-ci.org/sindresorhus/quick-lru) [![Coverage Status](https://coveralls.io/repos/github/sindresorhus/quick-lru/badge.svg?branch=master)](https://coveralls.io/github/sindresorhus/quick-lru?branch=master)
# quick-lru [![Coverage Status](https://codecov.io/gh/sindresorhus/quick-lru/branch/master/graph/badge.svg)](https://codecov.io/gh/sindresorhus/quick-lru/branch/master)

@@ -18,3 +18,3 @@ > Simple [“Least Recently Used” (LRU) cache](https://en.m.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29)

```js
const QuickLRU = require('quick-lru');
import QuickLRU from 'quick-lru';

@@ -49,2 +49,14 @@ const lru = new QuickLRU({maxSize: 1000});

#### maxAge
Type: `number`\
Default: `Infinity`
The maximum number of milliseconds an item should remain in cache.
By default maxAge will be Infinity, which means that items will never expire.
Lazy expiration happens upon the next `write` or `read` call.
Individual expiration of an item can be specified by the `set(key, value, options)` method.
#### onEviction

@@ -61,10 +73,12 @@

The instance is [`iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
The instance is an [`Iterable`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols) of `[key, value]` pairs so you can use it directly in a [`for…of`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...of) loop.
Both `key` and `value` can be of any type.
#### .set(key, value)
#### .set(key, value, options?)
Set an item. Returns the instance.
Individual expiration of an item can be specified with the `maxAge` option. If not specified, the global `maxAge` value will be used in case it is specified on the constructor, otherwise the item will never expire.
#### .get(key)

@@ -92,2 +106,8 @@

#### .resize(maxSize)
Update the `maxSize`, discarding items as necessary. Insertion order is mostly preserved, though this is not a strong guarantee.
Useful for on-the-fly tuning of cache sizes in live systems.
#### .keys()

@@ -101,2 +121,10 @@

#### .entriesAscending()
Iterable for all entries, starting with the oldest (ascending in recency).
#### .entriesDescending()
Iterable for all entries, starting with the newest (descending in recency).
#### .size

@@ -106,2 +134,6 @@

## Related
- [yocto-queue](https://github.com/sindresorhus/yocto-queue) - Tiny queue data structure
---

@@ -108,0 +140,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc