@isograph/react-disposable-state 0.0.0-main-1cd3db6d → 0.0.0-main-2c275831
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/dist/CacheItem.d.ts +4 -4
- package/dist/CacheItem.js +51 -51
- package/dist/ParentCache.d.ts +2 -2
- package/dist/index.d.ts +8 -8
- package/dist/useCachedPrecommitValue.d.ts +2 -2
- package/dist/useCachedPrecommitValue.js +1 -1
- package/dist/useDisposableState.d.ts +3 -3
- package/dist/useDisposableState.js +5 -7
- package/dist/useHasCommittedRef.d.ts +1 -1
- package/dist/useLazyDisposableState.d.ts +1 -1
- package/dist/useLazyDisposableState.js +3 -3
- package/dist/useUpdatableDisposableState.d.ts +1 -1
- package/dist/useUpdatableDisposableState.js +3 -3
- package/package.json +2 -2
- package/src/CacheItem.test.ts +184 -222
- package/src/CacheItem.ts +64 -81
- package/src/ParentCache.test.ts +9 -10
- package/src/ParentCache.ts +7 -9
- package/src/index.ts +8 -8
- package/src/useCachedPrecommitValue.test.tsx +47 -77
- package/src/useCachedPrecommitValue.ts +9 -13
- package/src/useDisposableState.ts +13 -16
- package/src/useHasCommittedRef.ts +1 -1
- package/src/useLazyDisposableState.ts +7 -7
- package/src/useUpdatableDisposableState.test.tsx +24 -33
- package/src/useUpdatableDisposableState.ts +9 -11
package/src/CacheItem.ts
CHANGED
@@ -1,16 +1,12 @@
|
|
1
|
-
import {
|
2
|
-
CleanupFn,
|
3
|
-
Factory,
|
4
|
-
ItemCleanupPair,
|
5
|
-
} from "@isograph/disposable-types";
|
1
|
+
import { CleanupFn, Factory, ItemCleanupPair } from '@isograph/disposable-types';
|
6
2
|
|
7
3
|
const DEFAULT_TEMPORARY_RETAIN_TIME = 5000;
|
8
4
|
|
9
5
|
export type NotInParentCacheAndDisposed = {
|
10
|
-
kind:
|
6
|
+
kind: 'NotInParentCacheAndDisposed';
|
11
7
|
};
|
12
8
|
export type NotInParentCacheAndNotDisposed<T> = {
|
13
|
-
kind:
|
9
|
+
kind: 'NotInParentCacheAndNotDisposed';
|
14
10
|
value: T;
|
15
11
|
disposeValue: () => void;
|
16
12
|
|
@@ -18,7 +14,7 @@ export type NotInParentCacheAndNotDisposed<T> = {
|
|
18
14
|
permanentRetainCount: number;
|
19
15
|
};
|
20
16
|
export type InParentCacheAndNotDisposed<T> = {
|
21
|
-
kind:
|
17
|
+
kind: 'InParentCacheAndNotDisposed';
|
22
18
|
value: T;
|
23
19
|
disposeValue: () => void;
|
24
20
|
removeFromParentCache: () => void;
|
@@ -74,12 +70,12 @@ export class CacheItem<T> {
|
|
74
70
|
constructor(
|
75
71
|
factory: Factory<T>,
|
76
72
|
removeFromParentCache: CleanupFn,
|
77
|
-
options: CacheItemOptions | void
|
73
|
+
options: CacheItemOptions | void,
|
78
74
|
) {
|
79
75
|
this.__options = options ?? null;
|
80
76
|
const [value, disposeValue] = factory();
|
81
77
|
this.__state = {
|
82
|
-
kind:
|
78
|
+
kind: 'InParentCacheAndNotDisposed',
|
83
79
|
value,
|
84
80
|
disposeValue,
|
85
81
|
removeFromParentCache,
|
@@ -92,26 +88,24 @@ export class CacheItem<T> {
|
|
92
88
|
|
93
89
|
getValue(): T {
|
94
90
|
switch (this.__state.kind) {
|
95
|
-
case
|
91
|
+
case 'InParentCacheAndNotDisposed': {
|
96
92
|
return this.__state.value;
|
97
93
|
}
|
98
|
-
case
|
94
|
+
case 'NotInParentCacheAndNotDisposed': {
|
99
95
|
return this.__state.value;
|
100
96
|
}
|
101
97
|
default: {
|
102
98
|
throw new Error(
|
103
|
-
|
104
|
-
|
99
|
+
'Attempted to access disposed value from CacheItem. ' +
|
100
|
+
'This indicates a bug in react-disposable-state.',
|
105
101
|
);
|
106
102
|
}
|
107
103
|
}
|
108
104
|
}
|
109
105
|
|
110
|
-
permanentRetainIfNotDisposed(
|
111
|
-
disposeOfTemporaryRetain: CleanupFn
|
112
|
-
): ItemCleanupPair<T> | null {
|
106
|
+
permanentRetainIfNotDisposed(disposeOfTemporaryRetain: CleanupFn): ItemCleanupPair<T> | null {
|
113
107
|
switch (this.__state.kind) {
|
114
|
-
case
|
108
|
+
case 'InParentCacheAndNotDisposed': {
|
115
109
|
let cleared = false;
|
116
110
|
this.__state.permanentRetainCount++;
|
117
111
|
disposeOfTemporaryRetain();
|
@@ -120,35 +114,33 @@ export class CacheItem<T> {
|
|
120
114
|
() => {
|
121
115
|
if (cleared) {
|
122
116
|
throw new Error(
|
123
|
-
|
124
|
-
|
117
|
+
'A permanent retain should only be cleared once. ' +
|
118
|
+
'This indicates a bug in react-disposable-state.',
|
125
119
|
);
|
126
120
|
}
|
127
121
|
cleared = true;
|
128
122
|
switch (this.__state.kind) {
|
129
|
-
case
|
123
|
+
case 'InParentCacheAndNotDisposed': {
|
130
124
|
this.__state.permanentRetainCount--;
|
131
125
|
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
132
126
|
return;
|
133
127
|
}
|
134
|
-
case
|
128
|
+
case 'NotInParentCacheAndNotDisposed': {
|
135
129
|
this.__state.permanentRetainCount--;
|
136
|
-
this.__maybeExitNotInParentCacheAndNotDisposedState(
|
137
|
-
this.__state
|
138
|
-
);
|
130
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
139
131
|
return;
|
140
132
|
}
|
141
133
|
default: {
|
142
134
|
throw new Error(
|
143
|
-
|
144
|
-
|
135
|
+
'CacheItem was in a disposed state, but there existed a permanent retain. ' +
|
136
|
+
'This indicates a bug in react-disposable-state.',
|
145
137
|
);
|
146
138
|
}
|
147
139
|
}
|
148
140
|
},
|
149
141
|
];
|
150
142
|
}
|
151
|
-
case
|
143
|
+
case 'NotInParentCacheAndNotDisposed': {
|
152
144
|
let cleared = false;
|
153
145
|
this.__state.permanentRetainCount++;
|
154
146
|
disposeOfTemporaryRetain();
|
@@ -157,23 +149,21 @@ export class CacheItem<T> {
|
|
157
149
|
() => {
|
158
150
|
if (cleared) {
|
159
151
|
throw new Error(
|
160
|
-
|
161
|
-
|
152
|
+
'A permanent retain should only be cleared once. ' +
|
153
|
+
'This indicates a bug in react-disposable-state.',
|
162
154
|
);
|
163
155
|
}
|
164
156
|
cleared = true;
|
165
157
|
switch (this.__state.kind) {
|
166
|
-
case
|
158
|
+
case 'NotInParentCacheAndNotDisposed': {
|
167
159
|
this.__state.permanentRetainCount--;
|
168
|
-
this.__maybeExitNotInParentCacheAndNotDisposedState(
|
169
|
-
this.__state
|
170
|
-
);
|
160
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
171
161
|
return;
|
172
162
|
}
|
173
163
|
default: {
|
174
164
|
throw new Error(
|
175
|
-
|
176
|
-
|
165
|
+
'CacheItem was in an unexpected state. ' +
|
166
|
+
'This indicates a bug in react-disposable-state.',
|
177
167
|
);
|
178
168
|
}
|
179
169
|
}
|
@@ -188,24 +178,21 @@ export class CacheItem<T> {
|
|
188
178
|
}
|
189
179
|
|
190
180
|
temporaryRetain(): CleanupFn {
|
191
|
-
type TemporaryRetainStatus =
|
192
|
-
| "Uncleared"
|
193
|
-
| "ClearedByCallback"
|
194
|
-
| "ClearedByTimeout";
|
181
|
+
type TemporaryRetainStatus = 'Uncleared' | 'ClearedByCallback' | 'ClearedByTimeout';
|
195
182
|
|
196
183
|
switch (this.__state.kind) {
|
197
|
-
case
|
198
|
-
let status: TemporaryRetainStatus =
|
184
|
+
case 'InParentCacheAndNotDisposed': {
|
185
|
+
let status: TemporaryRetainStatus = 'Uncleared';
|
199
186
|
this.__state.temporaryRetainCount++;
|
200
187
|
const clearTemporaryRetainByCallack: CleanupFn = () => {
|
201
|
-
if (status ===
|
188
|
+
if (status === 'ClearedByCallback') {
|
202
189
|
throw new Error(
|
203
|
-
|
204
|
-
|
190
|
+
'A temporary retain should only be cleared once. ' +
|
191
|
+
'This indicates a bug in react-disposable-state.',
|
205
192
|
);
|
206
|
-
} else if (status ===
|
193
|
+
} else if (status === 'Uncleared') {
|
207
194
|
switch (this.__state.kind) {
|
208
|
-
case
|
195
|
+
case 'InParentCacheAndNotDisposed': {
|
209
196
|
this.__state.temporaryRetainCount--;
|
210
197
|
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
211
198
|
clearTimeout(timeoutId);
|
@@ -213,8 +200,8 @@ export class CacheItem<T> {
|
|
213
200
|
}
|
214
201
|
default: {
|
215
202
|
throw new Error(
|
216
|
-
|
217
|
-
|
203
|
+
'A temporary retain was cleared, for which the CacheItem is in an invalid state. ' +
|
204
|
+
'This indicates a bug in react-disposable-state.',
|
218
205
|
);
|
219
206
|
}
|
220
207
|
}
|
@@ -222,17 +209,17 @@ export class CacheItem<T> {
|
|
222
209
|
};
|
223
210
|
|
224
211
|
const clearTemporaryRetainByTimeout = () => {
|
225
|
-
status =
|
212
|
+
status = 'ClearedByTimeout';
|
226
213
|
switch (this.__state.kind) {
|
227
|
-
case
|
214
|
+
case 'InParentCacheAndNotDisposed': {
|
228
215
|
this.__state.temporaryRetainCount--;
|
229
216
|
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
230
217
|
return;
|
231
218
|
}
|
232
219
|
default: {
|
233
220
|
throw new Error(
|
234
|
-
|
235
|
-
|
221
|
+
'A temporary retain was cleared, for which the CacheItem is in an invalid state. ' +
|
222
|
+
'This indicates a bug in react-disposable-state.',
|
236
223
|
);
|
237
224
|
}
|
238
225
|
}
|
@@ -240,14 +227,14 @@ export class CacheItem<T> {
|
|
240
227
|
|
241
228
|
const timeoutId = setTimeout(
|
242
229
|
clearTemporaryRetainByTimeout,
|
243
|
-
this.__options?.temporaryRetainTime ?? DEFAULT_TEMPORARY_RETAIN_TIME
|
230
|
+
this.__options?.temporaryRetainTime ?? DEFAULT_TEMPORARY_RETAIN_TIME,
|
244
231
|
);
|
245
232
|
return clearTemporaryRetainByCallack;
|
246
233
|
}
|
247
234
|
default: {
|
248
235
|
throw new Error(
|
249
|
-
|
250
|
-
|
236
|
+
'temporaryRetain was called, for which the CacheItem is in an invalid state. ' +
|
237
|
+
'This indicates a bug in react-disposable-state.',
|
251
238
|
);
|
252
239
|
}
|
253
240
|
}
|
@@ -255,58 +242,58 @@ export class CacheItem<T> {
|
|
255
242
|
|
256
243
|
permanentRetain(): CleanupFn {
|
257
244
|
switch (this.__state.kind) {
|
258
|
-
case
|
245
|
+
case 'InParentCacheAndNotDisposed': {
|
259
246
|
let cleared = false;
|
260
247
|
this.__state.permanentRetainCount++;
|
261
248
|
return () => {
|
262
249
|
if (cleared) {
|
263
250
|
throw new Error(
|
264
|
-
|
265
|
-
|
251
|
+
'A permanent retain should only be cleared once. ' +
|
252
|
+
'This indicates a bug in react-disposable-state.',
|
266
253
|
);
|
267
254
|
}
|
268
255
|
cleared = true;
|
269
256
|
switch (this.__state.kind) {
|
270
|
-
case
|
257
|
+
case 'InParentCacheAndNotDisposed': {
|
271
258
|
this.__state.permanentRetainCount--;
|
272
259
|
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
273
260
|
return;
|
274
261
|
}
|
275
|
-
case
|
262
|
+
case 'NotInParentCacheAndNotDisposed': {
|
276
263
|
this.__state.permanentRetainCount--;
|
277
264
|
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
278
265
|
return;
|
279
266
|
}
|
280
267
|
default: {
|
281
268
|
throw new Error(
|
282
|
-
|
283
|
-
|
269
|
+
'CacheItem was in a disposed state, but there existed a permanent retain. ' +
|
270
|
+
'This indicates a bug in react-disposable-state.',
|
284
271
|
);
|
285
272
|
}
|
286
273
|
}
|
287
274
|
};
|
288
275
|
}
|
289
|
-
case
|
276
|
+
case 'NotInParentCacheAndNotDisposed': {
|
290
277
|
let cleared = false;
|
291
278
|
this.__state.permanentRetainCount++;
|
292
279
|
return () => {
|
293
280
|
if (cleared) {
|
294
281
|
throw new Error(
|
295
|
-
|
296
|
-
|
282
|
+
'A permanent retain should only be cleared once. ' +
|
283
|
+
'This indicates a bug in react-disposable-state.',
|
297
284
|
);
|
298
285
|
}
|
299
286
|
cleared = true;
|
300
287
|
switch (this.__state.kind) {
|
301
|
-
case
|
288
|
+
case 'NotInParentCacheAndNotDisposed': {
|
302
289
|
this.__state.permanentRetainCount--;
|
303
290
|
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
304
291
|
return;
|
305
292
|
}
|
306
293
|
default: {
|
307
294
|
throw new Error(
|
308
|
-
|
309
|
-
|
295
|
+
'CacheItem was in an unexpected state. ' +
|
296
|
+
'This indicates a bug in react-disposable-state.',
|
310
297
|
);
|
311
298
|
}
|
312
299
|
}
|
@@ -314,26 +301,24 @@ export class CacheItem<T> {
|
|
314
301
|
}
|
315
302
|
default: {
|
316
303
|
throw new Error(
|
317
|
-
|
318
|
-
|
304
|
+
'permanentRetain was called, but the CacheItem is in an invalid state. ' +
|
305
|
+
'This indicates a bug in react-disposable-state.',
|
319
306
|
);
|
320
307
|
}
|
321
308
|
}
|
322
309
|
}
|
323
310
|
|
324
|
-
private __maybeExitInParentCacheAndNotDisposedState(
|
325
|
-
state: InParentCacheAndNotDisposed<T>
|
326
|
-
) {
|
311
|
+
private __maybeExitInParentCacheAndNotDisposedState(state: InParentCacheAndNotDisposed<T>) {
|
327
312
|
if (state.temporaryRetainCount === 0 && state.permanentRetainCount === 0) {
|
328
313
|
state.removeFromParentCache();
|
329
314
|
state.disposeValue();
|
330
315
|
this.__state = {
|
331
|
-
kind:
|
316
|
+
kind: 'NotInParentCacheAndDisposed',
|
332
317
|
};
|
333
318
|
} else if (state.temporaryRetainCount === 0) {
|
334
319
|
state.removeFromParentCache();
|
335
320
|
this.__state = {
|
336
|
-
kind:
|
321
|
+
kind: 'NotInParentCacheAndNotDisposed',
|
337
322
|
value: state.value,
|
338
323
|
disposeValue: state.disposeValue,
|
339
324
|
permanentRetainCount: state.permanentRetainCount,
|
@@ -341,13 +326,11 @@ export class CacheItem<T> {
|
|
341
326
|
}
|
342
327
|
}
|
343
328
|
|
344
|
-
private __maybeExitNotInParentCacheAndNotDisposedState(
|
345
|
-
state: NotInParentCacheAndNotDisposed<T>
|
346
|
-
) {
|
329
|
+
private __maybeExitNotInParentCacheAndNotDisposedState(state: NotInParentCacheAndNotDisposed<T>) {
|
347
330
|
if (state.permanentRetainCount === 0) {
|
348
331
|
state.disposeValue();
|
349
332
|
this.__state = {
|
350
|
-
kind:
|
333
|
+
kind: 'NotInParentCacheAndDisposed',
|
351
334
|
};
|
352
335
|
}
|
353
336
|
}
|
@@ -356,7 +339,7 @@ export class CacheItem<T> {
|
|
356
339
|
export function createTemporarilyRetainedCacheItem<T>(
|
357
340
|
factory: Factory<T>,
|
358
341
|
removeFromParentCache: CleanupFn,
|
359
|
-
options: CacheItemOptions | void
|
342
|
+
options: CacheItemOptions | void,
|
360
343
|
): [CacheItem<T>, CleanupFn] {
|
361
344
|
const cacheItem = new CacheItem(factory, removeFromParentCache, options);
|
362
345
|
const disposeTemporaryRetain = cacheItem.temporaryRetain();
|
package/src/ParentCache.test.ts
CHANGED
@@ -1,22 +1,21 @@
|
|
1
|
-
import { describe, assert, test, vi, expect } from
|
2
|
-
import { ParentCache } from
|
3
|
-
import { ItemCleanupPair } from
|
4
|
-
import { CacheItem } from
|
1
|
+
import { describe, assert, test, vi, expect } from 'vitest';
|
2
|
+
import { ParentCache } from './ParentCache';
|
3
|
+
import { ItemCleanupPair } from '@isograph/disposable-types';
|
4
|
+
import { CacheItem } from './CacheItem';
|
5
5
|
|
6
6
|
function getValue<T>(cache: ParentCache<T>): CacheItem<T> | null {
|
7
7
|
return (cache as any).__item as CacheItem<T> | null;
|
8
8
|
}
|
9
9
|
|
10
|
-
describe(
|
11
|
-
test(
|
10
|
+
describe('ParentCache', () => {
|
11
|
+
test('Populated, emptied, repopulated cache is not re-emptied by original temporary retain being disposed', () => {
|
12
12
|
const factory = vi.fn(() => {
|
13
13
|
const pair: ItemCleanupPair<number> = [1, vi.fn()];
|
14
14
|
return pair;
|
15
15
|
});
|
16
16
|
const parentCache = new ParentCache<number>(factory);
|
17
17
|
|
18
|
-
const [_cacheItem, value, clearTemporaryRetain] =
|
19
|
-
parentCache.getOrPopulateAndTemporaryRetain();
|
18
|
+
const [_cacheItem, value, clearTemporaryRetain] = parentCache.getOrPopulateAndTemporaryRetain();
|
20
19
|
|
21
20
|
expect(factory.mock.calls.length).toBe(1);
|
22
21
|
assert(value === 1);
|
@@ -35,7 +34,7 @@ describe("ParentCache", () => {
|
|
35
34
|
assert(getValue(parentCache) != null);
|
36
35
|
});
|
37
36
|
|
38
|
-
test(
|
37
|
+
test('Clearing the only temporary retain removes the item from the parent cache', () => {
|
39
38
|
const factory = vi.fn(() => {
|
40
39
|
const pair: ItemCleanupPair<number> = [1, vi.fn()];
|
41
40
|
return pair;
|
@@ -49,7 +48,7 @@ describe("ParentCache", () => {
|
|
49
48
|
assert(getValue(parentCache) === null);
|
50
49
|
});
|
51
50
|
|
52
|
-
test(
|
51
|
+
test('Clearing one of two temporary retains does not remove the item from the parent cache', () => {
|
53
52
|
const factory = vi.fn(() => {
|
54
53
|
const pair: ItemCleanupPair<number> = [1, vi.fn()];
|
55
54
|
return pair;
|
package/src/ParentCache.ts
CHANGED
@@ -1,9 +1,5 @@
|
|
1
|
-
import { CacheItem, createTemporarilyRetainedCacheItem } from
|
2
|
-
import {
|
3
|
-
CleanupFn,
|
4
|
-
Factory,
|
5
|
-
ItemCleanupPair,
|
6
|
-
} from "@isograph/disposable-types";
|
1
|
+
import { CacheItem, createTemporarilyRetainedCacheItem } from './CacheItem';
|
2
|
+
import { CleanupFn, Factory, ItemCleanupPair } from '@isograph/disposable-types';
|
7
3
|
|
8
4
|
// TODO convert cache impl to a getter and setter and free functions
|
9
5
|
// TODO accept options that get passed to CacheItem
|
@@ -55,8 +51,9 @@ export class ParentCache<T> {
|
|
55
51
|
}
|
56
52
|
|
57
53
|
private __populateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn] {
|
58
|
-
const pair: ItemCleanupPair<CacheItem<T>> =
|
59
|
-
|
54
|
+
const pair: ItemCleanupPair<CacheItem<T>> = createTemporarilyRetainedCacheItem(
|
55
|
+
this.__factory,
|
56
|
+
() => {
|
60
57
|
// We are doing this check because we don't want to remove the cache item
|
61
58
|
// if it is not the one that was created when the temporary retain was created.
|
62
59
|
//
|
@@ -73,7 +70,8 @@ export class ParentCache<T> {
|
|
73
70
|
if (this.__cacheItem === pair[0]) {
|
74
71
|
this.empty();
|
75
72
|
}
|
76
|
-
}
|
73
|
+
},
|
74
|
+
);
|
77
75
|
|
78
76
|
// We deconstruct this here instead of at the definition site because otherwise,
|
79
77
|
// typescript thinks that cacheItem is any, because it's referenced in the closure.
|
package/src/index.ts
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
export * from
|
1
|
+
export * from '@isograph/disposable-types';
|
2
2
|
|
3
|
-
export * from
|
4
|
-
export * from
|
5
|
-
export * from
|
6
|
-
export * from
|
7
|
-
export * from
|
8
|
-
export * from
|
9
|
-
export * from
|
3
|
+
export * from './CacheItem';
|
4
|
+
export * from './ParentCache';
|
5
|
+
export * from './useCachedPrecommitValue';
|
6
|
+
export * from './useDisposableState';
|
7
|
+
export * from './useHasCommittedRef';
|
8
|
+
export * from './useLazyDisposableState';
|
9
|
+
export * from './useUpdatableDisposableState';
|