Files
Aislo/resources/tester/helper_152_5_pavement_pick.cjs
T
eomsangdonandClaude Opus 5.5 de0141b8fc refactor(472-6 6-B 한 벌): 노선 바뀜 넘김 규칙 · 세션 고침 얹기 · [저장] patch 바탕을 순수 TS 로 떼어 냄 — 동작 같음
- logic/B06_Section_Route_Carry.ts = 측점 열쇠 목록 · 측점 열쇠 칸 · 누가거리 칸 넘김(Station_Keys 몸통) · Station_Keys = 세션 겉
- B06_Section_Route_Carry_Patch.ts = 조정창 · 옮긴 고침 · 관 옵션 얹기 · crossPatchesFromCache · 서버용 routeCarryPatches(옛 carryAfterRouteSave 차례) · Section_Adjusts · Section_Store = 겉 · 내줌
- 칸 목록 USER_TOUCHED_KEYS · STRUCTURE_ADJUST_KEYS = logic/B06_Section_Design_Keys.ts · PIPE_MATCH_M = common_util_pipe_match.ts(옛 자리는 내줌)
- 시험 헬퍼 · 글 단언 시험 = 옮긴 자리로(목록 한 벌 자리만 바뀜)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:33:28 +09:00

104 lines
4.2 KiB
JavaScript

/* 152-5 노면공 강조 헬퍼 — 포장층 범위 표식 · 고른 노면공 포장층만 is-active · 카드 누름(③ 덮는 구조물)에서 노면공 뺌을
* Node 로 돌려 표준출력 JSON 한 벌로. TS 는 그 자리에서 트랜스파일 · SVG 그릇은 쓰는 만큼만 흉내.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const ROOT = path.join(__dirname, "..", "..");
class FakeNode {
constructor(tag) {
this.tagName = tag;
this.children = [];
this.dataset = {};
this.attrs = {};
this.style = {};
this._classes = new Set();
const self = this;
this.classList = {
contains: (name) => self._classes.has(name),
toggle: (name, on) => (on ? self._classes.add(name) : self._classes.delete(name)),
};
}
setAttribute(key, value) {
this.attrs[key] = String(value);
if (key === "class") this._classes = new Set(String(value).split(/\s+/).filter(Boolean));
}
append(...kids) {
this.children.push(...kids);
}
querySelectorAll(selector) {
const name = selector.slice(1);
const all = (node) => node.children.flatMap((kid) => [kid, ...all(kid)]);
return all(this).filter((kid) => kid.classList.contains(name));
}
}
globalThis.document = { createElementNS: (_, tag) => new FakeNode(tag) };
function loadTs(file, stubs = {}) {
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(`stub 없음: ${request}`);
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
const surface = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Design_Surface.ts"));
const selection = loadTs(path.join(ROOT, "A00_Common", "design", "design_selection.ts"), {
"../../common_util/common_util_pipe_match": { PIPE_MATCH_M: 0.51 }, // 찾는 거리 정의 자리(472-6)
"../b_page_state": { readState: () => null, writeState: () => {} },
});
const out = {};
// 포장층 — 같은 측점 노면공 둘(겹침) · 범위 표식
const svg = new FakeNode("svg");
const edge = (offset) => ({ offset_m: offset, elevation_m: 100 });
const design = { carriageway_edges: { left: edge(-2), right: edge(2) }, pavement_thickness_m: 0.2 };
const entry = (start, end) => ({
type_id: "pavement_concrete",
spec: null,
thickness_m: 0.2,
start_m: start,
end_m: end,
widening_on: true,
});
surface.appendPavementOverlay(
svg,
design,
(v) => v,
(v) => v,
[entry(0, 40), entry(20, 60)],
);
const layers = () => svg.querySelectorAll(".b06-chart__pavement");
const active = () => layers().map((layer) => layer.classList.contains("is-active"));
out.marks = layers().map((layer) => ({ ...layer.dataset }));
surface.highlightPavement(svg, { type_id: "pavement_concrete", start_m: 60, end_m: 20 });
out.pickSecond = active();
surface.highlightPavement(svg, { type_id: "gravel_surfacing", start_m: 20, end_m: 60 });
out.otherType = active();
surface.highlightPavement(svg, { type_id: "pavement_concrete", start_m: 0, end_m: 40 });
out.pickFirst = active();
surface.highlightPavement(svg, undefined);
out.cleared = active();
// 카드 누름 — ③ 덮는 구조물에서 노면공 뺌 · ① id 길은 그대로
const pave = { structure_id: "pave", type_id: "pavement_concrete", start_m: 0, end_m: 40 };
const wall = { structure_id: "wall", type_id: "retaining_wall", start_m: 10, end_m: 30 };
const coverable = (s) => s.type_id !== "pavement_concrete";
const resolve = (sel, list, fn) => selection.resolveSelection(sel, [], list, fn);
out.cover = {
default: resolve({ chainageM: 5, structureId: null }, [pave]).structureId,
skipped: resolve({ chainageM: 5, structureId: null }, [pave], coverable).structureId,
wallFirst: resolve({ chainageM: 20, structureId: null }, [pave, wall], coverable).structureId,
byId: resolve({ chainageM: 5, structureId: "pave" }, [pave], coverable).structureId,
};
process.stdout.write(JSON.stringify(out));