summaryrefslogtreecommitdiffhomepage
path: root/src/adapters/local-storage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-26 22:21:55 +0900
committerAdam Malczewski <[email protected]>2026-06-26 22:23:39 +0900
commitc333fcec32b1f90bf0da6bb14d2609c20e38a74f (patch)
tree0db3ec77a6838c4f800c362df0de3c6cd8544431 /src/adapters/local-storage
parent1285564f12238b22f6b39b9f3fbcecaca8456911 (diff)
downloaddispatch-web-c333fcec32b1f90bf0da6bb14d2609c20e38a74f.tar.gz
dispatch-web-c333fcec32b1f90bf0da6bb14d2609c20e38a74f.zip
style: switch from tabs to 2-space indentation (incl. svelte)
Diffstat (limited to 'src/adapters/local-storage')
-rw-r--r--src/adapters/local-storage/index.test.ts224
-rw-r--r--src/adapters/local-storage/index.ts86
2 files changed, 155 insertions, 155 deletions
diff --git a/src/adapters/local-storage/index.test.ts b/src/adapters/local-storage/index.test.ts
index 57103dd..3370dd7 100644
--- a/src/adapters/local-storage/index.test.ts
+++ b/src/adapters/local-storage/index.test.ts
@@ -2,119 +2,119 @@ import { describe, expect, it } from "vitest";
import { createLocalStore } from "./index";
function createMemoryStorage(): Storage {
- const map = new Map<string, string>();
- return {
- get length() {
- return map.size;
- },
- clear() {
- map.clear();
- },
- getItem(key: string) {
- return map.get(key) ?? null;
- },
- key(index: number) {
- return [...map.keys()][index] ?? null;
- },
- removeItem(key: string) {
- map.delete(key);
- },
- setItem(key: string, value: string) {
- map.set(key, value);
- },
- };
+ const map = new Map<string, string>();
+ return {
+ get length() {
+ return map.size;
+ },
+ clear() {
+ map.clear();
+ },
+ getItem(key: string) {
+ return map.get(key) ?? null;
+ },
+ key(index: number) {
+ return [...map.keys()][index] ?? null;
+ },
+ removeItem(key: string) {
+ map.delete(key);
+ },
+ setItem(key: string, value: string) {
+ map.set(key, value);
+ },
+ };
}
describe("createLocalStore", () => {
- it("save then load round-trips an object", () => {
- const storage = createMemoryStorage();
- const store = createLocalStore<{ name: string; count: number }>("test", { storage });
-
- store.save({ name: "alice", count: 42 });
- const loaded = store.load();
-
- expect(loaded).toEqual({ name: "alice", count: 42 });
- });
-
- it("load returns null when key is absent", () => {
- const storage = createMemoryStorage();
- const store = createLocalStore<string>("missing", { storage });
-
- expect(store.load()).toBeNull();
- });
-
- it("load returns null on corrupt JSON", () => {
- const storage = createMemoryStorage();
- storage.setItem("corrupt", "{not valid json!!!");
- const store = createLocalStore<object>("corrupt", { storage });
-
- expect(store.load()).toBeNull();
- });
-
- it("clear removes the value", () => {
- const storage = createMemoryStorage();
- const store = createLocalStore<string>("key", { storage });
-
- store.save("hello");
- expect(store.load()).toBe("hello");
-
- store.clear();
- expect(store.load()).toBeNull();
- });
-
- it("save swallows a throwing setItem (quota) without throwing", () => {
- const storage = createMemoryStorage();
- const originalSetItem = storage.setItem.bind(storage);
- let callCount = 0;
- storage.setItem = (_key: string, _value: string) => {
- callCount++;
- if (callCount > 1) {
- throw new DOMException("QuotaExceededError", "QuotaExceededError");
- }
- originalSetItem(_key, _value);
- };
-
- const store = createLocalStore<number[]>("quota", { storage });
-
- // First save works
- store.save([1, 2, 3]);
- expect(store.load()).toEqual([1, 2, 3]);
-
- // Second save throws but is swallowed
- expect(() => store.save([4, 5, 6])).not.toThrow();
- });
-
- it("construction with undefined storage yields a safe no-op store", () => {
- const store = createLocalStore<string>("noop", { storage: undefined });
-
- // All operations are safe no-ops
- expect(store.load()).toBeNull();
- expect(() => store.save("hello")).not.toThrow();
- expect(() => store.clear()).not.toThrow();
- });
-
- it("round-trips arrays", () => {
- const storage = createMemoryStorage();
- const store = createLocalStore<number[]>("arr", { storage });
-
- store.save([1, 2, 3]);
- expect(store.load()).toEqual([1, 2, 3]);
- });
-
- it("round-trips nested objects", () => {
- const storage = createMemoryStorage();
- const store = createLocalStore<{ a: { b: string[] } }>("nested", { storage });
-
- store.save({ a: { b: ["x", "y"] } });
- expect(store.load()).toEqual({ a: { b: ["x", "y"] } });
- });
-
- it("overwrites previous value on repeated save", () => {
- const storage = createMemoryStorage();
- const store = createLocalStore<string>("key", { storage });
-
- store.save("first");
- store.save("second");
- expect(store.load()).toBe("second");
- });
+ it("save then load round-trips an object", () => {
+ const storage = createMemoryStorage();
+ const store = createLocalStore<{ name: string; count: number }>("test", { storage });
+
+ store.save({ name: "alice", count: 42 });
+ const loaded = store.load();
+
+ expect(loaded).toEqual({ name: "alice", count: 42 });
+ });
+
+ it("load returns null when key is absent", () => {
+ const storage = createMemoryStorage();
+ const store = createLocalStore<string>("missing", { storage });
+
+ expect(store.load()).toBeNull();
+ });
+
+ it("load returns null on corrupt JSON", () => {
+ const storage = createMemoryStorage();
+ storage.setItem("corrupt", "{not valid json!!!");
+ const store = createLocalStore<object>("corrupt", { storage });
+
+ expect(store.load()).toBeNull();
+ });
+
+ it("clear removes the value", () => {
+ const storage = createMemoryStorage();
+ const store = createLocalStore<string>("key", { storage });
+
+ store.save("hello");
+ expect(store.load()).toBe("hello");
+
+ store.clear();
+ expect(store.load()).toBeNull();
+ });
+
+ it("save swallows a throwing setItem (quota) without throwing", () => {
+ const storage = createMemoryStorage();
+ const originalSetItem = storage.setItem.bind(storage);
+ let callCount = 0;
+ storage.setItem = (_key: string, _value: string) => {
+ callCount++;
+ if (callCount > 1) {
+ throw new DOMException("QuotaExceededError", "QuotaExceededError");
+ }
+ originalSetItem(_key, _value);
+ };
+
+ const store = createLocalStore<number[]>("quota", { storage });
+
+ // First save works
+ store.save([1, 2, 3]);
+ expect(store.load()).toEqual([1, 2, 3]);
+
+ // Second save throws but is swallowed
+ expect(() => store.save([4, 5, 6])).not.toThrow();
+ });
+
+ it("construction with undefined storage yields a safe no-op store", () => {
+ const store = createLocalStore<string>("noop", { storage: undefined });
+
+ // All operations are safe no-ops
+ expect(store.load()).toBeNull();
+ expect(() => store.save("hello")).not.toThrow();
+ expect(() => store.clear()).not.toThrow();
+ });
+
+ it("round-trips arrays", () => {
+ const storage = createMemoryStorage();
+ const store = createLocalStore<number[]>("arr", { storage });
+
+ store.save([1, 2, 3]);
+ expect(store.load()).toEqual([1, 2, 3]);
+ });
+
+ it("round-trips nested objects", () => {
+ const storage = createMemoryStorage();
+ const store = createLocalStore<{ a: { b: string[] } }>("nested", { storage });
+
+ store.save({ a: { b: ["x", "y"] } });
+ expect(store.load()).toEqual({ a: { b: ["x", "y"] } });
+ });
+
+ it("overwrites previous value on repeated save", () => {
+ const storage = createMemoryStorage();
+ const store = createLocalStore<string>("key", { storage });
+
+ store.save("first");
+ store.save("second");
+ expect(store.load()).toBe("second");
+ });
});
diff --git a/src/adapters/local-storage/index.ts b/src/adapters/local-storage/index.ts
index 72135ce..9dd2ffd 100644
--- a/src/adapters/local-storage/index.ts
+++ b/src/adapters/local-storage/index.ts
@@ -1,58 +1,58 @@
export interface LocalStore<T> {
- load(): T | null;
- save(value: T): void;
- clear(): void;
+ load(): T | null;
+ save(value: T): void;
+ clear(): void;
}
export interface CreateLocalStoreOptions {
- storage?: Storage | undefined;
+ storage?: Storage | undefined;
}
function createNoopStore<T>(): LocalStore<T> {
- return {
- load() {
- return null;
- },
- save() {},
- clear() {},
- };
+ return {
+ load() {
+ return null;
+ },
+ save() {},
+ clear() {},
+ };
}
export function createLocalStore<T>(key: string, opts?: CreateLocalStoreOptions): LocalStore<T> {
- let storage: Storage | undefined;
- if (opts !== undefined && "storage" in opts) {
- storage = opts.storage;
- } else {
- storage = globalThis.localStorage;
- }
+ let storage: Storage | undefined;
+ if (opts !== undefined && "storage" in opts) {
+ storage = opts.storage;
+ } else {
+ storage = globalThis.localStorage;
+ }
- if (storage === undefined || storage === null) {
- return createNoopStore<T>();
- }
+ if (storage === undefined || storage === null) {
+ return createNoopStore<T>();
+ }
- return {
- load(): T | null {
- try {
- const raw = storage.getItem(key);
- if (raw === null) {
- return null;
- }
- return JSON.parse(raw) as T;
- } catch {
- return null;
- }
- },
+ return {
+ load(): T | null {
+ try {
+ const raw = storage.getItem(key);
+ if (raw === null) {
+ return null;
+ }
+ return JSON.parse(raw) as T;
+ } catch {
+ return null;
+ }
+ },
- save(value: T): void {
- try {
- storage.setItem(key, JSON.stringify(value));
- } catch {
- // Swallow quota / write errors — persistence is best-effort.
- }
- },
+ save(value: T): void {
+ try {
+ storage.setItem(key, JSON.stringify(value));
+ } catch {
+ // Swallow quota / write errors — persistence is best-effort.
+ }
+ },
- clear(): void {
- storage.removeItem(key);
- },
- };
+ clear(): void {
+ storage.removeItem(key);
+ },
+ };
}