@isograph/react-disposable-state 0.0.0-main-9a9a4679 → 0.0.0-main-c8dd6185

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.
@@ -21,21 +21,25 @@ export type CacheItemOptions = {
21
21
  temporaryRetainTime: number;
22
22
  };
23
23
  /**
24
+ * CacheItem:
25
+ *
26
+ * Terminology:
24
27
  * - TRC = Temporary Retain Count
25
28
  * - PRC = Permanent Retain Count
26
29
  *
27
- * Rules:
28
- * - In parent cache <=> TRC > 0
29
- * - Removed from parent cache <=> TRC === 0
30
- * - In parent cache => not disposed
31
- * - Disposed => removed from parent cache + PRC === 0
32
- *
33
30
  * A CacheItem<T> can be in three states:
34
- * - Removed from the parent cache, item disposed, TRC === 0, PRC === 0
35
- * - Removed from the parent cache, item not disposed, PRC > 0, TRC === 0
36
- * - In parent cache, item not disposed, TRC > 0, PRC >= 0
31
+ * In parent cache? | Item disposed? | TRC | PRC | Name
32
+ * -----------------+----------------+-----+-----+-------------------------------
33
+ * In parent cache | Not disposed | >0 | >=0 | InParentCacheAndNotDisposed
34
+ * Removed | Not disposed | 0 | >0 | NotInParentCacheAndNotDisposed
35
+ * Removed | Disposed | 0 | 0 | NotInParentCacheAndNotDisposed
36
+ *
37
+ * A cache item can only move down rows. As in, if its in the parent cache,
38
+ * it can be removed. It can never be replaced in the parent cache. (If a
39
+ * parent cache becomes full again, it will contain a new CacheItem.) The
40
+ * contained item can be disposed, but never un-disposed.
37
41
  *
38
- * Valid transitions are:
42
+ * So, the valid transitions are:
39
43
  * - InParentCacheAndNotDisposed => NotInParentCacheAndNotDisposed
40
44
  * - InParentCacheAndNotDisposed => NotInParentCacheAndDisposed
41
45
  * - NotInParentCacheAndNotDisposed => NotInParentCacheAndDisposed
package/dist/CacheItem.js CHANGED
@@ -5,21 +5,25 @@ const DEFAULT_TEMPORARY_RETAIN_TIME = 5000;
5
5
  // TODO don't export this class, only export type (interface) instead
6
6
  // TODO convert cacheitem impl to a getter and setter and free functions
7
7
  /**
8
+ * CacheItem:
9
+ *
10
+ * Terminology:
8
11
  * - TRC = Temporary Retain Count
9
12
  * - PRC = Permanent Retain Count
10
13
  *
11
- * Rules:
12
- * - In parent cache <=> TRC > 0
13
- * - Removed from parent cache <=> TRC === 0
14
- * - In parent cache => not disposed
15
- * - Disposed => removed from parent cache + PRC === 0
16
- *
17
14
  * A CacheItem<T> can be in three states:
18
- * - Removed from the parent cache, item disposed, TRC === 0, PRC === 0
19
- * - Removed from the parent cache, item not disposed, PRC > 0, TRC === 0
20
- * - In parent cache, item not disposed, TRC > 0, PRC >= 0
15
+ * In parent cache? | Item disposed? | TRC | PRC | Name
16
+ * -----------------+----------------+-----+-----+-------------------------------
17
+ * In parent cache | Not disposed | >0 | >=0 | InParentCacheAndNotDisposed
18
+ * Removed | Not disposed | 0 | >0 | NotInParentCacheAndNotDisposed
19
+ * Removed | Disposed | 0 | 0 | NotInParentCacheAndNotDisposed
20
+ *
21
+ * A cache item can only move down rows. As in, if its in the parent cache,
22
+ * it can be removed. It can never be replaced in the parent cache. (If a
23
+ * parent cache becomes full again, it will contain a new CacheItem.) The
24
+ * contained item can be disposed, but never un-disposed.
21
25
  *
22
- * Valid transitions are:
26
+ * So, the valid transitions are:
23
27
  * - InParentCacheAndNotDisposed => NotInParentCacheAndNotDisposed
24
28
  * - InParentCacheAndNotDisposed => NotInParentCacheAndDisposed
25
29
  * - NotInParentCacheAndNotDisposed => NotInParentCacheAndDisposed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@isograph/react-disposable-state",
3
- "version": "0.0.0-main-9a9a4679",
3
+ "version": "0.0.0-main-c8dd6185",
4
4
  "description": "Primitives for managing disposable state in React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,7 +16,7 @@
16
16
  "prepack": "yarn run compile"
17
17
  },
18
18
  "dependencies": {
19
- "@isograph/disposable-types": "0.0.0-main-9a9a4679",
19
+ "@isograph/disposable-types": "0.0.0-main-c8dd6185",
20
20
  "react": "^18.2.0"
21
21
  },
22
22
  "devDependencies": {
package/src/CacheItem.ts CHANGED
@@ -43,21 +43,25 @@ export type CacheItemOptions = {
43
43
  // TODO convert cacheitem impl to a getter and setter and free functions
44
44
 
45
45
  /**
46
+ * CacheItem:
47
+ *
48
+ * Terminology:
46
49
  * - TRC = Temporary Retain Count
47
50
  * - PRC = Permanent Retain Count
48
51
  *
49
- * Rules:
50
- * - In parent cache <=> TRC > 0
51
- * - Removed from parent cache <=> TRC === 0
52
- * - In parent cache => not disposed
53
- * - Disposed => removed from parent cache + PRC === 0
54
- *
55
52
  * A CacheItem<T> can be in three states:
56
- * - Removed from the parent cache, item disposed, TRC === 0, PRC === 0
57
- * - Removed from the parent cache, item not disposed, PRC > 0, TRC === 0
58
- * - In parent cache, item not disposed, TRC > 0, PRC >= 0
53
+ * In parent cache? | Item disposed? | TRC | PRC | Name
54
+ * -----------------+----------------+-----+-----+-------------------------------
55
+ * In parent cache | Not disposed | >0 | >=0 | InParentCacheAndNotDisposed
56
+ * Removed | Not disposed | 0 | >0 | NotInParentCacheAndNotDisposed
57
+ * Removed | Disposed | 0 | 0 | NotInParentCacheAndNotDisposed
58
+ *
59
+ * A cache item can only move down rows. As in, if its in the parent cache,
60
+ * it can be removed. It can never be replaced in the parent cache. (If a
61
+ * parent cache becomes full again, it will contain a new CacheItem.) The
62
+ * contained item can be disposed, but never un-disposed.
59
63
  *
60
- * Valid transitions are:
64
+ * So, the valid transitions are:
61
65
  * - InParentCacheAndNotDisposed => NotInParentCacheAndNotDisposed
62
66
  * - InParentCacheAndNotDisposed => NotInParentCacheAndDisposed
63
67
  * - NotInParentCacheAndNotDisposed => NotInParentCacheAndDisposed
@@ -4,36 +4,40 @@ import { ItemCleanupPair } from '@isograph/disposable-types';
4
4
  import { CacheItem } from './CacheItem';
5
5
 
6
6
  function getValue<T>(cache: ParentCache<T>): CacheItem<T> | null {
7
- return (cache as any).__item as CacheItem<T> | null;
7
+ return (cache as any).__cacheItem as CacheItem<T> | null;
8
8
  }
9
9
 
10
10
  describe('ParentCache', () => {
11
- test('Populated, emptied, repopulated cache is not re-emptied by original temporary retain being disposed', () => {
12
- const factory = vi.fn(() => {
13
- const pair: ItemCleanupPair<number> = [1, vi.fn()];
14
- return pair;
15
- });
16
- const parentCache = new ParentCache<number>(factory);
11
+ test(
12
+ 'Populated, emptied, repopulated cache is not ' +
13
+ 're-emptied by original temporary retain being disposed',
14
+ () => {
15
+ const factory = vi.fn(() => {
16
+ const pair: ItemCleanupPair<number> = [1, vi.fn()];
17
+ return pair;
18
+ });
19
+ const parentCache = new ParentCache<number>(factory);
20
+
21
+ const [_cacheItem, value, clearTemporaryRetain] =
22
+ parentCache.getOrPopulateAndTemporaryRetain();
23
+
24
+ expect(factory.mock.calls.length).toBe(1);
25
+ assert(value === 1);
26
+ assert(getValue(parentCache) != null, 'Parent cache should not be empty');
27
+
28
+ parentCache.empty();
29
+ assert(getValue(parentCache) === null);
17
30
 
18
- const [_cacheItem, value, clearTemporaryRetain] =
19
31
  parentCache.getOrPopulateAndTemporaryRetain();
32
+ expect(factory.mock.calls.length).toBe(2);
20
33
 
21
- expect(factory.mock.calls.length).toBe(1);
22
- assert(value === 1);
23
- assert(getValue(parentCache) != null);
24
-
25
- parentCache.empty();
26
- assert(getValue(parentCache) === null);
27
-
28
- parentCache.getOrPopulateAndTemporaryRetain();
29
- expect(factory.mock.calls.length).toBe(2);
34
+ assert(getValue(parentCache) != null);
30
35
 
31
- assert(getValue(parentCache) != null);
36
+ clearTemporaryRetain();
32
37
 
33
- clearTemporaryRetain();
34
-
35
- assert(getValue(parentCache) != null);
36
- });
38
+ assert(getValue(parentCache) != null);
39
+ },
40
+ );
37
41
 
38
42
  test('Clearing the only temporary retain removes the item from the parent cache', () => {
39
43
  const factory = vi.fn(() => {
@@ -7,7 +7,7 @@ import { create } from 'react-test-renderer';
7
7
  import { CacheItem, CacheItemState } from './CacheItem';
8
8
 
9
9
  function getItem<T>(cache: ParentCache<T>): CacheItem<T> | null {
10
- return (cache as any).__item;
10
+ return (cache as any).__cacheItem;
11
11
  }
12
12
 
13
13
  function getState<T>(cacheItem: CacheItem<T>): CacheItemState<T> {
@@ -512,9 +512,8 @@ describe('useCachedPrecommitValue', () => {
512
512
  );
513
513
 
514
514
  test(
515
- 'If the component unmounts before committing, ' +
516
- 'the item will remain in the parent cache, ' +
517
- 'temporarily retained',
515
+ 'After render but before commit, the item will ' +
516
+ 'be in the parent cache, temporarily retained',
518
517
  async () => {
519
518
  const disposeItem = vi.fn();
520
519
  const factory = vi.fn(() => {
@@ -541,35 +540,20 @@ describe('useCachedPrecommitValue', () => {
541
540
  // wat is going on?
542
541
  //
543
542
  // We want to test a scenario where the component unmounts before committing.
543
+ // However, we cannot distinguish between an unmount before commit and a
544
+ // render and a commit that hasn't happened yet.
544
545
  //
545
- // The subcomponents are rendered in order: TestComponent followed by CodeExecutor.
546
- // So, during CodeExecutor, we trigger a state update that causes the ParentComponent
547
- // to not render the children.
548
- function CodeExecutor() {
549
- setShowChildren(false);
550
- return null;
551
- }
552
-
553
- let setShowChildren;
554
- function ParentComponent({ children }) {
555
- const [showChildren, _setShowChildren] = React.useState(true);
556
- setShowChildren = _setShowChildren;
557
-
558
- if (showChildren) {
559
- return children;
560
- } else {
561
- return null;
562
- }
563
- }
546
+ // This can be simulated with suspense.
547
+ //
548
+ // This test and 'on initial render, it should call getOrPopulateAndTemporaryRetain'
549
+ // can be merged
564
550
 
551
+ const { promise, isResolvedRef } = promiseAndResolver();
565
552
  const element = await awaitableCreate(
566
- <ParentComponent>
553
+ <React.Suspense fallback={null}>
567
554
  <TestComponent />
568
- <CodeExecutor />
569
- </ParentComponent>,
570
- // If we're not in concurrent mode, TestComponent will mount before
571
- // unmounting. This perhaps is a bug in react-test-renderer. Regardless,
572
- // we're not interested in that scenario.
555
+ <Suspender promise={promise} isResolvedRef={isResolvedRef} />
556
+ </React.Suspense>,
573
557
  true,
574
558
  );
575
559