- 시험: test_346_3_route_save_screen 9 · 관련 97 통과 · typecheck 통과 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn
175 lines
6.1 KiB
JavaScript
175 lines
6.1 KiB
JavaScript
/* 346-3 노선 저장 이음 헬퍼 — `B05_Profile_UI_RouteEdit_Apply.ts` 를 트랜스파일해 서버 · 화면 창구는 가짜로,
|
|
* 가게 · 캐시(`design_store` · `b_page_state`)는 진짜로 돌림. 보낸 본문 · 부른 차례를 적어 JSON 한 벌로 냄.
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
|
|
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;
|
|
},
|
|
};
|
|
}
|
|
const session = memoryStorage();
|
|
globalThis.window = { sessionStorage: session, localStorage: memoryStorage() };
|
|
globalThis.sessionStorage = session;
|
|
|
|
const calls = [];
|
|
const bodies = [];
|
|
let failReplan = false;
|
|
const STUBS = {
|
|
"@ui/ui_template_elements": {
|
|
showToast: (text, kind) => calls.push(`toast:${kind}:${text}`),
|
|
showLoadingOverlay: () => calls.push("overlay:on"),
|
|
hideLoadingOverlay: () => calls.push("overlay:off"),
|
|
},
|
|
"../A00_Common/router": {
|
|
currentRoute: () => "b05-profile",
|
|
remountRoute: () => calls.push("remount"),
|
|
},
|
|
"../B06_Section/B06_Section_Section_Store": {
|
|
invalidateSectionDetail: (_p, routeId) => calls.push(`invalidate:${routeId ?? "all"}`),
|
|
loadSectionDetail: async (_p, routeId) => (calls.push(`load:${routeId}`), { tag: routeId }),
|
|
saveCachedCrossPatches: async (_p, routeId) => (calls.push(`crossSave:${routeId}`), 1),
|
|
},
|
|
"../B06_Section/B06_Section_Station_Keys": {
|
|
useStationKeys: (_p, routeId, detail) => calls.push(`keys:${routeId}:${detail.tag}`),
|
|
carryStationDrafts: (_p, from, to, opts) => (
|
|
calls.push(`carry:${from}->${to}${opts?.quiet ? ":quiet" : ""}`),
|
|
2
|
|
),
|
|
},
|
|
"./B05_Profile_Api_Fetch": { clearRouteLatestCache: () => calls.push("latest:clear") },
|
|
"./B05_Profile_Api_Replan": {
|
|
replanRoute: async (_p, body) => {
|
|
bodies.push(JSON.parse(JSON.stringify(body)));
|
|
calls.push("replan");
|
|
if (failReplan) throw new Error("체인 실패");
|
|
return {
|
|
route_id: 9,
|
|
pipes: { kept: 3, crossing: 1, concave: 2 },
|
|
structures: { moved: 1, far: 0 },
|
|
cross_dropped: 1,
|
|
drainage_stale: true,
|
|
};
|
|
},
|
|
},
|
|
};
|
|
|
|
const cache = new Map();
|
|
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);
|
|
return box.exports;
|
|
}
|
|
|
|
const { useDesignStore } = loadTs(path.join(ROOT, "A00_Common", "design", "design_store.ts"));
|
|
const { readState, writeState } = loadTs(path.join(ROOT, "A00_Common", "b_page_state.ts"));
|
|
const apply = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Apply.ts"));
|
|
|
|
(async () => {
|
|
const out = {};
|
|
const draft = {
|
|
rev: 3,
|
|
nodes: [
|
|
[0, 0],
|
|
[5, 5],
|
|
[10, 0],
|
|
],
|
|
curveOn: [true, true, true],
|
|
};
|
|
// 편집기 없음 — 가게 routeDraft 를 보냄 · 없으면 null
|
|
out.noneAtAll = await apply.pendingRouteSave("p1");
|
|
useDesignStore("p1", null).set("routeDraft", draft);
|
|
out.storeOnly = await apply.pendingRouteSave("p1");
|
|
|
|
// 편집기 등록 — 안 바뀌었으면 null(가게에 초안이 있어도 편집기가 정함) · 바뀌면 계약 꼴
|
|
let changed = false;
|
|
let kept = 0;
|
|
let rebuilt = 0;
|
|
apply.bindRouteApply({
|
|
projectId: "p1",
|
|
nodes: () => ({
|
|
planned: [
|
|
[0, 0],
|
|
[5, 5],
|
|
[10, 0],
|
|
],
|
|
curveOn: [true, false],
|
|
curveRadius: [null, 25],
|
|
}),
|
|
changed: () => changed,
|
|
terrain: () => "sheet",
|
|
stationSnap: () => true,
|
|
initial: { current: () => ({ mode: "follow" }), keep: () => (kept += 1) },
|
|
profileShown: async () => true,
|
|
onApplied: () => (rebuilt += 1),
|
|
});
|
|
out.unchanged = await apply.pendingRouteSave("p1");
|
|
changed = true;
|
|
const body = await apply.pendingRouteSave("p1");
|
|
out.body = body;
|
|
|
|
// 저장 — 가게 초안 비움 · 결과 캐시 비움 · 추천 다시 적음
|
|
writeState("design-stations", [{ k: 1 }], "p1");
|
|
const saved = await apply.saveRouteDraft("p1", body);
|
|
out.savedRouteId = saved.route_id;
|
|
out.storeAfterSave = useDesignStore("p1", null).get("routeDraft");
|
|
out.keptAfterSave = kept;
|
|
out.summary = apply.routeSaveSummary(saved, 2);
|
|
|
|
// 저장 뒤 횡단 초안 넘김 차례 — 새 상세 → 측점 열쇠 → 넘김 → 넘긴 고침 저장
|
|
calls.length = 0;
|
|
out.outside = await apply.carryAfterRouteSave("p1", 7, 9);
|
|
out.carryCalls = [...calls];
|
|
|
|
// 추천 [적용] — as_initial · 잠금 막 · 초안 비움 · 다시 세움
|
|
useDesignStore("p1", null).set("routeDraft", draft);
|
|
writeState("pipes", [{ chainage_m: 1 }], "p1");
|
|
calls.length = 0;
|
|
const snapshot = {
|
|
planned: [
|
|
[1, 1],
|
|
[9, 9],
|
|
],
|
|
curveOn: [true, true],
|
|
curveRadius: [null, null],
|
|
};
|
|
out.recommendOk = await apply.saveRecommendedRoute("p1", snapshot, { mode: "earthwork" }, true);
|
|
out.recommendBody = bodies[bodies.length - 1];
|
|
out.recommendCalls = calls.filter((c) => !c.startsWith("toast:"));
|
|
out.recommendDraftsLeft = {
|
|
route: useDesignStore("p1", null).get("routeDraft"),
|
|
pipes: readState("pipes", "p1"),
|
|
};
|
|
out.rebuilt = rebuilt;
|
|
|
|
// 추천 저장 실패 — false · 오류 한 줄 · 다시 안 세움
|
|
failReplan = true;
|
|
calls.length = 0;
|
|
out.recommendFail = await apply.saveRecommendedRoute("p1", snapshot, null, false);
|
|
out.recommendFailCalls = [...calls];
|
|
out.rebuiltAfterFail = rebuilt;
|
|
console.log(JSON.stringify(out));
|
|
})();
|