/* PLAN 429 단위검증 헬퍼 — [저장] 길 정합. * ④ 노선 저장 뒤 횡단 저장 = 고침이 없어도 한 번(`saveCachedCrossPatches`) * ⑨ 추가 측점 = 계산 묶음 입력(`plusStations` · stations 부터) · 가게 초안 바뀜 → 묶음에 넣음(`feedFacilities`) * TS 를 그 자리에서 트랜스파일해 Node 로 돌림 · 서버 창구 · 화면 모듈은 가짜. 짝 = `test_429_save_path.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 = { sessionStorage: null, localStorage: null, setTimeout, clearTimeout }; /** 아무 이름이나 받는 가짜 모듈 — 부르면 undefined. */ const anything = () => new Proxy({}, { get: (_target, key) => (key === "__esModule" ? false : () => undefined) }); function loader(stubs, real = () => false) { const cache = new Map(); const load = (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]; const target = path.join(path.dirname(full), `${request}.ts`); if (request.startsWith(".") && real(target)) return load(target); return anything(); }; new Function("exports", "module", "require", js)(box.exports, box, localRequire); cache.set(full, box.exports); return box.exports; }; return load; } async function run() { const out = {}; // ④ 고침이 없어도 횡단 저장 한 번 — 서버가 지금 종단으로 횡단을 다시 셈 const sent = []; const store = loader({ "./B06_Section_Api_Fetch": { saveSections: async (...args) => (sent.push(args.map((a) => a ?? null)), {}), fetchSectionDetail: async () => null, }, })(path.join(ROOT, "B06_Section", "B06_Section_Section_Store.ts")); out.noPatchReturn = await store.saveCachedCrossPatches("p1", 9); out.noPatchSent = sent; // ⑨ 묶음 — 추가 측점이 바뀌면 stations 부터 · 같은 값이면 안 셈 const DESIGN = path.join(ROOT, "A00_Common", "design"); const pipeMod = loader({}, () => true)(path.join(DESIGN, "logic", "design_pipeline.ts")); out.stationsDeps = pipeMod.STAGE_DEPS.stations; const ran = []; const stages = {}; for (const name of [...pipeMod.BROWSER_STAGES, ...pipeMod.AFTER_STAGES]) stages[name] = (ctx) => (ran.push(name), { name, plus: ctx.inputs.plusStations ?? null }); stages.follow = () => (ran.push("follow"), null); // 입력 고침 없음 const pipe = pipeMod.createDesignPipeline({ stages }); await pipe.start({ route: null, alignment: null, cross: null, pipes: [], structures: [], plusStations: [], }); ran.length = 0; await pipe.update("plus", [40]); out.plusRan = [...ran]; out.plusSeen = pipe.output("stations")?.plus ?? null; ran.length = 0; out.sameValue = pipe.update("plus", [40]); // 같은 값 = 차례 안 띄움(null) await new Promise((resolve) => setTimeout(resolve, 0)); out.sameRan = [...ran]; // ⑨ 먹이기 — 가게 추가 측점 초안이 바뀌면 묶음에 · 비면 저장분 · 되돌리기는 입력과 견줘 다를 때만 let restore = null; const listeners = new Map(); const values = new Map(); const fakeStore = { get: (key) => values.get(key) ?? null, set: (key, value) => ( values.set(key, value), (listeners.get(key) ?? []).forEach((fn) => fn(value)) ), subscribe: (key, fn) => { listeners.set(key, [...(listeners.get(key) ?? []), fn]); return () => undefined; }, }; const fed = []; const inputNow = { plusStations: [12] }; const feeder = loader({ "../../B05_Profile/B05_Profile_UI_Profile_History": { onPageHistory: (hooks) => ((restore = hooks.restore), () => undefined), }, "./design_save": { savingDesign: () => false }, })(path.join(DESIGN, "design_pipeline_facilities.ts")); feeder.feedFacilities({ projectId: "p1", store: fakeStore, ready: () => true, gone: () => false, saved: (key) => (key === "plusStations" ? [12] : []), input: (key) => inputNow[key] ?? null, routed: () => false, feed: (source, value) => fed.push([source, value]), resync: async () => undefined, }); fakeStore.set("plusStations", [12, 30]); fakeStore.set("plusStations", null); // 초안 비움 = 저장분 out.fed = [...fed]; fed.length = 0; values.set("plusStations", [12, 55]); // 되돌리기 = 세션만 되씀(알림 없음) restore?.(); out.restoreFed = fed.filter(([source]) => source === "plus"); return out; } run().then( (out) => console.log(JSON.stringify(out)), (error) => { console.error(error); process.exit(1); }, );