- 명세 항목 꼴 「글」(kind text · 길이 상한 TEXT_MAX 100 · 비우기 · 이름 표 · M02 이름 나무 꼴 「글」)
- 다 빈 선택 인스턴스도 첫 칸을 빈 글로 남겨 자리 지킴 — 잇기 · 집계 줄 · 다시 열기
- 기타 = 선택 컨테이너 「상세 내용」(비고 글 · etc_detail_{n}_note · 잇기 getcdetail{n}) · 종류 단위 잇기 줄 가림 규칙 그대로
- 집계 모음: 기타 건 이름(그룹) = 상세 종류 이름 · 비면 「기타」 · 컨테이너 건 = 이름 + n · 서버 컨테이너 표에 기타 짝
- 시험: test_52_14_etc_text · 헬퍼 etc · ui_checks 52-10 에 기타 컨테이너 단계 · 52-1 스크립트는 보이는 명세 폼을 잡음
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
152 lines
5.8 KiB
JavaScript
152 lines
5.8 KiB
JavaScript
/* 구조물 명세 공용 틀 · 배관 명세 단위검증 헬퍼(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);
|
||
}
|
||
|
||
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));
|