/* M02 구조물 명세 이름 고치기(`M02_SO_Def_Spec_Model.ts` · PLAN 52-11) 단위검증 헬퍼 — * TS 를 그 자리에서 트랜스파일해 Node 로 돌리고 결과를 JSON 으로 냄(pytest 가 판정). * 정의는 진짜 `구조물정의.json` 을 읽어 메모리 사본만 고침(파일 쓰기 없음). */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const ROOT = path.join(__dirname, "..", ".."); // 이웃 TS(`./…`)는 같은 길로 읽음 — 명세 파일이 서로 import 함 const cache = {}; const load = (...parts) => { const file = path.join(ROOT, ...parts); if (cache[file]) return cache[file].exports; const js = ts.transpileModule(fs.readFileSync(file, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const box = (cache[file] = { exports: {} }); const near = (id) => id.startsWith(".") ? load(path.relative(ROOT, path.resolve(path.dirname(file), `${id}.ts`))) : require(id); new Function("exports", "module", "require", js)(box.exports, box, near); return box.exports; }; const m = load("M02_MasterTemplete", "StructOptions", "M02_SO_Def_Spec_Model.ts"); const { PIPE_SPEC } = load("A00_Common", "design", "design_structure_pipe.ts"); const real = () => JSON.parse( fs.readFileSync(path.join(ROOT, "resources", "master_template", "구조물정의.json"), "utf8"), ); const out = {}; const def = real(); const rows = m.specNameRows(def, PIPE_SPEC); out.levels = [0, 1, 2].map((lv) => rows.filter((r) => r.level === lv).length); out.unique = new Set(rows.map((r) => r.nameKey)).size === rows.length; out.pipeTitle = rows.find((r) => r.nameKey === "pipe"); out.optional = rows.find((r) => r.nameKey === "soil_add"); out.basinForm = rows.find((r) => r.nameKey === "inlet.form=I"); // 이름 고침 — 그룹 제목 · 항목 · 값 · 선택 컨테이너 const work = real(); const pick = (k) => m.specNameRows(work, PIPE_SPEC).find((r) => r.nameKey === k); m.setSpecName(work, "pipe", pick("pipe"), "관 본체"); m.setSpecName(work, "pipe", pick("pipe.diameter"), "관 지름"); m.setSpecName(work, "pipe", pick("pipe.diameter=800"), "Ø800"); m.setSpecName(work, "pipe", pick("soil_add"), "흙막이 더"); out.groupName = work.그룹.pipe.find((g) => g.id === "grv6lny").이름; out.names = ["pipe", "pipe.diameter", "pipe.diameter=800", "soil_add"].map( (k) => work.종류.pipe.이름[k] ?? null, ); out.reread = ["pipe", "pipe.diameter", "pipe.diameter=800", "soil_add"].map((k) => pick(k).label); // 구조는 그대로 — types · 동작 · 다른 종류 · 이름 표 키 수(새 키 없음) const before = real(); out.sameTypes = JSON.stringify(work.types) === JSON.stringify(before.types); out.sameKeys = Object.keys(work.종류.pipe.이름).length === Object.keys(before.종류.pipe.이름).length; // 이름 표가 빈 종류 — 명세 글로 읽고 고치면 이름 표가 생김 const bare = real(); delete bare.종류.pipe.이름; const bareRows = m.specNameRows(bare, PIPE_SPEC); out.bareLabel = bareRows.find((r) => r.nameKey === "inlet.structure=기슭막이").label; m.setSpecName( bare, "pipe", bareRows.find((r) => r.nameKey === "inlet"), "유입", ); out.bareGroup = bare.그룹.pipe.find((g) => g.id === "gnbf9m9").이름; // 정의 그룹 꼴(52-12) — 맹암거 = 그룹 제목 › 칸 · 옆도랑 = 그룹 밖 칸 › 선택지 const g = real(); const ud = g.types.find((t) => t.type_id === "cross_underdrain"); const udRows = m.groupNameRows(g, ud); out.udRows = udRows.map((r) => [r.level, r.nameKey, r.label]); m.setSpecName(g, ud.type_id, udRows[0], "맹암거 본체"); m.setSpecName(g, ud.type_id, udRows[1], "암거 높이 칸"); out.udGroup = g.그룹.cross_underdrain[0].이름; out.udLabel = ud.options[0].label; const side = g.types.find((t) => t.type_id === "ditch_side"); const sideRows = m.groupNameRows(g, side); out.sideHead = sideRows[0]; const lshape = sideRows.find((r) => r.nameKey === "form=L형"); out.sideChoice = lshape && [lshape.level, lshape.label]; m.setSpecName(g, side.type_id, lshape, "L 모양"); out.sideName = g.종류.ditch_side.이름["form=L형"]; out.sideChoices = side.options.find((o) => o.key === "form").choices; out.sideReread = m.groupNameRows(g, side).find((r) => r.nameKey === "form=L형").label; out.bareKind = m.groupNameRows( g, g.types.find((t) => t.type_id === "open_ditch"), ).length; process.stdout.write(JSON.stringify(out));