Skip to content

Commit f3bb56d

Browse files
committed
Migrate folder node map from writable stores to runes
1 parent dffb8c6 commit f3bb56d

13 files changed

+179
-291
lines changed

src/treetop/BookmarksManager.test.ts

Lines changed: 98 additions & 182 deletions
Large diffs are not rendered by default.

src/treetop/BookmarksManager.ts

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { get, writable } from 'svelte/store';
2-
31
import { isBookmark, isFolder } from './bookmarktreenode-utils';
42
import { MOBILE_BOOKMARKS_GUID } from './constants';
53
import * as Treetop from './types';
64

75
/**
8-
* Class to initialize and manage updating bookmark node stores.
6+
* Class to initialize and manage updating bookmark nodes.
97
*/
108
export class BookmarksManager {
119
constructor(
@@ -14,7 +12,7 @@ export class BookmarksManager {
1412
) {}
1513

1614
/**
17-
* Load all bookmarks and initialize node stores for folders.
15+
* Load all bookmarks and initialize nodes for folders.
1816
* Initialize built-in folder info.
1917
*/
2018
async loadBookmarks(): Promise<void> {
@@ -34,7 +32,7 @@ export class BookmarksManager {
3432
({ id }) => id,
3533
);
3634

37-
// Initialize node stores for folders
35+
// Initialize nodes for folders
3836
while (nodes.length > 0) {
3937
const node = nodes.pop()!;
4038

@@ -88,16 +86,15 @@ export class BookmarksManager {
8886
}
8987

9088
/**
91-
* Create and record a node store for the specified bookmark node.
89+
* Create and record a node for the specified bookmark node.
9290
*/
9391
private buildFolderNode(node: chrome.bookmarks.BookmarkTreeNode): void {
94-
const newNode = this.convertNode(node);
95-
const folderNode = writable(newNode);
92+
const folderNode = this.convertNode(node);
9693
this.folderNodeMap.set(node.id, folderNode);
9794
}
9895

9996
/**
100-
* Update the node store for the specified bookmark ID.
97+
* Update the node for the specified bookmark ID.
10198
*/
10299
private async updateFolderNode(nodeId: string): Promise<void> {
103100
const [node] = await chrome.bookmarks.get(nodeId);
@@ -108,20 +105,19 @@ export class BookmarksManager {
108105

109106
node.children = await chrome.bookmarks.getChildren(node.id);
110107

111-
const newNode = this.convertNode(node);
112-
const folderNode = this.folderNodeMap.get(nodeId)!;
113-
folderNode.set(newNode);
108+
const folderNode = this.convertNode(node);
109+
this.folderNodeMap.set(nodeId, folderNode);
114110
}
115111

116112
/**
117-
* Create a store for a newly created bookmark node.
113+
* Create a node for a newly created bookmark node.
118114
*/
119115
async handleBookmarkCreated(
120116
id: string,
121117
bookmark: chrome.bookmarks.BookmarkTreeNode,
122118
): Promise<void> {
123119
if (isFolder(bookmark)) {
124-
// Add node store for the new folder
120+
// Add node for the new folder
125121
const [node] = await chrome.bookmarks.get(id);
126122
node.children = await chrome.bookmarks.getChildren(id);
127123
this.buildFolderNode(node);
@@ -132,8 +128,8 @@ export class BookmarksManager {
132128
}
133129

134130
/**
135-
* Delete stores for removed bookmarks. When the removed bookmark is a folder,
136-
* recursively delete stores for its children.
131+
* Delete nodes for removed bookmarks. When the removed bookmark is a folder,
132+
* recursively delete nodes for its children.
137133
*
138134
* @return Array of the removed bookmark node IDs.
139135
*/
@@ -145,9 +141,8 @@ export class BookmarksManager {
145141

146142
if (isFolder(removeInfo.node)) {
147143
const folderNode = this.folderNodeMap.get(id)!;
148-
const nodes: [Treetop.FolderNode] = [get(folderNode)];
144+
const nodes = [folderNode];
149145

150-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
151146
while (nodes.length) {
152147
const node = nodes.pop()!;
153148
this.folderNodeMap.delete(node.id);
@@ -162,9 +157,8 @@ export class BookmarksManager {
162157

163158
// Enqueue child folders for removal
164159
for (const childFolderNode of this.folderNodeMap.values()) {
165-
const currentNode: Treetop.FolderNode = get(childFolderNode);
166-
if (currentNode.parentId === node.id) {
167-
nodes.push(currentNode);
160+
if (childFolderNode.parentId === node.id) {
161+
nodes.push(childFolderNode);
168162
}
169163
}
170164
}
@@ -179,7 +173,7 @@ export class BookmarksManager {
179173
}
180174

181175
/**
182-
* Update the store for a modified bookmark.
176+
* Update the node for a modified bookmark.
183177
*/
184178
async handleBookmarkChanged(
185179
id: string,
@@ -196,7 +190,7 @@ export class BookmarksManager {
196190
}
197191

198192
/**
199-
* Update stores when a bookmark is moved to a different folder or to a new
193+
* Update nodes when a bookmark is moved to a different folder or to a new
200194
* offset within its folder.
201195
*/
202196
async handleBookmarkMoved(

src/treetop/FilterManager.test.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/* eslint no-irregular-whitespace: ["error", { "skipComments": true }] */
22

3-
import { SvelteSet } from 'svelte/reactivity';
4-
import { writable } from 'svelte/store';
3+
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
54
import { faker } from '@faker-js/faker';
65
import { beforeEach, describe, expect, it } from 'vitest';
76

@@ -36,7 +35,7 @@ let folderNode5: Treetop.FolderNode;
3635
let folderNode6: Treetop.FolderNode;
3736

3837
beforeEach(() => {
39-
folderNodeMap = new Map() as Treetop.FolderNodeMap;
38+
folderNodeMap = new SvelteMap();
4039
filterSet = new SvelteSet();
4140
filterManager = new FilterManager(filterSet, folderNodeMap);
4241

@@ -114,12 +113,12 @@ beforeEach(() => {
114113
});
115114
folderNode5.children.push(folderNode6);
116115

117-
folderNodeMap.set(folderNode1.id, writable(folderNode1));
118-
folderNodeMap.set(folderNode2.id, writable(folderNode2));
119-
folderNodeMap.set(folderNode3.id, writable(folderNode3));
120-
folderNodeMap.set(folderNode4.id, writable(folderNode4));
121-
folderNodeMap.set(folderNode5.id, writable(folderNode5));
122-
folderNodeMap.set(folderNode6.id, writable(folderNode6));
116+
folderNodeMap.set(folderNode1.id, folderNode1);
117+
folderNodeMap.set(folderNode2.id, folderNode2);
118+
folderNodeMap.set(folderNode3.id, folderNode3);
119+
folderNodeMap.set(folderNode4.id, folderNode4);
120+
folderNodeMap.set(folderNode5.id, folderNode5);
121+
folderNodeMap.set(folderNode6.id, folderNode6);
123122
});
124123

125124
describe('setFilter', () => {

src/treetop/FilterManager.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { get } from 'svelte/store';
2-
31
import { isBookmark } from './bookmarktreenode-utils';
42
import * as Treetop from './types';
53

@@ -32,8 +30,7 @@ export class FilterManager {
3230
for (const folderNode of this.folderNodeMap.values()) {
3331
let addedChild = false;
3432

35-
const node: Treetop.FolderNode = get(folderNode);
36-
for (const child of node.children) {
33+
for (const child of folderNode.children) {
3734
if (child.type === Treetop.NodeType.Bookmark) {
3835
if (
3936
this.matchesFilter(child.title) ||
@@ -46,19 +43,18 @@ export class FilterManager {
4643
}
4744

4845
if (addedChild) {
49-
this.filterSet.add(node.id);
46+
this.filterSet.add(folderNode.id);
5047
}
5148
}
5249

5350
// Pass 2
5451
// For each folder in the FilterSet, add the folders on the path to the root
5552
// folder.
5653
for (const folderNode of this.folderNodeMap.values()) {
57-
const node: Treetop.FolderNode = get(folderNode);
58-
if (this.filterSet.has(node.id)) {
59-
let curNode = node;
54+
if (this.filterSet.has(folderNode.id)) {
55+
let curNode = folderNode;
6056
while (curNode.parentId) {
61-
curNode = get(this.folderNodeMap.get(curNode.parentId)!);
57+
curNode = this.folderNodeMap.get(curNode.parentId)!;
6258
this.filterSet.add(curNode.id);
6359
}
6460
}
@@ -102,9 +98,9 @@ export class FilterManager {
10298
// Add the folders on the path to the root folder to the FilterSet
10399
let parentId = bookmark.parentId;
104100
while (parentId) {
105-
const node = get(this.folderNodeMap.get(parentId)!);
106-
this.filterSet.add(node.id);
107-
parentId = node.parentId;
101+
const folderNode = this.folderNodeMap.get(parentId)!;
102+
this.filterSet.add(folderNode.id);
103+
parentId = folderNode.parentId;
108104
}
109105
}
110106

src/treetop/Folder.svelte

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<script lang="ts">
22
import { getContext } from 'svelte';
3-
import { get, type Writable } from 'svelte/store';
43
54
import Bookmark from './Bookmark.svelte';
65
import Folder from './Folder.svelte';
@@ -19,12 +18,12 @@
1918
const filterActive = getContext<() => boolean>('filterActive');
2019
const filterSet = getContext<Treetop.FilterSet>('filterSet');
2120
22-
let node: Writable<Treetop.FolderNode> = folderNodeMap.get(nodeId)!;
21+
const node = $derived(folderNodeMap.get(nodeId)!);
2322
2423
// Nodes for the folder heading.
2524
// For the root folder, get the folder nodes from bookmarks root to the selected root.
2625
// Otherwise, include only the folder node itself.
27-
const folderNodes = $derived(root ? getFolderNodes($node) : [$node]);
26+
const folderNodes = $derived(root ? getFolderNodes(node) : [node]);
2827
2928
/**
3029
* Get folder nodes from bookmarks root to the selected root.
@@ -33,8 +32,7 @@
3332
const nodes = [node];
3433
3534
while (node.parentId) {
36-
const folderNode = folderNodeMap.get(node.parentId)!;
37-
node = get(folderNode);
35+
node = folderNodeMap.get(node.parentId)!;
3836
nodes.unshift(node);
3937
}
4038
@@ -59,7 +57,7 @@
5957
// Include selected root title in document title.
6058
// Don't use fallback title.
6159
const documentTitle = $derived(
62-
$node.title ? `Treetop: ${$node.title}` : 'Treetop',
60+
node.title ? `Treetop: ${node.title}` : 'Treetop',
6361
);
6462
</script>
6563

@@ -117,7 +115,7 @@
117115
{/if}
118116
</svelte:head>
119117

120-
{#if root || !filterActive() || filterSet.has($node.id)}
118+
{#if root || !filterActive() || filterSet.has(node.id)}
121119
<div class="folder" class:root>
122120
<div class="heading">
123121
<div class="title">
@@ -133,7 +131,7 @@
133131
{#if root && filterActive() && !filterSet.has(nodeId)}
134132
<em>{chrome.i18n.getMessage('noResults')}</em>
135133
{/if}
136-
{#each $node.children as child (child.id)}
134+
{#each node.children as child (child.id)}
137135
{#if child.type === Treetop.NodeType.Bookmark}
138136
<!--
139137
Destructure child to work around the following false positive linter

src/treetop/Folder.svelte.test.ts

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint no-irregular-whitespace: ["error", { "skipComments": true }] */
22

3-
import { SvelteDate, SvelteSet } from 'svelte/reactivity';
3+
import { SvelteDate, SvelteMap, SvelteSet } from 'svelte/reactivity';
44
import { type Writable, writable } from 'svelte/store';
55
import { render, screen } from '@testing-library/svelte';
66
import type { MockInstance } from 'vitest';
@@ -111,8 +111,8 @@ beforeEach(() => {
111111
rootNodeId: 'bookmarks-root-id',
112112
builtInFolderIds: ['bookmarks-toolbar-id', 'other-bookmarks-id'],
113113
};
114-
folderNodeMap = new Map() as Treetop.FolderNodeMap;
115-
lastVisitTimeMap = new Map() as Treetop.LastVisitTimeMap;
114+
folderNodeMap = new SvelteMap();
115+
lastVisitTimeMap = new SvelteMap();
116116
currentFilterActive = false;
117117
filterSet = new SvelteSet();
118118
truncate = writable(false);
@@ -129,7 +129,7 @@ describe('rooted at bookmarks root', () => {
129129
// rootNode
130130
rootNode = createFolderNode({ id: builtInFolderInfo.rootNodeId! });
131131

132-
folderNodeMap.set(rootNode.id, writable(rootNode));
132+
folderNodeMap.set(rootNode.id, rootNode);
133133

134134
nodeId = rootNode.id;
135135

@@ -174,7 +174,7 @@ describe('rooted at bookmarks root', () => {
174174
title: '',
175175
});
176176

177-
folderNodeMap.set(rootNode.id, writable(rootNode));
177+
folderNodeMap.set(rootNode.id, rootNode);
178178

179179
nodeId = rootNode.id;
180180

@@ -219,8 +219,8 @@ describe('rooted at bookmarks root', () => {
219219
folderNode.parentId = rootNode.id;
220220
rootNode.children.push(folderNode);
221221

222-
folderNodeMap.set(rootNode.id, writable(rootNode));
223-
folderNodeMap.set(folderNode.id, writable(folderNode));
222+
folderNodeMap.set(rootNode.id, rootNode);
223+
folderNodeMap.set(folderNode.id, folderNode);
224224

225225
nodeId = rootNode.id;
226226

@@ -287,9 +287,9 @@ describe('rooted at bookmarks root', () => {
287287
folderNode2.children.push(createBookmarkNode());
288288
folderNode1.children.push(folderNode2);
289289

290-
folderNodeMap.set(rootNode.id, writable(rootNode));
291-
folderNodeMap.set(folderNode1.id, writable(folderNode1));
292-
folderNodeMap.set(folderNode2.id, writable(folderNode2));
290+
folderNodeMap.set(rootNode.id, rootNode);
291+
folderNodeMap.set(folderNode1.id, folderNode1);
292+
folderNodeMap.set(folderNode2.id, folderNode2);
293293

294294
nodeId = rootNode.id;
295295

@@ -399,9 +399,9 @@ describe('rooted at bookmarks root', () => {
399399
folderNode2.children.push(createBookmarkNode());
400400
rootNode.children.push(folderNode2);
401401

402-
folderNodeMap.set(rootNode.id, writable(rootNode));
403-
folderNodeMap.set(folderNode1.id, writable(folderNode1));
404-
folderNodeMap.set(folderNode2.id, writable(folderNode2));
402+
folderNodeMap.set(rootNode.id, rootNode);
403+
folderNodeMap.set(folderNode1.id, folderNode1);
404+
folderNodeMap.set(folderNode2.id, folderNode2);
405405

406406
nodeId = rootNode.id;
407407

@@ -506,10 +506,10 @@ describe('rooted at subfolder', () => {
506506
folderNode3.children.push(createBookmarkNode());
507507
folderNode2.children.push(folderNode3);
508508

509-
folderNodeMap.set(rootNode.id, writable(rootNode));
510-
folderNodeMap.set(folderNode1.id, writable(folderNode1));
511-
folderNodeMap.set(folderNode2.id, writable(folderNode2));
512-
folderNodeMap.set(folderNode3.id, writable(folderNode3));
509+
folderNodeMap.set(rootNode.id, rootNode);
510+
folderNodeMap.set(folderNode1.id, folderNode1);
511+
folderNodeMap.set(folderNode2.id, folderNode2);
512+
folderNodeMap.set(folderNode3.id, folderNode3);
513513

514514
nodeId = folderNode2.id;
515515

@@ -664,10 +664,10 @@ describe('filter active', () => {
664664
folderNode3.children.push(bookmarkNode6);
665665
folderNode2.children.push(folderNode3);
666666

667-
folderNodeMap.set(rootNode.id, writable(rootNode));
668-
folderNodeMap.set(folderNode1.id, writable(folderNode1));
669-
folderNodeMap.set(folderNode2.id, writable(folderNode2));
670-
folderNodeMap.set(folderNode3.id, writable(folderNode3));
667+
folderNodeMap.set(rootNode.id, rootNode);
668+
folderNodeMap.set(folderNode1.id, folderNode1);
669+
folderNodeMap.set(folderNode2.id, folderNode2);
670+
folderNodeMap.set(folderNode3.id, folderNode3);
671671

672672
// Enable filter
673673
currentFilterActive = true;

0 commit comments

Comments
 (0)