/* PLAN 349-0u 덧 sub7 헬퍼 — 노선을 저장한 [저장]에서 세션 관 초안(옛 노선 누가거리)이 서버가 따라 옮긴 관을 * 덮지 않음 · 사용자 관 고침만 얹음. 실제 `design_save.ts` · 관 초안 창구 · 가게를 Node 로 · 서버 창구 · * 화면 알림만 가짜. 노선 저장 전 GET = `before` · 뒤 GET = `after`(서버 따라감 + 새 교차 관). * 덤 — `placeOnLine` 이 안 옮긴 관에 정본 좌표를 씀. 입력 argv[2] JSON. 짝 = `test_349_0u_save_rebase.py`. */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const CATALOG = require("./helper_322_catalog_module.cjs"); const ROOT = path.join(__dirname, "..", ".."); const job = JSON.parse(fs.readFileSync(process.argv[2], "utf8")); 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; }, }; } globalThis.window = { sessionStorage: memoryStorage(), localStorage: memoryStorage(), setTimeout, clearTimeout, }; const STUBS = {}; const cache = new Map(); function loadTs(full) { 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 (CATALOG.isCatalogRequest(request)) return CATALOG; const key = Object.keys(STUBS).find((name) => request.endsWith(name)); if (key) return STUBS[key]; if (request.startsWith("@config/")) return { API_BASE_URL: "http://fake" }; if (request.startsWith("@util/")) return loadTs(path.join(ROOT, "common_util", `${request.slice(6)}.ts`)); 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); return box.exports; } const load = (...parts) => loadTs(path.join(ROOT, ...parts)); const calls = []; const sent = []; let routeSavedOnServer = false; let routeBody = null; const withLonlat = (list) => list.map((pipe) => ({ ...pipe, lonlat: [0, 0] })); STUBS["ui_template_elements"] = { showLoadingOverlay: () => undefined, hideLoadingOverlay: () => undefined, showToast: () => undefined, }; STUBS["B04_PreProcess_Api_Fetch"] = { fetchDetailPipePoints: async () => { calls.push("GET"); return { pipe_points: withLonlat(routeSavedOnServer ? job.after : job.before) }; }, saveDetailPipePoints: async (_projectId, pipes) => { calls.push("PUT"); sent.push(pipes); return {}; }, }; STUBS["B05_Profile_Api_Structures"] = { flushPendingStructures: async () => undefined }; STUBS["B05_Profile_Api_Fetch"] = { flushUphillOverrides: async () => undefined, saveProfileAlignment: async () => ({}), }; STUBS["B05_Profile_UI_Profile_Edit"] = { markAlignmentSaved: () => undefined, pendingAlignment: () => null, }; STUBS["B06_Section_Api_Culvert_Options"] = { flushCulvertOptions: async () => undefined }; STUBS["B05_Profile_UI_RouteEdit_Apply"] = { pendingRouteSave: async () => routeBody, saveRouteDraft: async () => { calls.push("ROUTE"); routeSavedOnServer = true; return { route_id: 8 }; }, carryAfterRouteSave: async () => 0, routeSaveSummary: () => "", rebuildAfterRouteSave: async () => undefined, }; const save = load("A00_Common", "design", "design_save.ts"); const drafts = load("B05_Profile", "B05_Profile_Api_Pipes_Draft.ts"); const follow = load("common_util", "common_util_route_follow.ts"); const P = "proj-3490u-save"; async function once(route, draft) { calls.length = 0; sent.length = 0; routeSavedOnServer = false; routeBody = route ? { draft: {} } : null; drafts.writePendingPipes(P, draft); let failure = null; const ok = await save.saveDesign({ projectId: P, routeId: () => 7, cross: async () => undefined, failed: (error) => (failure = String(error && error.stack ? error.stack : error)), }); if (failure) throw new Error(failure); return { ok, calls: [...calls], sent: [...sent], left: drafts.readPendingPipes(P) }; } async function run() { window.localStorage.setItem("frd_current_project_id", P); const rebased = await once(true, job.draft); const noDraft = await once(true, null); const noRoute = await once(false, job.draft); // 덤 — 좌표 없는 초안 관: 같은 id · 같은 누가거리 정본이면 그 좌표(노선 밖이어도) · 아니면 노선 위 const placed = follow.placeOnLine( [{ id: "a", chainage_m: 40 }, { id: "b", chainage_m: 60 }, { chainage_m: 70 }], [ { x: 0, y: 0 }, { x: 100, y: 0 }, ], [ { id: "a", chainage_m: 40, x: 40.4, y: 3 }, { id: "b", chainage_m: 55, x: 55, y: 0 }, ], ); return { rebased, noDraft, noRoute, placed }; } run() .then((out) => { process.stdout.write(JSON.stringify(out)); process.exit(0); }) .catch((error) => { process.stderr.write(String(error && error.stack ? error.stack : error)); process.exit(1); });