/* ============================================================================= * 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 { 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; } const isObject = (value: unknown): value is Record => !!value && typeof value === "object"; function cellOf(key: string): Record { try { const parsed: unknown = JSON.parse(readByKey(key) ?? "null"); return isObject(parsed) ? parsed : {}; } catch { return {}; // 손상된 세션 값 = 빈 칸(정본 · 기본값으로) } } /** * 세션 칸 창구를 만듦. `accept` = 항목마다 검증 · 정규화(`undefined` = 버림 · 손상값 · 옛 꼴 정리 자리) · * `part` = 칸 안 한 겹(연동 칸 `{ detached, grade }`). 빈 맵을 쓰면 칸 지움(272 · 연동은 두 겹 다 빌 때). */ export function sessionCells( sessionKey: () => string | null, accept: (value: unknown) => V | undefined, part?: string, ): SessionCells { const read = (): Map => { const values = new Map(); 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): 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) => 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, }; }