/* 고르기 모달 상단 표(224-1) 시험 헬퍼 — `ui_template_item_picker_table.ts` 를 트랜스파일해 * 표 부품 · 집계표 모듈 · 서버 읽기를 대역으로 갈아 끼우고 돌려 부름 기록을 JSON 한 벌로 냄. * 동적 `import()` 도 CommonJS 변환에서 같은 `require` 길을 타 대역이 먹음. * ⚠ 확장자가 `.cjs` 인 까닭은 `helper_b05_curve_radius_floor.cjs` 머리와 같다. */ const fs = require("fs"); const path = require("path"); const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); const ROOT = path.join(__dirname, "..", ".."); const UI = path.join(ROOT, "ui_template"); const log = []; const state = { numbersFail: false, tableFail: null }; const node = (props = {}) => ({ className: props.className ?? "", hidden: "attrs" in props && props.attrs && "hidden" in props.attrs, text: props.text ?? "", children: props.children ?? [], replaceChildren(...kids) { this.children = kids; }, }); const STUBS = { "./ui_template_elements": { el: (_tag, props) => node(props) }, "./ui_template_locale": { t: (key) => (key === "M02_PickerTableFailed" ? "표 실패 {value}" : "읽는 중"), }, "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch": { readTemplate: async (...args) => { log.push(["readTemplate", ...args]); if (state.tableFail) throw new Error(state.tableFail); return { 문서: { 열: [], tag: `${args[0]}|${args[4]}` } }; }, fetchStructureNumbersAt: async (...args) => { log.push(["numbers", ...args]); if (state.numbersFail) throw new Error("numbers down"); return { rv1: { 도번: "SD1" } }; }, }, "../M02_MasterTemplete/M02_MasterTemplete_Structure": { STRUCTURE_TABLE: "구조물집계표", comboView: (doc) => ({ ...doc, comboView: true }), numberLabels: (numbers) => ({ laborLabel: () => "", seenNumbers: numbers() }), }, "./sheet/ui_template_sheet": { createSheet: (host, doc, opts) => { const entry = { doc, opts, selected: [], destroyed: false, host }; log.push(["createSheet", entry]); host.replaceChildren({ sheet: true }); return { selectColumn: (id) => entry.selected.push(id), destroy: () => (entry.destroyed = true), }; }, }, }; const cache = new Map(); function loadTs(file) { const full = path.resolve(file); if (cache.has(full)) return cache.get(full); const js = ts.transpileModule(fs.readFileSync(full, "utf8"), { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText; const box = { exports: {} }; cache.set(full, box.exports); const localRequire = (request) => { if (STUBS[request]) return STUBS[request]; if (request.startsWith(".")) return loadTs(`${path.resolve(path.dirname(full), request)}.ts`); return require(request); }; new Function("exports", "module", "require", js)(box.exports, box, localRequire); cache.set(full, box.exports); return box.exports; } const flush = () => new Promise((resolve) => setTimeout(resolve, 20)); const row = (key, 열, layer, owner) => ({ key, 열, layer, owner }); const names = () => log.map((entry) => entry[0]); // 280-2 — 표는 층(+ 주인) · 열을 받음 const at = (r) => (r ? { layer: r.layer, owner: r.owner } : null); const show = (table, r) => table.show(at(r), r ? r.열 : ""); const picked = []; const creates = () => log.filter((entry) => entry[0] === "createSheet").map((entry) => entry[1]); (async () => { const { createComboTable } = loadTs(path.join(UI, "ui_template_item_picker_table.ts")); const data = loadTs(path.join(UI, "ui_template_item_picker_data.ts")); const out = {}; const mine = row("SS1", "rv1", "personal", "1/3"); const sameLayer = row("SS2", "rv2", "personal", "1/3"); const master = row("SS9", "rv9", "system", null); const table = createComboTable((colId) => picked.push(colId)); out.startHidden = table.root.hidden; show(table, null); out.nullHidden = table.root.hidden; out.nullCalls = names(); show(table, mine); out.shownHidden = table.root.hidden; await flush(); out.firstReads = log.filter((e) => e[0] !== "createSheet"); const first = creates()[0]; out.first = { count: creates().length, readOnly: first.opts.readOnly, lockHead: first.opts.lockHead, mode: first.opts.mode, combo: !!first.opts.combo, comboDoc: first.doc.comboView, docTag: first.doc.tag, numbersSeen: first.opts.seenNumbers, selected: first.selected, }; log.length = 0; show(table, sameLayer); // 같은 층 다른 조합 — 표 그대로 · 열만 await flush(); out.sameLayer = { calls: names(), selected: first.selected, destroyed: first.destroyed }; log.length = 0; show(table, master); // 다른 층 — 그 층 표로 바뀜 await flush(); out.otherLayer = { reads: log.filter((e) => e[0] === "readTemplate"), creates: creates().length, oldDestroyed: first.destroyed, selected: creates()[0].selected, docTag: creates()[0].doc.tag, }; log.length = 0; show(table, null); out.hideAgain = table.root.hidden; // 읽는 사이에 다른 조합을 고름 — 마지막 것만 그려짐 log.length = 0; show(table, mine); show(table, master); await flush(); out.race = { creates: creates().length, docTag: creates()[0]?.doc.tag }; // 번호 읽기 실패 — 표는 그려짐 log.length = 0; state.numbersFail = true; const lone = createComboTable((colId) => picked.push(colId)); show(lone, mine); await flush(); out.numbersFail = { creates: creates().length, seen: creates()[0]?.opts.seenNumbers }; state.numbersFail = false; // 표 읽기 실패 — 까닭 글 · 표 없음 log.length = 0; state.tableFail = "그 층은 아직 만든 것이 없음"; const broken = createComboTable((colId) => picked.push(colId)); show(broken, mine); await flush(); out.tableFail = { creates: creates().length, text: broken.root.children[0].text }; out.keys = { mineSame: data.tableKey(mine) === data.tableKey(sameLayer), layerDiffers: data.tableKey(mine) !== data.tableKey(master), ownerDiffers: data.tableKey(mine) !== data.tableKey(row("SS1", "rv1", "personal", "1/4")), mine: data.tableKey(mine), }; // 280-2 — 표에서 고른 열은 부른 쪽에 넘김 · 열 없는 고름(colId null)은 안 넘김 state.tableFail = null; const fresh = createComboTable((colId) => picked.push(colId)); log.length = 0; show(fresh, mine); await flush(); const sheetOpts = creates()[0].opts; sheetOpts.onSelect({ colId: "rv2" }); sheetOpts.onSelect({ colId: null }); out.onColumn = picked.slice(-1); // 층만 바꿈(고른 열 없음) — 그 층 표를 그리고 열은 안 고름 log.length = 0; fresh.show({ layer: "system", owner: null }, ""); await flush(); out.layerOnly = { reads: log.filter((e) => e[0] === "readTemplate"), selected: creates()[0].selected, }; console.log(JSON.stringify(out)); })().catch((error) => { console.error(error); process.exit(1); });