/* 54-9 종단 알약 글 단위검증 헬퍼 — TS 를 그 자리에서 트랜스파일해 Node 로 돌린다. * 결과는 표준출력에 JSON 한 벌. 화면 그릇은 쓰지 않는다(세션 저장소만 흉내). * * ⚠ 확장자가 `.cjs` 인 까닭은 `helper_b05_structures_form_summary.cjs` 머리와 같다. */ 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(); const session = new Map(); const fakeStorage = { getItem: (k) => session.get(k) ?? null, setItem: (k, v) => session.set(k, String(v)), removeItem: (k) => session.delete(k), }; globalThis.window = { sessionStorage: fakeStorage, localStorage: fakeStorage }; globalThis.sessionStorage = fakeStorage; globalThis.localStorage = fakeStorage; const STUBS = { "@config/config_frontend": { API_BASE_URL: "/api", API_TIMEOUT_MS: 1000 }, }; 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(".json")) return require(path.join(path.dirname(full), request)); if (request.startsWith(".")) return loadTs(path.join(path.dirname(full), `${request}.ts`)); if (request.startsWith("@")) return new Proxy({}, { get: () => () => {} }); return require(request); }; new Function("exports", "module", "require", js)(box.exports, box, localRequire); cache.set(full, box.exports); return box.exports; } const marks = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Structures_Marks.ts")); const typeMap = new Map([ ["etc", { type_id: "etc", name: "기타", style: { abbr: "기타" }, options: [] }], [ "retaining_wall", { type_id: "retaining_wall", name: "옹벽", style: { abbr: "옹" }, options: [] }, ], ]); const etc = (id, chainage, name) => ({ structure_id: id, type_id: "etc", placement: "point", chainage_m: chainage, options: name === undefined ? {} : { name }, }); const wall = (id, chainage) => ({ structure_id: id, type_id: "retaining_wall", placement: "point", chainage_m: chainage, options: {}, }); const run = (structures) => Object.fromEntries( [...marks.structurePillTexts(structures, typeMap)].map(([id, text]) => [id, text]), ); const out = { // 53-2 시나리오 — 같은 이름 둘 · 다른 이름 · 빈 이름 둘(빈칸 이름 = 빈 이름) scenario: run([ etc("e1", 40, "배수로정비"), etc("e2", 60, "울타리"), etc("e3", 80, ""), etc("e4", 100, "배수로정비"), etc("e5", 120, " "), ]), // 머리가 같은 다른 이름 — 갈릴 때까지 늘림 · 이름이 남의 머리면 그 이름 그대로 prefix: run([ etc("p1", 10, "콘크리트 블록"), etc("p2", 20, "콘크리트 옹벽"), etc("p3", 30, "배수로"), etc("p4", 40, "배수로공"), etc("p5", 50, "기타 시설"), etc("p6", 60), ]), // 다른 종류 규칙은 그대로 — 약호 + 중복 번호 · 기타 하나 빈 이름 = 「기타」 others: run([wall("w1", 10), wall("w2", 30), etc("x1", 20, "가로등"), etc("x2", 40)]), }; process.stdout.write(JSON.stringify(out));