limited-cache 1.1.1 → 2.1.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/CHANGELOG.md +19 -5
- package/CODE_OF_CONDUCT.md +103 -47
- package/{CONTRIBUTING.md → CONTRIBUTING.template.md} +4 -2
- package/LICENSE +1 -1
- package/README.md +26 -18
- package/dist/core/LimitedCache.d.ts +4 -3
- package/dist/core/LimitedCache.d.ts.map +1 -0
- package/dist/core/LimitedCache.js +29 -0
- package/dist/core/LimitedCache.js.map +1 -0
- package/dist/core/LimitedCacheObject.d.ts +5 -3
- package/dist/core/LimitedCacheObject.d.ts.map +1 -0
- package/dist/core/LimitedCacheObject.js +52 -0
- package/dist/core/LimitedCacheObject.js.map +1 -0
- package/dist/core/builtIns.d.ts +12 -11
- package/dist/core/builtIns.d.ts.map +1 -0
- package/dist/core/builtIns.js +5 -0
- package/dist/core/builtIns.js.map +1 -0
- package/dist/core/defaultOptions.d.ts +6 -6
- package/dist/core/defaultOptions.d.ts.map +1 -0
- package/dist/core/defaultOptions.js +14 -0
- package/dist/core/defaultOptions.js.map +1 -0
- package/dist/core/limitedCacheUtil.d.ts +13 -12
- package/dist/core/limitedCacheUtil.d.ts.map +1 -0
- package/dist/core/limitedCacheUtil.js +14 -0
- package/dist/core/limitedCacheUtil.js.map +1 -0
- package/dist/core/lowLevelFunctions.d.ts +14 -13
- package/dist/core/lowLevelFunctions.d.ts.map +1 -0
- package/dist/core/lowLevelFunctions.js +240 -0
- package/dist/core/lowLevelFunctions.js.map +1 -0
- package/dist/index.cjs +388 -0
- package/dist/index.d.ts +7 -10
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -8
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +58 -60
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +86 -73
- package/src/__tests__/LimitedCache.test.ts +186 -0
- package/src/__tests__/LimitedCacheObject.test.ts +150 -0
- package/src/__tests__/lowLevelFunctions.test.ts +430 -0
- package/src/__tests__/scenarios/keys.test.ts +67 -0
- package/src/__tests__/scenarios/maxCacheSize.test.ts +126 -0
- package/src/__tests__/scenarios/maxCacheTime.test.ts +150 -0
- package/src/__tests__/scenarios/values.test.ts +49 -0
- package/src/__tests__/typeChecks/LimitedCacheObjectTypes.test.ts +70 -0
- package/src/__tests__/typeChecks/LimitedCacheTypes.test.ts +70 -0
- package/src/__tests__/typeChecks/lowLevelFunctionsTypes.test.ts +70 -0
- package/src/core/LimitedCache.ts +1 -1
- package/src/core/LimitedCacheObject.ts +15 -3
- package/src/core/defaultOptions.ts +1 -2
- package/src/core/limitedCacheUtil.ts +1 -1
- package/src/core/lowLevelFunctions.ts +6 -6
- package/src/index.ts +0 -8
- package/dist/limited-cache.cjs.development.js +0 -456
- package/dist/limited-cache.cjs.development.js.map +0 -1
- package/dist/limited-cache.cjs.production.min.js +0 -2
- package/dist/limited-cache.cjs.production.min.js.map +0 -1
- package/dist/limited-cache.esm.js +0 -436
- package/dist/limited-cache.esm.js.map +0 -1
- package/legacy-types/ts3.x/dist/core/LimitedCache.d.ts +0 -3
- package/legacy-types/ts3.x/dist/core/LimitedCacheObject.d.ts +0 -3
- package/legacy-types/ts3.x/dist/core/builtIns.d.ts +0 -11
- package/legacy-types/ts3.x/dist/core/defaultOptions.d.ts +0 -6
- package/legacy-types/ts3.x/dist/core/limitedCacheUtil.d.ts +0 -12
- package/legacy-types/ts3.x/dist/core/lowLevelFunctions.d.ts +0 -13
- package/legacy-types/ts3.x/dist/index.d.ts +0 -10
- package/legacy-types/ts3.x/dist/types.d.ts +0 -60
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, beforeEach, expect, it, vitest } from 'vitest';
|
|
2
|
+
import { LimitedCacheObject, LimitedCacheObjectInstance } from '../../index';
|
|
3
|
+
|
|
4
|
+
// To avoid race conditions or timing issues, since some expect() checks can take 10+ ms when busy,
|
|
5
|
+
// we use a long cache timeout even for 'immediate' expiration, and use delays slightly longer than that
|
|
6
|
+
const CACHE_TIMEOUT = 25;
|
|
7
|
+
const timeoutPromise = (): Promise<null> =>
|
|
8
|
+
new Promise((resolve) => setTimeout(resolve, CACHE_TIMEOUT + 2));
|
|
9
|
+
|
|
10
|
+
describe('maxCacheTime scenarios', () => {
|
|
11
|
+
let myCache: LimitedCacheObjectInstance;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vitest.restoreAllMocks();
|
|
14
|
+
myCache = LimitedCacheObject({
|
|
15
|
+
maxCacheTime: CACHE_TIMEOUT,
|
|
16
|
+
maxCacheSize: Number.MAX_SAFE_INTEGER,
|
|
17
|
+
opLimit: Number.MAX_SAFE_INTEGER,
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("doesn't have keys for expired items", async () => {
|
|
22
|
+
myCache.abc = 123;
|
|
23
|
+
myCache.def = 456;
|
|
24
|
+
await timeoutPromise();
|
|
25
|
+
myCache.ghi = 789;
|
|
26
|
+
|
|
27
|
+
const { hasOwnProperty } = Object.prototype;
|
|
28
|
+
expect(hasOwnProperty.call(myCache, 'abc')).toEqual(false);
|
|
29
|
+
expect(hasOwnProperty.call(myCache, 'def')).toEqual(false);
|
|
30
|
+
|
|
31
|
+
expect(Object.keys(myCache)).toEqual(['ghi']);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('removes expired items on get', async () => {
|
|
35
|
+
myCache.abc = 123;
|
|
36
|
+
myCache.def = 456;
|
|
37
|
+
await timeoutPromise();
|
|
38
|
+
|
|
39
|
+
expect(myCache.abc).toEqual(undefined);
|
|
40
|
+
expect(myCache.def).toEqual(undefined);
|
|
41
|
+
expect(Object.keys(myCache)).toEqual([]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('removes expired items on set', async () => {
|
|
45
|
+
myCache.abc = 123;
|
|
46
|
+
myCache.def = 456;
|
|
47
|
+
await timeoutPromise();
|
|
48
|
+
myCache.ghi = 789;
|
|
49
|
+
|
|
50
|
+
const { hasOwnProperty } = Object.prototype;
|
|
51
|
+
expect(hasOwnProperty.call(myCache, 'abc')).toEqual(false);
|
|
52
|
+
expect(hasOwnProperty.call(myCache, 'def')).toEqual(false);
|
|
53
|
+
expect(hasOwnProperty.call(myCache, 'ghi')).toEqual(true);
|
|
54
|
+
expect(myCache.abc).toEqual(undefined);
|
|
55
|
+
expect(myCache.def).toEqual(undefined);
|
|
56
|
+
expect(myCache.ghi).toEqual(789);
|
|
57
|
+
expect(Object.keys(myCache)).toEqual(['ghi']);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('removes older items before newer ones', async () => {
|
|
61
|
+
myCache = LimitedCacheObject({
|
|
62
|
+
maxCacheTime: Number.MAX_SAFE_INTEGER,
|
|
63
|
+
maxCacheSize: 3,
|
|
64
|
+
opLimit: Number.MAX_SAFE_INTEGER,
|
|
65
|
+
warnIfItemPurgedBeforeTime: 0,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
myCache.abc = 123;
|
|
69
|
+
await timeoutPromise();
|
|
70
|
+
myCache.def = 456;
|
|
71
|
+
await timeoutPromise();
|
|
72
|
+
myCache.ghi = 789;
|
|
73
|
+
await timeoutPromise();
|
|
74
|
+
|
|
75
|
+
// Now write over the 'oldest' key to reset its timestamp
|
|
76
|
+
myCache.abc = 123;
|
|
77
|
+
|
|
78
|
+
// Now, adding a new value (over maxCacheSize) should remove the actual oldest
|
|
79
|
+
myCache.newOne = 100;
|
|
80
|
+
expect(myCache.def).toEqual(undefined);
|
|
81
|
+
expect(Object.keys(myCache)).toEqual(['abc', 'ghi', 'newOne']);
|
|
82
|
+
|
|
83
|
+
// And then the next oldest, after that
|
|
84
|
+
myCache.newTwo = 200;
|
|
85
|
+
expect(myCache.ghi).toEqual(undefined);
|
|
86
|
+
expect(Object.keys(myCache)).toEqual(['abc', 'newOne', 'newTwo']);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('removes expired items before old ones', async () => {
|
|
90
|
+
myCache = LimitedCacheObject({
|
|
91
|
+
maxCacheTime: CACHE_TIMEOUT * 2,
|
|
92
|
+
maxCacheSize: 5,
|
|
93
|
+
opLimit: Number.MAX_SAFE_INTEGER,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// This first set will expire after the second set gets added
|
|
97
|
+
myCache.abc = 123;
|
|
98
|
+
myCache.def = 456;
|
|
99
|
+
myCache.ghi = 789;
|
|
100
|
+
await timeoutPromise();
|
|
101
|
+
myCache.jkl = 321;
|
|
102
|
+
myCache.mno = 654;
|
|
103
|
+
myCache.abc = 1000;
|
|
104
|
+
|
|
105
|
+
// At this point nothing has been removed, since reusing 'abc' keeps us within maxCacheSize
|
|
106
|
+
expect(myCache.abc).toEqual(1000);
|
|
107
|
+
expect(myCache.def).toEqual(456);
|
|
108
|
+
expect(myCache.ghi).toEqual(789);
|
|
109
|
+
|
|
110
|
+
await timeoutPromise();
|
|
111
|
+
|
|
112
|
+
// Now, adding a new value (over maxCacheSize) should remove both of the remaining expired values
|
|
113
|
+
myCache.newOne = 100;
|
|
114
|
+
expect(myCache.def).toEqual(undefined);
|
|
115
|
+
expect(myCache.ghi).toEqual(undefined);
|
|
116
|
+
expect(Object.keys(myCache)).toEqual(['abc', 'jkl', 'mno', 'newOne']);
|
|
117
|
+
|
|
118
|
+
// And then the next can go in without having to remove anything
|
|
119
|
+
myCache.newTwo = 200;
|
|
120
|
+
expect(myCache.jkl).toEqual(321);
|
|
121
|
+
expect(myCache.mno).toEqual(654);
|
|
122
|
+
expect(myCache.abc).toEqual(1000);
|
|
123
|
+
expect(Object.keys(myCache)).toEqual(['abc', 'jkl', 'mno', 'newOne', 'newTwo']);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('removes keys for already-removed items first', async () => {
|
|
127
|
+
myCache = LimitedCacheObject({
|
|
128
|
+
maxCacheTime: 0,
|
|
129
|
+
maxCacheSize: 5,
|
|
130
|
+
opLimit: Number.MAX_SAFE_INTEGER,
|
|
131
|
+
warnIfItemPurgedBeforeTime: 0,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// This first set will expire after the second set gets added
|
|
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
|
+
|
|
142
|
+
delete myCache.ghi;
|
|
143
|
+
delete myCache.jkl;
|
|
144
|
+
|
|
145
|
+
// Now, adding a new value (over maxCacheSize) should not remove anything else
|
|
146
|
+
myCache.newOne = 100;
|
|
147
|
+
|
|
148
|
+
expect(Object.keys(myCache)).toEqual(['abc', 'def', 'mno', 'newOne']);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, beforeEach, expect, it } from 'vitest';
|
|
2
|
+
import { limitedCacheUtil, LimitedCacheMeta } from '../../index';
|
|
3
|
+
|
|
4
|
+
describe('value types', () => {
|
|
5
|
+
let myCacheMeta: LimitedCacheMeta;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
myCacheMeta = limitedCacheUtil.init();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('null', () => {
|
|
11
|
+
limitedCacheUtil.set(myCacheMeta, 'test', null);
|
|
12
|
+
|
|
13
|
+
expect(limitedCacheUtil.has(myCacheMeta, 'test')).toEqual(true);
|
|
14
|
+
expect(limitedCacheUtil.get(myCacheMeta, 'test')).toEqual(null);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Setting an explicit `undefined` treats the value as absent
|
|
18
|
+
it('undefined', () => {
|
|
19
|
+
limitedCacheUtil.set(myCacheMeta, 'test', undefined);
|
|
20
|
+
|
|
21
|
+
expect(limitedCacheUtil.has(myCacheMeta, 'test')).toEqual(false);
|
|
22
|
+
expect(limitedCacheUtil.get(myCacheMeta, 'test')).toEqual(undefined);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('object', () => {
|
|
26
|
+
limitedCacheUtil.set(myCacheMeta, 'test', { foo: 'bar' });
|
|
27
|
+
|
|
28
|
+
expect(limitedCacheUtil.has(myCacheMeta, 'test')).toEqual(true);
|
|
29
|
+
expect(limitedCacheUtil.get(myCacheMeta, 'test')).toEqual({ foo: 'bar' });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('array', () => {
|
|
33
|
+
limitedCacheUtil.set(myCacheMeta, 'test', [1, 2, 3]);
|
|
34
|
+
|
|
35
|
+
expect(limitedCacheUtil.has(myCacheMeta, 'test')).toEqual(true);
|
|
36
|
+
expect(limitedCacheUtil.get(myCacheMeta, 'test')).toEqual([1, 2, 3]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('function', () => {
|
|
40
|
+
function testFunction(): null {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
limitedCacheUtil.set(myCacheMeta, 'test', testFunction);
|
|
45
|
+
|
|
46
|
+
expect(limitedCacheUtil.has(myCacheMeta, 'test')).toEqual(true);
|
|
47
|
+
expect(limitedCacheUtil.get(myCacheMeta, 'test')).toEqual(testFunction);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { LimitedCacheObject } from '../../index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This is not a source file or test file.
|
|
7
|
+
* Instead, it ensures that the typeChecks are correct.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let value;
|
|
11
|
+
|
|
12
|
+
const defaultCache = LimitedCacheObject();
|
|
13
|
+
|
|
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
|
+
|
|
21
|
+
const numberCache = LimitedCacheObject<number>();
|
|
22
|
+
|
|
23
|
+
numberCache.number = 1;
|
|
24
|
+
value = numberCache.number as number;
|
|
25
|
+
|
|
26
|
+
// @ts-expect-error Invalid type
|
|
27
|
+
numberCache.string = 'hello';
|
|
28
|
+
// @ts-expect-error Invalid type
|
|
29
|
+
numberCache.array = [];
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error Invalid type
|
|
32
|
+
value = numberCache.string as string;
|
|
33
|
+
// @ts-expect-error Invalid type
|
|
34
|
+
value = numberCache.array as Array<undefined>;
|
|
35
|
+
|
|
36
|
+
const primitiveCache = LimitedCacheObject<boolean | number | string>();
|
|
37
|
+
|
|
38
|
+
primitiveCache.number = 1;
|
|
39
|
+
primitiveCache.string = 'hello';
|
|
40
|
+
value = primitiveCache.number as number;
|
|
41
|
+
value = primitiveCache.string as string;
|
|
42
|
+
|
|
43
|
+
// @ts-expect-error Invalid type
|
|
44
|
+
primitiveCache.array = [];
|
|
45
|
+
|
|
46
|
+
// @ts-expect-error Invalid type
|
|
47
|
+
value = primitiveCache.array as Array<undefined>;
|
|
48
|
+
|
|
49
|
+
const arrayCache = LimitedCacheObject<Array<undefined>>();
|
|
50
|
+
|
|
51
|
+
arrayCache.array = [];
|
|
52
|
+
value = arrayCache.array as Array<undefined>;
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error Invalid type
|
|
55
|
+
arrayCache.number = 1;
|
|
56
|
+
// @ts-expect-error Invalid type
|
|
57
|
+
arrayCache.string = 'hello';
|
|
58
|
+
|
|
59
|
+
// @ts-expect-error Invalid type
|
|
60
|
+
value = arrayCache.number as number;
|
|
61
|
+
// @ts-expect-error Invalid type
|
|
62
|
+
value = arrayCache.string as string;
|
|
63
|
+
|
|
64
|
+
// Fake test, to make Vitest happy
|
|
65
|
+
describe('fake typeCheck test', () => {
|
|
66
|
+
it('does nothing', () => null);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Fake export, to make the linter happy
|
|
70
|
+
export { value };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { LimitedCache } from '../../index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This is not a source file or test file.
|
|
7
|
+
* Instead, it ensures that the typeChecks are correct.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let value;
|
|
11
|
+
|
|
12
|
+
const defaultCache = LimitedCache();
|
|
13
|
+
|
|
14
|
+
defaultCache.set('number', 1);
|
|
15
|
+
defaultCache.set('string', 'hello');
|
|
16
|
+
defaultCache.set('array', []);
|
|
17
|
+
value = defaultCache.get('number') as number;
|
|
18
|
+
value = defaultCache.get('string') as string;
|
|
19
|
+
value = defaultCache.get('array') as Array<undefined>;
|
|
20
|
+
|
|
21
|
+
const numberCache = LimitedCache<number>();
|
|
22
|
+
|
|
23
|
+
numberCache.set('number', 1);
|
|
24
|
+
value = numberCache.get('number') as number;
|
|
25
|
+
|
|
26
|
+
// @ts-expect-error Invalid type
|
|
27
|
+
numberCache.set('string', 'hello');
|
|
28
|
+
// @ts-expect-error Invalid type
|
|
29
|
+
numberCache.set('array', []);
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error Invalid type
|
|
32
|
+
value = numberCache.get('string') as string;
|
|
33
|
+
// @ts-expect-error Invalid type
|
|
34
|
+
value = numberCache.get('array') as Array<undefined>;
|
|
35
|
+
|
|
36
|
+
const primitiveCache = LimitedCache<boolean | number | string>();
|
|
37
|
+
|
|
38
|
+
primitiveCache.set('number', 1);
|
|
39
|
+
primitiveCache.set('string', 'hello');
|
|
40
|
+
value = primitiveCache.get('number') as number;
|
|
41
|
+
value = primitiveCache.get('string') as string;
|
|
42
|
+
|
|
43
|
+
// @ts-expect-error Invalid type
|
|
44
|
+
primitiveCache.set('array', []);
|
|
45
|
+
|
|
46
|
+
// @ts-expect-error Invalid type
|
|
47
|
+
value = primitiveCache.get('array') as Array<undefined>;
|
|
48
|
+
|
|
49
|
+
const arrayCache = LimitedCache<Array<undefined>>();
|
|
50
|
+
|
|
51
|
+
arrayCache.set('array', []);
|
|
52
|
+
value = arrayCache.get('array') as Array<undefined>;
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error Invalid type
|
|
55
|
+
arrayCache.set('number', 1);
|
|
56
|
+
// @ts-expect-error Invalid type
|
|
57
|
+
arrayCache.set('string', 'hello');
|
|
58
|
+
|
|
59
|
+
// @ts-expect-error Invalid type
|
|
60
|
+
value = arrayCache.get('number') as number;
|
|
61
|
+
// @ts-expect-error Invalid type
|
|
62
|
+
value = arrayCache.get('string') as string;
|
|
63
|
+
|
|
64
|
+
// Fake test, to make Vitest happy
|
|
65
|
+
describe('fake typeCheck test', () => {
|
|
66
|
+
it('does nothing', () => null);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Fake export, to make the linter happy
|
|
70
|
+
export { value };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { lowLevelInit, lowLevelGetOne, lowLevelSet } from '../../index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This is not a source file or test file.
|
|
7
|
+
* Instead, it ensures that the typeChecks are correct.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let value;
|
|
11
|
+
|
|
12
|
+
const defaultCacheMeta = lowLevelInit();
|
|
13
|
+
|
|
14
|
+
lowLevelSet(defaultCacheMeta, 'number', 1);
|
|
15
|
+
lowLevelSet(defaultCacheMeta, 'string', 'hello');
|
|
16
|
+
lowLevelSet(defaultCacheMeta, 'array', []);
|
|
17
|
+
value = lowLevelGetOne(defaultCacheMeta, 'number') as number;
|
|
18
|
+
value = lowLevelGetOne(defaultCacheMeta, 'string') as string;
|
|
19
|
+
value = lowLevelGetOne(defaultCacheMeta, 'array') as Array<undefined>;
|
|
20
|
+
|
|
21
|
+
const numberCacheMeta = lowLevelInit<number>();
|
|
22
|
+
|
|
23
|
+
lowLevelSet(numberCacheMeta, 'number', 1);
|
|
24
|
+
value = lowLevelGetOne(numberCacheMeta, 'number') as number;
|
|
25
|
+
|
|
26
|
+
// @ts-expect-error Invalid type
|
|
27
|
+
lowLevelSet(numberCacheMeta, 'string', 'hello');
|
|
28
|
+
// @ts-expect-error Invalid type
|
|
29
|
+
lowLevelSet(numberCacheMeta, 'array', []);
|
|
30
|
+
|
|
31
|
+
// @ts-expect-error Invalid type
|
|
32
|
+
value = lowLevelGetOne(numberCacheMeta, 'string') as string;
|
|
33
|
+
// @ts-expect-error Invalid type
|
|
34
|
+
value = lowLevelGetOne(numberCacheMeta, 'array') as Array<undefined>;
|
|
35
|
+
|
|
36
|
+
const primitiveCacheMeta = lowLevelInit<boolean | number | string>();
|
|
37
|
+
|
|
38
|
+
lowLevelSet(primitiveCacheMeta, 'number', 1);
|
|
39
|
+
lowLevelSet(primitiveCacheMeta, 'string', 'hello');
|
|
40
|
+
value = lowLevelGetOne(primitiveCacheMeta, 'number') as number;
|
|
41
|
+
value = lowLevelGetOne(primitiveCacheMeta, 'string') as string;
|
|
42
|
+
|
|
43
|
+
// @ts-expect-error Invalid type
|
|
44
|
+
lowLevelSet(primitiveCacheMeta, 'array', []);
|
|
45
|
+
|
|
46
|
+
// @ts-expect-error Invalid type
|
|
47
|
+
value = lowLevelGetOne(primitiveCacheMeta, 'array') as Array<undefined>;
|
|
48
|
+
|
|
49
|
+
const arrayCacheMeta = lowLevelInit<Array<undefined>>();
|
|
50
|
+
|
|
51
|
+
lowLevelSet(arrayCacheMeta, 'array', []);
|
|
52
|
+
value = lowLevelGetOne(arrayCacheMeta, 'array') as Array<undefined>;
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error Invalid type
|
|
55
|
+
lowLevelSet(arrayCacheMeta, 'number', 1);
|
|
56
|
+
// @ts-expect-error Invalid type
|
|
57
|
+
lowLevelSet(arrayCacheMeta, 'string', 'hello');
|
|
58
|
+
|
|
59
|
+
// @ts-expect-error Invalid type
|
|
60
|
+
value = lowLevelGetOne(arrayCacheMeta, 'number') as number;
|
|
61
|
+
// @ts-expect-error Invalid type
|
|
62
|
+
value = lowLevelGetOne(arrayCacheMeta, 'string') as string;
|
|
63
|
+
|
|
64
|
+
// Fake test, to make Vitest happy
|
|
65
|
+
describe('fake typeCheck test', () => {
|
|
66
|
+
it('does nothing', () => null);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Fake export, to make the linter happy
|
|
70
|
+
export { value };
|
package/src/core/LimitedCache.ts
CHANGED
|
@@ -21,7 +21,6 @@ const proxyHandler: ProxyHandler<LimitedCacheObjectInstance<any>> = {
|
|
|
21
21
|
if (cacheKey === 'hasOwnProperty') {
|
|
22
22
|
return hasOwnProperty;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
24
|
return lowLevelGetOne(cacheMeta, cacheKey);
|
|
26
25
|
},
|
|
27
26
|
getOwnPropertyDescriptor: (cacheMeta: LimitedCacheMeta, cacheKey: string) => {
|
|
@@ -51,11 +50,24 @@ const proxyHandler: ProxyHandler<LimitedCacheObjectInstance<any>> = {
|
|
|
51
50
|
ownKeys: (cacheMeta: LimitedCacheMeta) => Object.keys(lowLevelGetAll(cacheMeta)),
|
|
52
51
|
};
|
|
53
52
|
|
|
53
|
+
/**
|
|
54
|
+
* So that we can retrieve the cacheMeta for a LimitedCacheObject, without polluting its properties, each proxy
|
|
55
|
+
* is associated back to its internal cacheMeta here.
|
|
56
|
+
*/
|
|
57
|
+
const cacheMetasForProxies = new WeakMap();
|
|
58
|
+
|
|
54
59
|
const LimitedCacheObject = <ItemType = DefaultItemType>(
|
|
55
60
|
options?: LimitedCacheOptions,
|
|
56
61
|
): LimitedCacheObjectInstance<ItemType> => {
|
|
57
62
|
const cacheMeta = lowLevelInit(options);
|
|
58
|
-
|
|
63
|
+
const limitedCacheObject = new Proxy(cacheMeta, proxyHandler);
|
|
64
|
+
|
|
65
|
+
cacheMetasForProxies.set(limitedCacheObject, cacheMeta);
|
|
66
|
+
return limitedCacheObject;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const getCacheMetaFromObject = (instance: LimitedCacheObjectInstance): LimitedCacheMeta => {
|
|
70
|
+
return cacheMetasForProxies.get(instance);
|
|
59
71
|
};
|
|
60
72
|
|
|
61
|
-
export
|
|
73
|
+
export { LimitedCacheObject, getCacheMetaFromObject };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { objectAssign, objectCreate, dateNow, hasOwnProperty } from './builtIns';
|
|
2
|
-
import
|
|
2
|
+
import { CURRENT_META_VERSION, MAXIMUM_CACHE_TIME, defaultOptions } from './defaultOptions';
|
|
3
3
|
import {
|
|
4
4
|
LimitedCacheOptions,
|
|
5
5
|
LimitedCacheOptionsReadonly,
|
|
@@ -115,9 +115,9 @@ const lowLevelDoMaintenance = <ItemType = DefaultItemType>(
|
|
|
115
115
|
return acc;
|
|
116
116
|
},
|
|
117
117
|
[
|
|
118
|
-
{} as typeof cacheMeta['cache'],
|
|
119
|
-
[] as typeof cacheMeta['keyList'],
|
|
120
|
-
objectCreate(null) as typeof cacheMeta['keyInfo'],
|
|
118
|
+
{} as (typeof cacheMeta)['cache'],
|
|
119
|
+
[] as (typeof cacheMeta)['keyList'],
|
|
120
|
+
objectCreate(null) as (typeof cacheMeta)['keyInfo'],
|
|
121
121
|
],
|
|
122
122
|
);
|
|
123
123
|
|
|
@@ -169,7 +169,7 @@ const _removeItemsToMakeRoom = (cacheMeta: LimitedCacheMeta, now: number): void
|
|
|
169
169
|
const maxIndexToCheck = Math.min(keyList.length, scanLimit);
|
|
170
170
|
while (indexToCheck < maxIndexToCheck) {
|
|
171
171
|
const cacheKeyForIndex = keyList[indexToCheck];
|
|
172
|
-
|
|
172
|
+
const expireTimeForIndex = _getExpireTime(cacheMeta, cacheKeyForIndex);
|
|
173
173
|
|
|
174
174
|
// We only consider it if it's eligible for expiration: otherwise it can't be a better option
|
|
175
175
|
// than the default head-of-queue
|
|
@@ -196,7 +196,7 @@ const _removeItemsToMakeRoom = (cacheMeta: LimitedCacheMeta, now: number): void
|
|
|
196
196
|
oldestExpireTime > now
|
|
197
197
|
) {
|
|
198
198
|
const oldestItemKey = keyList[oldestItemIndex];
|
|
199
|
-
const [oldestItemSetTime, oldestItemExpireTime] = keyInfo[oldestItemKey]
|
|
199
|
+
const [oldestItemSetTime, oldestItemExpireTime] = keyInfo[oldestItemKey] as [number, number];
|
|
200
200
|
|
|
201
201
|
if (now - oldestItemSetTime < warnIfItemPurgedBeforeTime) {
|
|
202
202
|
console.warn(
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
export { default as defaultOptions } from './core/defaultOptions';
|
|
2
1
|
export * from './core/defaultOptions';
|
|
3
|
-
|
|
4
|
-
export { default as LimitedCache } from './core/LimitedCache';
|
|
5
2
|
export * from './core/LimitedCache';
|
|
6
|
-
|
|
7
|
-
export { default as LimitedCacheObject } from './core/LimitedCacheObject';
|
|
8
3
|
export * from './core/LimitedCacheObject';
|
|
9
|
-
|
|
10
|
-
export { default as limitedCacheUtil } from './core/limitedCacheUtil';
|
|
11
4
|
export * from './core/limitedCacheUtil';
|
|
12
5
|
|
|
13
6
|
export * from './core/lowLevelFunctions';
|
|
14
|
-
|
|
15
7
|
export * from './types';
|