limited-cache 2.2.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.
- package/CHANGELOG.md +12 -0
- package/README.md +4 -3
- package/dist/cjs/index.cjs +273 -380
- package/dist/cjs/index.d.cts +84 -76
- package/dist/cjs/index.d.cts.map +1 -0
- package/dist/esm/index.d.ts +99 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +279 -6
- package/dist/esm/index.js.map +1 -1
- package/package.json +34 -53
- package/src/__tests__/LimitedCache.test.ts +2 -2
- package/src/__tests__/LimitedCacheObject.test.ts +30 -27
- package/src/__tests__/lowLevelFunctions.test.ts +10 -8
- package/src/__tests__/scenarios/keys.test.ts +2 -2
- package/src/__tests__/scenarios/maxCacheSize.test.ts +8 -5
- package/src/__tests__/scenarios/maxCacheTime.test.ts +58 -58
- package/src/__tests__/scenarios/values.test.ts +2 -2
- package/src/__tests__/typeChecks/LimitedCacheObjectTypes.test.ts +15 -15
- package/src/__tests__/typeChecks/LimitedCacheTypes.test.ts +1 -1
- package/src/__tests__/typeChecks/lowLevelFunctionsTypes.test.ts +2 -2
- package/src/core/LimitedCache.ts +20 -21
- package/src/core/LimitedCacheObject.ts +30 -19
- package/src/core/defaultOptions.ts +5 -4
- package/src/core/limitedCacheUtil.ts +15 -3
- package/src/core/lowLevelFunctions.ts +43 -32
- package/src/types.ts +4 -3
- package/dist/esm/core/LimitedCache.d.ts +0 -4
- package/dist/esm/core/LimitedCache.d.ts.map +0 -1
- package/dist/esm/core/LimitedCache.js +0 -29
- package/dist/esm/core/LimitedCache.js.map +0 -1
- package/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/dist/esm/core/LimitedCacheObject.d.ts.map +0 -1
- package/dist/esm/core/LimitedCacheObject.js +0 -52
- package/dist/esm/core/LimitedCacheObject.js.map +0 -1
- package/dist/esm/core/builtIns.d.ts +0 -12
- package/dist/esm/core/builtIns.d.ts.map +0 -1
- package/dist/esm/core/builtIns.js +0 -5
- package/dist/esm/core/builtIns.js.map +0 -1
- package/dist/esm/core/defaultOptions.d.ts +0 -6
- package/dist/esm/core/defaultOptions.d.ts.map +0 -1
- package/dist/esm/core/defaultOptions.js +0 -14
- package/dist/esm/core/defaultOptions.js.map +0 -1
- package/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/dist/esm/core/limitedCacheUtil.d.ts.map +0 -1
- package/dist/esm/core/limitedCacheUtil.js +0 -14
- package/dist/esm/core/limitedCacheUtil.js.map +0 -1
- package/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/dist/esm/core/lowLevelFunctions.d.ts.map +0 -1
- package/dist/esm/core/lowLevelFunctions.js +0 -240
- package/dist/esm/core/lowLevelFunctions.js.map +0 -1
- package/dist/esm/types.d.ts +0 -58
- package/dist/esm/types.d.ts.map +0 -1
- package/dist/esm/types.js +0 -2
- package/dist/esm/types.js.map +0 -1
- package/legacy-types/ts3.5/dist/esm/core/LimitedCache.d.ts +0 -4
- package/legacy-types/ts3.5/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/legacy-types/ts3.5/dist/esm/core/builtIns.d.ts +0 -12
- package/legacy-types/ts3.5/dist/esm/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts3.5/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/legacy-types/ts3.5/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/legacy-types/ts3.5/dist/esm/index.d.ts +0 -7
- package/legacy-types/ts3.5/dist/esm/types.d.ts +0 -61
- package/legacy-types/ts4.0/dist/esm/core/LimitedCache.d.ts +0 -4
- package/legacy-types/ts4.0/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/legacy-types/ts4.0/dist/esm/core/builtIns.d.ts +0 -12
- package/legacy-types/ts4.0/dist/esm/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts4.0/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/legacy-types/ts4.0/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/legacy-types/ts4.0/dist/esm/index.d.ts +0 -7
- package/legacy-types/ts4.0/dist/esm/types.d.ts +0 -61
- package/legacy-types/ts4.5/dist/esm/core/LimitedCache.d.ts +0 -4
- package/legacy-types/ts4.5/dist/esm/core/LimitedCacheObject.d.ts +0 -5
- package/legacy-types/ts4.5/dist/esm/core/builtIns.d.ts +0 -12
- package/legacy-types/ts4.5/dist/esm/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts4.5/dist/esm/core/limitedCacheUtil.d.ts +0 -13
- package/legacy-types/ts4.5/dist/esm/core/lowLevelFunctions.d.ts +0 -14
- package/legacy-types/ts4.5/dist/esm/index.d.ts +0 -7
- package/legacy-types/ts4.5/dist/esm/types.d.ts +0 -61
- package/src/core/builtIns.ts +0 -9
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// biome-ignore-all lint/performance/noDelete: Delete is explicitly used to unset items for these tests
|
|
2
|
+
|
|
3
|
+
import { beforeEach, describe, expect, it, vitest } from 'vitest';
|
|
4
|
+
import { LimitedCacheObject, type LimitedCacheObjectInstance } from '../../index.js';
|
|
3
5
|
|
|
4
6
|
// To avoid race conditions or timing issues, since some expect() checks can take 10+ ms when busy,
|
|
5
7
|
// we use a long cache timeout even for 'immediate' expiration, and use delays slightly longer than that
|
|
6
8
|
const CACHE_TIMEOUT = 25;
|
|
7
|
-
const timeoutPromise = (): Promise<
|
|
9
|
+
const timeoutPromise = (): Promise<void> =>
|
|
8
10
|
new Promise((resolve) => setTimeout(resolve, CACHE_TIMEOUT + 2));
|
|
9
11
|
|
|
10
12
|
describe('maxCacheTime scenarios', () => {
|
|
@@ -19,41 +21,39 @@ describe('maxCacheTime scenarios', () => {
|
|
|
19
21
|
});
|
|
20
22
|
|
|
21
23
|
it("doesn't have keys for expired items", async () => {
|
|
22
|
-
myCache
|
|
23
|
-
myCache
|
|
24
|
+
myCache['abc'] = 123;
|
|
25
|
+
myCache['def'] = 456;
|
|
24
26
|
await timeoutPromise();
|
|
25
|
-
myCache
|
|
27
|
+
myCache['ghi'] = 789;
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
expect(
|
|
29
|
-
expect(hasOwnProperty.call(myCache, 'def')).toEqual(false);
|
|
29
|
+
expect(Object.hasOwn(myCache, 'abc')).toEqual(false);
|
|
30
|
+
expect(Object.hasOwn(myCache, 'def')).toEqual(false);
|
|
30
31
|
|
|
31
32
|
expect(Object.keys(myCache)).toEqual(['ghi']);
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
it('removes expired items on get', async () => {
|
|
35
|
-
myCache
|
|
36
|
-
myCache
|
|
36
|
+
myCache['abc'] = 123;
|
|
37
|
+
myCache['def'] = 456;
|
|
37
38
|
await timeoutPromise();
|
|
38
39
|
|
|
39
|
-
expect(myCache
|
|
40
|
-
expect(myCache
|
|
40
|
+
expect(myCache['abc']).toEqual(undefined);
|
|
41
|
+
expect(myCache['def']).toEqual(undefined);
|
|
41
42
|
expect(Object.keys(myCache)).toEqual([]);
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
it('removes expired items on set', async () => {
|
|
45
|
-
myCache
|
|
46
|
-
myCache
|
|
46
|
+
myCache['abc'] = 123;
|
|
47
|
+
myCache['def'] = 456;
|
|
47
48
|
await timeoutPromise();
|
|
48
|
-
myCache
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
expect(
|
|
52
|
-
expect(
|
|
53
|
-
expect(
|
|
54
|
-
expect(myCache
|
|
55
|
-
expect(myCache
|
|
56
|
-
expect(myCache.ghi).toEqual(789);
|
|
49
|
+
myCache['ghi'] = 789;
|
|
50
|
+
|
|
51
|
+
expect(Object.hasOwn(myCache, 'abc')).toEqual(false);
|
|
52
|
+
expect(Object.hasOwn(myCache, 'def')).toEqual(false);
|
|
53
|
+
expect(Object.hasOwn(myCache, 'ghi')).toEqual(true);
|
|
54
|
+
expect(myCache['abc']).toEqual(undefined);
|
|
55
|
+
expect(myCache['def']).toEqual(undefined);
|
|
56
|
+
expect(myCache['ghi']).toEqual(789);
|
|
57
57
|
expect(Object.keys(myCache)).toEqual(['ghi']);
|
|
58
58
|
});
|
|
59
59
|
|
|
@@ -65,24 +65,24 @@ describe('maxCacheTime scenarios', () => {
|
|
|
65
65
|
warnIfItemPurgedBeforeTime: 0,
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
myCache
|
|
68
|
+
myCache['abc'] = 123;
|
|
69
69
|
await timeoutPromise();
|
|
70
|
-
myCache
|
|
70
|
+
myCache['def'] = 456;
|
|
71
71
|
await timeoutPromise();
|
|
72
|
-
myCache
|
|
72
|
+
myCache['ghi'] = 789;
|
|
73
73
|
await timeoutPromise();
|
|
74
74
|
|
|
75
75
|
// Now write over the 'oldest' key to reset its timestamp
|
|
76
|
-
myCache
|
|
76
|
+
myCache['abc'] = 123;
|
|
77
77
|
|
|
78
78
|
// Now, adding a new value (over maxCacheSize) should remove the actual oldest
|
|
79
|
-
myCache
|
|
80
|
-
expect(myCache
|
|
79
|
+
myCache['newOne'] = 100;
|
|
80
|
+
expect(myCache['def']).toEqual(undefined);
|
|
81
81
|
expect(Object.keys(myCache)).toEqual(['abc', 'ghi', 'newOne']);
|
|
82
82
|
|
|
83
83
|
// And then the next oldest, after that
|
|
84
|
-
myCache
|
|
85
|
-
expect(myCache
|
|
84
|
+
myCache['newTwo'] = 200;
|
|
85
|
+
expect(myCache['ghi']).toEqual(undefined);
|
|
86
86
|
expect(Object.keys(myCache)).toEqual(['abc', 'newOne', 'newTwo']);
|
|
87
87
|
});
|
|
88
88
|
|
|
@@ -94,36 +94,36 @@ describe('maxCacheTime scenarios', () => {
|
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
// This first set will expire after the second set gets added
|
|
97
|
-
myCache
|
|
98
|
-
myCache
|
|
99
|
-
myCache
|
|
97
|
+
myCache['abc'] = 123;
|
|
98
|
+
myCache['def'] = 456;
|
|
99
|
+
myCache['ghi'] = 789;
|
|
100
100
|
await timeoutPromise();
|
|
101
|
-
myCache
|
|
102
|
-
myCache
|
|
103
|
-
myCache
|
|
101
|
+
myCache['jkl'] = 321;
|
|
102
|
+
myCache['mno'] = 654;
|
|
103
|
+
myCache['abc'] = 1000;
|
|
104
104
|
|
|
105
105
|
// At this point nothing has been removed, since reusing 'abc' keeps us within maxCacheSize
|
|
106
|
-
expect(myCache
|
|
107
|
-
expect(myCache
|
|
108
|
-
expect(myCache
|
|
106
|
+
expect(myCache['abc']).toEqual(1000);
|
|
107
|
+
expect(myCache['def']).toEqual(456);
|
|
108
|
+
expect(myCache['ghi']).toEqual(789);
|
|
109
109
|
|
|
110
110
|
await timeoutPromise();
|
|
111
111
|
|
|
112
112
|
// Now, adding a new value (over maxCacheSize) should remove both of the remaining expired values
|
|
113
|
-
myCache
|
|
114
|
-
expect(myCache
|
|
115
|
-
expect(myCache
|
|
113
|
+
myCache['newOne'] = 100;
|
|
114
|
+
expect(myCache['def']).toEqual(undefined);
|
|
115
|
+
expect(myCache['ghi']).toEqual(undefined);
|
|
116
116
|
expect(Object.keys(myCache)).toEqual(['abc', 'jkl', 'mno', 'newOne']);
|
|
117
117
|
|
|
118
118
|
// And then the next can go in without having to remove anything
|
|
119
|
-
myCache
|
|
120
|
-
expect(myCache
|
|
121
|
-
expect(myCache
|
|
122
|
-
expect(myCache
|
|
119
|
+
myCache['newTwo'] = 200;
|
|
120
|
+
expect(myCache['jkl']).toEqual(321);
|
|
121
|
+
expect(myCache['mno']).toEqual(654);
|
|
122
|
+
expect(myCache['abc']).toEqual(1000);
|
|
123
123
|
expect(Object.keys(myCache)).toEqual(['abc', 'jkl', 'mno', 'newOne', 'newTwo']);
|
|
124
124
|
});
|
|
125
125
|
|
|
126
|
-
it('removes keys for already-removed items first',
|
|
126
|
+
it('removes keys for already-removed items first', () => {
|
|
127
127
|
myCache = LimitedCacheObject({
|
|
128
128
|
maxCacheTime: 0,
|
|
129
129
|
maxCacheSize: 5,
|
|
@@ -132,18 +132,18 @@ describe('maxCacheTime scenarios', () => {
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
// This first set will expire after the second set gets added
|
|
135
|
-
myCache
|
|
136
|
-
myCache
|
|
137
|
-
myCache
|
|
138
|
-
myCache
|
|
139
|
-
myCache
|
|
140
|
-
myCache
|
|
135
|
+
myCache['abc'] = 123;
|
|
136
|
+
myCache['def'] = 456;
|
|
137
|
+
myCache['ghi'] = 789;
|
|
138
|
+
myCache['jkl'] = 321;
|
|
139
|
+
myCache['mno'] = 654;
|
|
140
|
+
myCache['abc'] = 1000;
|
|
141
141
|
|
|
142
|
-
delete myCache
|
|
143
|
-
delete myCache
|
|
142
|
+
delete myCache['ghi'];
|
|
143
|
+
delete myCache['jkl'];
|
|
144
144
|
|
|
145
145
|
// Now, adding a new value (over maxCacheSize) should not remove anything else
|
|
146
|
-
myCache
|
|
146
|
+
myCache['newOne'] = 100;
|
|
147
147
|
|
|
148
148
|
expect(Object.keys(myCache)).toEqual(['abc', 'def', 'mno', 'newOne']);
|
|
149
149
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { type LimitedCacheMeta, limitedCacheUtil } from '../../index.js';
|
|
3
3
|
|
|
4
4
|
describe('value types', () => {
|
|
5
5
|
let myCacheMeta: LimitedCacheMeta;
|
|
@@ -7,21 +7,21 @@ import { LimitedCacheObject } from '../../index.js';
|
|
|
7
7
|
* Instead, it ensures that the typeChecks are correct.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
let value;
|
|
10
|
+
let value: unknown;
|
|
11
11
|
|
|
12
12
|
const defaultCache = LimitedCacheObject();
|
|
13
13
|
|
|
14
|
-
defaultCache
|
|
15
|
-
defaultCache
|
|
16
|
-
defaultCache
|
|
17
|
-
value = defaultCache
|
|
18
|
-
value = defaultCache
|
|
19
|
-
value = defaultCache
|
|
14
|
+
defaultCache['number'] = 1;
|
|
15
|
+
defaultCache['string'] = 'hello';
|
|
16
|
+
defaultCache['array'] = [];
|
|
17
|
+
value = defaultCache['number'] as number;
|
|
18
|
+
value = defaultCache['string'] as string;
|
|
19
|
+
value = defaultCache['array'] as Array<undefined>;
|
|
20
20
|
|
|
21
21
|
const numberCache = LimitedCacheObject<number>();
|
|
22
22
|
|
|
23
|
-
numberCache
|
|
24
|
-
value = numberCache
|
|
23
|
+
numberCache['number'] = 1;
|
|
24
|
+
value = numberCache['number'];
|
|
25
25
|
|
|
26
26
|
// @ts-expect-error Invalid type
|
|
27
27
|
numberCache.string = 'hello';
|
|
@@ -35,10 +35,10 @@ value = numberCache.array as Array<undefined>;
|
|
|
35
35
|
|
|
36
36
|
const primitiveCache = LimitedCacheObject<boolean | number | string>();
|
|
37
37
|
|
|
38
|
-
primitiveCache
|
|
39
|
-
primitiveCache
|
|
40
|
-
value = primitiveCache
|
|
41
|
-
value = primitiveCache
|
|
38
|
+
primitiveCache['number'] = 1;
|
|
39
|
+
primitiveCache['string'] = 'hello';
|
|
40
|
+
value = primitiveCache['number'];
|
|
41
|
+
value = primitiveCache['string'];
|
|
42
42
|
|
|
43
43
|
// @ts-expect-error Invalid type
|
|
44
44
|
primitiveCache.array = [];
|
|
@@ -48,8 +48,8 @@ value = primitiveCache.array as Array<undefined>;
|
|
|
48
48
|
|
|
49
49
|
const arrayCache = LimitedCacheObject<Array<undefined>>();
|
|
50
50
|
|
|
51
|
-
arrayCache
|
|
52
|
-
value = arrayCache
|
|
51
|
+
arrayCache['array'] = [];
|
|
52
|
+
value = arrayCache['array'];
|
|
53
53
|
|
|
54
54
|
// @ts-expect-error Invalid type
|
|
55
55
|
arrayCache.number = 1;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { describe, it } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { lowLevelGetOne, lowLevelInit, lowLevelSet } from '../../index.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* This is not a source file or test file.
|
|
7
7
|
* Instead, it ensures that the typeChecks are correct.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
let value;
|
|
10
|
+
let value: unknown;
|
|
11
11
|
|
|
12
12
|
const defaultCacheMeta = lowLevelInit();
|
|
13
13
|
|
package/src/core/LimitedCache.ts
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DefaultItemType,
|
|
3
|
+
LimitedCacheInstance,
|
|
4
|
+
LimitedCacheMeta,
|
|
5
|
+
LimitedCacheOptions,
|
|
6
|
+
LimitedCacheOptionsReadonly,
|
|
7
|
+
} from '../types.js';
|
|
1
8
|
import {
|
|
2
|
-
|
|
3
|
-
lowLevelGetOne,
|
|
9
|
+
lowLevelDoMaintenance,
|
|
4
10
|
lowLevelGetAll,
|
|
11
|
+
lowLevelGetOne,
|
|
5
12
|
lowLevelHas,
|
|
6
|
-
|
|
13
|
+
lowLevelInit,
|
|
7
14
|
lowLevelRemove,
|
|
8
15
|
lowLevelReset,
|
|
16
|
+
lowLevelSet,
|
|
9
17
|
lowLevelSetOptions,
|
|
10
|
-
lowLevelDoMaintenance,
|
|
11
18
|
} from './lowLevelFunctions.js';
|
|
12
|
-
import {
|
|
13
|
-
LimitedCacheOptions,
|
|
14
|
-
LimitedCacheOptionsReadonly,
|
|
15
|
-
LimitedCacheInstance,
|
|
16
|
-
LimitedCacheMeta,
|
|
17
|
-
DefaultItemType,
|
|
18
|
-
} from '../types.js';
|
|
19
19
|
|
|
20
20
|
// Most public functions just call a low-level function directly, passing the cacheMeta.
|
|
21
21
|
// Doing this via a helper function makes the typeChecks easier, and minifies better.
|
|
22
|
-
const bindFunctionToCacheMeta = <ItemType>(
|
|
23
|
-
|
|
24
|
-
fn: (cacheMeta: LimitedCacheMeta<ItemType>, ...otherArgs: any) => any,
|
|
22
|
+
const bindFunctionToCacheMeta = <ItemType, OtherArgs extends unknown[], ReturnValue>(
|
|
23
|
+
fn: (cacheMeta: LimitedCacheMeta<ItemType>, ...otherArgs: OtherArgs) => ReturnValue,
|
|
25
24
|
cacheMeta: LimitedCacheMeta<ItemType>,
|
|
26
|
-
) => fn.bind(null, cacheMeta);
|
|
25
|
+
): ((...otherArgs: OtherArgs) => ReturnValue) => fn.bind(null, cacheMeta);
|
|
27
26
|
|
|
28
27
|
const LimitedCache = <ItemType = DefaultItemType>(
|
|
29
28
|
options?: LimitedCacheOptions,
|
|
@@ -31,9 +30,9 @@ const LimitedCache = <ItemType = DefaultItemType>(
|
|
|
31
30
|
const cacheMeta = lowLevelInit<ItemType>(options);
|
|
32
31
|
|
|
33
32
|
return {
|
|
34
|
-
get: bindFunctionToCacheMeta
|
|
35
|
-
getAll: bindFunctionToCacheMeta
|
|
36
|
-
has: bindFunctionToCacheMeta
|
|
33
|
+
get: bindFunctionToCacheMeta(lowLevelGetOne, cacheMeta),
|
|
34
|
+
getAll: bindFunctionToCacheMeta(lowLevelGetAll, cacheMeta),
|
|
35
|
+
has: bindFunctionToCacheMeta(lowLevelHas, cacheMeta),
|
|
37
36
|
set: (cacheKey, item): ItemType => {
|
|
38
37
|
lowLevelSet(cacheMeta, cacheKey, item);
|
|
39
38
|
return item;
|
|
@@ -42,11 +41,11 @@ const LimitedCache = <ItemType = DefaultItemType>(
|
|
|
42
41
|
lowLevelRemove(cacheMeta, cacheKey);
|
|
43
42
|
return true;
|
|
44
43
|
},
|
|
45
|
-
reset: bindFunctionToCacheMeta
|
|
44
|
+
reset: bindFunctionToCacheMeta(lowLevelReset, cacheMeta),
|
|
46
45
|
getCacheMeta: (): LimitedCacheMeta<ItemType> => cacheMeta,
|
|
47
46
|
getOptions: (): LimitedCacheOptionsReadonly => cacheMeta.options,
|
|
48
|
-
setOptions: bindFunctionToCacheMeta
|
|
49
|
-
doMaintenance: bindFunctionToCacheMeta
|
|
47
|
+
setOptions: bindFunctionToCacheMeta(lowLevelSetOptions, cacheMeta),
|
|
48
|
+
doMaintenance: bindFunctionToCacheMeta(lowLevelDoMaintenance, cacheMeta),
|
|
50
49
|
};
|
|
51
50
|
};
|
|
52
51
|
|
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
|
+
DefaultItemType,
|
|
3
|
+
LimitedCacheMeta,
|
|
4
|
+
LimitedCacheObjectInstance,
|
|
5
|
+
LimitedCacheOptions,
|
|
6
|
+
} from '../types.js';
|
|
2
7
|
import {
|
|
3
|
-
lowLevelInit,
|
|
4
|
-
lowLevelGetOne,
|
|
5
8
|
lowLevelGetAll,
|
|
9
|
+
lowLevelGetOne,
|
|
6
10
|
lowLevelHas,
|
|
7
|
-
|
|
11
|
+
lowLevelInit,
|
|
8
12
|
lowLevelRemove,
|
|
13
|
+
lowLevelSet,
|
|
9
14
|
} from './lowLevelFunctions.js';
|
|
10
|
-
import {
|
|
11
|
-
LimitedCacheOptions,
|
|
12
|
-
LimitedCacheObjectInstance,
|
|
13
|
-
LimitedCacheMeta,
|
|
14
|
-
DefaultItemType,
|
|
15
|
-
} from '../types.js';
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
-
const proxyHandler: ProxyHandler<LimitedCacheObjectInstance<any>> = {
|
|
16
|
+
const proxyHandler: ProxyHandler<LimitedCacheMeta> = {
|
|
20
17
|
get: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {
|
|
21
18
|
if (cacheKey === 'hasOwnProperty') {
|
|
22
|
-
return hasOwnProperty;
|
|
19
|
+
return Object.prototype.hasOwnProperty;
|
|
23
20
|
}
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
24
22
|
return lowLevelGetOne(cacheMeta, cacheKey);
|
|
25
23
|
},
|
|
26
24
|
getOwnPropertyDescriptor: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {
|
|
27
25
|
const hasResult = lowLevelHas(cacheMeta, cacheKey);
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
28
27
|
const getResult = lowLevelGetOne(cacheMeta, cacheKey);
|
|
29
28
|
|
|
30
29
|
if (hasResult) {
|
|
31
30
|
return {
|
|
32
31
|
configurable: true,
|
|
33
32
|
enumerable: hasResult,
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
34
34
|
value: getResult,
|
|
35
35
|
writable: true,
|
|
36
36
|
};
|
|
@@ -38,8 +38,7 @@ const proxyHandler: ProxyHandler<LimitedCacheObjectInstance<any>> = {
|
|
|
38
38
|
return;
|
|
39
39
|
},
|
|
40
40
|
has: lowLevelHas,
|
|
41
|
-
|
|
42
|
-
set: (cacheMeta: LimitedCacheMeta, cacheKey: string, item: any): any => {
|
|
41
|
+
set: <T>(cacheMeta: LimitedCacheMeta, cacheKey: string, item: T): T => {
|
|
43
42
|
lowLevelSet(cacheMeta, cacheKey, item);
|
|
44
43
|
return item;
|
|
45
44
|
},
|
|
@@ -50,6 +49,16 @@ const proxyHandler: ProxyHandler<LimitedCacheObjectInstance<any>> = {
|
|
|
50
49
|
ownKeys: (cacheMeta: LimitedCacheMeta) => Object.keys(lowLevelGetAll(cacheMeta)),
|
|
51
50
|
};
|
|
52
51
|
|
|
52
|
+
/**
|
|
53
|
+
* TypeScript's Proxy type models the runtime target, but LimitedCacheObject intentionally returns
|
|
54
|
+
* a facade with a different surface from the internal cache metadata target.
|
|
55
|
+
*/
|
|
56
|
+
const internal_createLimitedCacheObjectProxy = <ItemType = DefaultItemType>(
|
|
57
|
+
cacheMeta: LimitedCacheMeta<ItemType>,
|
|
58
|
+
): LimitedCacheObjectInstance<ItemType> => {
|
|
59
|
+
return new Proxy(cacheMeta, proxyHandler) as unknown as LimitedCacheObjectInstance<ItemType>;
|
|
60
|
+
};
|
|
61
|
+
|
|
53
62
|
/**
|
|
54
63
|
* So that we can retrieve the cacheMeta for a LimitedCacheObject, without polluting its properties, each proxy
|
|
55
64
|
* is associated back to its internal cacheMeta here.
|
|
@@ -59,15 +68,17 @@ const cacheMetasForProxies = new WeakMap();
|
|
|
59
68
|
const LimitedCacheObject = <ItemType = DefaultItemType>(
|
|
60
69
|
options?: LimitedCacheOptions,
|
|
61
70
|
): LimitedCacheObjectInstance<ItemType> => {
|
|
62
|
-
const cacheMeta = lowLevelInit(options);
|
|
63
|
-
const limitedCacheObject =
|
|
71
|
+
const cacheMeta = lowLevelInit<ItemType>(options);
|
|
72
|
+
const limitedCacheObject = internal_createLimitedCacheObjectProxy(cacheMeta);
|
|
64
73
|
|
|
65
74
|
cacheMetasForProxies.set(limitedCacheObject, cacheMeta);
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
66
76
|
return limitedCacheObject;
|
|
67
77
|
};
|
|
68
78
|
|
|
69
79
|
const getCacheMetaFromObject = (instance: LimitedCacheObjectInstance): LimitedCacheMeta => {
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
70
81
|
return cacheMetasForProxies.get(instance);
|
|
71
82
|
};
|
|
72
83
|
|
|
73
|
-
export {
|
|
84
|
+
export { getCacheMetaFromObject, LimitedCacheObject };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { LimitedCacheOptionsReadonly } from '../types.js';
|
|
1
|
+
import type { LimitedCacheOptionsReadonly } from '../types.js';
|
|
2
2
|
|
|
3
|
-
const CURRENT_META_VERSION = 2;
|
|
4
|
-
|
|
3
|
+
const CURRENT_META_VERSION = 2 as const;
|
|
4
|
+
// Default = 1 year
|
|
5
|
+
const MAXIMUM_CACHE_TIME: number = 365 * 86400 * 1000;
|
|
5
6
|
|
|
6
7
|
const defaultOptions: LimitedCacheOptionsReadonly = {
|
|
7
8
|
// Public
|
|
@@ -14,4 +15,4 @@ const defaultOptions: LimitedCacheOptionsReadonly = {
|
|
|
14
15
|
scanLimit: 50,
|
|
15
16
|
};
|
|
16
17
|
|
|
17
|
-
export { CURRENT_META_VERSION,
|
|
18
|
+
export { CURRENT_META_VERSION, defaultOptions, MAXIMUM_CACHE_TIME };
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
lowLevelDoMaintenance,
|
|
3
3
|
lowLevelGetAll,
|
|
4
|
+
lowLevelGetOne,
|
|
4
5
|
lowLevelHas,
|
|
5
6
|
lowLevelInit,
|
|
6
|
-
lowLevelDoMaintenance,
|
|
7
7
|
lowLevelRemove,
|
|
8
8
|
lowLevelReset,
|
|
9
9
|
lowLevelSet,
|
|
10
10
|
lowLevelSetOptions,
|
|
11
11
|
} from './lowLevelFunctions.js';
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
type LimitedCacheUtil = {
|
|
14
|
+
init: typeof lowLevelInit;
|
|
15
|
+
get: typeof lowLevelGetOne;
|
|
16
|
+
getAll: typeof lowLevelGetAll;
|
|
17
|
+
has: typeof lowLevelHas;
|
|
18
|
+
set: typeof lowLevelSet;
|
|
19
|
+
remove: typeof lowLevelRemove;
|
|
20
|
+
reset: typeof lowLevelReset;
|
|
21
|
+
doMaintenance: typeof lowLevelDoMaintenance;
|
|
22
|
+
setOptions: typeof lowLevelSetOptions;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const limitedCacheUtil: LimitedCacheUtil = {
|
|
14
26
|
init: lowLevelInit,
|
|
15
27
|
get: lowLevelGetOne,
|
|
16
28
|
getAll: lowLevelGetAll,
|