Files
Aislo/resources/tester/helper_52_structure_spec.cjs
T
eomsangdonandClaude Opus 5.5 6f1d0508a2 feat(design): 공용 틀 선택 컨테이너 「하나만」 표시(max) — 물넘이 포장 도수로/돌붙임 · 기타 상세 내용(52-17)
- 명세 컨테이너 칸 max — 차면 [추가] 숨김 · 빼면 다시 보임 · 옛 저장이 넘쳐도 다 보이고 지우지 않음
- 물넘이 포장 chute · 기타 detail = max 1 · 배관 흙막이 추가 · 도수로/돌붙임은 여러 개 그대로
- 시험: test_52_17_single_container · 헬퍼 max · ui_checks 52-3 · 52-10 을 하나만 흐름으로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
2026-10-06 00:50:55 +09:00

169 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 구조물 명세 공용 틀 · 배관 명세 단위검증 헬퍼(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));