/* 472-5 5-C 헬퍼 — 종단 편집 · 페이지 설정 값 주인 = 설계 가게 칸 하나. 진짜 `b_page_state` · `design_store` · * `_Profile_Edit` · `_Api_PageSettings` 를 Node 로(세션 = 메모리 · 되돌리기 = 세션 칸 되쓰기 + 훅 부름 흉내). * node helper_472_5_value_owner.cjs (짝 = `test_472_5_value_owner.py`) */ const fs = require("fs"); const path = require("path"); const ROOT = path.join(__dirname, "..", ".."); const ts = require(path.join(ROOT, "config", "node_modules", "typescript")); function memoryStorage() { const map = new Map(); return { getItem: (k) => (map.has(k) ? map.get(k) : null), setItem: (k, v) => map.set(k, String(v)), removeItem: (k) => map.delete(k), key: (i) => [...map.keys()][i] ?? null, get length() { return map.size; }, }; } globalThis.window = { sessionStorage: memoryStorage(), localStorage: memoryStorage() }; const REAL = new Set( [ "A00_Common/b_page_state.ts", "A00_Common/design/design_store.ts", "B05_Profile/B05_Profile_UI_Profile_Edit.ts", "B05_Profile/B05_Profile_Api_PageSettings.ts", "B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts", ].map((rel) => path.join(ROOT, rel)), ); const historyHooks = []; const STUBS = { B05_Profile_UI_Profile_History: { onPageHistory: (entry) => historyHooks.push(entry) }, B05_Profile_Api_Fetch: { readRouteLatestCache: (p) => state().readState("latest", p), writeRouteLatestCache: (p, value) => state().writeState("latest", value, p), savePageSettings: async () => ({}), }, }; const anything = () => new Proxy({}, { get: (_target, key) => (key === "__esModule" ? false : () => undefined) }); const cache = new Map(); function load(file) { if (cache.has(file)) return cache.get(file); const box = { exports: {} }; cache.set(file, box.exports); const js = ts.transpileModule(fs.readFileSync(file, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const req = (request) => { const stub = STUBS[path.basename(request)]; if (stub) return stub; if (request === "@ui/ui_template_locale") return { ui_locales: {}, currentLanguageIndex: 0 }; if (!request.startsWith(".")) return anything(); const target = path.resolve(path.dirname(file), request); const full = fs.existsSync(`${target}.ts`) ? `${target}.ts` : target; return REAL.has(full) ? load(full) : anything(); }; new Function("exports", "module", "require", js)(box.exports, box, req); return box.exports; } const state = () => load(path.join(ROOT, "A00_Common", "b_page_state.ts")); const P = "P4725"; const ROUTE = 7; const store = load(path.join(ROOT, "A00_Common", "design", "design_store.ts")); store.pinDraftProject(P); const edit = load(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Profile_Edit.ts")); const settings = load(path.join(ROOT, "B05_Profile", "B05_Profile_Api_PageSettings.ts")); const out = {}; // ① 두 보기 = 창구 둘 · 같은 노선 — ↶ 가 세션 칸을 되쓰면 둘 다 그 값(모듈 사본이 옛 값을 쥐지 않음) const saved = { station_offsets: {}, curve_radii: { "40.000": 30 } }; const a = edit.createProfileEditStore(ROUTE, saved, () => undefined); const b = edit.createProfileEditStore(ROUTE, saved, () => undefined); const x = { station_offsets: { "20.000": 0.5 }, curve_radii: { "40.000": 30 } }; const y = { station_offsets: { "20.000": 0.2 }, curve_radii: { "40.000": 30 } }; a.replace(x); state().writeState("alignment-draft", y, P, ROUTE); // 되돌리기 = 세션 되쓰기 out.undo = { a: a.edits(), b: b.edits(), aDirty: a.dirty(), resync: a.resync?.() ?? "없음", again: a.resync?.() ?? "없음", }; // ② [저장] 뒤 ↶ 로 초안 칸이 비면 = 저장한 값(저장 전 서버 값으로 안 돌아감) a.replace(x); a.markSaved(); state().writeState("alignment-draft", null, P, ROUTE); out.afterSave = { edits: b.edits(), dirty: b.dirty(), canRestore: b.canRestoreSaved() }; // ③ 페이지 설정 — ↶ 훅이 가게로 다시 알림(폼 · 기울기 한도 · 시작 측점이 들음 · N6) const heard = []; store.useDesignStore(P, null).subscribe("pageSettings", (value) => heard.push(value)); const draft = { design_speed_kph: 30, terrain_type: "normal", max_grade_pct: 12, min_vertical_radius_m: null, min_tangent_length_m: null, enforce_pipe_clearance: true, station_display: { station: 0, cumulative: 0 }, }; settings.writePageSettings(P, draft); state().writeState("pagesettings", null, P); // 되돌리기 = 세션 되쓰기 historyHooks.forEach((entry) => entry.restore?.("undo")); out.settingsHeard = [...heard]; // ④ 최소고 강제 = 페이지 설정 한 칸(초안 ?? 저장 노선) · 사본 세션 칸 없음(N7) state().writeState("latest", { project_id: P, route_params: { enforce_pipe_clearance: true } }, P); out.enforceSaved = settings.enforceMinCoverOf?.(P) ?? "없음"; // 옛 코드 = 창구 없음 settings.writePageSettings(P, { ...draft, enforce_pipe_clearance: false }); out.enforceDraft = settings.enforceMinCoverOf?.(P) ?? "없음"; // 등록부에 없으면 열쇠가 안 섬(null) — 옛 코드는 결과 통 열쇠가 섬 out.copyKey = state().stateKey("profile-enforce-min-cover", P) ?? "none"; console.log(JSON.stringify(out));