/* 472-5 남음 헬퍼 — node helper_472_5r_rock.mjs <묶음.mjs> · 표준출력 JSON. * ① 암 경계(▲▼ · 되돌림) · 암 절토 경사를 고침 → ↶ → 다른 측점을 고침 → ↶ ↷ — 세션 칸 · 카드 읽기 · 저장 재료가 * 되돌린 값을 따르는가(옛 코드 = 메모리 맵이 옛 값을 쥐고 다음 조작이 칸을 통째로 다시 씀 · N5). * ② clearRouteDrafts — 그 노선 번호의 노선 범위 초안만 비움(다른 노선 · 프로젝트 칸 그대로). */ import { pathToFileURL } from "node:url"; const storage = () => { const m = new Map(); return { getItem: (k) => (m.has(k) ? m.get(k) : null), setItem: (k, v) => m.set(k, String(v)), removeItem: (k) => m.delete(k), key: (i) => [...m.keys()][i] ?? null, get length() { return m.size; }, clear: () => m.clear(), }; }; const any = new Proxy(function () {}, { get: (_t, k) => (k === Symbol.toPrimitive ? () => 0 : any), apply: () => any, construct: () => any, }); globalThis.window = { sessionStorage: storage(), localStorage: storage() }; // 손길 듣기 없음 = 열 때 규칙 꺼짐 globalThis.sessionStorage = window.sessionStorage; globalThis.localStorage = window.localStorage; globalThis.document = any; const m = await import(pathToFileURL(process.argv[2]).href); const P = "p4725rock"; const R = 7; localStorage.setItem("frd_current_project_id", P); const SAVED_ROCK = -0.8; // 저장분 암 경계(측점 100) const sections = [100, 120, 140].map((chainage_m) => ({ chainage_m, station_id: `s${chainage_m}`, design: chainage_m === 100 ? { rock_boundary_offset_m: SAVED_ROCK } : {}, })); const detail = { cross_sections: sections }; const refreshed = []; const rock = m.createRockBoundaryStore({ sessionKey: () => m.stateKey("rockb", P, R), detail: () => detail, refreshCard: (at) => refreshed.push(at), recompute: () => undefined, }); rock.setDefaults(-0.5, 0.1); const cut = m.createCutSlopeStore({ sessionKey: () => m.stateKey("cutslope", P, R), standard: () => ({ rock: { cut_slope_ratio: 0.4 }, soil: { cut_slope_ratio: 1.0 } }), refreshCard: () => undefined, recompute: () => undefined, }); const cell = (name) => { const raw = m.readState(name, P, R) ?? {}; // 측점 열쇠 칸 = 열쇠 → 값 · `@at`(쓴 때 누가거리) · `@seat` — 누가거리 → 값으로 풀어 봄 const at = raw["@at"] ?? {}; return Object.fromEntries( Object.entries(raw) .filter(([key]) => !key.startsWith("@")) .map(([key, value]) => [Number(at[key] ?? key).toFixed(2), value]), ); }; const cells = () => ({ rockb: cell("rockb"), cutslope: cell("cutslope") }); const reads = () => Object.fromEntries( sections.map((s) => [ s.chainage_m, { rock: rock.control.offsetFor(s), cut: cut.control.ratioFor(s) }, ]), ); const out = {}; const history = m.createProfileHistory(() => undefined, 100); // 조작 A — 100 ▼(저장분 −0.8 → −0.9) · 120 ▲(기본 −0.5 → −0.4) · 140 암 경사 0.7 rock.control.adjust(100, -0.1); rock.control.adjust(120, 0.1); cut.control.set(140, 0.7); history.record(); out.afterA = cells(); out.readsA = reads(); history.undo(); // ↶ = 세션 칸을 조작 전으로 되씀(저장소를 안 거침) out.afterUndo = cells(); out.readsUndo = reads(); // 조작 B — 다른 측점(옛 코드 = 메모리 맵이 A 값을 쥐고 통째로 다시 씀) rock.control.adjust(140, -0.1); cut.control.set(100, 0.5); out.afterB = cells(); out.payloadB = { rock: Object.fromEntries(typeof rock.offsets === "function" ? rock.offsets() : rock.offsets), // 옛 꼴 = Map cut: Object.fromEntries(typeof cut.ratios === "function" ? cut.ratios() : cut.ratios), }; history.record(); history.undo(); out.afterUndo2 = cells(); history.redo(); // ↷ = B 그대로 out.afterRedo = cells(); out.readsRedo = reads(); // 되돌림(↺) — 암 경계 = 기본값 · 암 경사 = 0(표준 표시) rock.control.reset(140); cut.control.set(100, null); out.afterReset = cells(); out.readsReset = reads(); // ② 노선 저장 뒤 옛 노선 칸만 비움 m.writeState("rockb", { "grid:1": -0.7 }, P, 8); m.writeState("crossw", { "100.00": 6 }, P, R); m.writeState("uphill", { "100.000": "left" }, P); m.writeState("rockb", { "grid:1": -0.6 }, "other", R); const keys = () => Array.from({ length: sessionStorage.length }, (_, i) => sessionStorage.key(i)) .filter((key) => key.startsWith("aislo:draft:")) .sort(); out.keysBefore = keys(); m.clearRouteDrafts(P, R); out.keysAfter = keys(); process.stdout.write(JSON.stringify(out));