Files
Aislo/resources/tester/helper_322_2_check.cjs
T
eomsangdonandClaude Opus 5.5 0da2fa0767 fix(구조물표): 322-2 다듬기(브레인 화면 확인) — 화면에 영어 키 안 보임 · 검사 글 한국어(화면 · 서버 짝) · 부품 탭 읽는 칸 = 정의 이름 · 줄바꿈 · 한눈 표 폭 줄임 · 바꿨다 되돌리면 [저장] 꺼짐
- 자리꼴 점 · 구간 · 터 · 정본 관 지점 · 구조물(키는 툴팁) · 고르기 글 = 부품 짧은 이름(괄호 설명 · 키는 툴팁) · 횡단도 없음 = 「안 만듦」 · 「벽 스윕」 → 「벽」 · 종류 키는 툴팁
- 검사 글: 「형상이 「없음」이면 횡단도도 「안 만듦」」 · 부품 짧은 이름 · 칸 이름 · 종류 이름(M02_SO_Def_Check.ts = M02_SO_Check.py)
- 부품 탭: 읽는 칸 = 그 부품을 쓰는 종류의 칸 이름(단위) · 표 줄바꿈(table-layout fixed)
- 한눈 표 형상칸 「기본 형태」 = 그림 형태 고르기(REVET_FORMS)
- [저장] 켬 = 저장할 꼴(tidy · 목록 짝 enabled)끼리 지금 판과 다를 때만(M02_SO_Def_Reflect.differs)
- 시험: 322-2 검사 글 · 되돌림 견본

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
2026-10-14 16:29:30 +09:00

128 lines
5.9 KiB
JavaScript

/* 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", "design_structure_spec.ts"));
const { STRUCTURE_SPECS } = load(
path.join(ROOT, "A00_Common", "design", "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));