Files
Aislo/resources/tester/helper_313_clear_all.cjs
T
eomsangdonandClaude Opus 5.5 bbd6254892 feat(구조물표): 322-1 부품 상자 · 표 읽기 — 목록 · 측점 · 카드 이름 · 형상 고르기 · 3D 몸체 · 알약 띠가 종류 키 · 군 글자 · 자리꼴 · managed_by 대신 구조물 표(catalog) 한 줄을 읽음 · 코드 숨김 목록 걷음 · ★ 넷 + 관 공식 한 벌
- 부품 상자 common_util_structure_parts.json(갈래마다 부품 · 읽는 칸 · 자리꼴 · 정본 · 42종 처음값) · 표 읽기 common_util_structure_catalog.ts / .py 짝(정의 반영 ⊕ 처음값 ⊕ 부품 끔) · 거울 시험 test_322_1_catalog_mirror
- 목록: pickGroups 군 차례 = 구조물군 열쇠 · 페이지 거르기 listPick(B05 both · B06 both + b06) · HIDDEN_PICK_GROUPS · HIDDEN_PICK_TYPES · pickable 걷음(옛 대피 셋 asRoad 그대로)
- 측점: structureStationMarks · pipeStationMarks · is_station_planting_type · resolve_extra_stations = 표 횡단도(anchor · span3 · none)
- 카드 이름: cardTitle / card_title 한 공식(빈칸 = 그 종류 정의 기본값) · 표시 이름이 정의 관종도 앎
- 형상: 벽 = shape wall(형태 = 형상칸.form · 물빼기 = 형상칸.weep) · 포장 = shape pavement(「사용 중」 거르기 없앰) · 맹암거 · 사토 · 관 지점 시설 세트 = shape
- 3D 몸체 = 그림 자료 주인 종류의 표 3D 부품 · 알약 띠 = 표 자리꼴 구간(관 지점 시설은 알약만)
- ★1 노출형 · 개거 횡단도 none · ★2 쇄석 화면에서도 포장층 · ★3 기슭막이 표 자리꼴 interval(정의 파일 그대로) · ★4 코드 숨김 10종 list hidden · ★5 관 빈칸 D800 → 정의 기본 D1000
- 옛 시험: 도움 파일 로더 27개가 표 모듈 공용 한 벌(helper_322_catalog_module) 씀 · 기대값 고침(272_1 · b05_extra_stations · roundtrip · 314 · 52_7 · walls 거울 · wall_drain_pipe)

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

184 lines
6.1 KiB
JavaScript

