Files
Aislo/B06_Section/B06_Section_Session_Cells.ts
T

92 lines
3.6 KiB
TypeScript

/* =============================================================================
* B06_Section_Session_Cells.ts
* 조정창 값 창구(472-5 5-D) — 측점별 조작값(반폭 · 기슭막이 4축 · 유입 형식 · 집수정 · 단 수 · 단별 구간 · 연동 ·
* 세월교 · BOX)의 주인은 **세션 칸 하나**. 메모리 사본 없음 — 읽을 때마다 칸을 풀고 쓸 때마다 칸에 씀(창구 =
* 등록부 `b_page_state` 열쇠 · 가게도 밑은 이것). 되돌리기 · 다시하기 · 측점 갈아끼움 이동(`Station_Keys`)이 칸을
* 되써도 다음 조작이 옛 값으로 덮지 않음(N5).
* 가벼운 자리 — 등록부만 끎(세월교 · BOX 제어 · 시험 로더가 화면 줄기를 안 끌게).
* ========================================================================== */
import { readByKey, writeByKey } from "../A00_Common/b_page_state";
/** 세션 칸 한 겹(열쇠 = 누가거리 0.01 m 글 · `:역할` · `b` 앞머리). */
export interface SessionCells<V> {
get(key: string): V | undefined;
has(key: string): boolean;
set(key: string, value: V): void;
delete(key: string): void;
clear(): void;
forEach(fn: (value: V, key: string) => void): void;
keys(): string[];
/** 지금 칸 값(새 Map) — [저장] patch 재료. */
entries(): Map<string, V>;
}
const isObject = (value: unknown): value is Record<string, unknown> =>
!!value && typeof value === "object";
function cellOf(key: string): Record<string, unknown> {
try {
const parsed: unknown = JSON.parse(readByKey(key) ?? "null");
return isObject(parsed) ? parsed : {};
} catch {
return {}; // 손상된 세션 값 = 빈 칸(정본 · 기본값으로)
}
}
/**
* 세션 칸 창구를 만듦. `accept` = 항목마다 검증 · 정규화(`undefined` = 버림 · 손상값 · 옛 꼴 정리 자리) ·
* `part` = 칸 안 한 겹(연동 칸 `{ detached, grade }`). 빈 맵을 쓰면 칸 지움(272 · 연동은 두 겹 다 빌 때).
*/
export function sessionCells<V>(
sessionKey: () => string | null,
accept: (value: unknown) => V | undefined,
part?: string,
): SessionCells<V> {
const read = (): Map<string, V> => {
const values = new Map<string, V>();
const key = sessionKey();
if (!key) return values;
const whole = cellOf(key);
const cells = part ? whole[part] : whole;
if (!isObject(cells)) return values;
for (const [entry, value] of Object.entries(cells)) {
const taken = accept(value);
if (taken !== undefined) values.set(entry, taken);
}
return values;
};
const write = (values: Map<string, V>): void => {
const key = sessionKey();
if (!key) return;
const cells = Object.fromEntries(values);
const whole = part ? { ...cellOf(key), [part]: cells } : cells;
const empty = part
? Object.values(whole).every((v) => !isObject(v) || !Object.keys(v).length)
: !values.size;
try {
writeByKey(key, empty ? null : JSON.stringify(whole));
} catch {
/* 세션 저장 실패(용량 초과 등) — 그 조작만 안 남음. */
}
};
const edit = (change: (values: Map<string, V>) => void): void => {
const values = read();
change(values);
write(values);
};
return {
get: (key) => read().get(key),
has: (key) => read().has(key),
set: (key, value) => edit((values) => values.set(key, value)),
delete: (key) => {
const values = read();
if (values.delete(key)) write(values);
},
clear: () => write(new Map()),
forEach: (fn) => read().forEach(fn),
keys: () => [...read().keys()],
entries: read,
};
}