- POST /design/save 에 route(노선 초안) · carry(옛 노선 세션 칸) 칸 · 서버 = 노선 저장 → Node facility.rebase(rebasePipeDraft · rebaseStructureDraft) → 6-A 차례(새 노선) → Node stations.carry(routeCarryPatches) → 횡단 저장 - 되돌림 범위 = 노선 행 · 자식 표 · 단계 · 배수 폴더 · 노선 파일 · 지표면 확정(설계 지형 바꿈) - 손 상단측은 안 넘김(요구 274) · 노선 바뀐 [확정] = [저장](새 노선 본 뒤 다시) - 브라우저 = 노선 초안 + 사용자 칸만 한 본문 · 옛 차례 길(saveRouteDraft 뒤 flush · carryAfterRouteSave · keepDraftsOnNewRoute) · 부름 0 된 flush 창구 여섯 · saveCachedCrossPatches 걷음 - 등록부 R9 stations.carry · F10 facility.rebase · 옛 차례 단언 시험 한 본문 꼴로 · test_472_6_route_save(옛 길 = 새 길 · 실패 되돌림) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
4.2 KiB
JavaScript
107 lines
4.2 KiB
JavaScript
/* PLAN 443 단위검증 헬퍼 — 저장 누락 ① (H6 · M3 · M6).
|
|
* H6 구조물 저장 실패(409 · 그 밖) = 던짐 · 초안 남음 · 다음 [저장]이 줄에 안 막힘
|
|
* M3 상단측 차례 성공 = uphill 세션 비움 · 실패 = 그대로
|
|
* M6 확정 응답 failed_parts = 던짐(그 차례에서 멈춤)
|
|
* TS 를 그 자리에서 트랜스파일해 Node 로 돌림 · 서버 창구는 가짜. 짝 = `test_443_save_stops.py`. */
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
globalThis.window = { setTimeout, clearTimeout };
|
|
|
|
const anything = () =>
|
|
new Proxy({}, { get: (_target, key) => (key === "__esModule" ? false : () => undefined) });
|
|
|
|
function load(file, stubs) {
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", "require", js)(box.exports, box, (r) => stubs[r] ?? anything());
|
|
return box.exports;
|
|
}
|
|
|
|
const settle = (promise) =>
|
|
promise.then(
|
|
() => "ok",
|
|
(error) => String(error.message),
|
|
);
|
|
|
|
async function run() {
|
|
const out = {};
|
|
|
|
// ── H6 구조물 ──
|
|
class StructureConflictError extends Error {}
|
|
let pending = [{ structure_id: "s1" }];
|
|
let mode = "conflict";
|
|
const puts = [];
|
|
const bridgeMod = load(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Page_Structures.ts"), {
|
|
"./B05_Profile_Api_Structures": {
|
|
StructureConflictError,
|
|
fetchStructures: async () => ({ revision: 3, structures: [] }),
|
|
saveStructures: async (_p, revision, list) => {
|
|
puts.push(revision);
|
|
if (mode === "conflict") throw new StructureConflictError("409");
|
|
if (mode === "boom") throw new Error("서버 500");
|
|
return { revision: revision + 1 };
|
|
},
|
|
readPendingStructures: () => pending,
|
|
writePendingStructures: (_p, next) => (pending = next),
|
|
definitionStale: () => false,
|
|
staleDefinitionNotice: () => null,
|
|
},
|
|
"@ui/ui_template_elements": { showToast: () => undefined },
|
|
});
|
|
const quiet = new Proxy({}, { get: () => () => undefined });
|
|
const bridge = bridgeMod.createStructuresBridge({
|
|
projectId: "p1",
|
|
panel: () => ({ structures: quiet, values: () => ({}) }),
|
|
lane: quiet, // 시설 줄 한 벌(462)
|
|
isRestoring: () => false,
|
|
});
|
|
out.conflict = await settle(bridge.saveStructuresIfDirty());
|
|
out.pendingAfterConflict = pending;
|
|
mode = "boom";
|
|
out.boom = await settle(bridge.saveStructuresIfDirty()); // 앞 실패에 줄이 안 막힘
|
|
out.pendingAfterBoom = pending;
|
|
mode = "ok";
|
|
out.ok = await settle(bridge.saveStructuresIfDirty());
|
|
out.pendingAfterOk = pending;
|
|
out.puts = puts;
|
|
|
|
// ── M3 · M6 상단측 · 확정 하위 ──
|
|
const state = new Map();
|
|
let reply = {};
|
|
const bodies = [];
|
|
globalThis.fetch = async (_url, init) => {
|
|
bodies.push(JSON.parse(init.body));
|
|
return { ok: true, json: async () => reply };
|
|
};
|
|
const api = load(path.join(ROOT, "B05_Profile", "B05_Profile_Api_Fetch.ts"), {
|
|
"../A00_Common/b_page_state": {
|
|
readState: (name, p) => state.get(`${name}:${p}`) ?? null,
|
|
writeState: (name, value, p) => state.set(`${name}:${p}`, value),
|
|
clearState: (name, p) => state.delete(`${name}:${p}`),
|
|
},
|
|
"@config/config_frontend": { API_BASE_URL: "", API_TIMEOUT_MS: 1000 },
|
|
});
|
|
// 472-6 — 상단측 차례 = 한 본문 `uphill` 칸(본문은 세션 · 비우기는 서버가 다 저장한 뒤 조각 정리 ·
|
|
// 하위 차례 실패 = 서버가 그 차례에서 되돌림 · 옛 창구 `flushUphillOverrides` · `saveRouteParts` 걷음)
|
|
state.set("uphill:p1", { "40.000": "right" });
|
|
out.exported = ["flushUphillOverrides", "saveRouteParts", "routePartsBody"].filter(
|
|
(name) => typeof api[name] === "function",
|
|
);
|
|
out.uphillAfterBody = state.get("uphill:p1") ?? null;
|
|
out.bodies = bodies;
|
|
return out;
|
|
}
|
|
|
|
run().then(
|
|
(out) => process.stdout.write(JSON.stringify(out)),
|
|
(error) => {
|
|
process.stderr.write(String(error.stack ?? error));
|
|
process.exit(1);
|
|
},
|
|
);
|