/* 476-2 추천 모달 「적용될 초기 종단」 헬퍼 — `_Initial_Model` · `_Recommend_Profile` 을 그 자리에서 * 트랜스파일해 Node 로 돌려 서버 `initial_profile` 펴기 · 한 줄 · 그림 · 캐시 빼기를 JSON 한 벌로. */ 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(); 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 session = memoryStorage(); globalThis.window = { localStorage: memoryStorage(), sessionStorage: session }; 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.endsWith(".css")) return {}; if (request.startsWith("@ui/")) return loadTs(path.join(ROOT, "ui_template", `${request.slice(4)}.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); cache.set(full, box.exports); return box.exports; } const model = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Initial_Model.ts")); const prof = loadTs( path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Recommend_Profile.ts"), ); // 476-1 응답 꼴(분석 2.3) — 결과 옆 `initial_profile`. const initialRaw = { fingerprint: "abc", with_profile: false, curve_length_m: 20, stations_m: [0, 20, 40], ground_m: [100, 103, 101], plan_m: [100, 102, 101], line: [ [0, 100], [10, 101], [20, 102], [30, 101.5], [40, 101], ], pvi_count: 3, curve_count: 1, straightened: 2, max_grade_pct: 10.04, warnings: [], seconds: 0.1, }; const answer = { nodes: [ { x: 0, y: 0 }, { x: 40, y: 0 }, ], curves: [], initial_profile: initialRaw, }; const off = model.normalizeRouteInitial(answer, "follow", null, null, false); model.writeInitialChoice("p-476", off); const failed = model.normalizeRouteInitial( { ...answer, initial_profile: { error: "지반고 종단 — 측점이 모자랍니다" } }, "follow", null, null, false, ); const balance = { stationsM: [0, 20, 40], groundM: [100, 103, 101], planM: [100, 101, 101] }; process.stdout.write( JSON.stringify({ parsed: off.initialProfile, cached: model.readInitialChoice("p-476"), line: prof.initialLine(off.initialProfile), svgOff: prof.profileSvg(null, off.initialProfile), svgOn: prof.profileSvg(balance, off.initialProfile), svgOld: prof.profileSvg(balance), legendOff: prof.profileLegend(false, true), failed: failed.initialProfile, failedLine: prof.initialLine(failed.initialProfile), missing: model.normalizeRouteInitial({ ...answer, initial_profile: undefined }, "follow", null) .initialProfile, warnLine: prof.initialLine(prof.parseInitialProfile({ ...initialRaw, warnings: ["a", "b"] })), shortLine: prof.parseInitialProfile({ ...initialRaw, line: [[0, 100]] }), }), );