/* PLAN 322-2 구조물 표 검사 · 편집 헬퍼 — 진짜 `M02_SO_Def_Check.ts` · `M02_SO_Def_Reflect.ts` · * `design_structure_spec.ts` 를 그 자리에서 트랜스파일해 Node 로 돌림 · 결과 = 표준출력 JSON 한 벌. * 입력 = argv[2] JSON `{cases: {이름: [정의, 앞 판|null]}, definition}`. 짝 = `test_322_2_check_mirror.py`. */ const fs = require("fs"); const path = require("path"); const ROOT = path.join(__dirname, "..", ".."); const ts = require(path.join(ROOT, "config", "node_modules", "typescript")); const cache = new Map(); function load(file) { const full = path.resolve(file); if (cache.has(full)) return cache.get(full); if (full.endsWith(".json")) return JSON.parse(fs.readFileSync(full, "utf8")); const js = ts.transpileModule(fs.readFileSync(full, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020, esModuleInterop: true, }, }).outputText; const box = { exports: {} }; cache.set(full, box.exports); const need = (spec) => { const base = path.join(path.dirname(full), spec); const hit = [base, `${base}.ts`, base.replace(/\.js$/, ".ts")].find( (p) => fs.existsSync(p) && fs.statSync(p).isFile(), ); if (!hit) throw new Error(`모름: ${spec} (${full})`); return load(hit); }; new Function("exports", "module", "require", js)(box.exports, box, need); return box.exports; } const SO = (name) => path.join(ROOT, "M02_MasterTemplete", "StructOptions", `${name}.ts`); const check = load(SO("M02_SO_Def_Check")); const reflect = load(SO("M02_SO_Def_Reflect")); const spec = load(path.join(ROOT, "A00_Common", "design", "logic", "design_structure_spec.ts")); const { STRUCTURE_SPECS } = load( path.join(ROOT, "A00_Common", "design", "logic", "design_structure_pipe.ts"), ); const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8")); const clone = (v) => JSON.parse(JSON.stringify(v)); const out = { cases: {} }; for (const [name, [doc, before]] of Object.entries(input.cases)) out.cases[name] = check.catalogProblems(doc, before); // 반영 손질 — 목록 + enabled 짝 · 처음 값이면 지움 · 형상칸 · 보임 · 부품 쓰는 종류 const def = clone(input.definition); const enabled = (id) => def.types.find((t) => t.type_id === id).enabled; const own = (id) => clone(reflect.reflectOf(def)[id] ?? null); reflect.setReflect(def, "wildlife_path", "목록", "both"); reflect.setReflect(def, "retaining_wall", "목록", "b06"); reflect.setReflect(def, "open_ditch", "횡단도", "none"); reflect.setReflect(def, "cross_drain_exposed", "횡단도", "anchor"); const setBefore = reflect.isSet(def, "cross_drain_exposed", "횡단도"); reflect.setShapeOpt(def, "soil_guard", "weep", true); const weepOn = own("soil_guard"); reflect.setShapeOpt(def, "soil_guard", "weep", false); reflect.setShown(def, "pipe", ["inlet_type", "없는키"], false); out.reflect = { wildlife: [own("wildlife_path"), enabled("wildlife_path")], wall: [own("retaining_wall"), enabled("retaining_wall")], openDitch: own("open_ditch"), exposed: [own("cross_drain_exposed"), setBefore], weepOn, weepOff: own("soil_guard"), shown: clone(def.표시.pipe), readPipe: [...reflect.readKeys(def, "pipe")].sort(), wallUsers: reflect.usersOf(def, "형상", "wall").map((row) => row.typeId), }; reflect.resetRow(def, "cross_drain_exposed"); reflect.resetRow(def, "retaining_wall"); out.reflect.reset = [own("cross_drain_exposed"), own("retaining_wall"), enabled("retaining_wall")]; // 저장 전 목록 + enabled 함께 — 목록은 그대로 · enabled = both 일 때만 참 const plain = clone(input.definition); const lists = (d) => [...reflect.rowsOf(d).values()].map((row) => `${row.typeId}:${row.list}`); const listBefore = lists(plain); reflect.syncEnabled(plain); out.sync = { same: JSON.stringify(lists(plain)) === JSON.stringify(listBefore), enabled: plain.types.filter((t) => t.enabled).map((t) => t.type_id), }; reflect.setPartOn(plain, "형상.wall", false); out.partOff = [clone(plain.부품), reflect.rowsOf(plain).get("retaining_wall").shape]; reflect.setPartOn(plain, "형상.wall", true); out.partOn = clone(plain.부품); // 바꿨다 되돌리면 저장할 것 없음(322-2 다듬기) — 목록 · 횡단도 · 형상칸 · 보임 · 부품 const base = clone(input.definition); const work = clone(input.definition); const steps = []; reflect.setReflect(work, "masonry_wet", "목록", "both"); steps.push(reflect.differs(work, base)); reflect.setReflect(work, "masonry_wet", "목록", "hidden"); reflect.setReflect(work, "open_ditch", "횡단도", "anchor"); reflect.setReflect(work, "open_ditch", "횡단도", "none"); reflect.setShapeOpt(work, "soil_guard", "form", "콘크리트"); reflect.setShapeOpt(work, "soil_guard", "form", "통나무·목재틀"); reflect.setShown(work, "pipe", ["wing_wall_type"], false); reflect.setShown(work, "pipe", ["wing_wall_type"], true); reflect.setPartOn(work, "3D.chute", false); reflect.setPartOn(work, "3D.chute", true); steps.push(reflect.differs(work, base)); out.revert = steps; // 명세 폼 숨김 — 저장 · 갈래 키가 모두 숨김인 칸 · 키 있는 칸이 모두 숨긴 상자 out.spec = {}; for (const [tid, sp] of Object.entries(STRUCTURE_SPECS)) { const keys = sp.containers.flatMap((c) => c.items.flatMap((i) => spec.specItemKeys(i))); const hidden = new Set(keys.slice(0, 1)); const all = new Set(keys); out.spec[tid] = { first: keys[0] ?? null, hiddenItems: sp.containers.flatMap((c) => c.items.filter((i) => spec.specItemHidden(i, hidden)).map((i) => `${c.id}.${i.id}`), ), allBoxes: sp.containers.filter((c) => spec.specContainerHidden(c, all)).map((c) => c.id), keyedBoxes: sp.containers .filter((c) => c.items.some((i) => spec.specItemKeys(i).length)) .map((c) => c.id), noneHidden: sp.containers.filter((c) => spec.specContainerHidden(c, new Set())).length, }; } process.stdout.write(JSON.stringify(out));