@isograph/react-disposable-state 0.4.3 → 0.5.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/.turbo/turbo-compile-libs.log +10 -3
- package/dist/CacheItem.d.mts +63 -0
- package/dist/CacheItem.d.mts.map +1 -0
- package/dist/CacheItem.d.ts +33 -29
- package/dist/CacheItem.d.ts.map +1 -1
- package/dist/CacheItem.js +191 -266
- package/dist/CacheItem.mjs +193 -0
- package/dist/CacheItem.mjs.map +1 -0
- package/dist/ParentCache.d.mts +45 -0
- package/dist/ParentCache.d.mts.map +1 -0
- package/dist/ParentCache.d.ts +27 -22
- package/dist/ParentCache.d.ts.map +1 -1
- package/dist/ParentCache.js +69 -85
- package/dist/ParentCache.mjs +73 -0
- package/dist/ParentCache.mjs.map +1 -0
- package/dist/_virtual/rolldown_runtime.js +25 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.d.ts +9 -9
- package/dist/index.js +24 -24
- package/dist/index.mjs +11 -0
- package/dist/useCachedResponsivePrecommitValue.d.mts +43 -0
- package/dist/useCachedResponsivePrecommitValue.d.mts.map +1 -0
- package/dist/useCachedResponsivePrecommitValue.d.ts +9 -4
- package/dist/useCachedResponsivePrecommitValue.d.ts.map +1 -1
- package/dist/useCachedResponsivePrecommitValue.js +55 -90
- package/dist/useCachedResponsivePrecommitValue.mjs +57 -0
- package/dist/useCachedResponsivePrecommitValue.mjs.map +1 -0
- package/dist/useDisposableState.d.mts +13 -0
- package/dist/useDisposableState.d.mts.map +1 -0
- package/dist/useDisposableState.d.ts +10 -7
- package/dist/useDisposableState.d.ts.map +1 -1
- package/dist/useDisposableState.js +36 -69
- package/dist/useDisposableState.mjs +37 -0
- package/dist/useDisposableState.mjs.map +1 -0
- package/dist/useHasCommittedRef.d.mts +11 -0
- package/dist/useHasCommittedRef.d.mts.map +1 -0
- package/dist/useHasCommittedRef.d.ts +7 -2
- package/dist/useHasCommittedRef.d.ts.map +1 -1
- package/dist/useHasCommittedRef.js +15 -11
- package/dist/useHasCommittedRef.mjs +17 -0
- package/dist/useHasCommittedRef.mjs.map +1 -0
- package/dist/useLazyDisposableState.d.mts +20 -0
- package/dist/useLazyDisposableState.d.mts.map +1 -0
- package/dist/useLazyDisposableState.d.ts +9 -4
- package/dist/useLazyDisposableState.d.ts.map +1 -1
- package/dist/useLazyDisposableState.js +32 -39
- package/dist/useLazyDisposableState.mjs +34 -0
- package/dist/useLazyDisposableState.mjs.map +1 -0
- package/dist/useUpdatableDisposableState.d.mts +43 -0
- package/dist/useUpdatableDisposableState.d.mts.map +1 -0
- package/dist/useUpdatableDisposableState.d.ts +10 -7
- package/dist/useUpdatableDisposableState.d.ts.map +1 -1
- package/dist/useUpdatableDisposableState.js +73 -89
- package/dist/useUpdatableDisposableState.mjs +74 -0
- package/dist/useUpdatableDisposableState.mjs.map +1 -0
- package/package.json +24 -17
- package/src/CacheItem.test.ts +4 -7
- package/src/CacheItem.ts +16 -11
- package/src/ParentCache.test.ts +5 -5
- package/src/ParentCache.ts +5 -4
- package/src/useCachedResponsivePrecommitValue.test.tsx +15 -14
- package/src/useCachedResponsivePrecommitValue.ts +4 -4
- package/src/useDisposableState.ts +21 -16
- package/src/useHasCommittedRef.ts +1 -1
- package/src/useLazyDisposableState.test.tsx +2 -2
- package/src/useLazyDisposableState.ts +1 -1
- package/src/useUpdatableDisposableState.test.tsx +19 -5
- package/src/useUpdatableDisposableState.ts +1 -1
- package/dist/index.d.ts.map +0 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
//#region src/CacheItem.ts
|
|
2
|
+
const DEFAULT_TEMPORARY_RETAIN_TIME = 5e3;
|
|
3
|
+
/**
|
|
4
|
+
* CacheItem:
|
|
5
|
+
*
|
|
6
|
+
* Terminology:
|
|
7
|
+
* - TRC = Temporary Retain Count
|
|
8
|
+
* - PRC = Permanent Retain Count
|
|
9
|
+
*
|
|
10
|
+
* A CacheItem<T> can be in three states:
|
|
11
|
+
* In parent cache? | Item disposed? | TRC | PRC | Name
|
|
12
|
+
* -----------------+----------------+-----+-----+-------------------------------
|
|
13
|
+
* In parent cache | Not disposed | >0 | >=0 | InParentCacheAndNotDisposed
|
|
14
|
+
* Removed | Not disposed | 0 | >0 | NotInParentCacheAndNotDisposed
|
|
15
|
+
* Removed | Disposed | 0 | 0 | NotInParentCacheAndNotDisposed
|
|
16
|
+
*
|
|
17
|
+
* A cache item can only move down rows. As in, if its in the parent cache,
|
|
18
|
+
* it can be removed. It can never be replaced in the parent cache. (If a
|
|
19
|
+
* parent cache becomes full again, it will contain a new CacheItem.) The
|
|
20
|
+
* contained item can be disposed, but never un-disposed.
|
|
21
|
+
*
|
|
22
|
+
* So, the valid transitions are:
|
|
23
|
+
* - InParentCacheAndNotDisposed => NotInParentCacheAndNotDisposed
|
|
24
|
+
* - InParentCacheAndNotDisposed => NotInParentCacheAndDisposed
|
|
25
|
+
* - NotInParentCacheAndNotDisposed => NotInParentCacheAndDisposed
|
|
26
|
+
*/
|
|
27
|
+
var CacheItem = class {
|
|
28
|
+
constructor(factory, removeFromParentCache, options) {
|
|
29
|
+
this.__options = options ?? null;
|
|
30
|
+
const [value, disposeValue] = factory();
|
|
31
|
+
this.__state = {
|
|
32
|
+
kind: "InParentCacheAndNotDisposed",
|
|
33
|
+
value,
|
|
34
|
+
disposeValue,
|
|
35
|
+
removeFromParentCache,
|
|
36
|
+
temporaryRetainCount: 0,
|
|
37
|
+
permanentRetainCount: 0
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
getValue() {
|
|
41
|
+
switch (this.__state.kind) {
|
|
42
|
+
case "InParentCacheAndNotDisposed": return this.__state.value;
|
|
43
|
+
case "NotInParentCacheAndNotDisposed": return this.__state.value;
|
|
44
|
+
case "NotInParentCacheAndDisposed": throw new Error("Attempted to access disposed value from CacheItem. This indicates a bug in react-disposable-state.");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
permanentRetainIfNotDisposed(disposeOfTemporaryRetain) {
|
|
48
|
+
switch (this.__state.kind) {
|
|
49
|
+
case "InParentCacheAndNotDisposed": {
|
|
50
|
+
let cleared = false;
|
|
51
|
+
this.__state.permanentRetainCount++;
|
|
52
|
+
disposeOfTemporaryRetain();
|
|
53
|
+
return [this.__state.value, () => {
|
|
54
|
+
if (cleared) throw new Error("A permanent retain should only be cleared once. This indicates a bug in react-disposable-state.");
|
|
55
|
+
cleared = true;
|
|
56
|
+
switch (this.__state.kind) {
|
|
57
|
+
case "InParentCacheAndNotDisposed":
|
|
58
|
+
this.__state.permanentRetainCount--;
|
|
59
|
+
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
|
60
|
+
return;
|
|
61
|
+
case "NotInParentCacheAndNotDisposed":
|
|
62
|
+
this.__state.permanentRetainCount--;
|
|
63
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
|
64
|
+
return;
|
|
65
|
+
case "NotInParentCacheAndDisposed": throw new Error("CacheItem was in a disposed state, but there existed a permanent retain. This indicates a bug in react-disposable-state.");
|
|
66
|
+
}
|
|
67
|
+
}];
|
|
68
|
+
}
|
|
69
|
+
case "NotInParentCacheAndNotDisposed": {
|
|
70
|
+
let cleared = false;
|
|
71
|
+
this.__state.permanentRetainCount++;
|
|
72
|
+
disposeOfTemporaryRetain();
|
|
73
|
+
return [this.__state.value, () => {
|
|
74
|
+
if (cleared) throw new Error("A permanent retain should only be cleared once. This indicates a bug in react-disposable-state.");
|
|
75
|
+
cleared = true;
|
|
76
|
+
switch (this.__state.kind) {
|
|
77
|
+
case "NotInParentCacheAndNotDisposed":
|
|
78
|
+
this.__state.permanentRetainCount--;
|
|
79
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
|
80
|
+
return;
|
|
81
|
+
case "InParentCacheAndNotDisposed":
|
|
82
|
+
case "NotInParentCacheAndDisposed": throw new Error("CacheItem was in an unexpected state. This indicates a bug in react-disposable-state.");
|
|
83
|
+
}
|
|
84
|
+
}];
|
|
85
|
+
}
|
|
86
|
+
case "NotInParentCacheAndDisposed": return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
temporaryRetain() {
|
|
90
|
+
switch (this.__state.kind) {
|
|
91
|
+
case "InParentCacheAndNotDisposed": {
|
|
92
|
+
let status = "Uncleared";
|
|
93
|
+
this.__state.temporaryRetainCount++;
|
|
94
|
+
const clearTemporaryRetainByCallack = () => {
|
|
95
|
+
if (status === "ClearedByCallback") throw new Error("A temporary retain should only be cleared once. This indicates a bug in react-disposable-state.");
|
|
96
|
+
else if (status === "Uncleared") switch (this.__state.kind) {
|
|
97
|
+
case "InParentCacheAndNotDisposed":
|
|
98
|
+
this.__state.temporaryRetainCount--;
|
|
99
|
+
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
|
100
|
+
clearTimeout(timeoutId);
|
|
101
|
+
return;
|
|
102
|
+
case "NotInParentCacheAndDisposed":
|
|
103
|
+
case "NotInParentCacheAndNotDisposed": throw new Error("A temporary retain was cleared, for which the CacheItem is in an invalid state. This indicates a bug in react-disposable-state.");
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const clearTemporaryRetainByTimeout = () => {
|
|
107
|
+
status = "ClearedByTimeout";
|
|
108
|
+
switch (this.__state.kind) {
|
|
109
|
+
case "InParentCacheAndNotDisposed":
|
|
110
|
+
this.__state.temporaryRetainCount--;
|
|
111
|
+
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
|
112
|
+
return;
|
|
113
|
+
case "NotInParentCacheAndDisposed":
|
|
114
|
+
case "NotInParentCacheAndNotDisposed": throw new Error("A temporary retain was cleared, for which the CacheItem is in an invalid state. This indicates a bug in react-disposable-state.");
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const timeoutId = setTimeout(clearTemporaryRetainByTimeout, this.__options?.temporaryRetainTime ?? DEFAULT_TEMPORARY_RETAIN_TIME);
|
|
118
|
+
return clearTemporaryRetainByCallack;
|
|
119
|
+
}
|
|
120
|
+
case "NotInParentCacheAndDisposed":
|
|
121
|
+
case "NotInParentCacheAndNotDisposed": throw new Error("temporaryRetain was called, for which the CacheItem is in an invalid state. This indicates a bug in react-disposable-state.");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
permanentRetain() {
|
|
125
|
+
switch (this.__state.kind) {
|
|
126
|
+
case "InParentCacheAndNotDisposed": {
|
|
127
|
+
let cleared = false;
|
|
128
|
+
this.__state.permanentRetainCount++;
|
|
129
|
+
return () => {
|
|
130
|
+
if (cleared) throw new Error("A permanent retain should only be cleared once. This indicates a bug in react-disposable-state.");
|
|
131
|
+
cleared = true;
|
|
132
|
+
switch (this.__state.kind) {
|
|
133
|
+
case "InParentCacheAndNotDisposed":
|
|
134
|
+
this.__state.permanentRetainCount--;
|
|
135
|
+
this.__maybeExitInParentCacheAndNotDisposedState(this.__state);
|
|
136
|
+
return;
|
|
137
|
+
case "NotInParentCacheAndNotDisposed":
|
|
138
|
+
this.__state.permanentRetainCount--;
|
|
139
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
|
140
|
+
return;
|
|
141
|
+
case "NotInParentCacheAndDisposed": throw new Error("CacheItem was in a disposed state, but there existed a permanent retain. This indicates a bug in react-disposable-state.");
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
case "NotInParentCacheAndNotDisposed": {
|
|
146
|
+
let cleared = false;
|
|
147
|
+
this.__state.permanentRetainCount++;
|
|
148
|
+
return () => {
|
|
149
|
+
if (cleared) throw new Error("A permanent retain should only be cleared once. This indicates a bug in react-disposable-state.");
|
|
150
|
+
cleared = true;
|
|
151
|
+
switch (this.__state.kind) {
|
|
152
|
+
case "NotInParentCacheAndNotDisposed":
|
|
153
|
+
this.__state.permanentRetainCount--;
|
|
154
|
+
this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);
|
|
155
|
+
return;
|
|
156
|
+
case "InParentCacheAndNotDisposed":
|
|
157
|
+
case "NotInParentCacheAndDisposed": throw new Error("CacheItem was in an unexpected state. This indicates a bug in react-disposable-state.");
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
case "NotInParentCacheAndDisposed": throw new Error("permanentRetain was called, but the CacheItem is in an invalid state. This indicates a bug in react-disposable-state.");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
__maybeExitInParentCacheAndNotDisposedState(state) {
|
|
165
|
+
if (state.temporaryRetainCount === 0 && state.permanentRetainCount === 0) {
|
|
166
|
+
state.removeFromParentCache();
|
|
167
|
+
state.disposeValue();
|
|
168
|
+
this.__state = { kind: "NotInParentCacheAndDisposed" };
|
|
169
|
+
} else if (state.temporaryRetainCount === 0) {
|
|
170
|
+
state.removeFromParentCache();
|
|
171
|
+
this.__state = {
|
|
172
|
+
kind: "NotInParentCacheAndNotDisposed",
|
|
173
|
+
value: state.value,
|
|
174
|
+
disposeValue: state.disposeValue,
|
|
175
|
+
permanentRetainCount: state.permanentRetainCount
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
__maybeExitNotInParentCacheAndNotDisposedState(state) {
|
|
180
|
+
if (state.permanentRetainCount === 0) {
|
|
181
|
+
state.disposeValue();
|
|
182
|
+
this.__state = { kind: "NotInParentCacheAndDisposed" };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
function createTemporarilyRetainedCacheItem(factory, removeFromParentCache, options) {
|
|
187
|
+
const cacheItem = new CacheItem(factory, removeFromParentCache, options);
|
|
188
|
+
return [cacheItem, cacheItem.temporaryRetain()];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
export { CacheItem, createTemporarilyRetainedCacheItem };
|
|
193
|
+
//# sourceMappingURL=CacheItem.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheItem.mjs","names":["status: TemporaryRetainStatus","clearTemporaryRetainByCallack: CleanupFn"],"sources":["../src/CacheItem.ts"],"sourcesContent":["import type {\n CleanupFn,\n Factory,\n ItemCleanupPair,\n} from '@isograph/disposable-types';\n\nconst DEFAULT_TEMPORARY_RETAIN_TIME = 5000;\n\nexport type NotInParentCacheAndDisposed = {\n kind: 'NotInParentCacheAndDisposed';\n};\nexport type NotInParentCacheAndNotDisposed<T> = {\n kind: 'NotInParentCacheAndNotDisposed';\n value: T;\n disposeValue: () => void;\n\n // Invariant: >0\n permanentRetainCount: number;\n};\nexport type InParentCacheAndNotDisposed<T> = {\n kind: 'InParentCacheAndNotDisposed';\n value: T;\n disposeValue: () => void;\n removeFromParentCache: () => void;\n\n // Invariant: >0\n temporaryRetainCount: number;\n\n // Invariant: >= 0\n permanentRetainCount: number;\n};\n\nexport type CacheItemState<T> =\n | InParentCacheAndNotDisposed<T>\n | NotInParentCacheAndNotDisposed<T>\n | NotInParentCacheAndDisposed;\n\nexport type CacheItemOptions = {\n temporaryRetainTime: number;\n};\n\n// TODO don't export this class, only export type (interface) instead\n// TODO convert cacheitem impl to a getter and setter and free functions\n\n/**\n * CacheItem:\n *\n * Terminology:\n * - TRC = Temporary Retain Count\n * - PRC = Permanent Retain Count\n *\n * A CacheItem<T> can be in three states:\n * In parent cache? | Item disposed? | TRC | PRC | Name\n * -----------------+----------------+-----+-----+-------------------------------\n * In parent cache | Not disposed | >0 | >=0 | InParentCacheAndNotDisposed\n * Removed | Not disposed | 0 | >0 | NotInParentCacheAndNotDisposed\n * Removed | Disposed | 0 | 0 | NotInParentCacheAndNotDisposed\n *\n * A cache item can only move down rows. As in, if its in the parent cache,\n * it can be removed. It can never be replaced in the parent cache. (If a\n * parent cache becomes full again, it will contain a new CacheItem.) The\n * contained item can be disposed, but never un-disposed.\n *\n * So, the valid transitions are:\n * - InParentCacheAndNotDisposed => NotInParentCacheAndNotDisposed\n * - InParentCacheAndNotDisposed => NotInParentCacheAndDisposed\n * - NotInParentCacheAndNotDisposed => NotInParentCacheAndDisposed\n */\nexport class CacheItem<T> {\n private __state: CacheItemState<T>;\n private __options: CacheItemOptions | null;\n\n // Private. Do not call this constructor directly. Use\n // createTemporarilyRetainedCacheItem instead. This is because this\n // constructor creates a CacheItem in an invalid state. It must be\n // temporarily retained to enter a valid state, and JavaScript doesn't\n // let you return a tuple from a constructor.\n constructor(\n factory: Factory<T>,\n removeFromParentCache: CleanupFn,\n options: CacheItemOptions | void,\n ) {\n this.__options = options ?? null;\n const [value, disposeValue] = factory();\n this.__state = {\n kind: 'InParentCacheAndNotDisposed',\n value,\n disposeValue,\n removeFromParentCache,\n // NOTE: we are creating the CacheItem in an invalid state. This is okay, because\n // we are immediately calling .temporaryRetain.\n temporaryRetainCount: 0,\n permanentRetainCount: 0,\n };\n }\n\n getValue(): T {\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n return this.__state.value;\n }\n case 'NotInParentCacheAndNotDisposed': {\n return this.__state.value;\n }\n case 'NotInParentCacheAndDisposed': {\n throw new Error(\n 'Attempted to access disposed value from CacheItem. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n }\n\n permanentRetainIfNotDisposed(\n disposeOfTemporaryRetain: CleanupFn,\n ): ItemCleanupPair<T> | null {\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n let cleared = false;\n this.__state.permanentRetainCount++;\n disposeOfTemporaryRetain();\n return [\n this.__state.value,\n () => {\n if (cleared) {\n throw new Error(\n 'A permanent retain should only be cleared once. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n cleared = true;\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n this.__state.permanentRetainCount--;\n this.__maybeExitInParentCacheAndNotDisposedState(this.__state);\n return;\n }\n case 'NotInParentCacheAndNotDisposed': {\n this.__state.permanentRetainCount--;\n this.__maybeExitNotInParentCacheAndNotDisposedState(\n this.__state,\n );\n return;\n }\n case 'NotInParentCacheAndDisposed': {\n throw new Error(\n 'CacheItem was in a disposed state, but there existed a permanent retain. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n },\n ];\n }\n case 'NotInParentCacheAndNotDisposed': {\n let cleared = false;\n this.__state.permanentRetainCount++;\n disposeOfTemporaryRetain();\n return [\n this.__state.value,\n () => {\n if (cleared) {\n throw new Error(\n 'A permanent retain should only be cleared once. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n cleared = true;\n switch (this.__state.kind) {\n case 'NotInParentCacheAndNotDisposed': {\n this.__state.permanentRetainCount--;\n this.__maybeExitNotInParentCacheAndNotDisposedState(\n this.__state,\n );\n return;\n }\n case 'InParentCacheAndNotDisposed':\n case 'NotInParentCacheAndDisposed': {\n throw new Error(\n 'CacheItem was in an unexpected state. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n },\n ];\n }\n case 'NotInParentCacheAndDisposed': {\n // The CacheItem is disposed, so disposeOfTemporaryRetain is a no-op\n return null;\n }\n }\n }\n\n temporaryRetain(): CleanupFn {\n type TemporaryRetainStatus =\n | 'Uncleared'\n | 'ClearedByCallback'\n | 'ClearedByTimeout';\n\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n let status: TemporaryRetainStatus = 'Uncleared';\n this.__state.temporaryRetainCount++;\n const clearTemporaryRetainByCallack: CleanupFn = () => {\n if (status === 'ClearedByCallback') {\n throw new Error(\n 'A temporary retain should only be cleared once. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n } else if (status === 'Uncleared') {\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n this.__state.temporaryRetainCount--;\n this.__maybeExitInParentCacheAndNotDisposedState(this.__state);\n clearTimeout(timeoutId);\n return;\n }\n case 'NotInParentCacheAndDisposed':\n case 'NotInParentCacheAndNotDisposed': {\n throw new Error(\n 'A temporary retain was cleared, for which the CacheItem is in an invalid state. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n }\n };\n\n const clearTemporaryRetainByTimeout = () => {\n status = 'ClearedByTimeout';\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n this.__state.temporaryRetainCount--;\n this.__maybeExitInParentCacheAndNotDisposedState(this.__state);\n return;\n }\n case 'NotInParentCacheAndDisposed':\n case 'NotInParentCacheAndNotDisposed': {\n throw new Error(\n 'A temporary retain was cleared, for which the CacheItem is in an invalid state. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n };\n\n const timeoutId = setTimeout(\n clearTemporaryRetainByTimeout,\n this.__options?.temporaryRetainTime ?? DEFAULT_TEMPORARY_RETAIN_TIME,\n );\n return clearTemporaryRetainByCallack;\n }\n case 'NotInParentCacheAndDisposed':\n case 'NotInParentCacheAndNotDisposed': {\n throw new Error(\n 'temporaryRetain was called, for which the CacheItem is in an invalid state. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n }\n\n permanentRetain(): CleanupFn {\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n let cleared = false;\n this.__state.permanentRetainCount++;\n return () => {\n if (cleared) {\n throw new Error(\n 'A permanent retain should only be cleared once. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n cleared = true;\n switch (this.__state.kind) {\n case 'InParentCacheAndNotDisposed': {\n this.__state.permanentRetainCount--;\n this.__maybeExitInParentCacheAndNotDisposedState(this.__state);\n return;\n }\n case 'NotInParentCacheAndNotDisposed': {\n this.__state.permanentRetainCount--;\n this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);\n return;\n }\n case 'NotInParentCacheAndDisposed': {\n throw new Error(\n 'CacheItem was in a disposed state, but there existed a permanent retain. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n };\n }\n case 'NotInParentCacheAndNotDisposed': {\n let cleared = false;\n this.__state.permanentRetainCount++;\n return () => {\n if (cleared) {\n throw new Error(\n 'A permanent retain should only be cleared once. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n cleared = true;\n switch (this.__state.kind) {\n case 'NotInParentCacheAndNotDisposed': {\n this.__state.permanentRetainCount--;\n this.__maybeExitNotInParentCacheAndNotDisposedState(this.__state);\n return;\n }\n case 'InParentCacheAndNotDisposed':\n case 'NotInParentCacheAndDisposed': {\n throw new Error(\n 'CacheItem was in an unexpected state. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n };\n }\n case 'NotInParentCacheAndDisposed': {\n throw new Error(\n 'permanentRetain was called, but the CacheItem is in an invalid state. ' +\n 'This indicates a bug in react-disposable-state.',\n );\n }\n }\n }\n\n private __maybeExitInParentCacheAndNotDisposedState(\n state: InParentCacheAndNotDisposed<T>,\n ) {\n if (state.temporaryRetainCount === 0 && state.permanentRetainCount === 0) {\n state.removeFromParentCache();\n state.disposeValue();\n this.__state = {\n kind: 'NotInParentCacheAndDisposed',\n };\n } else if (state.temporaryRetainCount === 0) {\n state.removeFromParentCache();\n this.__state = {\n kind: 'NotInParentCacheAndNotDisposed',\n value: state.value,\n disposeValue: state.disposeValue,\n permanentRetainCount: state.permanentRetainCount,\n };\n }\n }\n\n private __maybeExitNotInParentCacheAndNotDisposedState(\n state: NotInParentCacheAndNotDisposed<T>,\n ) {\n if (state.permanentRetainCount === 0) {\n state.disposeValue();\n this.__state = {\n kind: 'NotInParentCacheAndDisposed',\n };\n }\n }\n}\n\nexport function createTemporarilyRetainedCacheItem<T>(\n factory: Factory<T>,\n removeFromParentCache: CleanupFn,\n options: CacheItemOptions | void,\n): [CacheItem<T>, CleanupFn] {\n const cacheItem = new CacheItem(factory, removeFromParentCache, options);\n const disposeTemporaryRetain = cacheItem.temporaryRetain();\n return [cacheItem, disposeTemporaryRetain];\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CacheItem } from "./CacheItem.mjs";
|
|
2
|
+
import { CleanupFn, Factory, ItemCleanupPair } from "@isograph/disposable-types";
|
|
3
|
+
|
|
4
|
+
//#region src/ParentCache.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ParentCache
|
|
8
|
+
* - A ParentCache can be in two states: populated and unpopulated.
|
|
9
|
+
* - A ParentCache holds a CacheItem, which can choose to remove itself from
|
|
10
|
+
* the parent ParentCache.
|
|
11
|
+
* - If the ParentCache is populated, the CacheItem (i.e. this.__value) must be
|
|
12
|
+
* in the InParentCacheAndNotDisposed state, i.e. not disposed, so after we
|
|
13
|
+
* null-check this.__value, this.__value.getValue(), this.__value.temporaryRetain()
|
|
14
|
+
* and this.__value.permanentRetain() are safe to be called.
|
|
15
|
+
*
|
|
16
|
+
* - Though we do not do so, it is always safe to call parentCache.delete().
|
|
17
|
+
*
|
|
18
|
+
* Invariant:
|
|
19
|
+
* - A parent cache at a given "location" (conceptually, an ID) should always
|
|
20
|
+
* be called
|
|
21
|
+
*/
|
|
22
|
+
declare class ParentCache<T> {
|
|
23
|
+
private __cacheItem;
|
|
24
|
+
private readonly __factory;
|
|
25
|
+
constructor(factory: Factory<T>);
|
|
26
|
+
/**
|
|
27
|
+
* This is called from useCachedResponsivePrecommitValue, when the parent cache is populated
|
|
28
|
+
* and a previous temporary retain has been disposed. This can occur in scenarios like:
|
|
29
|
+
* - temporary retain A is created by component B rendering
|
|
30
|
+
* - temporary retain A expires, emptying the parent cache
|
|
31
|
+
* - another component renders, sharing the same parent cache, filling
|
|
32
|
+
* by calling getOrPopulateAndTemporaryRetain
|
|
33
|
+
* - component B commits. We see that temporary retain A has been disposed,
|
|
34
|
+
* and re-check the parent cache by calling this method.
|
|
35
|
+
*/
|
|
36
|
+
getAndPermanentRetainIfPresent(): ItemCleanupPair<T> | null;
|
|
37
|
+
getOrPopulateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn];
|
|
38
|
+
private __populateAndTemporaryRetain;
|
|
39
|
+
empty(): void;
|
|
40
|
+
get factory(): Factory<T>;
|
|
41
|
+
isEmpty(): boolean;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { ParentCache };
|
|
45
|
+
//# sourceMappingURL=ParentCache.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParentCache.d.mts","names":[],"sources":["../src/ParentCache.ts"],"sourcesContent":[],"mappings":";;;;;;;AA2BA;;;;;;;;;;;;;;cAAa;;;uBAMU,QAAQ;;;;;;;;;;;oCAcK,gBAAgB;sCAMd,UAAU,IAAI,GAAG;;;iBAsCtC,QAAQ"}
|
package/dist/ParentCache.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { CacheItem } from "./CacheItem.js";
|
|
2
|
+
import { CleanupFn, Factory, ItemCleanupPair } from "@isograph/disposable-types";
|
|
3
|
+
|
|
4
|
+
//#region src/ParentCache.d.ts
|
|
5
|
+
|
|
3
6
|
/**
|
|
4
7
|
* ParentCache
|
|
5
8
|
* - A ParentCache can be in two states: populated and unpopulated.
|
|
@@ -16,25 +19,27 @@ import { CacheItem } from './CacheItem';
|
|
|
16
19
|
* - A parent cache at a given "location" (conceptually, an ID) should always
|
|
17
20
|
* be called
|
|
18
21
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
declare class ParentCache<T> {
|
|
23
|
+
private __cacheItem;
|
|
24
|
+
private readonly __factory;
|
|
25
|
+
constructor(factory: Factory<T>);
|
|
26
|
+
/**
|
|
27
|
+
* This is called from useCachedResponsivePrecommitValue, when the parent cache is populated
|
|
28
|
+
* and a previous temporary retain has been disposed. This can occur in scenarios like:
|
|
29
|
+
* - temporary retain A is created by component B rendering
|
|
30
|
+
* - temporary retain A expires, emptying the parent cache
|
|
31
|
+
* - another component renders, sharing the same parent cache, filling
|
|
32
|
+
* by calling getOrPopulateAndTemporaryRetain
|
|
33
|
+
* - component B commits. We see that temporary retain A has been disposed,
|
|
34
|
+
* and re-check the parent cache by calling this method.
|
|
35
|
+
*/
|
|
36
|
+
getAndPermanentRetainIfPresent(): ItemCleanupPair<T> | null;
|
|
37
|
+
getOrPopulateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn];
|
|
38
|
+
private __populateAndTemporaryRetain;
|
|
39
|
+
empty(): void;
|
|
40
|
+
get factory(): Factory<T>;
|
|
41
|
+
isEmpty(): boolean;
|
|
39
42
|
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { ParentCache };
|
|
40
45
|
//# sourceMappingURL=ParentCache.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParentCache.d.ts","
|
|
1
|
+
{"version":3,"file":"ParentCache.d.ts","names":[],"sources":["../src/ParentCache.ts"],"sourcesContent":[],"mappings":";;;;;;;AA2BA;;;;;;;;;;;;;;cAAa;;;uBAMU,QAAQ;;;;;;;;;;;oCAcK,gBAAgB;sCAMd,UAAU,IAAI,GAAG;;;iBAsCtC,QAAQ"}
|
package/dist/ParentCache.js
CHANGED
|
@@ -1,88 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const CacheItem_1 = require("./CacheItem");
|
|
5
|
-
// TODO convert cache impl to a getter and setter and free functions
|
|
6
|
-
// TODO accept options that get passed to CacheItem
|
|
1
|
+
const require_CacheItem = require('./CacheItem.js');
|
|
2
|
+
|
|
3
|
+
//#region src/ParentCache.ts
|
|
7
4
|
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.empty();
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
// We deconstruct this here instead of at the definition site because otherwise,
|
|
70
|
-
// typescript thinks that cacheItem is any, because it's referenced in the closure.
|
|
71
|
-
const [cacheItem, disposeTemporaryRetain] = pair;
|
|
72
|
-
this.__cacheItem = cacheItem;
|
|
73
|
-
return [cacheItem, cacheItem.getValue(), disposeTemporaryRetain];
|
|
74
|
-
}
|
|
75
|
-
empty() {
|
|
76
|
-
this.__cacheItem = null;
|
|
77
|
-
}
|
|
78
|
-
get factory() {
|
|
79
|
-
return this.__factory;
|
|
80
|
-
}
|
|
81
|
-
isEmpty() {
|
|
82
|
-
return this.__cacheItem === null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
exports.ParentCache = ParentCache;
|
|
5
|
+
* ParentCache
|
|
6
|
+
* - A ParentCache can be in two states: populated and unpopulated.
|
|
7
|
+
* - A ParentCache holds a CacheItem, which can choose to remove itself from
|
|
8
|
+
* the parent ParentCache.
|
|
9
|
+
* - If the ParentCache is populated, the CacheItem (i.e. this.__value) must be
|
|
10
|
+
* in the InParentCacheAndNotDisposed state, i.e. not disposed, so after we
|
|
11
|
+
* null-check this.__value, this.__value.getValue(), this.__value.temporaryRetain()
|
|
12
|
+
* and this.__value.permanentRetain() are safe to be called.
|
|
13
|
+
*
|
|
14
|
+
* - Though we do not do so, it is always safe to call parentCache.delete().
|
|
15
|
+
*
|
|
16
|
+
* Invariant:
|
|
17
|
+
* - A parent cache at a given "location" (conceptually, an ID) should always
|
|
18
|
+
* be called
|
|
19
|
+
*/
|
|
20
|
+
var ParentCache = class {
|
|
21
|
+
constructor(factory) {
|
|
22
|
+
this.__cacheItem = null;
|
|
23
|
+
this.__factory = factory;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* This is called from useCachedResponsivePrecommitValue, when the parent cache is populated
|
|
27
|
+
* and a previous temporary retain has been disposed. This can occur in scenarios like:
|
|
28
|
+
* - temporary retain A is created by component B rendering
|
|
29
|
+
* - temporary retain A expires, emptying the parent cache
|
|
30
|
+
* - another component renders, sharing the same parent cache, filling
|
|
31
|
+
* by calling getOrPopulateAndTemporaryRetain
|
|
32
|
+
* - component B commits. We see that temporary retain A has been disposed,
|
|
33
|
+
* and re-check the parent cache by calling this method.
|
|
34
|
+
*/
|
|
35
|
+
getAndPermanentRetainIfPresent() {
|
|
36
|
+
return this.__cacheItem != null ? [this.__cacheItem.getValue(), this.__cacheItem.permanentRetain()] : null;
|
|
37
|
+
}
|
|
38
|
+
getOrPopulateAndTemporaryRetain() {
|
|
39
|
+
return this.__cacheItem == null ? this.__populateAndTemporaryRetain() : temporaryRetain(this.__cacheItem);
|
|
40
|
+
}
|
|
41
|
+
__populateAndTemporaryRetain() {
|
|
42
|
+
const pair = require_CacheItem.createTemporarilyRetainedCacheItem(this.__factory, () => {
|
|
43
|
+
if (this.__cacheItem === pair[0]) this.empty();
|
|
44
|
+
});
|
|
45
|
+
const [cacheItem, disposeTemporaryRetain] = pair;
|
|
46
|
+
this.__cacheItem = cacheItem;
|
|
47
|
+
return [
|
|
48
|
+
cacheItem,
|
|
49
|
+
cacheItem.getValue(),
|
|
50
|
+
disposeTemporaryRetain
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
empty() {
|
|
54
|
+
this.__cacheItem = null;
|
|
55
|
+
}
|
|
56
|
+
get factory() {
|
|
57
|
+
return this.__factory;
|
|
58
|
+
}
|
|
59
|
+
isEmpty() {
|
|
60
|
+
return this.__cacheItem == null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
86
63
|
function temporaryRetain(value) {
|
|
87
|
-
|
|
64
|
+
return [
|
|
65
|
+
value,
|
|
66
|
+
value.getValue(),
|
|
67
|
+
value.temporaryRetain()
|
|
68
|
+
];
|
|
88
69
|
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
exports.ParentCache = ParentCache;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createTemporarilyRetainedCacheItem } from "./CacheItem.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/ParentCache.ts
|
|
4
|
+
/**
|
|
5
|
+
* ParentCache
|
|
6
|
+
* - A ParentCache can be in two states: populated and unpopulated.
|
|
7
|
+
* - A ParentCache holds a CacheItem, which can choose to remove itself from
|
|
8
|
+
* the parent ParentCache.
|
|
9
|
+
* - If the ParentCache is populated, the CacheItem (i.e. this.__value) must be
|
|
10
|
+
* in the InParentCacheAndNotDisposed state, i.e. not disposed, so after we
|
|
11
|
+
* null-check this.__value, this.__value.getValue(), this.__value.temporaryRetain()
|
|
12
|
+
* and this.__value.permanentRetain() are safe to be called.
|
|
13
|
+
*
|
|
14
|
+
* - Though we do not do so, it is always safe to call parentCache.delete().
|
|
15
|
+
*
|
|
16
|
+
* Invariant:
|
|
17
|
+
* - A parent cache at a given "location" (conceptually, an ID) should always
|
|
18
|
+
* be called
|
|
19
|
+
*/
|
|
20
|
+
var ParentCache = class {
|
|
21
|
+
constructor(factory) {
|
|
22
|
+
this.__cacheItem = null;
|
|
23
|
+
this.__factory = factory;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* This is called from useCachedResponsivePrecommitValue, when the parent cache is populated
|
|
27
|
+
* and a previous temporary retain has been disposed. This can occur in scenarios like:
|
|
28
|
+
* - temporary retain A is created by component B rendering
|
|
29
|
+
* - temporary retain A expires, emptying the parent cache
|
|
30
|
+
* - another component renders, sharing the same parent cache, filling
|
|
31
|
+
* by calling getOrPopulateAndTemporaryRetain
|
|
32
|
+
* - component B commits. We see that temporary retain A has been disposed,
|
|
33
|
+
* and re-check the parent cache by calling this method.
|
|
34
|
+
*/
|
|
35
|
+
getAndPermanentRetainIfPresent() {
|
|
36
|
+
return this.__cacheItem != null ? [this.__cacheItem.getValue(), this.__cacheItem.permanentRetain()] : null;
|
|
37
|
+
}
|
|
38
|
+
getOrPopulateAndTemporaryRetain() {
|
|
39
|
+
return this.__cacheItem == null ? this.__populateAndTemporaryRetain() : temporaryRetain(this.__cacheItem);
|
|
40
|
+
}
|
|
41
|
+
__populateAndTemporaryRetain() {
|
|
42
|
+
const pair = createTemporarilyRetainedCacheItem(this.__factory, () => {
|
|
43
|
+
if (this.__cacheItem === pair[0]) this.empty();
|
|
44
|
+
});
|
|
45
|
+
const [cacheItem, disposeTemporaryRetain] = pair;
|
|
46
|
+
this.__cacheItem = cacheItem;
|
|
47
|
+
return [
|
|
48
|
+
cacheItem,
|
|
49
|
+
cacheItem.getValue(),
|
|
50
|
+
disposeTemporaryRetain
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
empty() {
|
|
54
|
+
this.__cacheItem = null;
|
|
55
|
+
}
|
|
56
|
+
get factory() {
|
|
57
|
+
return this.__factory;
|
|
58
|
+
}
|
|
59
|
+
isEmpty() {
|
|
60
|
+
return this.__cacheItem == null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
function temporaryRetain(value) {
|
|
64
|
+
return [
|
|
65
|
+
value,
|
|
66
|
+
value.getValue(),
|
|
67
|
+
value.temporaryRetain()
|
|
68
|
+
];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { ParentCache };
|
|
73
|
+
//# sourceMappingURL=ParentCache.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParentCache.mjs","names":["pair: ItemCleanupPair<CacheItem<T>>"],"sources":["../src/ParentCache.ts"],"sourcesContent":["import type {\n CleanupFn,\n Factory,\n ItemCleanupPair,\n} from '@isograph/disposable-types';\nimport type { CacheItem } from './CacheItem';\nimport { createTemporarilyRetainedCacheItem } from './CacheItem';\n\n// TODO convert cache impl to a getter and setter and free functions\n// TODO accept options that get passed to CacheItem\n\n/**\n * ParentCache\n * - A ParentCache can be in two states: populated and unpopulated.\n * - A ParentCache holds a CacheItem, which can choose to remove itself from\n * the parent ParentCache.\n * - If the ParentCache is populated, the CacheItem (i.e. this.__value) must be\n * in the InParentCacheAndNotDisposed state, i.e. not disposed, so after we\n * null-check this.__value, this.__value.getValue(), this.__value.temporaryRetain()\n * and this.__value.permanentRetain() are safe to be called.\n *\n * - Though we do not do so, it is always safe to call parentCache.delete().\n *\n * Invariant:\n * - A parent cache at a given \"location\" (conceptually, an ID) should always\n * be called\n */\nexport class ParentCache<T> {\n private __cacheItem: CacheItem<T> | null = null;\n private readonly __factory: Factory<T>;\n\n // TODO pass an onEmpty function, which can e.g. remove this ParentCache\n // from some parent object.\n constructor(factory: Factory<T>) {\n this.__factory = factory;\n }\n\n /**\n * This is called from useCachedResponsivePrecommitValue, when the parent cache is populated\n * and a previous temporary retain has been disposed. This can occur in scenarios like:\n * - temporary retain A is created by component B rendering\n * - temporary retain A expires, emptying the parent cache\n * - another component renders, sharing the same parent cache, filling\n * by calling getOrPopulateAndTemporaryRetain\n * - component B commits. We see that temporary retain A has been disposed,\n * and re-check the parent cache by calling this method.\n */\n getAndPermanentRetainIfPresent(): ItemCleanupPair<T> | null {\n return this.__cacheItem != null\n ? [this.__cacheItem.getValue(), this.__cacheItem.permanentRetain()]\n : null;\n }\n\n getOrPopulateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn] {\n return this.__cacheItem == null\n ? this.__populateAndTemporaryRetain()\n : temporaryRetain(this.__cacheItem);\n }\n\n private __populateAndTemporaryRetain(): [CacheItem<T>, T, CleanupFn] {\n const pair: ItemCleanupPair<CacheItem<T>> =\n createTemporarilyRetainedCacheItem(this.__factory, () => {\n // We are doing this check because we don't want to remove the cache item\n // if it is not the one that was created when the temporary retain was created.\n //\n // Consider the following scenario:\n // - we populate the cache with CacheItem A,\n // - then manually delete CacheItem A (e.g. to force a refetch)\n // - then, we re-populate the parent cache with CacheItem B\n // - then, the temporary retain of CacheItem A is disposed or expires.\n //\n // At this point, we don't want to delete CacheItem B from the cache.\n //\n // TODO consider what happens if items are === comparable to each other,\n // e.g. the item is a number!\n if (this.__cacheItem === pair[0]) {\n this.empty();\n }\n });\n\n // We deconstruct this here instead of at the definition site because otherwise,\n // typescript thinks that cacheItem is any, because it's referenced in the closure.\n const [cacheItem, disposeTemporaryRetain] = pair;\n this.__cacheItem = cacheItem;\n return [cacheItem, cacheItem.getValue(), disposeTemporaryRetain];\n }\n\n empty() {\n this.__cacheItem = null;\n }\n\n get factory(): Factory<T> {\n return this.__factory;\n }\n\n isEmpty(): boolean {\n return this.__cacheItem == null;\n }\n}\n\nfunction temporaryRetain<T>(value: CacheItem<T>): [CacheItem<T>, T, CleanupFn] {\n return [value, value.getValue(), value.temporaryRetain()];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA2BA,IAAa,cAAb,MAA4B;CAM1B,YAAY,SAAqB;qBALU;AAMzC,OAAK,YAAY;;;;;;;;;;;;CAanB,iCAA4D;AAC1D,SAAO,KAAK,eAAe,OACvB,CAAC,KAAK,YAAY,UAAU,EAAE,KAAK,YAAY,iBAAiB,CAAC,GACjE;;CAGN,kCAAgE;AAC9D,SAAO,KAAK,eAAe,OACvB,KAAK,8BAA8B,GACnC,gBAAgB,KAAK,YAAY;;CAGvC,AAAQ,+BAA6D;EACnE,MAAMA,OACJ,mCAAmC,KAAK,iBAAiB;AAcvD,OAAI,KAAK,gBAAgB,KAAK,GAC5B,MAAK,OAAO;IAEd;EAIJ,MAAM,CAAC,WAAW,0BAA0B;AAC5C,OAAK,cAAc;AACnB,SAAO;GAAC;GAAW,UAAU,UAAU;GAAE;GAAuB;;CAGlE,QAAQ;AACN,OAAK,cAAc;;CAGrB,IAAI,UAAsB;AACxB,SAAO,KAAK;;CAGd,UAAmB;AACjB,SAAO,KAAK,eAAe;;;AAI/B,SAAS,gBAAmB,OAAmD;AAC7E,QAAO;EAAC;EAAO,MAAM,UAAU;EAAE,MAAM,iBAAiB;EAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
|
|
25
|
+
exports.__toESM = __toESM;
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CacheItem, CacheItemOptions, CacheItemState, InParentCacheAndNotDisposed, NotInParentCacheAndDisposed, NotInParentCacheAndNotDisposed, createTemporarilyRetainedCacheItem } from "./CacheItem.mjs";
|
|
2
|
+
import { ParentCache } from "./ParentCache.mjs";
|
|
3
|
+
import { useCachedResponsivePrecommitValue } from "./useCachedResponsivePrecommitValue.mjs";
|
|
4
|
+
import { UNASSIGNED_STATE, UnassignedState, useUpdatableDisposableState } from "./useUpdatableDisposableState.mjs";
|
|
5
|
+
import { useDisposableState } from "./useDisposableState.mjs";
|
|
6
|
+
import { useHasCommittedRef } from "./useHasCommittedRef.mjs";
|
|
7
|
+
import { useLazyDisposableState } from "./useLazyDisposableState.mjs";
|
|
8
|
+
export * from "@isograph/disposable-types";
|
|
9
|
+
export { CacheItem, CacheItemOptions, CacheItemState, InParentCacheAndNotDisposed, NotInParentCacheAndDisposed, NotInParentCacheAndNotDisposed, ParentCache, UNASSIGNED_STATE, UnassignedState, createTemporarilyRetainedCacheItem, useCachedResponsivePrecommitValue, useDisposableState, useHasCommittedRef, useLazyDisposableState, useUpdatableDisposableState };
|