pnpm 7.9.1 → 7.9.2

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 (108) hide show
  1. package/README.md +22 -7
  2. package/bin/pnpm.cjs +3 -0
  3. package/bin/pnpx.cjs +1 -15
  4. package/dist/node_modules/.modules.yaml +3 -3
  5. package/dist/node_modules/.pnpm/lock.yaml +76 -42
  6. package/dist/node_modules/@npmcli/fs/lib/common/owner-sync.js +96 -0
  7. package/dist/node_modules/@npmcli/fs/lib/common/owner.js +8 -4
  8. package/dist/node_modules/@npmcli/fs/lib/copy-file.js +3 -9
  9. package/dist/node_modules/@npmcli/fs/lib/fs.js +9 -3
  10. package/dist/node_modules/@npmcli/fs/lib/index.js +3 -1
  11. package/dist/node_modules/@npmcli/fs/lib/mkdir.js +19 -0
  12. package/dist/node_modules/@npmcli/fs/lib/mkdtemp.js +3 -8
  13. package/dist/node_modules/@npmcli/fs/lib/with-owner-sync.js +21 -0
  14. package/dist/node_modules/@npmcli/fs/lib/with-owner.js +21 -0
  15. package/dist/node_modules/@npmcli/fs/lib/with-temp-dir.js +4 -2
  16. package/dist/node_modules/@npmcli/fs/lib/write-file.js +3 -8
  17. package/dist/node_modules/@npmcli/fs/package.json +21 -9
  18. package/dist/node_modules/@npmcli/move-file/{index.js → lib/index.js} +50 -27
  19. package/dist/node_modules/@npmcli/move-file/package.json +20 -7
  20. package/dist/node_modules/@tootallnate/once/LICENSE +21 -0
  21. package/dist/node_modules/@tootallnate/once/dist/index.js +21 -36
  22. package/dist/node_modules/@tootallnate/once/dist/index.js.map +1 -1
  23. package/dist/node_modules/@tootallnate/once/dist/overloaded-parameters.js +3 -0
  24. package/dist/node_modules/@tootallnate/once/dist/overloaded-parameters.js.map +1 -0
  25. package/dist/node_modules/@tootallnate/once/dist/types.js +3 -0
  26. package/dist/node_modules/@tootallnate/once/dist/types.js.map +1 -0
  27. package/dist/node_modules/@tootallnate/once/package.json +22 -15
  28. package/dist/node_modules/cacache/lib/content/read.js +99 -102
  29. package/dist/node_modules/cacache/lib/content/rm.js +9 -8
  30. package/dist/node_modules/cacache/lib/content/write.js +67 -67
  31. package/dist/node_modules/cacache/lib/entry-index.js +128 -118
  32. package/dist/node_modules/cacache/{get.js → lib/get.js} +88 -100
  33. package/dist/node_modules/cacache/{index.js → lib/index.js} +5 -6
  34. package/dist/node_modules/cacache/lib/memoization.js +10 -11
  35. package/dist/node_modules/cacache/{put.js → lib/put.js} +23 -26
  36. package/dist/node_modules/cacache/{rm.js → lib/rm.js} +3 -3
  37. package/dist/node_modules/cacache/lib/util/fix-owner.js +41 -38
  38. package/dist/node_modules/cacache/lib/util/move-file.js +36 -47
  39. package/dist/node_modules/cacache/lib/util/tmp.js +5 -7
  40. package/dist/node_modules/cacache/lib/verify.js +160 -190
  41. package/dist/node_modules/cacache/node_modules/brace-expansion/.github/FUNDING.yml +2 -0
  42. package/dist/node_modules/cacache/node_modules/brace-expansion/LICENSE +21 -0
  43. package/dist/node_modules/cacache/node_modules/brace-expansion/index.js +203 -0
  44. package/dist/node_modules/cacache/node_modules/brace-expansion/package.json +46 -0
  45. package/dist/node_modules/cacache/node_modules/glob/LICENSE +15 -0
  46. package/dist/node_modules/cacache/node_modules/glob/common.js +240 -0
  47. package/dist/node_modules/cacache/node_modules/glob/glob.js +790 -0
  48. package/dist/node_modules/cacache/node_modules/glob/package.json +55 -0
  49. package/dist/node_modules/cacache/node_modules/glob/sync.js +486 -0
  50. package/dist/node_modules/cacache/node_modules/minimatch/LICENSE +15 -0
  51. package/dist/node_modules/cacache/node_modules/minimatch/lib/path.js +4 -0
  52. package/dist/node_modules/cacache/node_modules/minimatch/minimatch.js +906 -0
  53. package/dist/node_modules/cacache/node_modules/minimatch/package.json +32 -0
  54. package/dist/node_modules/cacache/package.json +34 -30
  55. package/dist/node_modules/http-proxy-agent/dist/agent.js +3 -3
  56. package/dist/node_modules/http-proxy-agent/dist/agent.js.map +1 -1
  57. package/dist/node_modules/http-proxy-agent/package.json +4 -4
  58. package/dist/node_modules/lru-cache/LICENSE +1 -1
  59. package/dist/node_modules/lru-cache/index.js +921 -247
  60. package/dist/node_modules/lru-cache/package.json +49 -9
  61. package/dist/node_modules/make-fetch-happen/LICENSE +1 -1
  62. package/dist/node_modules/make-fetch-happen/lib/agent.js +34 -14
  63. package/dist/node_modules/make-fetch-happen/lib/cache/entry.js +90 -106
  64. package/dist/node_modules/make-fetch-happen/lib/cache/errors.js +1 -0
  65. package/dist/node_modules/make-fetch-happen/lib/cache/index.js +10 -6
  66. package/dist/node_modules/make-fetch-happen/lib/cache/policy.js +21 -21
  67. package/dist/node_modules/make-fetch-happen/lib/dns.js +49 -0
  68. package/dist/node_modules/make-fetch-happen/lib/fetch.js +40 -22
  69. package/dist/node_modules/make-fetch-happen/lib/index.js +4 -3
  70. package/dist/node_modules/make-fetch-happen/lib/options.js +17 -9
  71. package/dist/node_modules/make-fetch-happen/lib/pipeline.js +41 -0
  72. package/dist/node_modules/make-fetch-happen/lib/remote.js +28 -9
  73. package/dist/node_modules/make-fetch-happen/package.json +36 -33
  74. package/dist/node_modules/minipass-fetch/lib/blob.js +4 -4
  75. package/dist/node_modules/minipass-fetch/lib/body.js +63 -49
  76. package/dist/node_modules/minipass-fetch/lib/fetch-error.js +2 -1
  77. package/dist/node_modules/minipass-fetch/lib/headers.js +38 -21
  78. package/dist/node_modules/minipass-fetch/lib/index.js +130 -106
  79. package/dist/node_modules/minipass-fetch/lib/request.js +46 -28
  80. package/dist/node_modules/minipass-fetch/lib/response.js +3 -2
  81. package/dist/node_modules/minipass-fetch/package.json +27 -14
  82. package/dist/node_modules/node-gyp/.github/workflows/release-please.yml +1 -1
  83. package/dist/node_modules/node-gyp/.github/workflows/tests.yml +16 -9
  84. package/dist/node_modules/node-gyp/.github/workflows/visual-studio.yml +16 -8
  85. package/dist/node_modules/node-gyp/lib/build.js +7 -0
  86. package/dist/node_modules/node-gyp/lib/configure.js +26 -1
  87. package/dist/node_modules/node-gyp/lib/create-config-gypi.js +2 -1
  88. package/dist/node_modules/node-gyp/lib/find-visualstudio.js +9 -8
  89. package/dist/node_modules/node-gyp/lib/node-gyp.js +4 -0
  90. package/dist/node_modules/node-gyp/package.json +4 -4
  91. package/dist/node_modules/semver/node_modules/lru-cache/LICENSE +15 -0
  92. package/dist/node_modules/semver/node_modules/lru-cache/index.js +334 -0
  93. package/dist/node_modules/semver/node_modules/lru-cache/package.json +34 -0
  94. package/dist/node_modules/socks-proxy-agent/dist/index.js +3 -3
  95. package/dist/node_modules/socks-proxy-agent/dist/index.js.map +1 -1
  96. package/dist/node_modules/socks-proxy-agent/package.json +2 -2
  97. package/dist/node_modules/ssri/{index.js → lib/index.js} +78 -24
  98. package/dist/node_modules/ssri/package.json +27 -16
  99. package/dist/pnpm.cjs +67042 -65886
  100. package/package.json +6 -6
  101. package/dist/node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js +0 -17
  102. package/dist/node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js +0 -121
  103. package/dist/node_modules/@npmcli/fs/lib/mkdir/index.js +0 -32
  104. package/dist/node_modules/@npmcli/fs/lib/mkdir/polyfill.js +0 -81
  105. package/dist/node_modules/cacache/lib/util/disposer.js +0 -30
  106. package/dist/node_modules/cacache/ls.js +0 -6
  107. package/dist/node_modules/cacache/verify.js +0 -3
  108. package/dist/node_modules/minipass-fetch/index.js +0 -1
