Skip to content

Commit 95a7415

Browse files
committed
Migrate last visit time map values from writable stores to runes
1 parent e955876 commit 95a7415

File tree

6 files changed

+54
-71
lines changed

6 files changed

+54
-71
lines changed

src/treetop/Bookmark.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
const tooltips = getContext<Writable<boolean>>('tooltips');
2222
const clock = getContext<SvelteDate>('clock');
2323
24-
let lastVisitTime = lastVisitTimeMap.get(nodeId)!;
24+
const lastVisitTime = $derived(lastVisitTimeMap.get(nodeId)!);
2525
2626
// Maximum length of displayed bookmark titles and, in tooltips, URLs.
2727
const maxLength = 78;
@@ -52,7 +52,7 @@
5252
5353
// Approximate number of days since last visit
5454
const lastVisitTimeDays = $derived(
55-
(clock.getTime() - $lastVisitTime) / MILLISECONDS_PER_DAY,
55+
(clock.getTime() - lastVisitTime) / MILLISECONDS_PER_DAY,
5656
);
5757
5858
// Set visited class based on number of days since last visit

src/treetop/Bookmark.svelte.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SvelteDate } from 'svelte/reactivity';
1+
import { SvelteDate, SvelteMap } from 'svelte/reactivity';
22
import { type Writable, writable } from 'svelte/store';
33
import { faker } from '@faker-js/faker';
44
import { render, screen } from '@testing-library/svelte';
@@ -45,8 +45,8 @@ beforeEach(() => {
4545
title = faker.word.words();
4646
url = faker.internet.url();
4747

48-
lastVisitTimeMap = new Map() as Treetop.LastVisitTimeMap;
49-
lastVisitTimeMap.set(nodeId, writable(0));
48+
lastVisitTimeMap = new SvelteMap();
49+
lastVisitTimeMap.set(nodeId, 0);
5050

5151
truncate = writable(false);
5252
tooltips = writable(false);
@@ -186,7 +186,7 @@ describe('sets class based on last visit time', () => {
186186
({ deltaHours, className }) => {
187187
const deltaMs = deltaHours * MILLISECONDS_PER_HOUR;
188188
const lastVisitTime = Date.now() - deltaMs;
189-
lastVisitTimeMap.get(nodeId)!.set(lastVisitTime);
189+
lastVisitTimeMap.set(nodeId, lastVisitTime);
190190

191191
setup();
192192

@@ -202,7 +202,7 @@ describe('sets class based on last visit time', () => {
202202
`('visited $deltaHours ago -> no class', ({ deltaHours }) => {
203203
const deltaMs = deltaHours * MILLISECONDS_PER_HOUR;
204204
const lastVisitTime = Date.now() - deltaMs;
205-
lastVisitTimeMap.get(nodeId)!.set(lastVisitTime);
205+
lastVisitTimeMap.set(nodeId, lastVisitTime);
206206

207207
setup();
208208

src/treetop/HistoryManager.test.ts

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint no-irregular-whitespace: ["error", { "skipComments": true }] */
2-
import { get, writable } from 'svelte/store';
2+
import { SvelteMap } from 'svelte/reactivity';
3+
import { writable } from 'svelte/store';
34
import { faker } from '@faker-js/faker';
45
import { beforeEach, describe, expect, it, vi } from 'vitest';
56

@@ -36,7 +37,7 @@ let folderNode2: Treetop.FolderNode;
3637

3738
beforeEach(() => {
3839
nodeStoreMap = new Map() as Treetop.NodeStoreMap;
39-
lastVisitTimeMap = new Map() as Treetop.LastVisitTimeMap;
40+
lastVisitTimeMap = new SvelteMap();
4041
historyManager = new HistoryManager(lastVisitTimeMap);
4142

4243
// Create node tree:
@@ -71,8 +72,8 @@ describe('init', () => {
7172

7273
expect(lastVisitTimeMap.size).toBe(7);
7374

74-
for (const lastVisitTimeStore of lastVisitTimeMap.values()) {
75-
expect(get(lastVisitTimeStore)).toBe(0);
75+
for (const lastVisitTime of lastVisitTimeMap.values()) {
76+
expect(lastVisitTime).toBe(0);
7677
}
7778
});
7879
});
@@ -116,9 +117,9 @@ describe('loadHistory', () => {
116117
expect(getVisits).toHaveBeenNthCalledWith(7, { url: bookmarkNodes[6].url });
117118

118119
expect(lastVisitTimeMap.size).toBe(7);
119-
for (const [nodeId, lastVisitTimeStore] of lastVisitTimeMap.entries()) {
120+
for (const [nodeId, lastVisitTime] of lastVisitTimeMap.entries()) {
120121
const visitTime = visitTimeMap.get(nodeId) ?? 0;
121-
expect(get(lastVisitTimeStore)).toBe(visitTime);
122+
expect(lastVisitTime).toBe(visitTime);
122123
}
123124
});
124125

@@ -157,13 +158,13 @@ describe('unloadHistory', () => {
157158
];
158159

159160
for (const nodeId of nodeIds) {
160-
lastVisitTimeMap.set(nodeId, writable(faker.date.past().getTime()));
161+
lastVisitTimeMap.set(nodeId, faker.date.past().getTime());
161162
}
162163

163164
historyManager.unloadHistory();
164165

165166
for (const nodeId of nodeIds) {
166-
expect(get(lastVisitTimeMap.get(nodeId)!)).toBe(0);
167+
expect(lastVisitTimeMap.get(nodeId)!).toBe(0);
167168
}
168169
});
169170
});
@@ -182,7 +183,7 @@ describe('handleBookmarkCreated', () => {
182183
expect(getVisits).toHaveBeenCalledWith({ url: bookmarkNode.url });
183184

184185
expect(lastVisitTimeMap.has(bookmarkNode.id)).toBe(true);
185-
expect(get(lastVisitTimeMap.get(bookmarkNode.id)!)).toBe(0);
186+
expect(lastVisitTimeMap.get(bookmarkNode.id)!).toBe(0);
186187
});
187188

188189
it('sets last visit time for a new visited bookmark', async () => {
@@ -200,9 +201,7 @@ describe('handleBookmarkCreated', () => {
200201
expect(getVisits).toHaveBeenCalledWith({ url: bookmarkNode.url });
201202

202203
expect(lastVisitTimeMap.has(bookmarkNode.id)).toBe(true);
203-
expect(get(lastVisitTimeMap.get(bookmarkNode.id)!)).toBe(
204-
visitItem.visitTime!,
205-
);
204+
expect(lastVisitTimeMap.get(bookmarkNode.id)!).toBe(visitItem.visitTime!);
206205
});
207206

208207
it('ignores new folders', async () => {
@@ -217,7 +216,7 @@ describe('handleBookmarkRemoved', () => {
217216
it('removes last visit time for a bookmark', () => {
218217
const baseNode = createOtherBookmarksNode();
219218
const bookmarkNode = createBrowserBookmarkNode(baseNode);
220-
lastVisitTimeMap.set(bookmarkNode.id, writable(0));
219+
lastVisitTimeMap.set(bookmarkNode.id, 0);
221220
const initialSize = lastVisitTimeMap.size;
222221

223222
historyManager.handleBookmarkRemoved(bookmarkNode.id);
@@ -241,7 +240,7 @@ describe('handleBookmarkChanged', () => {
241240
it('updates last visit time of a bookmark when its URL is visited', async () => {
242241
const baseNode = createOtherBookmarksNode();
243242
const bookmarkNode = createBrowserBookmarkNode(baseNode);
244-
lastVisitTimeMap.set(bookmarkNode.id, writable(0));
243+
lastVisitTimeMap.set(bookmarkNode.id, 0);
245244

246245
const newUrl = faker.internet.url();
247246
const changeInfo: Treetop.BookmarkChangeInfo = {
@@ -259,15 +258,13 @@ describe('handleBookmarkChanged', () => {
259258
expect(getVisits).toHaveBeenCalledOnce();
260259
expect(getVisits).toHaveBeenCalledWith({ url: newUrl });
261260

262-
expect(get(lastVisitTimeMap.get(bookmarkNode.id)!)).toBe(
263-
visitItem.visitTime!,
264-
);
261+
expect(lastVisitTimeMap.get(bookmarkNode.id)!).toBe(visitItem.visitTime!);
265262
});
266263

267264
it('resets last visit time of a bookmark when its URL is not visited', async () => {
268265
const baseNode = createOtherBookmarksNode();
269266
const bookmarkNode = createBrowserBookmarkNode(baseNode);
270-
lastVisitTimeMap.set(bookmarkNode.id, writable(0));
267+
lastVisitTimeMap.set(bookmarkNode.id, 0);
271268

272269
const newUrl = faker.internet.url();
273270
const changeInfo: Treetop.BookmarkChangeInfo = {
@@ -283,7 +280,7 @@ describe('handleBookmarkChanged', () => {
283280
expect(getVisits).toHaveBeenCalledOnce();
284281
expect(getVisits).toHaveBeenCalledWith({ url: newUrl });
285282

286-
expect(get(lastVisitTimeMap.get(bookmarkNode.id)!)).toBe(0);
283+
expect(lastVisitTimeMap.get(bookmarkNode.id)!).toBe(0);
287284
});
288285

289286
it('ignores folders', async () => {
@@ -305,8 +302,8 @@ describe('handleVisited', () => {
305302
const bookmarkNode2 = createBrowserBookmarkNode(baseNode);
306303
bookmarkNode1.url = historyItem.url!;
307304
bookmarkNode2.url = historyItem.url!;
308-
lastVisitTimeMap.set(bookmarkNode1.id, writable(0));
309-
lastVisitTimeMap.set(bookmarkNode2.id, writable(0));
305+
lastVisitTimeMap.set(bookmarkNode1.id, 0);
306+
lastVisitTimeMap.set(bookmarkNode2.id, 0);
310307

311308
const search = vi.fn().mockResolvedValue([bookmarkNode1, bookmarkNode2]);
312309
vi.spyOn(chrome.bookmarks, 'search').mockImplementation(search);
@@ -316,10 +313,10 @@ describe('handleVisited', () => {
316313
expect(search).toHaveBeenCalledOnce();
317314
expect(search).toHaveBeenCalledWith({ url: historyItem.url });
318315

319-
expect(get(lastVisitTimeMap.get(bookmarkNode1.id)!)).toBe(
316+
expect(lastVisitTimeMap.get(bookmarkNode1.id)!).toBe(
320317
historyItem.lastVisitTime!,
321318
);
322-
expect(get(lastVisitTimeMap.get(bookmarkNode2.id)!)).toBe(
319+
expect(lastVisitTimeMap.get(bookmarkNode2.id)!).toBe(
323320
historyItem.lastVisitTime!,
324321
);
325322
});
@@ -329,8 +326,8 @@ describe('handleVisited', () => {
329326
const baseNode = createOtherBookmarksNode();
330327
const bookmarkNode1 = createBrowserBookmarkNode(baseNode);
331328
const bookmarkNode2 = createBrowserBookmarkNode(baseNode);
332-
lastVisitTimeMap.set(bookmarkNode1.id, writable(0));
333-
lastVisitTimeMap.set(bookmarkNode2.id, writable(0));
329+
lastVisitTimeMap.set(bookmarkNode1.id, 0);
330+
lastVisitTimeMap.set(bookmarkNode2.id, 0);
334331

335332
const search = vi.fn().mockResolvedValue([]);
336333
vi.spyOn(chrome.bookmarks, 'search').mockImplementation(search);
@@ -340,16 +337,16 @@ describe('handleVisited', () => {
340337
expect(search).toHaveBeenCalledOnce();
341338
expect(search).toHaveBeenCalledWith({ url: historyItem.url });
342339

343-
expect(get(lastVisitTimeMap.get(bookmarkNode1.id)!)).toBe(0);
344-
expect(get(lastVisitTimeMap.get(bookmarkNode2.id)!)).toBe(0);
340+
expect(lastVisitTimeMap.get(bookmarkNode1.id)!).toBe(0);
341+
expect(lastVisitTimeMap.get(bookmarkNode2.id)!).toBe(0);
345342
});
346343
});
347344

348345
describe('handleVisitRemoved', () => {
349346
it('resets last visit time when a bookmarked URL is removed from history', async () => {
350347
const baseNode = createOtherBookmarksNode();
351348
const bookmarkNode = createBrowserBookmarkNode(baseNode);
352-
lastVisitTimeMap.set(bookmarkNode.id, writable(1e6));
349+
lastVisitTimeMap.set(bookmarkNode.id, 1e6);
353350

354351
const search = vi.fn().mockResolvedValue([bookmarkNode]);
355352
vi.spyOn(chrome.bookmarks, 'search').mockImplementation(search);
@@ -364,13 +361,13 @@ describe('handleVisitRemoved', () => {
364361
expect(search).toHaveBeenCalledOnce();
365362
expect(search).toHaveBeenCalledWith({ url: bookmarkNode.url });
366363

367-
expect(get(lastVisitTimeMap.get(bookmarkNode.id)!)).toBe(0);
364+
expect(lastVisitTimeMap.get(bookmarkNode.id)!).toBe(0);
368365
});
369366

370367
it('ignores when a non-bookmarked URL is removed from history', async () => {
371368
const baseNode = createOtherBookmarksNode();
372369
const bookmarkNode = createBrowserBookmarkNode(baseNode);
373-
lastVisitTimeMap.set(bookmarkNode.id, writable(1e6));
370+
lastVisitTimeMap.set(bookmarkNode.id, 1e6);
374371

375372
const url = faker.internet.url();
376373

@@ -387,21 +384,15 @@ describe('handleVisitRemoved', () => {
387384
expect(search).toHaveBeenCalledOnce();
388385
expect(search).toHaveBeenCalledWith({ url });
389386

390-
expect(get(lastVisitTimeMap.get(bookmarkNode.id)!)).toBe(1e6);
387+
expect(lastVisitTimeMap.get(bookmarkNode.id)!).toBe(1e6);
391388
});
392389

393390
it('resets all last visit times when all history is removed', async () => {
394391
const baseNode = createOtherBookmarksNode();
395392
const bookmarkNode1 = createBrowserBookmarkNode(baseNode);
396393
const bookmarkNode2 = createBrowserBookmarkNode(baseNode);
397-
lastVisitTimeMap.set(
398-
bookmarkNode1.id,
399-
writable(faker.date.past().getTime()),
400-
);
401-
lastVisitTimeMap.set(
402-
bookmarkNode2.id,
403-
writable(faker.date.past().getTime()),
404-
);
394+
lastVisitTimeMap.set(bookmarkNode1.id, faker.date.past().getTime());
395+
lastVisitTimeMap.set(bookmarkNode2.id, faker.date.past().getTime());
405396

406397
const removeInfo: Treetop.HistoryRemovedResult = {
407398
allHistory: true,
@@ -410,7 +401,7 @@ describe('handleVisitRemoved', () => {
410401

411402
await historyManager.handleVisitRemoved(removeInfo);
412403

413-
expect(get(lastVisitTimeMap.get(bookmarkNode1.id)!)).toBe(0);
414-
expect(get(lastVisitTimeMap.get(bookmarkNode2.id)!)).toBe(0);
404+
expect(lastVisitTimeMap.get(bookmarkNode1.id)!).toBe(0);
405+
expect(lastVisitTimeMap.get(bookmarkNode2.id)!).toBe(0);
415406
});
416407
});

src/treetop/HistoryManager.ts

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { get, writable } from 'svelte/store';
1+
import { get } from 'svelte/store';
22

33
import { isBookmark } from './bookmarktreenode-utils';
44
import * as Treetop from './types';
@@ -19,7 +19,7 @@ export class HistoryManager {
1919
const node: Treetop.FolderNode = get(nodeStore);
2020
node.children.forEach((child) => {
2121
if (child.type === Treetop.NodeType.Bookmark) {
22-
this.lastVisitTimeMap.set(child.id, writable(0));
22+
this.lastVisitTimeMap.set(child.id, 0);
2323
}
2424
});
2525
}
@@ -58,8 +58,7 @@ export class HistoryManager {
5858
const results = await Promise.all(promises);
5959
results.forEach((items, index) => {
6060
if (items.length > 0) {
61-
const lastVisitTime = this.lastVisitTimeMap.get(nodeIds[index])!;
62-
lastVisitTime.set(items[0].visitTime!);
61+
this.lastVisitTimeMap.set(nodeIds[index], items[0].visitTime!);
6362
}
6463
});
6564

@@ -70,8 +69,8 @@ export class HistoryManager {
7069
* Reset all last visit time stores.
7170
*/
7271
unloadHistory(): void {
73-
for (const lastVisitTime of this.lastVisitTimeMap.values()) {
74-
lastVisitTime.set(0);
72+
for (const nodeId of this.lastVisitTimeMap.keys()) {
73+
this.lastVisitTimeMap.set(nodeId, 0);
7574
}
7675

7776
this.loaded = false;
@@ -93,8 +92,7 @@ export class HistoryManager {
9392
});
9493

9594
const visitTime = items.length > 0 ? items[0].visitTime! : 0;
96-
const lastVisitTime = writable(visitTime);
97-
this.lastVisitTimeMap.set(bookmark.id, lastVisitTime);
95+
this.lastVisitTimeMap.set(bookmark.id, visitTime);
9896
}
9997

10098
/**
@@ -120,9 +118,8 @@ export class HistoryManager {
120118
url: changeInfo.url,
121119
});
122120

123-
const lastVisitTime = this.lastVisitTimeMap.get(id)!;
124121
const newLastVisitTime = items.length > 0 ? items[0].visitTime! : 0;
125-
lastVisitTime.set(newLastVisitTime);
122+
this.lastVisitTimeMap.set(id, newLastVisitTime);
126123
}
127124

128125
/**
@@ -135,8 +132,7 @@ export class HistoryManager {
135132
});
136133

137134
nodes.forEach((node) => {
138-
const lastVisitTime = this.lastVisitTimeMap.get(node.id)!;
139-
lastVisitTime.set(result.lastVisitTime!);
135+
this.lastVisitTimeMap.set(node.id, result.lastVisitTime!);
140136
});
141137
}
142138

@@ -149,8 +145,8 @@ export class HistoryManager {
149145
): Promise<void> {
150146
if (removed.allHistory) {
151147
// All history was removed
152-
for (const lastVisitTime of this.lastVisitTimeMap.values()) {
153-
lastVisitTime.set(0);
148+
for (const nodeId of this.lastVisitTimeMap.keys()) {
149+
this.lastVisitTimeMap.set(nodeId, 0);
154150
}
155151
} else {
156152
// TODO: Investigate why `removed.urls` is sometimes empty on Chrome
@@ -160,8 +156,7 @@ export class HistoryManager {
160156
const nodes = await chrome.bookmarks.search({ url });
161157

162158
nodes.forEach((node) => {
163-
const lastVisitTime = this.lastVisitTimeMap.get(node.id)!;
164-
lastVisitTime.set(0);
159+
this.lastVisitTimeMap.set(node.id, 0);
165160
});
166161
}
167162
}

src/treetop/Treetop.svelte

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts">
22
import { onDestroy, onMount, setContext } from 'svelte';
3-
import { SvelteSet } from 'svelte/reactivity';
3+
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
44
import { get, type Unsubscriber, type Writable } from 'svelte/store';
55
import { fade } from 'svelte/transition';
66
import LinearProgress from '@smui/linear-progress';
@@ -64,10 +64,7 @@
6464
6565
// ID to last visit time map.
6666
// Populated with a store for each bookmark.
67-
const lastVisitTimeMap: Treetop.LastVisitTimeMap = new Map<
68-
string,
69-
Writable<number>
70-
>();
67+
const lastVisitTimeMap: Treetop.LastVisitTimeMap = new SvelteMap();
7168
7269
// Set of node IDs that match the active filter.
7370
const filterSet: Treetop.FilterSet = new SvelteSet();

0 commit comments

Comments
 (0)