/* 313 [구조물 전체 삭제] 헬퍼 — 진짜 TS(목록 그리기 · 입력 배선)를 Node 로 돌려 표준출력 JSON 한 벌로.
* 확인창(@ui showConfirmDialog)은 답을 정해 둔 가짜로 막음.
*/
const fs = require("fs");
const path = require("path");
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
const CATALOG = require("./helper_322_catalog_module.cjs"); // 구조물 표(322-1)
const ROOT = path.join(__dirname, "..", "..");
const cache = new Map();
const confirms = [];
let answer = true;
const UI = {
showConfirmDialog: async (message, ok) => {
confirms.push([message, ok]);
return answer;
},
showToast: () => {},
};
const load = (file) => {
if (cache.has(file)) return cache.get(file);
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
cache.set(file, box.exports);
const near = (m) => {
if (CATALOG.isCatalogRequest(m)) return CATALOG;
if (m.startsWith("@ui/")) return UI;
if (m.startsWith("@config/")) return load(path.join(ROOT, "config", `${m.slice(8)}.ts`));
if (m.startsWith("@util/")) return load(path.join(ROOT, "common_util", `${m.slice(6)}.ts`));
if (m.endsWith(".json")) return require(path.join(path.dirname(file), m));
if (m.startsWith(".")) return load(path.join(path.dirname(file), `${m}.ts`));
return new Proxy({}, { get: () => () => {} });
};
new Function("exports", "module", "require", js)(box.exports, box, near);
return box.exports;
};
// DOM 흉내 — 목록이 쓰는 것만
class Node {
constructor(tag) {
this.tag = tag;
this.children = [];
this.className = "";
this.textContent = "";
this.style = { setProperty() {} };
this.listeners = {};
this.title = "";
}
get classList() {
const names = () => this.className.split(" ").filter(Boolean);
return {
add: (c) => (this.className = [...names(), c].join(" ")),
toggle: (c, on) => {
const rest = names().filter((n) => n !== c);
this.className = (on ? [...rest, c] : rest).join(" ");
},
contains: (c) => names().includes(c),
};
}
append(...kids) {
this.children.push(...kids);
}
replaceChildren(...kids) {
this.children = [...kids];
}
addEventListener(type, fn) {
this.listeners[type] = fn;
}
scrollIntoView() {}
}
globalThis.document = { createElement: (tag) => new Node(tag), activeElement: null };
globalThis.requestAnimationFrame = (fn) => fn();
const memory = new Map();
globalThis.window = {
sessionStorage: {
getItem: (k) => memory.get(k) ?? null,
setItem: (k, v) => memory.set(k, String(v)),
removeItem: (k) => memory.delete(k),
},
requestAnimationFrame: (fn) => fn(),
};
globalThis.sessionStorage = globalThis.window.sessionStorage;
const B05 = (f) => load(path.join(ROOT, "B05_Profile", `${f}.ts`));
const { renderStructureList } = B05("B05_Profile_UI_Structures_List");
const { bindStructuresEvents } = B05("B05_Profile_UI_Structures_Panel_Events");
const typeMap = new Map([
["sign", { type_id: "sign", name: "표지", group: "E" }],
["pipe", { type_id: "pipe", name: "배수관", group: "A" }],
]);
const sign = { structure_id: "s1", type_id: "sign", placement: "point", chainage_m: 40 };
const pipe = { chainage_m: 80, facility: "pipe", source: "auto" };
const draw = (structures, pipes, withClear = true) => {
const list = new Node("ul");
let cleared = 0;
renderStructureList({
list,
structures,
pipeFacilities: pipes,
typeMap,
intervalM: 20,
editingId: null,
selectedPipeChainage: null,
onSelectStructure: () => {},
onSelectPipe: () => {},
...(withClear ? { onClearAll: () => (cleared += 1) } : {}),
});
const last = list.children.at(-1);
const button = last?.children?.[0];
const clear = last?.className === "b05-route__irregular-clear";
if (clear) button.listeners.click();
return {
rows: list.children.length,
lastClass: last?.className ?? null,
button: clear
? { text: button.textContent, className: button.className, type: button.type }
: null,
cleared,
};
};
const listCases = {
filled: draw([sign], [pipe]),
empty: draw([], []),
noHandler: draw([sign], [pipe], false),
};
// 입력 배선 — 가짜 ctx(누름 듣개는 담기만)
const el = () => new Node("div");
const makeCtx = (structures, pipes) => {
const calls = { reset: 0, release: 0, removed: [], emit: 0 };
let pipeList = pipes.map((p) => ({ ...p }));
const ctx = {
groupSelect: el(),
typeSelect: el(),
primary: el(),
removeButton: el(),
resetButton: el(),
positionRow: el(),
memoField: el(),
optionRow: el(),
optionInputs: [],
anchorFields: { station: el(), remainder: el() },
startFields: { station: el(), remainder: el() },
endFields: { station: el(), remainder: el() },
facilityOptions: { root: el() },
structures,
pipeFacilities: () => pipeList,
projectId: "p",
callbacks: {
onListRelease: () => (calls.release += 1),
onPipeRemove: (at) => {
calls.removed.push(at);
pipeList = pipeList.filter((p) => p.chainage_m !== at); // 하나씩 빼기 길이 목록을 갈아 끼움
},
},
resetForm: () => (calls.reset += 1),
emit: () => (calls.emit += 1),
};
return { ctx, calls, left: () => structures.length + pipeList.length };
};
const runClear = async (structures, pipes, ok) => {
answer = ok;
confirms.length = 0;
const { ctx, calls, left } = makeCtx(structures, pipes);
const { clearAll } = bindStructuresEvents(ctx);
await clearAll();
return { confirms: [...confirms], calls, left: left() };
};
(async () => {
const pipes = [pipe, { chainage_m: 160.37, facility: "ford_pavement", source: "user" }];
const result = {
listCases,
confirmed: await runClear([{ ...sign }, { ...sign, structure_id: "s2" }], pipes, true),
cancelled: await runClear([{ ...sign }], pipes, false),
pipesOnly: await runClear([], [pipe], true),
nothing: await runClear([], [], true),
};
process.stdout.write(JSON.stringify(result));
})();