/* 463 B05 · B06 한 페이지 [저장] 같은 본문(요구 271-5 · 분석 4장 (D)) — 진짜 저장 한 줄기(`design_save`) · * 종단 보기 몫(`B05_Profile_UI_Page_Actions.profileSaveParts`) · B05 · B04 서버 창구 · 세션 칸. fetch 는 가짜(요청 줄 기록) · * 그 밖 차례 창구 · 화면은 가짜. 종단 보기를 안 연 [저장](기본 창구) · 연 뒤 [저장]의 요청 줄을 견줌. * node helper_271_save_same.cjs (짝 = `test_271_save_same.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(), setTimeout, clearTimeout, }; /** 진짜로 읽는 파일 — 그 밖은 가짜(부르면 undefined). */ const REAL = new Set( [ "A00_Common/design/design_save.ts", "A00_Common/design/design_save_api.ts", "A00_Common/design/design_page_route.ts", "A00_Common/b_page_state.ts", "B05_Profile/B05_Profile_Api_Fetch.ts", "B05_Profile/B05_Profile_UI_Page_Actions.ts", "B04_PreProcess/B04_PreProcess_Api_Fetch.ts", ].map((rel) => path.join(ROOT, rel)), ); const CONFIG = { API_BASE_URL: "/api", API_TIMEOUT_MS: 1000, API_ANALYSIS_TIMEOUT_MS: 1000 }; 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) => { if (request === "@config/config_frontend") return CONFIG; 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 save = load(path.join(ROOT, "A00_Common", "design", "design_save.ts")); const actions = load(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Page_Actions.ts")); const state = load(path.join(ROOT, "A00_Common", "b_page_state.ts")); const route = load(path.join(ROOT, "A00_Common", "design", "design_page_route.ts")); const P = "P463"; const LATEST = { project_id: P, route: { id: 3 }, route_points: [ { x: 0, y: 0 }, { x: 100, y: 0 }, ], surface_params: { source_filter: "csf", method: "tin", smooth: true, contour_interval_m: 1 }, route_params: {}, }; let lines = []; globalThis.fetch = async (url, init) => { const method = init?.method ?? "GET"; lines.push(`${method} ${url}${init?.body ? ` ${init.body}` : ""}`); let reply = {}; if (url.includes("/surface/confirmed")) reply = { model_id: 7 }; else if (url.includes("/route/latest")) reply = LATEST; else if (url.includes("/route/confirm")) reply = { failed_parts: [] }; else if (url.includes("/design/save")) reply = { status: "success", steps: { uphill: {} } }; return { ok: true, status: 200, json: async () => reply }; }; /** 세션을 같은 출발점으로 — 노선 캐시(있으면) · 상단측 한 곳. */ function seed(withLatest) { window.sessionStorage = memoryStorage(); if (withLatest) state.writeState("latest", LATEST, P); state.writeState("uphill", { "40.000": "right" }, P); } async function run(parts) { lines = []; const failed = []; const ok = await save.saveDesign({ projectId: P, routeId: () => 3, parts, crossPart: async () => null, failed: (error) => failed.push(String(error?.message ?? error)), }); return { ok, failed, lines, uphillAfter: state.readState("uphill", P) }; } (async () => { route.setPageRouteId(P, 3); const out = {}; // ① 종단 보기를 안 연 [저장] = 기본 창구 seed(true); out.closed = await run(undefined); // ② 종단 보기를 연 뒤 [저장] = 종단 보기 몫 — 상단측 차례는 기본 조각 그대로(값 주인 = 세션 칸 · 472-5) seed(true); const parts = actions.profileSaveParts({ projectId: P, latest: () => LATEST, confirmedSurface: () => ({ model_id: 7 }), routeReady: () => true, bridge: () => ({ structuresSavePart: async () => null }), }); out.open = await run({ uphill: parts.parts.uphill }); out.openOwnUphill = typeof parts.parts.uphill; // ③ 새로고침해 B06 로 바로 — 노선 캐시 없음 = 서버에서 한 번 읽고 같은 본문 seed(false); out.noCache = await run(undefined); console.log(JSON.stringify(out)); })().catch((error) => { console.error(error); process.exit(1); });