Files
Aislo/resources/tester/helper_260_note_cad.cjs
T
eomsangdonandClaude Opus 5.5 2399c533c6 feat(b06,b07): 표 위 CAD 칸 미리 넣음 = 구조물 조합 이름 + 좌측 패널 옵션 줄 (166-1)
- 구조물마다 조합 줄 뒤에 좌측 패널 옵션 줄 — 폼과 같은 컨테이너 · 이름 · 보이는 칸(`structureOptionLines`) · 구조 갈래에 안 맞는 옛 값 뺌 · 필수 상자 빈 칸 = 폼 기본값
- B06 [상세] 모달 = 화면 TS 직접 · B07 = 같은 TS 를 Node 번들(B07_DesignDetail_Note_Options_Node · build:b07-note)로 받아 파이썬 짝이 붙임 · 실패는 조합 줄만
- 번들 낡음 판정에 A00_Common/design 더함
- 시험 test_166_1(진짜 명세 · B07 = 화면 같은 줄) · test_260 · test_265 기대값

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LLCk2y5xE8YGVgjbTntWsY
2026-10-11 17:55:45 +09:00

149 lines
5.9 KiB
JavaScript

/* PLAN 260 단위검증 헬퍼 — [상세] 표 위 CAD 칸 · 옛 글 옮김 · 횡단배수 미리 넣음.
* `B06_Section_UI_Cross_Detail_Cad.ts` 를 그 자리에서 트랜스파일해 Node 로 돌린다(CAD · 세션 · 서버 = 흉내).
* 결과는 표준출력에 JSON 한 벌 · 인자 `mirror` = 표준입력 입력으로 거울 결과(260-4). 확장자 `.cjs` 까닭은 `helper_108_drag_box_hit.cjs` 머리와 같다.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const ROOT = path.join(__dirname, "..", "..");
// 인자 `load` = 표준입력 {pipes, structures, types} 를 세션 · 서버 흉내로 `loadNoteThings`(265-2)
const DATA = { pipes: [], structures: [], types: [] };
const STUBS = {
"@ui/cad_host/cad_host": { createCadHost: () => ({}) },
"../A00_Common/b_page_state": { readState: () => null, writeState: () => undefined },
"../A00_Common/design/design_selection": { PIPE_MATCH_M: 0.51 },
"../B04_PreProcess/B04_PreProcess_Api_Fetch": {
fetchDetailPipePoints: async () => ({ pipe_points: DATA.pipes }),
},
"../B05_Profile/B05_Profile_Api_Pipes_Draft": { readPendingPipes: () => null },
"../B05_Profile/B05_Profile_Api_Structures": {
fetchStructures: async () => ({ structures: DATA.structures }),
fetchStructureTypes: async () => DATA.types,
readPendingStructures: () => null,
},
// 좌측 패널 옵션 줄(166-1)은 test_166_1 이 진짜 명세로 봄 — 여기는 조합 줄 · 마크만
"../B05_Profile/B05_Profile_UI_Structures_Balloon": { structureOptionLines: () => [] },
};
function loadTs(file) {
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const localRequire = (request) => {
if (STUBS[request]) return STUBS[request];
throw new Error(`흉내 없는 모듈: ${request}`);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
// 관 길이 정수(265-3) = 실제 `pipeLengthWhole` · 조합 참조 읽기(265-2) = 실제(둘 다 import 없음)
STUBS["./B06_Section_UI_Cross_Culvert_Const"] = loadTs(
path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Culvert_Const.ts"),
);
STUBS["../common_util/common_util_summary_item"] = loadTs(
path.join(ROOT, "common_util", "common_util_summary_item.ts"),
);
const cad = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Detail_Cad.ts"));
const wall = (role, form, height, length) => ({
role,
structure: "기슭막이",
revet_form: form,
revet_height_m: height,
revet_length_m: length,
});
const culvert = (extra = {}) => ({
type: "pipe",
chainage_m: 1433,
pipe_kind: null,
diameter_m: 1.2,
min_cover_m: 0.5,
inlet: wall("inlet", "돌쌓기(찰)", 2, 10),
outlet: wall("outlet", "돌쌓기(메)", 2, 10),
...extra,
});
const section = (spec, design = { pipe_length_m: 22 }, chainage = 1433) => ({
chainage_m: chainage,
station_id: "s",
samples: [],
culvert: spec,
design,
});
/** 엔티티 → 비교하기 쉬운 꼴(종류 · 글 · 자리 · 색). */
const brief = (entities) =>
entities.map((entity) => ({
type: entity.type,
label: entity.shapeData.label ?? null,
align: entity.shapeData.options?.textAlign ?? null,
x: entity.shapeData.basePoint?.x ?? entity.shapeData.center?.x ?? null,
y: entity.shapeData.basePoint?.y ?? entity.shapeData.center?.y ?? null,
color: entity.lineColor,
layer: entity.layerId,
}));
const run = (sec, lines = []) => brief(cad.noteEntities(sec, "NO.71+13", lines));
const LINES = ["기슭막이 찰쌓기 2.0m", "돌붙임 찰붙임"];
const out = {
full: run(section(culvert()), LINES),
noLength: run(section(culvert(), {})),
basin: run(
section(
culvert({
inlet: {
role: "inlet",
structure: "집수정",
basin_form: "L",
basin_height_m: 1.7,
basin_length_m: 2,
},
}),
),
[],
),
chuteFallback: run(section(culvert({ chute: { structure: "도수로", thickness_m: 0.45 } })), []),
noSides: run(
section(
culvert({
inlet: { role: "inlet", structure: "" },
outlet: { role: "outlet", structure: "" },
}),
),
[],
),
none: run(section(undefined)),
ford: run(section(culvert({ body: "ford" }))),
hidden: run(section(culvert({ hidden_pipe: true }))),
neighbour: run(section(culvert(), { pipe_length_m: 22 }, 1440)),
// 마크 없이 조합 줄만(구조물 측점 · 265-2) = 측점부터 왼쪽 끝
linesOnly: run(section(undefined), LINES),
legacy: brief(cad.legacyNoteEntities("\nL형 측구 \n\n집수정 보강\n")),
legacyEmpty: cad.legacyNoteEntities(" ").length,
station: [
cad.stationNoLabel(1433, 20),
cad.stationNoLabel(1420, 20),
cad.stationNoLabel(1439.97, 20),
],
};
// 거울(260-4 · 265-2) — 시험이 표준입력으로 준 같은 입력 [{section, station, things, chainage, interval}]
// → TS 조합 줄 · 엔티티 · 측점 이름(파이썬 짝 `_Engine_Cad_CulvertNote` 와 대조)
if (process.argv[2] === "mirror") {
const cases = JSON.parse(fs.readFileSync(0, "utf8"));
const mirrored = cases.map((item) => {
const lines = cad.structureNoteLines(item.things ?? [], item.section.chainage_m);
return {
lines,
entities: cad.noteEntities(item.section, item.station, lines),
station: cad.stationNoLabel(item.chainage, item.interval),
at: cad.thingsAt(item.things ?? [], item.section.chainage_m).length,
};
});
process.stdout.write(JSON.stringify(mirrored));
} else if (process.argv[2] === "load") {
Object.assign(DATA, JSON.parse(fs.readFileSync(0, "utf8")));
cad.loadNoteThings("p").then((things) => process.stdout.write(JSON.stringify(things)));
} else process.stdout.write(JSON.stringify(out));