@aws-cdk/cloud-assembly-schema 2.23.0 → 2.24.0
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.
- package/.jsii +3 -3
- package/.jsii.tabl.json +46 -46
- package/NOTICE +18 -1
- package/lib/manifest.js +1 -1
- package/node_modules/lru-cache/LICENSE +1 -1
- package/node_modules/lru-cache/README.md +99 -632
- package/node_modules/lru-cache/index.js +251 -732
- package/node_modules/lru-cache/package.json +7 -17
- package/node_modules/semver/bin/semver.js +2 -1
- package/node_modules/semver/classes/semver.js +1 -1
- package/node_modules/semver/functions/inc.js +4 -1
- package/node_modules/semver/package.json +6 -5
- package/node_modules/yallist/LICENSE +15 -0
- package/node_modules/yallist/README.md +204 -0
- package/node_modules/yallist/iterator.js +8 -0
- package/node_modules/yallist/package.json +29 -0
- package/node_modules/yallist/yallist.js +426 -0
- package/package.json +5 -5
|
@@ -1,815 +1,334 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const code = `LRU_CACHE_PROPERTY_${field}`
|
|
32
|
-
if (shouldWarn(code)) {
|
|
33
|
-
const { prototype } = LRUCache
|
|
34
|
-
const { get } = Object.getOwnPropertyDescriptor(prototype, field)
|
|
35
|
-
warn(code, `${field} property`, `cache.${instead}`, get)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
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 }
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
process &&
|
|
42
|
-
typeof process.emitWarning === 'function'
|
|
43
|
-
? process.emitWarning(...a)
|
|
44
|
-
: console.error(...a)
|
|
45
|
-
}
|
|
32
|
+
if (!options)
|
|
33
|
+
options = {}
|
|
46
34
|
|
|
47
|
-
|
|
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
|
|
48
39
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* And well before that point, you're caching the entire world, I mean,
|
|
60
|
-
* that's ~32GB of just integers for the next/prev links, plus whatever
|
|
61
|
-
* else to hold that many keys and values. Just filling the memory with
|
|
62
|
-
* zeroes at init time is brutal when you get that big.
|
|
63
|
-
* But why not be complete?
|
|
64
|
-
* Maybe in the future, these limits will have expanded. */
|
|
65
|
-
const getUintArray = max => !isPosInt(max) ? null
|
|
66
|
-
: max <= Math.pow(2, 8) ? Uint8Array
|
|
67
|
-
: max <= Math.pow(2, 16) ? Uint16Array
|
|
68
|
-
: max <= Math.pow(2, 32) ? Uint32Array
|
|
69
|
-
: max <= Number.MAX_SAFE_INTEGER ? ZeroArray
|
|
70
|
-
: null
|
|
71
|
-
|
|
72
|
-
class ZeroArray extends Array {
|
|
73
|
-
constructor (size) {
|
|
74
|
-
super(size)
|
|
75
|
-
this.fill(0)
|
|
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()
|
|
76
50
|
}
|
|
77
|
-
}
|
|
78
51
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this.heap[this.length++] = n
|
|
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')
|
|
56
|
+
|
|
57
|
+
this[MAX] = mL || Infinity
|
|
58
|
+
trim(this)
|
|
87
59
|
}
|
|
88
|
-
|
|
89
|
-
return this
|
|
60
|
+
get max () {
|
|
61
|
+
return this[MAX]
|
|
90
62
|
}
|
|
91
|
-
}
|
|
92
63
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const {
|
|
96
|
-
max = 0,
|
|
97
|
-
ttl,
|
|
98
|
-
ttlResolution = 1,
|
|
99
|
-
ttlAutopurge,
|
|
100
|
-
updateAgeOnGet,
|
|
101
|
-
updateAgeOnHas,
|
|
102
|
-
allowStale,
|
|
103
|
-
dispose,
|
|
104
|
-
disposeAfter,
|
|
105
|
-
noDisposeOnSet,
|
|
106
|
-
noUpdateTTL,
|
|
107
|
-
maxSize = 0,
|
|
108
|
-
sizeCalculation,
|
|
109
|
-
fetchMethod,
|
|
110
|
-
} = options
|
|
111
|
-
|
|
112
|
-
// deprecated options, don't trigger a warning for getting them if
|
|
113
|
-
// the thing being passed in is another LRUCache we're copying.
|
|
114
|
-
const {
|
|
115
|
-
length,
|
|
116
|
-
maxAge,
|
|
117
|
-
stale,
|
|
118
|
-
} = options instanceof LRUCache ? {} : options
|
|
119
|
-
|
|
120
|
-
if (max !== 0 && !isPosInt(max)) {
|
|
121
|
-
throw new TypeError('max option must be a nonnegative integer')
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const UintArray = max ? getUintArray(max) : Array
|
|
125
|
-
if (!UintArray) {
|
|
126
|
-
throw new Error('invalid max value: ' + max)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
this.max = max
|
|
130
|
-
this.maxSize = maxSize
|
|
131
|
-
this.sizeCalculation = sizeCalculation || length
|
|
132
|
-
if (this.sizeCalculation) {
|
|
133
|
-
if (!this.maxSize) {
|
|
134
|
-
throw new TypeError('cannot set sizeCalculation without setting maxSize')
|
|
135
|
-
}
|
|
136
|
-
if (typeof this.sizeCalculation !== 'function') {
|
|
137
|
-
throw new TypeError('sizeCalculation set to non-function')
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
this.fetchMethod = fetchMethod || null
|
|
142
|
-
if (this.fetchMethod && typeof this.fetchMethod !== 'function') {
|
|
143
|
-
throw new TypeError('fetchMethod must be a function if specified')
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
this.keyMap = new Map()
|
|
148
|
-
this.keyList = new Array(max).fill(null)
|
|
149
|
-
this.valList = new Array(max).fill(null)
|
|
150
|
-
this.next = new UintArray(max)
|
|
151
|
-
this.prev = new UintArray(max)
|
|
152
|
-
this.head = 0
|
|
153
|
-
this.tail = 0
|
|
154
|
-
this.free = new Stack(max)
|
|
155
|
-
this.initialFill = 1
|
|
156
|
-
this.size = 0
|
|
157
|
-
|
|
158
|
-
if (typeof dispose === 'function') {
|
|
159
|
-
this.dispose = dispose
|
|
160
|
-
}
|
|
161
|
-
if (typeof disposeAfter === 'function') {
|
|
162
|
-
this.disposeAfter = disposeAfter
|
|
163
|
-
this.disposed = []
|
|
164
|
-
} else {
|
|
165
|
-
this.disposeAfter = null
|
|
166
|
-
this.disposed = null
|
|
167
|
-
}
|
|
168
|
-
this.noDisposeOnSet = !!noDisposeOnSet
|
|
169
|
-
this.noUpdateTTL = !!noUpdateTTL
|
|
170
|
-
|
|
171
|
-
if (this.maxSize !== 0) {
|
|
172
|
-
if (!isPosInt(this.maxSize)) {
|
|
173
|
-
throw new TypeError('maxSize must be a positive integer if specified')
|
|
174
|
-
}
|
|
175
|
-
this.initializeSizeTracking()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
this.allowStale = !!allowStale || !!stale
|
|
179
|
-
this.updateAgeOnGet = !!updateAgeOnGet
|
|
180
|
-
this.updateAgeOnHas = !!updateAgeOnHas
|
|
181
|
-
this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0
|
|
182
|
-
? ttlResolution : 1
|
|
183
|
-
this.ttlAutopurge = !!ttlAutopurge
|
|
184
|
-
this.ttl = ttl || maxAge || 0
|
|
185
|
-
if (this.ttl) {
|
|
186
|
-
if (!isPosInt(this.ttl)) {
|
|
187
|
-
throw new TypeError('ttl must be a positive integer if specified')
|
|
188
|
-
}
|
|
189
|
-
this.initializeTTLTracking()
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// do not allow completely unbounded caches
|
|
193
|
-
if (this.max === 0 && this.ttl === 0 && this.maxSize === 0) {
|
|
194
|
-
throw new TypeError('At least one of max, maxSize, or ttl is required')
|
|
195
|
-
}
|
|
196
|
-
if (!this.ttlAutopurge && !this.max && !this.maxSize) {
|
|
197
|
-
const code = 'LRU_CACHE_UNBOUNDED'
|
|
198
|
-
if (shouldWarn(code)) {
|
|
199
|
-
warned.add(code)
|
|
200
|
-
const msg = 'TTL caching without ttlAutopurge, max, or maxSize can ' +
|
|
201
|
-
'result in unbounded memory consumption.'
|
|
202
|
-
emitWarning(msg, 'UnboundedCacheWarning', code, LRUCache)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (stale) {
|
|
207
|
-
deprecatedOption('stale', 'allowStale')
|
|
208
|
-
}
|
|
209
|
-
if (maxAge) {
|
|
210
|
-
deprecatedOption('maxAge', 'ttl')
|
|
211
|
-
}
|
|
212
|
-
if (length) {
|
|
213
|
-
deprecatedOption('length', 'sizeCalculation')
|
|
214
|
-
}
|
|
64
|
+
set allowStale (allowStale) {
|
|
65
|
+
this[ALLOW_STALE] = !!allowStale
|
|
215
66
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return this.has(key, { updateAgeOnHas: false }) ? Infinity : 0
|
|
67
|
+
get allowStale () {
|
|
68
|
+
return this[ALLOW_STALE]
|
|
219
69
|
}
|
|
220
70
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
this.setItemTTL = (index, ttl) => {
|
|
226
|
-
this.starts[index] = ttl !== 0 ? perf.now() : 0
|
|
227
|
-
this.ttls[index] = ttl
|
|
228
|
-
if (ttl !== 0 && this.ttlAutopurge) {
|
|
229
|
-
const t = setTimeout(() => {
|
|
230
|
-
if (this.isStale(index)) {
|
|
231
|
-
this.delete(this.keyList[index])
|
|
232
|
-
}
|
|
233
|
-
}, ttl + 1)
|
|
234
|
-
/* istanbul ignore else - unref() not supported on all platforms */
|
|
235
|
-
if (t.unref) {
|
|
236
|
-
t.unref()
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
71
|
+
set maxAge (mA) {
|
|
72
|
+
if (typeof mA !== 'number')
|
|
73
|
+
throw new TypeError('maxAge must be a non-negative number')
|
|
240
74
|
|
|
241
|
-
this
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// debounce calls to perf.now() to 1s so we're not hitting
|
|
246
|
-
// that costly call repeatedly.
|
|
247
|
-
let cachedNow = 0
|
|
248
|
-
const getNow = () => {
|
|
249
|
-
const n = perf.now()
|
|
250
|
-
if (this.ttlResolution > 0) {
|
|
251
|
-
cachedNow = n
|
|
252
|
-
const t = setTimeout(() => cachedNow = 0, this.ttlResolution)
|
|
253
|
-
/* istanbul ignore else - not available on all platforms */
|
|
254
|
-
if (t.unref) {
|
|
255
|
-
t.unref()
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return n
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
this.getRemainingTTL = (key) => {
|
|
262
|
-
const index = this.keyMap.get(key)
|
|
263
|
-
if (index === undefined) {
|
|
264
|
-
return 0
|
|
265
|
-
}
|
|
266
|
-
return this.ttls[index] === 0 || this.starts[index] === 0 ? Infinity
|
|
267
|
-
: ((this.starts[index] + this.ttls[index]) - (cachedNow || getNow()))
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
this.isStale = (index) => {
|
|
271
|
-
return this.ttls[index] !== 0 && this.starts[index] !== 0 &&
|
|
272
|
-
((cachedNow || getNow()) - this.starts[index] > this.ttls[index])
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
updateItemAge (index) {}
|
|
276
|
-
setItemTTL (index, ttl) {}
|
|
277
|
-
isStale (index) { return false }
|
|
278
|
-
|
|
279
|
-
initializeSizeTracking () {
|
|
280
|
-
this.calculatedSize = 0
|
|
281
|
-
this.sizes = new ZeroArray(this.max)
|
|
282
|
-
this.removeItemSize = index => this.calculatedSize -= this.sizes[index]
|
|
283
|
-
this.requireSize = (k, v, size, sizeCalculation) => {
|
|
284
|
-
if (!isPosInt(size)) {
|
|
285
|
-
if (sizeCalculation) {
|
|
286
|
-
if (typeof sizeCalculation !== 'function') {
|
|
287
|
-
throw new TypeError('sizeCalculation must be a function')
|
|
288
|
-
}
|
|
289
|
-
size = sizeCalculation(v, k)
|
|
290
|
-
if (!isPosInt(size)) {
|
|
291
|
-
throw new TypeError('sizeCalculation return invalid (expect positive integer)')
|
|
292
|
-
}
|
|
293
|
-
} else {
|
|
294
|
-
throw new TypeError('invalid size value (must be positive integer)')
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return size
|
|
298
|
-
}
|
|
299
|
-
this.addItemSize = (index, v, k, size) => {
|
|
300
|
-
this.sizes[index] = size
|
|
301
|
-
const maxSize = this.maxSize - this.sizes[index]
|
|
302
|
-
while (this.calculatedSize > maxSize) {
|
|
303
|
-
this.evict()
|
|
304
|
-
}
|
|
305
|
-
this.calculatedSize += this.sizes[index]
|
|
306
|
-
}
|
|
307
|
-
this.delete = k => {
|
|
308
|
-
if (this.size !== 0) {
|
|
309
|
-
const index = this.keyMap.get(k)
|
|
310
|
-
if (index !== undefined) {
|
|
311
|
-
this.calculatedSize -= this.sizes[index]
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return LRUCache.prototype.delete.call(this, k)
|
|
315
|
-
}
|
|
75
|
+
this[MAX_AGE] = mA
|
|
76
|
+
trim(this)
|
|
316
77
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
requireSize (k, v, size, sizeCalculation) {
|
|
320
|
-
if (size || sizeCalculation) {
|
|
321
|
-
throw new TypeError('cannot set size without setting maxSize on cache')
|
|
322
|
-
}
|
|
78
|
+
get maxAge () {
|
|
79
|
+
return this[MAX_AGE]
|
|
323
80
|
}
|
|
324
81
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
break
|
|
330
|
-
}
|
|
331
|
-
if (allowStale || !this.isStale(i)) {
|
|
332
|
-
yield i
|
|
333
|
-
}
|
|
334
|
-
if (i === this.head) {
|
|
335
|
-
break
|
|
336
|
-
} else {
|
|
337
|
-
i = this.prev[i]
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
82
|
+
// resize the cache when the lengthCalculator changes.
|
|
83
|
+
set lengthCalculator (lC) {
|
|
84
|
+
if (typeof lC !== 'function')
|
|
85
|
+
lC = naiveLength
|
|
342
86
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
yield i
|
|
351
|
-
}
|
|
352
|
-
if (i === this.tail) {
|
|
353
|
-
break
|
|
354
|
-
} else {
|
|
355
|
-
i = this.next[i]
|
|
356
|
-
}
|
|
357
|
-
}
|
|
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
|
+
})
|
|
358
94
|
}
|
|
95
|
+
trim(this)
|
|
359
96
|
}
|
|
97
|
+
get lengthCalculator () { return this[LENGTH_CALCULATOR] }
|
|
360
98
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
}
|
|
99
|
+
get length () { return this[LENGTH] }
|
|
100
|
+
get itemCount () { return this[LRU_LIST].length }
|
|
364
101
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
for (const i of this.rindexes()) {
|
|
372
|
-
yield [this.keyList[i], this.valList[i]]
|
|
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
|
|
373
108
|
}
|
|
374
109
|
}
|
|
375
110
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
for (const i of this.rindexes()) {
|
|
383
|
-
yield this.keyList[i]
|
|
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
|
|
384
117
|
}
|
|
385
118
|
}
|
|
386
119
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
yield this.valList[i]
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
*rvalues () {
|
|
393
|
-
for (const i of this.rindexes()) {
|
|
394
|
-
yield this.valList[i]
|
|
395
|
-
}
|
|
120
|
+
keys () {
|
|
121
|
+
return this[LRU_LIST].toArray().map(k => k.key)
|
|
396
122
|
}
|
|
397
123
|
|
|
398
|
-
|
|
399
|
-
return this.
|
|
124
|
+
values () {
|
|
125
|
+
return this[LRU_LIST].toArray().map(k => k.value)
|
|
400
126
|
}
|
|
401
127
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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))
|
|
407
133
|
}
|
|
408
|
-
}
|
|
409
134
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
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
|
|
414
138
|
}
|
|
415
139
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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)
|
|
420
147
|
}
|
|
421
148
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
return this.purgeStale
|
|
149
|
+
dumpLru () {
|
|
150
|
+
return this[LRU_LIST]
|
|
425
151
|
}
|
|
426
152
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
for (const i of this.rindexes({ allowStale: true })) {
|
|
430
|
-
if (this.isStale(i)) {
|
|
431
|
-
this.delete(this.keyList[i])
|
|
432
|
-
deleted = true
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
return deleted
|
|
436
|
-
}
|
|
153
|
+
set (key, value, maxAge) {
|
|
154
|
+
maxAge = maxAge || this[MAX_AGE]
|
|
437
155
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
for (const i of this.indexes()) {
|
|
441
|
-
const key = this.keyList[i]
|
|
442
|
-
const value = this.valList[i]
|
|
443
|
-
const entry = { value }
|
|
444
|
-
if (this.ttls) {
|
|
445
|
-
entry.ttl = this.ttls[i]
|
|
446
|
-
}
|
|
447
|
-
if (this.sizes) {
|
|
448
|
-
entry.size = this.sizes[i]
|
|
449
|
-
}
|
|
450
|
-
arr.unshift([key, entry])
|
|
451
|
-
}
|
|
452
|
-
return arr
|
|
453
|
-
}
|
|
156
|
+
if (maxAge && typeof maxAge !== 'number')
|
|
157
|
+
throw new TypeError('maxAge must be a number')
|
|
454
158
|
|
|
455
|
-
|
|
456
|
-
this
|
|
457
|
-
for (const [key, entry] of arr) {
|
|
458
|
-
this.set(key, entry.value, entry)
|
|
459
|
-
}
|
|
460
|
-
}
|
|
159
|
+
const now = maxAge ? Date.now() : 0
|
|
160
|
+
const len = this[LENGTH_CALCULATOR](value, key)
|
|
461
161
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
noDisposeOnSet = this.noDisposeOnSet,
|
|
467
|
-
size = 0,
|
|
468
|
-
sizeCalculation = this.sizeCalculation,
|
|
469
|
-
noUpdateTTL = this.noUpdateTTL,
|
|
470
|
-
} = {}) {
|
|
471
|
-
size = this.requireSize(k, v, size, sizeCalculation)
|
|
472
|
-
let index = this.size === 0 ? undefined : this.keyMap.get(k)
|
|
473
|
-
if (index === undefined) {
|
|
474
|
-
// addition
|
|
475
|
-
index = this.newIndex()
|
|
476
|
-
this.keyList[index] = k
|
|
477
|
-
this.valList[index] = v
|
|
478
|
-
this.keyMap.set(k, index)
|
|
479
|
-
this.next[this.tail] = index
|
|
480
|
-
this.prev[index] = this.tail
|
|
481
|
-
this.tail = index
|
|
482
|
-
this.size ++
|
|
483
|
-
this.addItemSize(index, v, k, size)
|
|
484
|
-
noUpdateTTL = false
|
|
485
|
-
} else {
|
|
486
|
-
// update
|
|
487
|
-
const oldVal = this.valList[index]
|
|
488
|
-
if (v !== oldVal) {
|
|
489
|
-
if (this.isBackgroundFetch(oldVal)) {
|
|
490
|
-
oldVal.__abortController.abort()
|
|
491
|
-
} else {
|
|
492
|
-
if (!noDisposeOnSet) {
|
|
493
|
-
this.dispose(oldVal, k, 'set')
|
|
494
|
-
if (this.disposeAfter) {
|
|
495
|
-
this.disposed.push([oldVal, k, 'set'])
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
this.removeItemSize(index)
|
|
500
|
-
this.valList[index] = v
|
|
501
|
-
this.addItemSize(index, v, k, size)
|
|
162
|
+
if (this[CACHE].has(key)) {
|
|
163
|
+
if (len > this[MAX]) {
|
|
164
|
+
del(this, this[CACHE].get(key))
|
|
165
|
+
return false
|
|
502
166
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
this
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
while (this.disposed.length) {
|
|
513
|
-
this.disposeAfter(...this.disposed.shift())
|
|
167
|
+
|
|
168
|
+
const node = this[CACHE].get(key)
|
|
169
|
+
const item = node.value
|
|
170
|
+
|
|
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)
|
|
514
176
|
}
|
|
515
|
-
}
|
|
516
|
-
return this
|
|
517
|
-
}
|
|
518
177
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
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
|
|
522
186
|
}
|
|
523
|
-
if (this.size === this.max) {
|
|
524
|
-
return this.evict()
|
|
525
|
-
}
|
|
526
|
-
if (this.free.length !== 0) {
|
|
527
|
-
return this.free.pop()
|
|
528
|
-
}
|
|
529
|
-
// initial fill, just keep writing down the list
|
|
530
|
-
return this.initialFill++
|
|
531
|
-
}
|
|
532
187
|
|
|
533
|
-
|
|
534
|
-
if (this.size) {
|
|
535
|
-
const val = this.valList[this.head]
|
|
536
|
-
this.evict()
|
|
537
|
-
return val
|
|
538
|
-
}
|
|
539
|
-
}
|
|
188
|
+
const hit = new Entry(key, value, len, now, maxAge)
|
|
540
189
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (this.isBackgroundFetch(v)) {
|
|
546
|
-
v.__abortController.abort()
|
|
547
|
-
} else {
|
|
548
|
-
this.dispose(v, k, 'evict')
|
|
549
|
-
if (this.disposeAfter) {
|
|
550
|
-
this.disposed.push([v, k, 'evict'])
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
this.removeItemSize(head)
|
|
554
|
-
this.head = this.next[head]
|
|
555
|
-
this.keyMap.delete(k)
|
|
556
|
-
this.size --
|
|
557
|
-
return head
|
|
558
|
-
}
|
|
190
|
+
// oversized objects fall out of cache automatically.
|
|
191
|
+
if (hit.length > this[MAX]) {
|
|
192
|
+
if (this[DISPOSE])
|
|
193
|
+
this[DISPOSE](key, value)
|
|
559
194
|
|
|
560
|
-
|
|
561
|
-
const index = this.keyMap.get(k)
|
|
562
|
-
if (index !== undefined) {
|
|
563
|
-
if (!this.isStale(index)) {
|
|
564
|
-
if (updateAgeOnHas) {
|
|
565
|
-
this.updateItemAge(index)
|
|
566
|
-
}
|
|
567
|
-
return true
|
|
568
|
-
}
|
|
195
|
+
return false
|
|
569
196
|
}
|
|
570
|
-
return false
|
|
571
|
-
}
|
|
572
197
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
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
|
|
579
203
|
}
|
|
580
204
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}
|
|
586
|
-
const ac = new AC()
|
|
587
|
-
const fetchOpts = {
|
|
588
|
-
signal: ac.signal,
|
|
589
|
-
options,
|
|
590
|
-
}
|
|
591
|
-
const p = Promise.resolve(this.fetchMethod(k, v, fetchOpts)).then(v => {
|
|
592
|
-
if (!ac.signal.aborted) {
|
|
593
|
-
this.set(k, v, fetchOpts.options)
|
|
594
|
-
}
|
|
595
|
-
return v
|
|
596
|
-
})
|
|
597
|
-
p.__abortController = ac
|
|
598
|
-
p.__staleWhileFetching = v
|
|
599
|
-
if (index === undefined) {
|
|
600
|
-
this.set(k, p, fetchOpts.options)
|
|
601
|
-
index = this.keyMap.get(k)
|
|
602
|
-
} else {
|
|
603
|
-
this.valList[index] = p
|
|
604
|
-
}
|
|
605
|
-
return p
|
|
205
|
+
has (key) {
|
|
206
|
+
if (!this[CACHE].has(key)) return false
|
|
207
|
+
const hit = this[CACHE].get(key).value
|
|
208
|
+
return !isStale(this, hit)
|
|
606
209
|
}
|
|
607
210
|
|
|
608
|
-
|
|
609
|
-
return
|
|
610
|
-
Object.prototype.hasOwnProperty.call(p, '__staleWhileFetching')
|
|
211
|
+
get (key) {
|
|
212
|
+
return get(this, key, true)
|
|
611
213
|
}
|
|
612
214
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
updateAgeOnGet = this.updateAgeOnGet,
|
|
617
|
-
ttl = this.ttl,
|
|
618
|
-
noDisposeOnSet = this.noDisposeOnSet,
|
|
619
|
-
size = 0,
|
|
620
|
-
sizeCalculation = this.sizeCalculation,
|
|
621
|
-
noUpdateTTL = this.noUpdateTTL,
|
|
622
|
-
} = {}) {
|
|
623
|
-
if (!this.fetchMethod) {
|
|
624
|
-
return this.get(k, {allowStale, updateAgeOnGet})
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
const options = {
|
|
628
|
-
allowStale,
|
|
629
|
-
updateAgeOnGet,
|
|
630
|
-
ttl,
|
|
631
|
-
noDisposeOnSet,
|
|
632
|
-
size,
|
|
633
|
-
sizeCalculation,
|
|
634
|
-
noUpdateTTL,
|
|
635
|
-
}
|
|
215
|
+
peek (key) {
|
|
216
|
+
return get(this, key, false)
|
|
217
|
+
}
|
|
636
218
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
// in cache, maybe already fetching
|
|
642
|
-
const v = this.valList[index]
|
|
643
|
-
if (this.isBackgroundFetch(v)) {
|
|
644
|
-
return allowStale && v.__staleWhileFetching !== undefined
|
|
645
|
-
? v.__staleWhileFetching : v
|
|
646
|
-
}
|
|
219
|
+
pop () {
|
|
220
|
+
const node = this[LRU_LIST].tail
|
|
221
|
+
if (!node)
|
|
222
|
+
return null
|
|
647
223
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
this.updateItemAge(index)
|
|
652
|
-
}
|
|
653
|
-
return v
|
|
654
|
-
}
|
|
224
|
+
del(this, node)
|
|
225
|
+
return node.value
|
|
226
|
+
}
|
|
655
227
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const p = this.backgroundFetch(k, index, options)
|
|
659
|
-
return allowStale && p.__staleWhileFetching !== undefined
|
|
660
|
-
? p.__staleWhileFetching : p
|
|
661
|
-
}
|
|
228
|
+
del (key) {
|
|
229
|
+
del(this, this[CACHE].get(key))
|
|
662
230
|
}
|
|
663
231
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
// if we're currently fetching it, we don't actually have it yet
|
|
682
|
-
// it's not stale, which means this isn't a staleWhileRefetching,
|
|
683
|
-
// so we just return undefined
|
|
684
|
-
if (fetching) {
|
|
685
|
-
return undefined
|
|
686
|
-
}
|
|
687
|
-
this.moveToTail(index)
|
|
688
|
-
if (updateAgeOnGet) {
|
|
689
|
-
this.updateItemAge(index)
|
|
232
|
+
load (arr) {
|
|
233
|
+
// reset the cache
|
|
234
|
+
this.reset()
|
|
235
|
+
|
|
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)
|
|
690
249
|
}
|
|
691
|
-
return value
|
|
692
250
|
}
|
|
693
251
|
}
|
|
694
252
|
}
|
|
695
253
|
|
|
696
|
-
|
|
697
|
-
this
|
|
698
|
-
this.next[p] = n
|
|
254
|
+
prune () {
|
|
255
|
+
this[CACHE].forEach((value, key) => get(this, key, false))
|
|
699
256
|
}
|
|
257
|
+
}
|
|
700
258
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
this.connect(this.prev[index], this.next[index])
|
|
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)
|
|
715
272
|
}
|
|
716
|
-
this.connect(this.tail, index)
|
|
717
|
-
this.tail = index
|
|
718
273
|
}
|
|
274
|
+
return hit.value
|
|
719
275
|
}
|
|
276
|
+
}
|
|
720
277
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
if (this.disposeAfter) {
|
|
741
|
-
this.disposed.push([v, k, 'delete'])
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
this.keyMap.delete(k)
|
|
745
|
-
this.keyList[index] = null
|
|
746
|
-
this.valList[index] = null
|
|
747
|
-
if (index === this.tail) {
|
|
748
|
-
this.tail = this.prev[index]
|
|
749
|
-
} else if (index === this.head) {
|
|
750
|
-
this.head = this.next[index]
|
|
751
|
-
} else {
|
|
752
|
-
this.next[this.prev[index]] = this.next[index]
|
|
753
|
-
this.prev[this.next[index]] = this.prev[index]
|
|
754
|
-
}
|
|
755
|
-
this.size --
|
|
756
|
-
this.free.push(index)
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
if (this.disposed) {
|
|
761
|
-
while (this.disposed.length) {
|
|
762
|
-
this.disposeAfter(...this.disposed.shift())
|
|
763
|
-
}
|
|
278
|
+
const isStale = (self, hit) => {
|
|
279
|
+
if (!hit || (!hit.maxAge && !self[MAX_AGE]))
|
|
280
|
+
return false
|
|
281
|
+
|
|
282
|
+
const diff = Date.now() - hit.now
|
|
283
|
+
return hit.maxAge ? diff > hit.maxAge
|
|
284
|
+
: self[MAX_AGE] && (diff > self[MAX_AGE])
|
|
285
|
+
}
|
|
286
|
+
|
|
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
|
|
764
297
|
}
|
|
765
|
-
return deleted
|
|
766
298
|
}
|
|
299
|
+
}
|
|
767
300
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
} else {
|
|
774
|
-
const k = this.keyList[index]
|
|
775
|
-
this.dispose(v, k, 'delete')
|
|
776
|
-
if (this.disposeAfter) {
|
|
777
|
-
this.disposed.push([v, k, 'delete'])
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
}
|
|
301
|
+
const del = (self, node) => {
|
|
302
|
+
if (node) {
|
|
303
|
+
const hit = node.value
|
|
304
|
+
if (self[DISPOSE])
|
|
305
|
+
self[DISPOSE](hit.key, hit.value)
|
|
781
306
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if (this.ttls) {
|
|
786
|
-
this.ttls.fill(0)
|
|
787
|
-
this.starts.fill(0)
|
|
788
|
-
}
|
|
789
|
-
if (this.sizes) {
|
|
790
|
-
this.sizes.fill(0)
|
|
791
|
-
}
|
|
792
|
-
this.head = 0
|
|
793
|
-
this.tail = 0
|
|
794
|
-
this.initialFill = 1
|
|
795
|
-
this.free.length = 0
|
|
796
|
-
this.calculatedSize = 0
|
|
797
|
-
this.size = 0
|
|
798
|
-
if (this.disposed) {
|
|
799
|
-
while (this.disposed.length) {
|
|
800
|
-
this.disposeAfter(...this.disposed.shift())
|
|
801
|
-
}
|
|
802
|
-
}
|
|
307
|
+
self[LENGTH] -= hit.length
|
|
308
|
+
self[CACHE].delete(hit.key)
|
|
309
|
+
self[LRU_LIST].removeNode(node)
|
|
803
310
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
311
|
+
}
|
|
312
|
+
|
|
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
|
|
807
320
|
}
|
|
321
|
+
}
|
|
808
322
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
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
|
|
812
329
|
}
|
|
330
|
+
if (hit)
|
|
331
|
+
fn.call(thisp, hit.value, hit.key, self)
|
|
813
332
|
}
|
|
814
333
|
|
|
815
334
|
module.exports = LRUCache
|