/* 계획노선 편집 창 **고정 한 벌**(계획서 22-4 · 22-5) 단위검증 헬퍼 — * `B05_Profile_UI_RouteEdit_Lock.ts` 를 그 자리에서 트랜스파일해 Node 로 돌린다. * * ⚠ 확장자가 `.cjs` 인 까닭은 `helper_b05_cut_merged_loop.cjs` 머리에 적힌 것과 같다. * 브라우저 전용인 저장소·팔레트는 가짜로 채운다 — 셈만 본다. */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const ROOT = path.join(__dirname, "..", ".."); const cache = new Map(); // 브라우저 저장소 흉내 — `b_page_state` 가 읽고 쓰는 자리. function memoryStorage() { const map = new Map(); return { getItem: (key) => (map.has(key) ? map.get(key) : null), setItem: (key, value) => map.set(key, String(value)), removeItem: (key) => map.delete(key), key: (index) => [...map.keys()][index] ?? null, get length() { return map.size; }, _map: map, }; } const local = memoryStorage(); globalThis.window = { localStorage: local, sessionStorage: memoryStorage() }; globalThis.fetch = () => Promise.resolve({ ok: false }); const STUBS = { "@ui/ui_template_palette": { themeColor: (_name, fallback) => fallback } }; function loadTs(file) { const full = path.resolve(file); if (cache.has(full)) return cache.get(full); const js = ts.transpileModule(fs.readFileSync(full, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const box = { exports: {} }; cache.set(full, box.exports); const localRequire = (request) => { if (STUBS[request]) return STUBS[request]; if (request.startsWith(".")) return loadTs(path.join(path.dirname(full), `${request}.ts`)); return require(request); }; new Function("exports", "module", "require", js)(box.exports, box, localRequire); cache.set(full, box.exports); return box.exports; } const lock = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Lock.ts")); const planned = [ [0, 0], [100, 0], [150, 80], [260, 90], ]; // ① 저장된 것이 없으면 시점 · 종점만 고정. const fresh = lock.readRouteLocks("p-1"); const freshColumn = lock.lockColumn(planned, fresh); // ② 시점을 풀고 교각점 둘을 고정해 적는다 → 같은 프로젝트로 다시 읽는다. const edited = [false, true, true, true]; lock.writeRouteLocks("p-1", planned, edited); const readBack = lock.readRouteLocks("p-1"); const otherProject = lock.readRouteLocks("p-2"); const storedKeys = [...local._map.keys()]; // ③ 서버가 끝자리만 조금 다른 좌표로 돌려줘도 같은 교각점 · 멀리 옮긴 점은 풀림. const nudged = [ [0, 0], [100.03, -0.02], [151, 80], [260, 90], ]; const nudgedColumn = lock.lockColumn(nudged, readBack); // ④ 선 · 호 고정 판정 — 곧은 선은 양 끝, 호는 교각점과 앞뒤. const straight = [0, 1, 2].map((index) => lock.straightLocked(edited, index)); const arc = [1, 2].map((index) => lock.arcLocked(edited, index)); const arcAll = [1, 2].map((index) => lock.arcLocked([true, true, true, true], index)); // ⑤ 노선을 못 읽은(노드 1개 이하) 채 닫으면 적어 둔 고정을 안 지운다 · 깨진 값은 기본값. lock.writeRouteLocks("p-1", [], []); const keptAfterEmpty = lock.readRouteLocks("p-1"); local.setItem("aislo:pref:routeedit-locks:p-3", "{\"start\":false,\"apex\":[[1,\"x\"],[2,3]]}"); const broken = lock.readRouteLocks("p-3"); process.stdout.write( JSON.stringify({ fresh, freshColumn, readBack, otherProject, storedKeys, nudgedColumn, straight, arc, arcAll, keptAfterEmpty, broken, }), );