@@ -1,334 +1,1008 @@
1
- 'use strict'
2
-
3
- // A linked list to keep track of recently-used-ness
4
- const Yallist = require('yallist')
5
-
6
- const MAX = Symbol('max')
7
- const LENGTH = Symbol('length')
8
- const LENGTH_CALCULATOR = Symbol('lengthCalculator')
9
- const ALLOW_STALE = Symbol('allowStale')
10
- const MAX_AGE = Symbol('maxAge')
11
- const DISPOSE = Symbol('dispose')
12
- const NO_DISPOSE_ON_SET = Symbol('noDisposeOnSet')
13
- const LRU_LIST = Symbol('lruList')
14
- const CACHE = Symbol('cache')
15
- const UPDATE_AGE_ON_GET = Symbol('updateAgeOnGet')
16
-
17
- const naiveLength = () => 1
18
-
19
- // lruList is a yallist where the head is the youngest
20
- // item, and the tail is the oldest. the list contains the Hit
21
- // objects as the entries.
22
- // Each Hit object has a reference to its Yallist.Node. This
23
- // never changes.
24
- //
25
- // cache is a Map (or PseudoMap) that matches the keys to
26
- // the Yallist.Node object.
27
- class LRUCache {
28
- constructor (options) {
29
- if (typeof options === 'number')
30
- options = { max: options }
31
-
32
- if (!options)
33
- options = {}
1
+ const perf =
2
+ typeof performance === 'object' &&
3
+ performance &&
4
+ typeof performance.now === 'function'
5
+ ? performance
6
+ : Date
7
+
8
+ const hasAbortController = typeof AbortController === 'function'
9
+
10
+ // minimal backwards-compatibility polyfill
11
+ // this doesn't have nearly all the checks and whatnot that
12
+ // actual AbortController/Signal has, but it's enough for
13
+ // our purposes, and if used properly, behaves the same.
14
+ const AC = hasAbortController
15
+ ? AbortController
16
+ : class AbortController {
17
+ constructor() {
18
+ this.signal = new AS()
19
+ }
20
+ abort() {
21
+ this.signal.dispatchEvent('abort')
22
+ }
23
+ }
34
24
 
35
- if (options.max && (typeof options.max !== 'number' || options.max < 0))
36
- throw new TypeError('max must be a non-negative number')
37
- // Kind of weird to have a default max of Infinity, but oh well.
38
- const max = this[MAX] = options.max || Infinity
25
+ const hasAbortSignal = typeof AbortSignal === 'function'
26
+ // Some polyfills put this on the AC class, not global
27
+ const hasACAbortSignal = typeof AC.AbortSignal === 'function'
28
+ const AS = hasAbortSignal
29
+ ? AbortSignal
30
+ : hasACAbortSignal
31
+ ? AC.AbortController
32
+ : class AbortSignal {
33
+ constructor() {
34
+ this.aborted = false
35
+ this._listeners = []
36
+ }
37
+ dispatchEvent(type) {
38
+ if (type === 'abort') {
39
+ this.aborted = true
40
+ const e = { type, target: this }
41
+ this.onabort(e)
42
+ this._listeners.forEach(f => f(e), this)
43
+ }
44
+ }
45
+ onabort() {}
46
+ addEventListener(ev, fn) {
47
+ if (ev === 'abort') {
48
+ this._listeners.push(fn)
49
+ }
50
+ }
51
+ removeEventListener(ev, fn) {
52
+ if (ev === 'abort') {
53
+ this._listeners = this._listeners.filter(f => f !== fn)
54
+ }
55
+ }
56
+ }
39
57
 
40
- const lc = options.length || naiveLength
41
- this[LENGTH_CALCULATOR] = (typeof lc !== 'function') ? naiveLength : lc
42
- this[ALLOW_STALE] = options.stale || false
43
- if (options.maxAge && typeof options.maxAge !== 'number')
44
- throw new TypeError('maxAge must be a number')
45
- this[MAX_AGE] = options.maxAge || 0
46
- this[DISPOSE] = options.dispose
47
- this[NO_DISPOSE_ON_SET] = options.noDisposeOnSet || false
48
- this[UPDATE_AGE_ON_GET] = options.updateAgeOnGet || false
49
- this.reset()
58
+ const warned = new Set()
59
+ const deprecatedOption = (opt, instead) => {
60
+ const code = `LRU_CACHE_OPTION_${opt}`
61
+ if (shouldWarn(code)) {
62
+ warn(code, `${opt} option`, `options.${instead}`, LRUCache)
63
+ }
64
+ }
65
+ const deprecatedMethod = (method, instead) => {
66
+ const code = `LRU_CACHE_METHOD_${method}`
67
+ if (shouldWarn(code)) {
68
+ const { prototype } = LRUCache
69
+ const { get } = Object.getOwnPropertyDescriptor(prototype, method)
70
+ warn(code, `${method} method`, `cache.${instead}()`, get)
50
71
  }
72
+ }
73
+ const deprecatedProperty = (field, instead) => {
74
+ const code = `LRU_CACHE_PROPERTY_${field}`
75
+ if (shouldWarn(code)) {
76
+ const { prototype } = LRUCache
77
+ const { get } = Object.getOwnPropertyDescriptor(prototype, field)
78
+ warn(code, `${field} property`, `cache.${instead}`, get)
79
+ }
80
+ }
51
81
 
52
- // resize the cache when the max changes.
53
- set max (mL) {
54
- if (typeof mL !== 'number' || mL < 0)
55
- throw new TypeError('max must be a non-negative number')
82
+ const emitWarning = (...a) => {
83
+ typeof process === 'object' &&
84
+ process &&
85
+ typeof process.emitWarning === 'function'
86
+ ? process.emitWarning(...a)
87
+ : console.error(...a)
88
+ }
56
89
 
57
- this[MAX] = mL || Infinity
58
- trim(this)
59
- }
60
- get max () {
61
- return this[MAX]
90
+ const shouldWarn = code => !warned.has(code)
91
+
92
+ const warn = (code, what, instead, fn) => {
93
+ warned.add(code)
94
+ const msg = `The ${what} is deprecated. Please use ${instead} instead.`
95
+ emitWarning(msg, 'DeprecationWarning', code, fn)
96
+ }
97
+
98
+ const isPosInt = n => n && n === Math.floor(n) && n > 0 && isFinite(n)
99
+
100
+ /* istanbul ignore next - This is a little bit ridiculous, tbh.
101
+ * The maximum array length is 2^32-1 or thereabouts on most JS impls.
102
+ * And well before that point, you're caching the entire world, I mean,
103
+ * that's ~32GB of just integers for the next/prev links, plus whatever
104
+ * else to hold that many keys and values. Just filling the memory with
105
+ * zeroes at init time is brutal when you get that big.
106
+ * But why not be complete?
107
+ * Maybe in the future, these limits will have expanded. */
108
+ const getUintArray = max =>
109
+ !isPosInt(max)
110
+ ? null
111
+ : max <= Math.pow(2, 8)
112
+ ? Uint8Array
113
+ : max <= Math.pow(2, 16)
114
+ ? Uint16Array
115
+ : max <= Math.pow(2, 32)
116
+ ? Uint32Array
117
+ : max <= Number.MAX_SAFE_INTEGER
118
+ ? ZeroArray
119
+ : null
120
+
121
+ class ZeroArray extends Array {
122
+ constructor(size) {
123
+ super(size)
124
+ this.fill(0)
62
125
  }
126
+ }
63
127
 
64
- set allowStale (allowStale) {
65
- this[ALLOW_STALE] = !!allowStale
128
+ class Stack {
129
+ constructor(max) {
130
+ if (max === 0) {
131
+ return []
132
+ }
133
+ const UintArray = getUintArray(max)
134
+ this.heap = new UintArray(max)
135
+ this.length = 0
136
+ }
137
+ push(n) {
138
+ this.heap[this.length++] = n
66
139
  }
67
- get allowStale () {
68
- return this[ALLOW_STALE]
140
+ pop() {
141
+ return this.heap[--this.length]
69
142
  }
143
+ }
144
+
145
+ class LRUCache {
146
+ constructor(options = {}) {
147
+ const {
148
+ max = 0,
149
+ ttl,
150
+ ttlResolution = 1,
151
+ ttlAutopurge,
152
+ updateAgeOnGet,
153
+ updateAgeOnHas,
154
+ allowStale,
155
+ dispose,
156
+ disposeAfter,
157
+ noDisposeOnSet,
158
+ noUpdateTTL,
159
+ maxSize = 0,
160
+ maxEntrySize = 0,
161
+ sizeCalculation,
162
+ fetchMethod,
163
+ fetchContext,
164
+ noDeleteOnFetchRejection,
165
+ noDeleteOnStaleGet,
166
+ } = options
167
+
168
+ // deprecated options, don't trigger a warning for getting them if
169
+ // the thing being passed in is another LRUCache we're copying.
170
+ const { length, maxAge, stale } =
171
+ options instanceof LRUCache ? {} : options
172
+
173
+ if (max !== 0 && !isPosInt(max)) {
174
+ throw new TypeError('max option must be a nonnegative integer')
175
+ }
176
+
177
+ const UintArray = max ? getUintArray(max) : Array
178
+ if (!UintArray) {
179
+ throw new Error('invalid max value: ' + max)
180
+ }
181
+
182
+ this.max = max
183
+ this.maxSize = maxSize
184
+ this.maxEntrySize = maxEntrySize || this.maxSize
185
+ this.sizeCalculation = sizeCalculation || length
186
+ if (this.sizeCalculation) {
187
+ if (!this.maxSize && !this.maxEntrySize) {
188
+ throw new TypeError(
189
+ 'cannot set sizeCalculation without setting maxSize or maxEntrySize'
190
+ )
191
+ }
192
+ if (typeof this.sizeCalculation !== 'function') {
193
+ throw new TypeError('sizeCalculation set to non-function')
194
+ }
195
+ }
70
196
 
71
- set maxAge (mA) {
72
- if (typeof mA !== 'number')
73
- throw new TypeError('maxAge must be a non-negative number')
197
+ this.fetchMethod = fetchMethod || null
198
+ if (this.fetchMethod && typeof this.fetchMethod !== 'function') {
199
+ throw new TypeError(
200
+ 'fetchMethod must be a function if specified'
201
+ )
202
+ }
203
+
204
+ this.fetchContext = fetchContext
205
+ if (!this.fetchMethod && fetchContext !== undefined) {
206
+ throw new TypeError(
207
+ 'cannot set fetchContext without fetchMethod'
208
+ )
209
+ }
210
+
211
+ this.keyMap = new Map()
212
+ this.keyList = new Array(max).fill(null)
213
+ this.valList = new Array(max).fill(null)
214
+ this.next = new UintArray(max)
215
+ this.prev = new UintArray(max)
216
+ this.head = 0
217
+ this.tail = 0
218
+ this.free = new Stack(max)
219
+ this.initialFill = 1
220
+ this.size = 0
221
+
222
+ if (typeof dispose === 'function') {
223
+ this.dispose = dispose
224
+ }
225
+ if (typeof disposeAfter === 'function') {
226
+ this.disposeAfter = disposeAfter
227
+ this.disposed = []
228
+ } else {
229
+ this.disposeAfter = null
230
+ this.disposed = null
231
+ }
232
+ this.noDisposeOnSet = !!noDisposeOnSet
233
+ this.noUpdateTTL = !!noUpdateTTL
234
+ this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection
235
+
236
+ // NB: maxEntrySize is set to maxSize if it's set
237
+ if (this.maxEntrySize !== 0) {
238
+ if (this.maxSize !== 0) {
239
+ if (!isPosInt(this.maxSize)) {
240
+ throw new TypeError(
241
+ 'maxSize must be a positive integer if specified'
242
+ )
243
+ }
244
+ }
245
+ if (!isPosInt(this.maxEntrySize)) {
246
+ throw new TypeError(
247
+ 'maxEntrySize must be a positive integer if specified'
248
+ )
249
+ }
250
+ this.initializeSizeTracking()
251
+ }
74
252
 
75
- this[MAX_AGE] = mA
76
- trim(this)
253
+ this.allowStale = !!allowStale || !!stale
254
+ this.noDeleteOnStaleGet = !!noDeleteOnStaleGet
255
+ this.updateAgeOnGet = !!updateAgeOnGet
256
+ this.updateAgeOnHas = !!updateAgeOnHas
257
+ this.ttlResolution =
258
+ isPosInt(ttlResolution) || ttlResolution === 0
259
+ ? ttlResolution
260
+ : 1
261
+ this.ttlAutopurge = !!ttlAutopurge
262
+ this.ttl = ttl || maxAge || 0
263
+ if (this.ttl) {
264
+ if (!isPosInt(this.ttl)) {
265
+ throw new TypeError(
266
+ 'ttl must be a positive integer if specified'
267
+ )
268
+ }
269
+ this.initializeTTLTracking()
270
+ }
271
+
272
+ // do not allow completely unbounded caches
273
+ if (this.max === 0 && this.ttl === 0 && this.maxSize === 0) {
274
+ throw new TypeError(
275
+ 'At least one of max, maxSize, or ttl is required'
276
+ )
277
+ }
278
+ if (!this.ttlAutopurge && !this.max && !this.maxSize) {
279
+ const code = 'LRU_CACHE_UNBOUNDED'
280
+ if (shouldWarn(code)) {
281
+ warned.add(code)
282
+ const msg =
283
+ 'TTL caching without ttlAutopurge, max, or maxSize can ' +
284
+ 'result in unbounded memory consumption.'
285
+ emitWarning(msg, 'UnboundedCacheWarning', code, LRUCache)
286
+ }
287
+ }
288
+
289
+ if (stale) {
290
+ deprecatedOption('stale', 'allowStale')
291
+ }
292
+ if (maxAge) {
293
+ deprecatedOption('maxAge', 'ttl')
294
+ }
295
+ if (length) {
296
+ deprecatedOption('length', 'sizeCalculation')
297
+ }
77
298
  }
78
- get maxAge () {
79
- return this[MAX_AGE]
299
+
300
+ getRemainingTTL(key) {
301
+ return this.has(key, { updateAgeOnHas: false }) ? Infinity : 0
80
302
  }
81
303
 
82
- // resize the cache when the lengthCalculator changes.
83
- set lengthCalculator (lC) {
84
- if (typeof lC !== 'function')
85
- lC = naiveLength
304
+ initializeTTLTracking() {
305
+ this.ttls = new ZeroArray(this.max)
306
+ this.starts = new ZeroArray(this.max)
307
+
308
+ this.setItemTTL = (index, ttl, start = perf.now()) => {
309
+ this.starts[index] = ttl !== 0 ? start : 0
310
+ this.ttls[index] = ttl
311
+ if (ttl !== 0 && this.ttlAutopurge) {
312
+ const t = setTimeout(() => {
313
+ if (this.isStale(index)) {
314
+ this.delete(this.keyList[index])
315
+ }
316
+ }, ttl + 1)
317
+ /* istanbul ignore else - unref() not supported on all platforms */
318
+ if (t.unref) {
319
+ t.unref()
320
+ }
321
+ }
322
+ }
86
323
 
87
- if (lC !== this[LENGTH_CALCULATOR]) {
88
- this[LENGTH_CALCULATOR] = lC
89
- this[LENGTH] = 0
90
- this[LRU_LIST].forEach(hit => {
91
- hit.length = this[LENGTH_CALCULATOR](hit.value, hit.key)
92
- this[LENGTH] += hit.length
93
- })
324
+ this.updateItemAge = index => {
325
+ this.starts[index] = this.ttls[index] !== 0 ? perf.now() : 0
326
+ }
327
+
328
+ // debounce calls to perf.now() to 1s so we're not hitting
329
+ // that costly call repeatedly.
330
+ let cachedNow = 0
331
+ const getNow = () => {
332
+ const n = perf.now()
333
+ if (this.ttlResolution > 0) {
334
+ cachedNow = n
335
+ const t = setTimeout(
336
+ () => (cachedNow = 0),
337
+ this.ttlResolution
338
+ )
339
+ /* istanbul ignore else - not available on all platforms */
340
+ if (t.unref) {
341
+ t.unref()
342
+ }
343
+ }
344
+ return n
345
+ }
346
+
347
+ this.getRemainingTTL = key => {
348
+ const index = this.keyMap.get(key)
349
+ if (index === undefined) {
350
+ return 0
351
+ }
352
+ return this.ttls[index] === 0 || this.starts[index] === 0
353
+ ? Infinity
354
+ : this.starts[index] +
355
+ this.ttls[index] -
356
+ (cachedNow || getNow())
357
+ }
358
+
359
+ this.isStale = index => {
360
+ return (
361
+ this.ttls[index] !== 0 &&
362
+ this.starts[index] !== 0 &&
363
+ (cachedNow || getNow()) - this.starts[index] >
364
+ this.ttls[index]
365
+ )
94
366
  }
95
- trim(this)
96
367
  }
97
- get lengthCalculator () { return this[LENGTH_CALCULATOR] }
368
+ updateItemAge(index) {}
369
+ setItemTTL(index, ttl, start) {}
370
+ isStale(index) {
371
+ return false
372
+ }
98
373
 
99
- get length () { return this[LENGTH] }
100
- get itemCount () { return this[LRU_LIST].length }
374
+ initializeSizeTracking() {
375
+ this.calculatedSize = 0
376
+ this.sizes = new ZeroArray(this.max)
377
+ this.removeItemSize = index => {
378
+ this.calculatedSize -= this.sizes[index]
379
+ this.sizes[index] = 0
380
+ }
381
+ this.requireSize = (k, v, size, sizeCalculation) => {
382
+ if (!isPosInt(size)) {
383
+ if (sizeCalculation) {
384
+ if (typeof sizeCalculation !== 'function') {
385
+ throw new TypeError('sizeCalculation must be a function')
386
+ }
387
+ size = sizeCalculation(v, k)
388
+ if (!isPosInt(size)) {
389
+ throw new TypeError(
390
+ 'sizeCalculation return invalid (expect positive integer)'
391
+ )
392
+ }
393
+ } else {
394
+ throw new TypeError(
395
+ 'invalid size value (must be positive integer)'
396
+ )
397
+ }
398
+ }
399
+ return size
400
+ }
401
+ this.addItemSize = (index, size) => {
402
+ this.sizes[index] = size
403
+ const maxSize = this.maxSize - this.sizes[index]
404
+ while (this.calculatedSize > maxSize) {
405
+ this.evict(true)
406
+ }
407
+ this.calculatedSize += this.sizes[index]
408
+ }
409
+ }
410
+ removeItemSize(index) {}
411
+ addItemSize(index, size) {}
412
+ requireSize(k, v, size, sizeCalculation) {
413
+ if (size || sizeCalculation) {
414
+ throw new TypeError(
415
+ 'cannot set size without setting maxSize or maxEntrySize on cache'
416
+ )
417
+ }
418
+ }
101
419
 
102
- rforEach (fn, thisp) {
103
- thisp = thisp || this
104
- for (let walker = this[LRU_LIST].tail; walker !== null;) {
105
- const prev = walker.prev
106
- forEachStep(this, fn, walker, thisp)
107
- walker = prev
420
+ *indexes({ allowStale = this.allowStale } = {}) {
421
+ if (this.size) {
422
+ for (let i = this.tail; true; ) {
423
+ if (!this.isValidIndex(i)) {
424
+ break
425
+ }
426
+ if (allowStale || !this.isStale(i)) {
427
+ yield i
428
+ }
429
+ if (i === this.head) {
430
+ break
431
+ } else {
432
+ i = this.prev[i]
433
+ }
434
+ }
108
435
  }
109
436
  }
110
437
 
111
- forEach (fn, thisp) {
112
- thisp = thisp || this
113
- for (let walker = this[LRU_LIST].head; walker !== null;) {
114
- const next = walker.next
115
- forEachStep(this, fn, walker, thisp)
116
- walker = next
438
+ *rindexes({ allowStale = this.allowStale } = {}) {
439
+ if (this.size) {
440
+ for (let i = this.head; true; ) {
441
+ if (!this.isValidIndex(i)) {
442
+ break
443
+ }
444
+ if (allowStale || !this.isStale(i)) {
445
+ yield i
446
+ }
447
+ if (i === this.tail) {
448
+ break
449
+ } else {
450
+ i = this.next[i]
451
+ }
452
+ }
117
453
  }
118
454
  }
119
455
 
120
- keys () {
121
- return this[LRU_LIST].toArray().map(k => k.key)
456
+ isValidIndex(index) {
457
+ return this.keyMap.get(this.keyList[index]) === index
122
458
  }
123
459
 
124
- values () {
125
- return this[LRU_LIST].toArray().map(k => k.value)
460
+ *entries() {
461
+ for (const i of this.indexes()) {
462
+ yield [this.keyList[i], this.valList[i]]
463
+ }
464
+ }
465
+ *rentries() {
466
+ for (const i of this.rindexes()) {
467
+ yield [this.keyList[i], this.valList[i]]
468
+ }
126
469
  }
127
470
 
128
- reset () {
129
- if (this[DISPOSE] &&
130
- this[LRU_LIST] &&
131
- this[LRU_LIST].length) {
132
- this[LRU_LIST].forEach(hit => this[DISPOSE](hit.key, hit.value))
471
+ *keys() {
472
+ for (const i of this.indexes()) {
473
+ yield this.keyList[i]
133
474
  }
475
+ }
476
+ *rkeys() {
477
+ for (const i of this.rindexes()) {
478
+ yield this.keyList[i]
479
+ }
480
+ }
134
481
 
135
- this[CACHE] = new Map() // hash of items by key
136
- this[LRU_LIST] = new Yallist() // list of items in order of use recency
137
- this[LENGTH] = 0 // length of items in the list
482
+ *values() {
483
+ for (const i of this.indexes()) {
484
+ yield this.valList[i]
485
+ }
486
+ }
487
+ *rvalues() {
488
+ for (const i of this.rindexes()) {
489
+ yield this.valList[i]
490
+ }
138
491
  }
139
492
 
140
- dump () {
141
- return this[LRU_LIST].map(hit =>
142
- isStale(this, hit) ? false : {
143
- k: hit.key,
144
- v: hit.value,
145
- e: hit.now + (hit.maxAge || 0)
146
- }).toArray().filter(h => h)
493
+ [Symbol.iterator]() {
494
+ return this.entries()
147
495
  }
148
496
 
149
- dumpLru () {
150
- return this[LRU_LIST]
497
+ find(fn, getOptions = {}) {
498
+ for (const i of this.indexes()) {
499
+ if (fn(this.valList[i], this.keyList[i], this)) {
500
+ return this.get(this.keyList[i], getOptions)
501
+ }
502
+ }
151
503
  }
152
504
 
153
- set (key, value, maxAge) {
154
- maxAge = maxAge || this[MAX_AGE]
505
+ forEach(fn, thisp = this) {
506
+ for (const i of this.indexes()) {
507
+ fn.call(thisp, this.valList[i], this.keyList[i], this)
508
+ }
509
+ }
155
510
 
156
- if (maxAge && typeof maxAge !== 'number')
157
- throw new TypeError('maxAge must be a number')
511
+ rforEach(fn, thisp = this) {
512
+ for (const i of this.rindexes()) {
513
+ fn.call(thisp, this.valList[i], this.keyList[i], this)
514
+ }
515
+ }
158
516
 
159
- const now = maxAge ? Date.now() : 0
160
- const len = this[LENGTH_CALCULATOR](value, key)
517
+ get prune() {
518
+ deprecatedMethod('prune', 'purgeStale')
519
+ return this.purgeStale
520
+ }
161
521
 
162
- if (this[CACHE].has(key)) {
163
- if (len > this[MAX]) {
164
- del(this, this[CACHE].get(key))
165
- return false
522
+ purgeStale() {
523
+ let deleted = false
524
+ for (const i of this.rindexes({ allowStale: true })) {
525
+ if (this.isStale(i)) {
526
+ this.delete(this.keyList[i])
527
+ deleted = true
166
528
  }
529
+ }
530
+ return deleted
531
+ }
167
532
 
168
- const node = this[CACHE].get(key)
169
- const item = node.value
533
+ dump() {
534
+ const arr = []
535
+ for (const i of this.indexes({ allowStale: true })) {
536
+ const key = this.keyList[i]
537
+ const v = this.valList[i]
538
+ const value = this.isBackgroundFetch(v)
539
+ ? v.__staleWhileFetching
540
+ : v
541
+ const entry = { value }
542
+ if (this.ttls) {
543
+ entry.ttl = this.ttls[i]
544
+ // always dump the start relative to a portable timestamp
545
+ // it's ok for this to be a bit slow, it's a rare operation.
546
+ const age = perf.now() - this.starts[i]
547
+ entry.start = Math.floor(Date.now() - age)
548
+ }
549
+ if (this.sizes) {
550
+ entry.size = this.sizes[i]
551
+ }
552
+ arr.unshift([key, entry])
553
+ }
554
+ return arr
555
+ }
170
556
 
171
- // dispose of the old one before overwriting
172
- // split out into 2 ifs for better coverage tracking
173
- if (this[DISPOSE]) {
174
- if (!this[NO_DISPOSE_ON_SET])
175
- this[DISPOSE](key, item.value)
557
+ load(arr) {
558
+ this.clear()
559
+ for (const [key, entry] of arr) {
560
+ if (entry.start) {
561
+ // entry.start is a portable timestamp, but we may be using
562
+ // node's performance.now(), so calculate the offset.
563
+ // it's ok for this to be a bit slow, it's a rare operation.
564
+ const age = Date.now() - entry.start
565
+ entry.start = perf.now() - age
176
566
  }
567
+ this.set(key, entry.value, entry)
568
+ }
569
+ }
177
570
 
178
- item.now = now
179
- item.maxAge = maxAge
180
- item.value = value
181
- this[LENGTH] += len - item.length
182
- item.length = len
183
- this.get(key)
184
- trim(this)
185
- return true
571
+ dispose(v, k, reason) {}
572
+
573
+ set(
574
+ k,
575
+ v,
576
+ {
577
+ ttl = this.ttl,
578
+ start,
579
+ noDisposeOnSet = this.noDisposeOnSet,
580
+ size = 0,
581
+ sizeCalculation = this.sizeCalculation,
582
+ noUpdateTTL = this.noUpdateTTL,
583
+ } = {}
584
+ ) {
585
+ size = this.requireSize(k, v, size, sizeCalculation)
586
+ // if the item doesn't fit, don't do anything
587
+ // NB: maxEntrySize set to maxSize by default
588
+ if (this.maxEntrySize && size > this.maxEntrySize) {
589
+ return this
186
590
  }
591
+ let index = this.size === 0 ? undefined : this.keyMap.get(k)
592
+ if (index === undefined) {
593
+ // addition
594
+ index = this.newIndex()
595
+ this.keyList[index] = k
596
+ this.valList[index] = v
597
+ this.keyMap.set(k, index)
598
+ this.next[this.tail] = index
599
+ this.prev[index] = this.tail
600
+ this.tail = index
601
+ this.size++
602
+ this.addItemSize(index, size)
603
+ noUpdateTTL = false
604
+ } else {
605
+ // update
606
+ const oldVal = this.valList[index]
607
+ if (v !== oldVal) {
608
+ if (this.isBackgroundFetch(oldVal)) {
609
+ oldVal.__abortController.abort()
610
+ } else {
611
+ if (!noDisposeOnSet) {
612
+ this.dispose(oldVal, k, 'set')
613
+ if (this.disposeAfter) {
614
+ this.disposed.push([oldVal, k, 'set'])
615
+ }
616
+ }
617
+ }
618
+ this.removeItemSize(index)
619
+ this.valList[index] = v
620
+ this.addItemSize(index, size)
621
+ }
622
+ this.moveToTail(index)
623
+ }
624
+ if (ttl !== 0 && this.ttl === 0 && !this.ttls) {
625
+ this.initializeTTLTracking()
626
+ }
627
+ if (!noUpdateTTL) {
628
+ this.setItemTTL(index, ttl, start)
629
+ }
630
+ if (this.disposeAfter) {
631
+ while (this.disposed.length) {
632
+ this.disposeAfter(...this.disposed.shift())
633
+ }
634
+ }
635
+ return this
636
+ }
187
637
 
188
- const hit = new Entry(key, value, len, now, maxAge)
638
+ newIndex() {
639
+ if (this.size === 0) {
640
+ return this.tail
641
+ }
642
+ if (this.size === this.max && this.max !== 0) {
643
+ return this.evict(false)
644
+ }
645
+ if (this.free.length !== 0) {
646
+ return this.free.pop()
647
+ }
648
+ // initial fill, just keep writing down the list
649
+ return this.initialFill++
650
+ }
189
651
 
190
- // oversized objects fall out of cache automatically.
191
- if (hit.length > this[MAX]) {
192
- if (this[DISPOSE])
193
- this[DISPOSE](key, value)
652
+ pop() {
653
+ if (this.size) {
654
+ const val = this.valList[this.head]
655
+ this.evict(true)
656
+ return val
657
+ }
658
+ }
194
659
 
195
- return false
660
+ evict(free) {
661
+ const head = this.head
662
+ const k = this.keyList[head]
663
+ const v = this.valList[head]
664
+ if (this.isBackgroundFetch(v)) {
665
+ v.__abortController.abort()
666
+ } else {
667
+ this.dispose(v, k, 'evict')
668
+ if (this.disposeAfter) {
669
+ this.disposed.push([v, k, 'evict'])
670
+ }
671
+ }
672
+ this.removeItemSize(head)
673
+ // if we aren't about to use the index, then null these out
674
+ if (free) {
675
+ this.keyList[head] = null
676
+ this.valList[head] = null
677
+ this.free.push(head)
196
678
  }
679
+ this.head = this.next[head]
680
+ this.keyMap.delete(k)
681
+ this.size--
682
+ return head
683
+ }
197
684
 
198
- this[LENGTH] += hit.length
199
- this[LRU_LIST].unshift(hit)
200
- this[CACHE].set(key, this[LRU_LIST].head)
201
- trim(this)
202
- return true
685
+ has(k, { updateAgeOnHas = this.updateAgeOnHas } = {}) {
686
+ const index = this.keyMap.get(k)
687
+ if (index !== undefined) {
688
+ if (!this.isStale(index)) {
689
+ if (updateAgeOnHas) {
690
+ this.updateItemAge(index)
691
+ }
692
+ return true
693
+ }
694
+ }
695
+ return false
203
696
  }
204
697
 
205
- has (key) {
206
- if (!this[CACHE].has(key)) return false
207
- const hit = this[CACHE].get(key).value
208
- return !isStale(this, hit)
698
+ // like get(), but without any LRU updating or TTL expiration
699
+ peek(k, { allowStale = this.allowStale } = {}) {
700
+ const index = this.keyMap.get(k)
701
+ if (index !== undefined && (allowStale || !this.isStale(index))) {
702
+ const v = this.valList[index]
703
+ // either stale and allowed, or forcing a refresh of non-stale value
704
+ return this.isBackgroundFetch(v) ? v.__staleWhileFetching : v
705
+ }
209
706
  }
210
707
 
211
- get (key) {
212
- return get(this, key, true)
708
+ backgroundFetch(k, index, options, context) {
709
+ const v = index === undefined ? undefined : this.valList[index]
710
+ if (this.isBackgroundFetch(v)) {
711
+ return v
712
+ }
713
+ const ac = new AC()
714
+ const fetchOpts = {
715
+ signal: ac.signal,
716
+ options,
717
+ context,
718
+ }
719
+ const cb = v => {
720
+ if (!ac.signal.aborted) {
721
+ this.set(k, v, fetchOpts.options)
722
+ }
723
+ return v
724
+ }
725
+ const eb = er => {
726
+ if (this.valList[index] === p) {
727
+ const del =
728
+ !options.noDeleteOnFetchRejection ||
729
+ p.__staleWhileFetching === undefined
730
+ if (del) {
731
+ this.delete(k)
732
+ } else {
733
+ // still replace the *promise* with the stale value,
734
+ // since we are done with the promise at this point.
735
+ this.valList[index] = p.__staleWhileFetching
736
+ }
737
+ }
738
+ if (p.__returned === p) {
739
+ throw er
740
+ }
741
+ }
742
+ const pcall = res => res(this.fetchMethod(k, v, fetchOpts))
743
+ const p = new Promise(pcall).then(cb, eb)
744
+ p.__abortController = ac
745
+ p.__staleWhileFetching = v
746
+ p.__returned = null
747
+ if (index === undefined) {
748
+ this.set(k, p, fetchOpts.options)
749
+ index = this.keyMap.get(k)
750
+ } else {
751
+ this.valList[index] = p
752
+ }
753
+ return p
213
754
  }
214
755
 
215
- peek (key) {
216
- return get(this, key, false)
756
+ isBackgroundFetch(p) {
757
+ return (
758
+ p &&
759
+ typeof p === 'object' &&
760
+ typeof p.then === 'function' &&
761
+ Object.prototype.hasOwnProperty.call(
762
+ p,
763
+ '__staleWhileFetching'
764
+ ) &&
765
+ Object.prototype.hasOwnProperty.call(p, '__returned') &&
766
+ (p.__returned === p || p.__returned === null)
767
+ )
217
768
  }
218
769
 
219
- pop () {
220
- const node = this[LRU_LIST].tail
221
- if (!node)
222
- return null
770
+ // this takes the union of get() and set() opts, because it does both
771
+ async fetch(
772
+ k,
773
+ {
774
+ // get options
775
+ allowStale = this.allowStale,
776
+ updateAgeOnGet = this.updateAgeOnGet,
777
+ noDeleteOnStaleGet = this.noDeleteOnStaleGet,
778
+ // set options
779
+ ttl = this.ttl,
780
+ noDisposeOnSet = this.noDisposeOnSet,
781
+ size = 0,
782
+ sizeCalculation = this.sizeCalculation,
783
+ noUpdateTTL = this.noUpdateTTL,
784
+ // fetch exclusive options
785
+ noDeleteOnFetchRejection = this.noDeleteOnFetchRejection,
786
+ fetchContext = this.fetchContext,
787
+ forceRefresh = false,
788
+ } = {}
789
+ ) {
790
+ if (!this.fetchMethod) {
791
+ return this.get(k, {
792
+ allowStale,
793
+ updateAgeOnGet,
794
+ noDeleteOnStaleGet,
795
+ })
796
+ }
223
797
 
224
- del(this, node)
225
- return node.value
226
- }
798
+ const options = {
799
+ allowStale,
800
+ updateAgeOnGet,
801
+ noDeleteOnStaleGet,
802
+ ttl,
803
+ noDisposeOnSet,
804
+ size,
805
+ sizeCalculation,
806
+ noUpdateTTL,
807
+ noDeleteOnFetchRejection,
808
+ }
227
809
 
228
- del (key) {
229
- del(this, this[CACHE].get(key))
230
- }
810
+ let index = this.keyMap.get(k)
811
+ if (index === undefined) {
812
+ const p = this.backgroundFetch(k, index, options, fetchContext)
813
+ return (p.__returned = p)
814
+ } else {
815
+ // in cache, maybe already fetching
816
+ const v = this.valList[index]
817
+ if (this.isBackgroundFetch(v)) {
818
+ return allowStale && v.__staleWhileFetching !== undefined
819
+ ? v.__staleWhileFetching
820
+ : (v.__returned = v)
821
+ }
231
822
 
232
- load (arr) {
233
- // reset the cache
234
- this.reset()
823
+ // if we force a refresh, that means do NOT serve the cached value,
824
+ // unless we are already in the process of refreshing the cache.
825
+ if (!forceRefresh && !this.isStale(index)) {
826
+ this.moveToTail(index)
827
+ if (updateAgeOnGet) {
828
+ this.updateItemAge(index)
829
+ }
830
+ return v
831
+ }
235
832
 
236
- const now = Date.now()
237
- // A previous serialized cache has the most recent items first
238
- for (let l = arr.length - 1; l >= 0; l--) {
239
- const hit = arr[l]
240
- const expiresAt = hit.e || 0
241
- if (expiresAt === 0)
242
- // the item was created without expiration in a non aged cache
243
- this.set(hit.k, hit.v)
244
- else {
245
- const maxAge = expiresAt - now
246
- // dont add already expired items
247
- if (maxAge > 0) {
248
- this.set(hit.k, hit.v, maxAge)
833
+ // ok, it is stale or a forced refresh, and not already fetching.
834
+ // refresh the cache.
835
+ const p = this.backgroundFetch(k, index, options, fetchContext)
836
+ return allowStale && p.__staleWhileFetching !== undefined
837
+ ? p.__staleWhileFetching
838
+ : (p.__returned = p)
839
+ }
840
+ }
841
+
842
+ get(
843
+ k,
844
+ {
845
+ allowStale = this.allowStale,
846
+ updateAgeOnGet = this.updateAgeOnGet,
847
+ noDeleteOnStaleGet = this.noDeleteOnStaleGet,
848
+ } = {}
849
+ ) {
850
+ const index = this.keyMap.get(k)
851
+ if (index !== undefined) {
852
+ const value = this.valList[index]
853
+ const fetching = this.isBackgroundFetch(value)
854
+ if (this.isStale(index)) {
855
+ // delete only if not an in-flight background fetch
856
+ if (!fetching) {
857
+ if (!noDeleteOnStaleGet) {
858
+ this.delete(k)
859
+ }
860
+ return allowStale ? value : undefined
861
+ } else {
862
+ return allowStale ? value.__staleWhileFetching : undefined
863
+ }
864
+ } else {
865
+ // if we're currently fetching it, we don't actually have it yet
866
+ // it's not stale, which means this isn't a staleWhileRefetching,
867
+ // so we just return undefined
868
+ if (fetching) {
869
+ return undefined
249
870
  }
871
+ this.moveToTail(index)
872
+ if (updateAgeOnGet) {
873
+ this.updateItemAge(index)
874
+ }
875
+ return value
250
876
  }
251
877
  }
252
878
  }
253
879
 
254
- prune () {
255
- this[CACHE].forEach((value, key) => get(this, key, false))
880
+ connect(p, n) {
881
+ this.prev[n] = p
882
+ this.next[p] = n
256
883
  }
257
- }
258
884
 
259
- const get = (self, key, doUse) => {
260
- const node = self[CACHE].get(key)
261
- if (node) {
262
- const hit = node.value
263
- if (isStale(self, hit)) {
264
- del(self, node)
265
- if (!self[ALLOW_STALE])
266
- return undefined
267
- } else {
268
- if (doUse) {
269
- if (self[UPDATE_AGE_ON_GET])
270
- node.value.now = Date.now()
271
- self[LRU_LIST].unshiftNode(node)
885
+ moveToTail(index) {
886
+ // if tail already, nothing to do
887
+ // if head, move head to next[index]
888
+ // else
889
+ // move next[prev[index]] to next[index] (head has no prev)
890
+ // move prev[next[index]] to prev[index]
891
+ // prev[index] = tail
892
+ // next[tail] = index
893
+ // tail = index
894
+ if (index !== this.tail) {
895
+ if (index === this.head) {
896
+ this.head = this.next[index]
897
+ } else {
898
+ this.connect(this.prev[index], this.next[index])
272
899
  }
900
+ this.connect(this.tail, index)
901
+ this.tail = index
273
902
  }
274
- return hit.value
275
903
  }
276
- }
277
-
278
- const isStale = (self, hit) => {
279
- if (!hit || (!hit.maxAge && !self[MAX_AGE]))
280
- return false
281
904
 
282
- const diff = Date.now() - hit.now
283
- return hit.maxAge ? diff > hit.maxAge
284
- : self[MAX_AGE] && (diff > self[MAX_AGE])
285
- }
905
+ get del() {
906
+ deprecatedMethod('del', 'delete')
907
+ return this.delete
908
+ }
286
909
 
287
- const trim = self => {
288
- if (self[LENGTH] > self[MAX]) {
289
- for (let walker = self[LRU_LIST].tail;
290
- self[LENGTH] > self[MAX] && walker !== null;) {
291
- // We know that we're about to delete this one, and also
292
- // what the next least recently used key will be, so just
293
- // go ahead and set it now.
294
- const prev = walker.prev
295
- del(self, walker)
296
- walker = prev
910
+ delete(k) {
911
+ let deleted = false
912
+ if (this.size !== 0) {
913
+ const index = this.keyMap.get(k)
914
+ if (index !== undefined) {
915
+ deleted = true
916
+ if (this.size === 1) {
917
+ this.clear()
918
+ } else {
919
+ this.removeItemSize(index)
920
+ const v = this.valList[index]
921
+ if (this.isBackgroundFetch(v)) {
922
+ v.__abortController.abort()
923
+ } else {
924
+ this.dispose(v, k, 'delete')
925
+ if (this.disposeAfter) {
926
+ this.disposed.push([v, k, 'delete'])
927
+ }
928
+ }
929
+ this.keyMap.delete(k)
930
+ this.keyList[index] = null
931
+ this.valList[index] = null
932
+ if (index === this.tail) {
933
+ this.tail = this.prev[index]
934
+ } else if (index === this.head) {
935
+ this.head = this.next[index]
936
+ } else {
937
+ this.next[this.prev[index]] = this.next[index]
938
+ this.prev[this.next[index]] = this.prev[index]
939
+ }
940
+ this.size--
941
+ this.free.push(index)
942
+ }
943
+ }
944
+ }
945
+ if (this.disposed) {
946
+ while (this.disposed.length) {
947
+ this.disposeAfter(...this.disposed.shift())
948
+ }
297
949
  }
950
+ return deleted
298
951
  }
299
- }
300
952
 
301
- const del = (self, node) => {
302
- if (node) {
303
- const hit = node.value
304
- if (self[DISPOSE])
305
- self[DISPOSE](hit.key, hit.value)
953
+ clear() {
954
+ for (const index of this.rindexes({ allowStale: true })) {
955
+ const v = this.valList[index]
956
+ if (this.isBackgroundFetch(v)) {
957
+ v.__abortController.abort()
958
+ } else {
959
+ const k = this.keyList[index]
960
+ this.dispose(v, k, 'delete')
961
+ if (this.disposeAfter) {
962
+ this.disposed.push([v, k, 'delete'])
963
+ }
964
+ }
965
+ }
306
966
 
307
- self[LENGTH] -= hit.length
308
- self[CACHE].delete(hit.key)
309
- self[LRU_LIST].removeNode(node)
967
+ this.keyMap.clear()
968
+ this.valList.fill(null)
969
+ this.keyList.fill(null)
970
+ if (this.ttls) {
971
+ this.ttls.fill(0)
972
+ this.starts.fill(0)
973
+ }
974
+ if (this.sizes) {
975
+ this.sizes.fill(0)
976
+ }
977
+ this.head = 0
978
+ this.tail = 0
979
+ this.initialFill = 1
980
+ this.free.length = 0
981
+ this.calculatedSize = 0
982
+ this.size = 0
983
+ if (this.disposed) {
984
+ while (this.disposed.length) {
985
+ this.disposeAfter(...this.disposed.shift())
986
+ }
987
+ }
310
988
  }
311
- }
312
989
 
313
- class Entry {
314
- constructor (key, value, length, now, maxAge) {
315
- this.key = key
316
- this.value = value
317
- this.length = length
318
- this.now = now
319
- this.maxAge = maxAge || 0
990
+ get reset() {
991
+ deprecatedMethod('reset', 'clear')
992
+ return this.clear
320
993
  }
321
- }
322
994
 
323
- const forEachStep = (self, fn, node, thisp) => {
324
- let hit = node.value
325
- if (isStale(self, hit)) {
326
- del(self, node)
327
- if (!self[ALLOW_STALE])
328
- hit = undefined
995
+ get length() {
996
+ deprecatedProperty('length', 'size')
997
+ return this.size
998
+ }
999
+
1000
+ static get AbortController() {
1001
+ return AC
1002
+ }
1003
+ static get AbortSignal() {
1004
+ return AS
329
1005
  }
330
- if (hit)
331
- fn.call(thisp, hit.value, hit.key, self)
332
1006
  }
333
1007
 
334
1008
  module.exports = LRUCache