/* 구조물 명세 공용 틀 · 배관 명세 단위검증 헬퍼(PLAN 52-1) — `design_structure_spec.ts` · * `design_structure_pipe.ts` 를 그 자리에서 트랜스파일해 Node 로 돌림(꼴만 import). 결과 = JSON 한 벌. * 인자 `names` 면 배관 이름 표(정의 `종류.pipe.이름`)만 냄. */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const ROOT = path.join(__dirname, "..", ".."); const load = (file, deps = {}) => { const src = fs.readFileSync(path.join(ROOT, "A00_Common", "design", file), "utf8"); const js = ts.transpileModule(src, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const box = { exports: {} }; const near = (m) => (m.startsWith("./") ? load(`${m.slice(2)}.ts`) : require(m)); // 같은 폴더 명세 new Function("exports", "module", "require", js)(box.exports, box, (m) => deps[m] ?? near(m)); return box.exports; }; const s = load("design_structure_spec.ts"); const road = load("design_structure_road.ts"); const { PIPE_SPEC, STRUCTURE_SPECS } = load("design_structure_pipe.ts", { "./design_structure_road": road, }); // 노면공 › 콘크리트 포장(PLAN 52-10) — 옛 상세 칸은 남고 명세 키만 오감 if (process.argv[2] === "road") { const spec = STRUCTURE_SPECS.pavement_concrete; const old = { length_m: 12, before_m: 4, after_m: 8, thickness_cm: 20, joint_spacing_m: 6, pave_spec: "콘크리트", height_m: 0.2, }; const state = s.readState(spec, old); const edited = JSON.parse(JSON.stringify(state)); edited.detail[0].height = "0.35"; const cleared = JSON.parse(JSON.stringify(state)); cleared.detail[0].height = ""; process.stdout.write( JSON.stringify({ registered: Object.keys(STRUCTURE_SPECS), same: spec === road.PAVEMENT_SPEC, containers: spec.containers.map((c) => [c.id, c.title, c.required, c.link]), choices: road.PAVE_SPEC_CHOICES.map((c) => c.value), state, edited: s.writeOptions(spec, edited), cleared: s.writeOptions(spec, cleared), keys: s.specKeys(spec), retired: spec.retired, }), ); process.exit(0); } // 기타(PLAN 52-14) — 선택 컨테이너 「상세 내용」 비고 글 · 길이 상한 · 비우기 · 이름 표 if (process.argv[2] === "etc") { const spec = STRUCTURE_SPECS.etc; const old = { name: "배수판", etc_detail_2_note: "옛 비고", etc_detail_5_note: "둘째" }; const state = s.readState(spec, old); const edited = JSON.parse(JSON.stringify(state)); edited.detail[0].note = " 새 비고 "; edited.detail[1].note = ""; edited.detail.push({ note: "가".repeat(s.TEXT_MAX + 30) }); const out = s.writeOptions(spec, edited); process.stdout.write( JSON.stringify({ same: spec === road.ETC_SPEC, containers: spec.containers.map((c) => [c.id, c.title, c.required, c.prefix, c.link]), items: spec.containers[0].items.map((i) => [i.id, i.label, i.kind]), state, edited: out, max: s.TEXT_MAX, longLen: out.etc_detail_3_note?.length ?? 0, keys: s.specKeys(spec), names: s.nameTable(spec), links: [1, 2].map((n) => s.linkOf(spec.containers[0], n)), }), ); process.exit(0); } // 선택 컨테이너 「하나만」(PLAN 52-17) — 종류.컨테이너 → max · 옛 저장 둘은 다 읽힘 if (process.argv[2] === "max") { const max = {}; for (const [type, spec] of Object.entries(STRUCTURE_SPECS)) for (const c of spec.containers) if (!c.required) max[`${type}.${c.id}`] = c.max ?? null; const old = { ford_chute_1_structure: "도수로", ford_chute_2_structure: "돌붙임" }; const state = s.readState(STRUCTURE_SPECS.ford_pavement, old); process.stdout.write( JSON.stringify({ max, oldTwo: state.chute.length, back: s.writeOptions(STRUCTURE_SPECS.ford_pavement, state), }), ); process.exit(0); } if (process.argv[2] === "names") { process.stdout.write(JSON.stringify(s.nameTable(PIPE_SPEC))); process.exit(0); } const old = { pipe_kind: "흄관", wing_wall_type: "A-TYPE", pipe_diameter_mm: 1000, inlet_type: "집수정", inlet_structure: "L", inlet_basin_length_m: 2, inlet_basin_before_m: 1, inlet_basin_after_m: 1, outlet_type: "기슭막이", outlet_revet_form: "돌쌓기(메)", outlet_revet_length_m: 10, outlet_revet_height_m: 2.5, soil_add_2_structure: "기슭막이", soil_add_2_form: "바자", soil_add_5_length_m: 4, chute_add_1_structure: "도수로", }; const state = s.readState(PIPE_SPEC, old); const back = s.writeOptions(PIPE_SPEC, state); // 흙막이로 바꿈 → 갈래 키가 기슭막이 쪽 · also(inlet_structure revet) const soil = JSON.parse(JSON.stringify(state)); soil.inlet[0].structure = "기슭막이"; soil.inlet[0].form = "콘크리트"; soil.inlet[0].length = "6"; const soilOut = s.writeOptions(PIPE_SPEC, soil); const inlet = PIPE_SPEC.containers.find((c) => c.id === "inlet"); const form = inlet.items.find((i) => i.id === "form"); const keys = s.specKeys(PIPE_SPEC); const out = { containers: PIPE_SPEC.containers.map((c) => [c.id, c.title, c.required]), state, back, soilOut, formBasin: s.choicesOf(form, { structure: "집수정" }).map((c) => c.label), formSoil: s.choicesOf(form, { structure: "기슭막이" }).map((c) => c.label), formNone: s.branchOf(form, {}), outletForms: s .choicesOf( PIPE_SPEC.containers.find((c) => c.id === "outlet").items.find((i) => i.id === "form"), { structure: "기슭막이" }, ) .map((c) => c.label), keys, links: PIPE_SPEC.containers.map((c) => s.linkOf(c, 2)), split: { lengthFromSides: s.solveSplit({ length: "10", before: "3", after: "4" }, ["after", "before"]), beforeFromLength: s.solveSplit({ length: "10", before: "3", after: "4" }, ["after", "length"]), defaultKeepsLength: s.solveSplit({ length: "10", before: "3", after: "" }, ["before"]), blankKept: s.solveSplit({ length: "", before: "3", after: "4" }, ["before", "length"]), clamp: s.solveSplit({ length: "2", before: "", after: "5" }, ["after", "length"]), }, names: { renamed: s.itemLabel(inlet, form, { "inlet.form": "모양" }), title: s.containerTitle(inlet, {}, "그룹 이름"), titleOwn: s.containerTitle(inlet, { inlet: "유입 보호" }, "그룹 이름"), choice: s.choiceLabel(inlet, form, { value: "U", label: "ㄷ형" }, {}), }, }; process.stdout.write(JSON.stringify(out));