Rework the Item code so it can be reused for the history.
This commit is contained in:
parent
451ebb8189
commit
091da70bea
|
@ -1,8 +1,13 @@
|
|||
import {type TestContext, setup} from "@holllo/test";
|
||||
import {type Value} from "@holllo/webextension-storage";
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
import {type Item, createItem, nextItem, nextItemId, storage} from "./item.js";
|
||||
import {
|
||||
type Item,
|
||||
createItem,
|
||||
nextItem,
|
||||
nextItemId,
|
||||
storageForPrefix,
|
||||
} from "./item.js";
|
||||
|
||||
const testText = "Test Item";
|
||||
const testUrl = "https://example.org/";
|
||||
|
@ -30,10 +35,8 @@ await setup(
|
|||
"Item",
|
||||
async (group) => {
|
||||
group.beforeAll(async () => {
|
||||
// If we're in production and testing, clear item storage.
|
||||
if (!$dev && $test) {
|
||||
await storage.clear();
|
||||
}
|
||||
// TODO: Temporarily store existing storage and run the tests, and then
|
||||
// restore it again.
|
||||
});
|
||||
|
||||
group.test("create & nextItem", async (test) => {
|
||||
|
@ -67,11 +70,7 @@ await setup(
|
|||
await Promise.all(items.map(async (item) => item.remove()));
|
||||
|
||||
// After all items have been removed test that `nextItem` returns nothing.
|
||||
// This test will fail if an item is left from development, to clear
|
||||
// storage automatically run in production and have test enabled.
|
||||
// ie. `NODE_ENV=production TEST=true makers dev`
|
||||
// TODO: Temporarily store existing storage and run the tests, and then
|
||||
// restore it again.
|
||||
// This test will fail if an item is left from development.
|
||||
storedNext = await nextItem();
|
||||
test.equals(storedNext, undefined, "next item is undefined");
|
||||
});
|
||||
|
|
|
@ -29,10 +29,13 @@ export type SerializedItem = {
|
|||
};
|
||||
|
||||
/** The key prefix for {@link Item}s. */
|
||||
export const itemKeyPrefix = "item-";
|
||||
export type ItemKeyPrefix = "item-" | "history-";
|
||||
|
||||
/** The default storage area to use for {@link Item}s. */
|
||||
export const storage = browser.storage.sync;
|
||||
export function storageForPrefix(
|
||||
prefix: ItemKeyPrefix,
|
||||
): browser.Storage.StorageArea {
|
||||
return prefix === "item-" ? browser.storage.sync : browser.storage.local;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize and JSON-stringify an {@link Item}.
|
||||
|
@ -83,18 +86,20 @@ export const deserializeItem: Value<Item>["deserialize"] = (
|
|||
*
|
||||
* @param text The text of the {@link Item} to create.
|
||||
* @param url The URL of the {@link Item} to create.
|
||||
* @param itemKeyPrefix The prefix for the {@link Item} key.
|
||||
* @returns The created {@link Value} with inner {@link Item}.
|
||||
*/
|
||||
export async function createItem(
|
||||
text: Item["text"],
|
||||
url: Item["url"],
|
||||
itemKeyPrefix: ItemKeyPrefix = "item-",
|
||||
): Promise<Value<Item>> {
|
||||
const nextId = await nextItemId();
|
||||
|
||||
const item = await createValue<Item>({
|
||||
deserialize: deserializeItem,
|
||||
serialize: serializeItem,
|
||||
storage,
|
||||
storage: storageForPrefix(itemKeyPrefix),
|
||||
key: `${itemKeyPrefix}${nextId}`,
|
||||
value: {
|
||||
dateAdded: new Date(),
|
||||
|
@ -108,11 +113,14 @@ export async function createItem(
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all keys from storage that start with the {@link itemKeyPrefix}.
|
||||
* Get all keys from storage that start with the {@link ItemKeyPrefix}.
|
||||
*
|
||||
* @returns The keys as a string array.
|
||||
*/
|
||||
export async function getItemKeys(): Promise<string[]> {
|
||||
export async function getItemKeys(
|
||||
itemKeyPrefix: ItemKeyPrefix,
|
||||
): Promise<string[]> {
|
||||
const storage = storageForPrefix(itemKeyPrefix);
|
||||
const stored = Object.keys(await storage.get());
|
||||
const keys = stored.filter((key) => key.startsWith(itemKeyPrefix));
|
||||
return keys;
|
||||
|
@ -123,9 +131,11 @@ export async function getItemKeys(): Promise<string[]> {
|
|||
*
|
||||
* @returns The next ID as a number.
|
||||
*/
|
||||
export async function nextItemId(): Promise<number> {
|
||||
export async function nextItemId(
|
||||
itemKeyPrefix: ItemKeyPrefix = "item-",
|
||||
): Promise<number> {
|
||||
// Get all the item keys and sort them so the highest ID is first.
|
||||
const keys = await getItemKeys();
|
||||
const keys = await getItemKeys(itemKeyPrefix);
|
||||
keys.sort((a, b) => b.localeCompare(a));
|
||||
|
||||
// Get the first key or use 0 if no items exist yet.
|
||||
|
@ -142,8 +152,10 @@ export async function nextItemId(): Promise<number> {
|
|||
* queue is empty.
|
||||
*/
|
||||
export async function nextItem(): Promise<Value<Item> | undefined> {
|
||||
const itemKeyPrefix: ItemKeyPrefix = "item-";
|
||||
|
||||
// Get all the item keys and sort them so the lowest ID is first.
|
||||
const keys = await getItemKeys();
|
||||
const keys = await getItemKeys(itemKeyPrefix);
|
||||
keys.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
// If no keys exist then exit early.
|
||||
|
@ -166,7 +178,8 @@ export async function nextItem(): Promise<Value<Item> | undefined> {
|
|||
* Set the WebExtension's badge text to show the current {@link Item} count.
|
||||
*/
|
||||
export async function setBadgeText(): Promise<void> {
|
||||
const keys = await getItemKeys();
|
||||
const itemKeyPrefix: ItemKeyPrefix = "item-";
|
||||
const keys = await getItemKeys(itemKeyPrefix);
|
||||
const count = keys.length;
|
||||
const action: browser.Action.Static =
|
||||
$browser === "firefox" ? browser.browserAction : browser.action;
|
||||
|
|
Loading…
Reference in New Issue