diff options
| author | Adam Malczewski <[email protected]> | 2026-06-26 22:21:55 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-26 22:23:39 +0900 |
| commit | c333fcec32b1f90bf0da6bb14d2609c20e38a74f (patch) | |
| tree | 0db3ec77a6838c4f800c362df0de3c6cd8544431 /src/adapters/local-storage | |
| parent | 1285564f12238b22f6b39b9f3fbcecaca8456911 (diff) | |
| download | dispatch-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.ts | 224 | ||||
| -rw-r--r-- | src/adapters/local-storage/index.ts | 86 |
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); + }, + }; } |
