evicting-cache 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +252 -16
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,7 +1,14 @@
1
1
  # Evicting Cache
2
- JavaScript Cache using an LRU (Least Recently Used) algorithm
3
2
 
4
- The cache is backed by a LinkedMap, which is a Map that maintains insertion order. When the cache is full, the least recently used item is evicted.
3
+ [![npm version](https://img.shields.io/npm/v/evicting-cache.svg)](https://www.npmjs.com/package/evicting-cache)
4
+ [![npm downloads](https://img.shields.io/npm/dm/evicting-cache.svg)](https://www.npmjs.com/package/evicting-cache)
5
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Test Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/D1g1talEntr0py/evicting-cache)
8
+
9
+ A lightweight, high-performance TypeScript implementation of an LRU (Least Recently Used) cache with automatic eviction.
10
+
11
+ The cache is backed by JavaScript's native `Map`, leveraging its insertion order guarantee for efficient LRU semantics. When the cache reaches capacity, the least recently used item is automatically evicted.
5
12
 
6
13
  ## Installation
7
14
 
@@ -13,27 +20,256 @@ pnpm add evicting-cache
13
20
  npm install evicting-cache
14
21
  ```
15
22
 
23
+ ## Features
24
+
25
+ - 🚀 **High Performance** - O(1) operations for get, put, delete, and evict
26
+ - 📦 **Lightweight** - Zero dependencies, small bundle size
27
+ - 🔄 **LRU Eviction** - Automatic removal of least recently used items
28
+ - 📊 **Statistics Tracking** - Built-in hit/miss ratio monitoring
29
+ - 🔢 **Batch Operations** - Efficient multi-key operations
30
+ - 🎯 **Type Safe** - Full TypeScript support with generics
31
+ - ✅ **100% Test Coverage** - Thoroughly tested and reliable
32
+ - 🌐 **Modern ES Modules** - Native ESM support
33
+ - 🔍 **Map-like API** - Familiar interface with additional features
34
+
16
35
  ## Usage
17
- ```javascript
18
- import EvictingCache from 'evicting-cache';
19
36
 
20
- // Constructor accepts a number, which is the maximum number of items to store.
21
- // default is 100
22
- const cache = new EvictingCache(3);
37
+ ### Basic Example
38
+
39
+ ```typescript
40
+ import { EvictingCache } from 'evicting-cache';
41
+
42
+ // Create a cache with capacity of 3 items (default is 100)
43
+ const cache = new EvictingCache<string, string>(3);
23
44
 
24
- // Obviously a contrived example, but this is what you get with AI...
25
45
  cache.put('key1', 'value1');
26
46
  cache.put('key2', 'value2');
27
47
  cache.put('key3', 'value3');
28
- cache.put('key4', 'value4');
48
+ cache.put('key4', 'value4'); // 'key1' is evicted (LRU)
49
+
50
+ console.log(cache.get('key1')); // null (evicted)
51
+ console.log(cache.get('key2')); // 'value2'
52
+ console.log(cache.get('key3')); // 'value3'
53
+ console.log(cache.get('key4')); // 'value4'
54
+
55
+ cache.put('key5', 'value5'); // 'key2' is evicted
56
+
57
+ console.log(cache.get('key2')); // null (evicted)
58
+ console.log(cache.size); // 3
59
+ ```
60
+
61
+ ### LRU Behavior
62
+
63
+ ```typescript
64
+ const cache = new EvictingCache<string, number>(3);
65
+
66
+ cache.put('a', 1);
67
+ cache.put('b', 2);
68
+ cache.put('c', 3);
69
+ // Order: a, b, c (a is LRU)
70
+
71
+ cache.get('a'); // Access 'a', moves it to most recent
72
+ // Order: b, c, a (b is now LRU)
73
+
74
+ cache.put('d', 4); // Evicts 'b' (LRU)
75
+ // Order: c, a, d
76
+
77
+ console.log(cache.has('b')); // false (evicted)
78
+ ```
79
+
80
+ ### Peek Without Affecting LRU
81
+
82
+ ```typescript
83
+ const cache = new EvictingCache<string, string>(2);
84
+
85
+ cache.put('x', 'hello');
86
+ cache.put('y', 'world');
87
+
88
+ // peek() reads without updating LRU order
89
+ console.log(cache.peek('x')); // 'hello'
90
+ // 'x' remains LRU
91
+
92
+ cache.put('z', 'new'); // 'x' is evicted
93
+ console.log(cache.has('x')); // false
94
+ ```
95
+
96
+ ### Get or Compute
97
+
98
+ ```typescript
99
+ const cache = new EvictingCache<string, number>(10);
100
+
101
+ // Get existing value or compute and cache it
102
+ const value = cache.getOrPut('userId:123', () => {
103
+ // Expensive computation only happens if key is missing
104
+ return fetchUserFromDatabase('123');
105
+ });
106
+
107
+ // If producer throws, cache remains unchanged
108
+ try {
109
+ cache.getOrPut('key', () => {
110
+ throw new Error('Failed to compute');
111
+ });
112
+ } catch (error) {
113
+ // Cache state is unmodified
114
+ }
115
+ ```
116
+
117
+ ### Batch Operations
118
+
119
+ ```typescript
120
+ const cache = new EvictingCache<string, number>(100);
121
+
122
+ // Add multiple entries at once
123
+ cache.putAll([
124
+ ['a', 1],
125
+ ['b', 2],
126
+ ['c', 3]
127
+ ]);
128
+
129
+ // Can also use a Map
130
+ cache.putAll(new Map([['d', 4], ['e', 5]]));
131
+
132
+ // Get multiple values (returns Map, excludes missing keys)
133
+ const values = cache.getAll(['a', 'b', 'missing']);
134
+ console.log(values.size); // 2
135
+ console.log(values.get('a')); // 1
136
+ console.log(values.has('missing')); // false
137
+
138
+ // Delete multiple keys (returns count removed)
139
+ const removed = cache.deleteAll(['a', 'c', 'missing']);
140
+ console.log(removed); // 2
141
+ ```
142
+
143
+ ### Cache Statistics
144
+
145
+ ```typescript
146
+ const cache = new EvictingCache<string, string>(10);
147
+
148
+ cache.put('a', 'value1');
149
+ cache.get('a'); // hit
150
+ cache.get('b'); // miss
151
+ cache.get('a'); // hit
152
+
153
+ const stats = cache.getStats();
154
+ console.log(stats.hits); // 2
155
+ console.log(stats.misses); // 1
156
+ console.log(stats.hitRate); // 0.667 (66.7%)
157
+
158
+ // Reset statistics
159
+ cache.resetStats();
160
+ console.log(cache.getStats().hits); // 0
161
+ ```
162
+
163
+ ### Iteration
164
+
165
+ ```typescript
166
+ const cache = new EvictingCache<string, number>(3);
167
+ cache.put('a', 1);
168
+ cache.put('b', 2);
169
+ cache.put('c', 3);
170
+
171
+ // Iterate over entries (LRU to MRU order)
172
+ for (const [key, value] of cache) {
173
+ console.log(key, value);
174
+ }
175
+
176
+ // Or use forEach
177
+ cache.forEach((value, key, cache) => {
178
+ console.log(key, value);
179
+ });
180
+
181
+ // Get keys, values, or entries
182
+ console.log([...cache.keys()]); // ['a', 'b', 'c']
183
+ console.log([...cache.values()]); // [1, 2, 3]
184
+ console.log([...cache.entries()]); // [['a', 1], ['b', 2], ['c', 3]]
185
+ ```
186
+
187
+ ## API Reference
188
+
189
+ ### Constructor
190
+
191
+ - `new EvictingCache<K, V>(capacity?: number)` - Creates a new cache with the specified capacity (default: 100)
192
+
193
+ ### Core Methods
194
+
195
+ - `get(key: K): V | null` - Returns value and updates LRU order
196
+ - `peek(key: K): V | null` - Returns value without updating LRU order
197
+ - `put(key: K, value: V): void` - Adds or updates a key-value pair
198
+ - `delete(key: K): boolean` - Removes a key from the cache
199
+ - `has(key: K): boolean` - Checks if a key exists
200
+ - `getOrPut(key: K, producer: () => V): V` - Gets existing value or computes and stores new one
201
+ - `evict(): boolean` - Manually removes the LRU item
202
+ - `clear(): void` - Removes all items from the cache
203
+
204
+ ### Batch Operations
205
+
206
+ - `putAll(entries: Iterable<[K, V]>): void` - Adds multiple entries
207
+ - `getAll(keys: Iterable<K>): Map<K, V>` - Gets multiple values
208
+ - `deleteAll(keys: Iterable<K>): number` - Removes multiple keys
209
+
210
+ ### Statistics
211
+
212
+ - `getStats(): { hits: number, misses: number, hitRate: number }` - Returns cache statistics
213
+ - `resetStats(): void` - Resets statistics counters
214
+
215
+ ### Iteration
216
+
217
+ - `keys(): IterableIterator<K>` - Returns an iterator over keys
218
+ - `values(): IterableIterator<V>` - Returns an iterator over values
219
+ - `entries(): IterableIterator<[K, V]>` - Returns an iterator over entries
220
+ - `forEach(callback: (value: V, key: K, cache: EvictingCache<K, V>) => void, thisArg?: unknown): void` - Executes callback for each entry
221
+ - `[Symbol.iterator]()` - Makes the cache iterable
222
+
223
+ ### Properties
224
+
225
+ - `capacity: number` - Maximum number of items (read-only)
226
+ - `size: number` - Current number of items (read-only)
227
+
228
+ ## Performance
229
+
230
+ All core operations have **O(1)** time complexity:
231
+
232
+ | Operation | Complexity | Updates LRU |
233
+ |-----------|------------|-------------|
234
+ | `get(key)` | O(1) | ✅ Yes |
235
+ | `peek(key)` | O(1) | ❌ No |
236
+ | `put(key, value)` | O(1) | ✅ Yes |
237
+ | `delete(key)` | O(1) | ❌ N/A |
238
+ | `evict()` | O(1) | ❌ N/A |
239
+ | `has(key)` | O(1) | ❌ No |
240
+ | `clear()` | O(1) | ❌ N/A |
241
+
242
+ **Space complexity:** O(n) where n is the capacity
243
+
244
+ ## TypeScript Support
245
+
246
+ Full TypeScript support with generic types:
247
+
248
+ ```typescript
249
+ // Strongly typed cache
250
+ const userCache = new EvictingCache<number, User>(100);
251
+ const configCache = new EvictingCache<string, Config>(50);
252
+
253
+ // Works with any key/value types
254
+ const complexCache = new EvictingCache<{ id: number; tenant: string }, Promise<Data>>(25);
255
+ ```
256
+
257
+ ## Browser Compatibility
258
+
259
+ Compatible with all modern browsers and Node.js environments that support ES2015+ features:
260
+ - Chrome/Edge: ✅ Latest
261
+ - Firefox: ✅ Latest
262
+ - Safari: ✅ 15+
263
+ - Node.js: ✅ 14+
264
+
265
+ ## License
266
+
267
+ ISC License - See [LICENSE](LICENSE) file for details
29
268
 
30
- console.log(cache.get('key1')); // undefined
31
- console.log(cache.get('key2')); // value2
32
- console.log(cache.get('key3')); // value3
33
- console.log(cache.get('key4')); // value4
269
+ ## Contributing
34
270
 
35
- cache.put('key5', 'value5');
271
+ Contributions are welcome! Please feel free to submit a Pull Request.
36
272
 
37
- console.log(cache.get('key2')); // undefined
273
+ ## Changelog
38
274
 
39
- ```
275
+ See [CHANGELOG.md](CHANGELOG.md) for release history.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "evicting-cache",
3
3
  "author": "D1g1talEntr0py",
4
- "version": "2.3.0",
4
+ "version": "2.3.1",
5
5
  "license": "ISC",
6
6
  "description": "Cache implementation with an LRU evicting policy",
7
7
  "type": "module",