a9dacf0b97
ESLint had 30 findings (13 errors, 17 warnings) that had accumulated
across the codebase. Most came out of --fix; the rest needed small
manual cleanups:
- storage.ts: replace import('zod') type annotations with the already-
imported ZodSchema type
- CityPickerPopup.tsx: drop a stale jsx-a11y disable directive for a
rule that isn't in the shared config, and narrow row.city1 so the
explicit non-null assertions are no longer needed
- keyboardLayoutConverter.ts: guard the per-index reads so we can drop
the trailing ! from the string indexing
- TimeGroup.tsx: narrow actual via the hasDelay condition and default
the day-change numbers to 0 instead of asserting non-null
- seo.ts: throw on the unreachable empty-flightIds branch rather than
fabricating a partial SeoHeadProps
- Various test files: remove captured-but-unused onCity/shouldApply
refs and stale makeStation/emptyCity locals that drifted during
earlier refactors
make check now passes typecheck + lint; the one remaining test
failure is the pre-existing OnlineBoardSearchPage timeout test that
flakes under the full suite and passes in isolation.
119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
import type { ZodSchema } from "zod";
|
|
|
|
const PREFIX = "afl_";
|
|
|
|
function prefixed(key: string): string {
|
|
return `${PREFIX}${key}`;
|
|
}
|
|
|
|
export const storage = {
|
|
get<T>(key: string, schema: ZodSchema<T>): T | null {
|
|
try {
|
|
const raw = localStorage.getItem(prefixed(key));
|
|
if (raw === null) return null;
|
|
const parsed: unknown = JSON.parse(raw);
|
|
const result = schema.safeParse(parsed);
|
|
return result.success ? result.data : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
set<T>(key: string, value: T, schema: ZodSchema<T>): void {
|
|
schema.parse(value);
|
|
localStorage.setItem(prefixed(key), JSON.stringify(value));
|
|
},
|
|
|
|
delete(key: string): void {
|
|
localStorage.removeItem(prefixed(key));
|
|
},
|
|
|
|
clear(): void {
|
|
const keysToRemove: string[] = [];
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
const k = localStorage.key(i);
|
|
if (k?.startsWith(PREFIX)) {
|
|
keysToRemove.push(k);
|
|
}
|
|
}
|
|
for (const k of keysToRemove) {
|
|
localStorage.removeItem(k);
|
|
}
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Thin wrapper over `sessionStorage` for same-tab ephemeral state —
|
|
* cross-page prefill handoff, non-persistent UI flags, etc. No schema
|
|
* validation; callers own their key namespace (e.g. `afl-prefill:*`)
|
|
* and serialize/deserialize JSON themselves. All operations no-op
|
|
* when `sessionStorage` is undefined (SSR-safe).
|
|
*
|
|
* Exists so the rest of the codebase can stay under the
|
|
* `no-restricted-globals` rule that blocks direct sessionStorage access.
|
|
*/
|
|
|
|
const SESSION_PREFIX = "afl_";
|
|
|
|
export const sessionStore = {
|
|
getRaw(key: string): string | null {
|
|
if (typeof sessionStorage === "undefined") return null;
|
|
try {
|
|
return sessionStorage.getItem(key);
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
setRaw(key: string, value: string): void {
|
|
if (typeof sessionStorage === "undefined") return;
|
|
try {
|
|
sessionStorage.setItem(key, value);
|
|
} catch {
|
|
// ignore quota/disabled
|
|
}
|
|
},
|
|
|
|
delete(key: string): void {
|
|
if (typeof sessionStorage === "undefined") return;
|
|
try {
|
|
sessionStorage.removeItem(key);
|
|
} catch {
|
|
// ignore disabled
|
|
}
|
|
},
|
|
|
|
clear(): void {
|
|
if (typeof sessionStorage === "undefined") return;
|
|
try {
|
|
sessionStorage.clear();
|
|
} catch {
|
|
// ignore disabled
|
|
}
|
|
},
|
|
|
|
/** Schema-validated get from sessionStorage under the `afl_` namespace. */
|
|
get<T>(key: string, schema: ZodSchema<T>): T | null {
|
|
try {
|
|
const raw = this.getRaw(SESSION_PREFIX + key);
|
|
if (raw === null) return null;
|
|
const parsed: unknown = JSON.parse(raw);
|
|
const result = schema.safeParse(parsed);
|
|
return result.success ? result.data : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
/** Schema-validated set into sessionStorage under the `afl_` namespace. */
|
|
set<T>(key: string, value: T, schema: ZodSchema<T>): void {
|
|
schema.parse(value);
|
|
this.setRaw(SESSION_PREFIX + key, JSON.stringify(value));
|
|
},
|
|
|
|
/** Delete a key from the `afl_` namespace in sessionStorage. */
|
|
deleteNs(key: string): void {
|
|
this.delete(SESSION_PREFIX + key);
|
|
},
|
|
};
|