/* M02 일위대가 실무자료(324-4 · 338-3) 헬퍼 — `M02_MasterTemplete_Hopyo_Pick.ts`(고르기 창 「실무 호표」 덧줄) · * `M02_MasterTemplete_Hopyo_Choose.ts` 글 도우미 · `M02_MasterTemplete_Hopyo_Sheet.ts` 엑셀 보기 창 도우미(329 · 행 → 호표)를 * 트랜스파일해 Node 로 돌림 · fetch 대역이 부른 길 · 몸을 모음 · * stdin = {rows, built} · stdout = {calls, kinds, rows, picked, project, view, sheet} JSON. */ const fs = require("fs"); const path = require("path"); const { makeLoader } = require("./helper_ts_stub_loader.cjs"); const ROOT = path.join(__dirname, "..", ".."); const STUBS = { "@config/config_frontend": { API_BASE_URL: "/api" } }; // 고르기 창 · 자재 창 · 입력 창 · 원문 창은 DOM · 모듈 메타를 씀 — 대역(글 도우미만 시험) const STUB_FILES = [ "M02_MasterTemplete_Labor_Pick", "M02_Material_Pick", "M02_MasterTemplete_Labor_Api", "M02_MasterTemplete_Labor_Input", "M01_MasterData_UI_LogicLab_Source", ]; const stub = new Proxy({}, { get: (_t, k) => (k === "currentLanguageIndex" ? () => 0 : () => {}) }); const { loadTs } = makeLoader({ root: ROOT, requireFor: (full) => (request) => { if (STUBS[request]) return STUBS[request]; if (STUB_FILES.some((name) => request.endsWith(name))) return stub; if (request.startsWith(".") && !request.endsWith(".css")) return loadTs(`${path.resolve(path.dirname(full), request)}.ts`); return stub; }, }); (async () => { const input = JSON.parse(fs.readFileSync(0, "utf8")); const calls = []; global.fetch = async (url, init = {}) => { calls.push({ url, method: init.method ?? "GET", body: init.body ? JSON.parse(init.body) : null, }); const body = url.includes("/hopyo-picks") ? { 줄: input.rows } : input.built; return { status: 200, ok: true, json: async () => body }; }; const M02 = path.join(ROOT, "M02_MasterTemplete"); const pick = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Pick.ts")); const picked = []; const lib = { layer: "company", owner: "7", pick: (ref, name, alias) => picked.push({ ref, name, alias }), }; const wrapped = pick.withHopyo(lib); const rows = (await wrapped.more()).map(({ onPick: _, ...r }) => r); await pick.pickHopyo(input.rows[0], lib); const project = pick.withHopyo({ ...lib, layer: "project" }); const view = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Choose.ts")); const sheet = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Sheet.ts")); const api = loadTs(path.join(M02, "M02_MasterTemplete_Hopyo_Api.ts")); await api.readHopyoGrid({ layer: "company", owner: "7" }, "HP-000001"); const spans = [ { 번: 3, 이름: "임도표지석", 행: [20, 24] }, { 번: 4, 이름: "배수관", 행: [25, 30] }, ]; const out = { calls, kinds: wrapped.kindFilter.map((k) => k.value), rows, picked, project: project.more === undefined && project.kindFilter === undefined, view: { target: [ view.targetText({ 로직: "GF000101", 이름: "구조물터파기", 단위: "㎥" }), view.targetText({ 자재: "MT1", 이름: "레미콘", 규격: "25-21-120", 단위: "㎥" }), view.targetText({ 호표: 46, 단위: "㎡" }), ], inputs: view.inputsText({ 횟수: "4회사용시", 지역: "서울" }, ["보정작업"]), }, basis: (() => { const hit = { 조항: ["건설 공통 3-2-1"], 직종: ["특별인부"], 단위: true, 점수: 1.65, 까닭: "조항 같음 · 직종 특별인부 · 단위 맞음", }; const half = { ...hit, 직종: [] }; const trade = { 출처: [["건설품셈", "3-2-1"]], 직종: ["특별인부", "보통인부"], 행: [1, 1] }; const plain = { ...trade, 직종: ["보통인부"] }; return { ok: [hit, half, { ...hit, 단위: false }, { ...hit, 까닭: "앞 마디 같음" }, undefined].map( (b) => view.basisOk(b, trade), ), // 엑셀 직종이 보통인부뿐 · 없음(기계) = 직종 안 봄 plain: [view.basisOk(half, plain), view.basisOk(half, { ...trade, 직종: [] })], tag: [hit, half, undefined].map(view.basisTag), source: [ view.sourceText({ 출처: [["건설표준품셈", "3-2-1"]], 직종: ["특별인부"], 행: [93, 101] }), view.sourceText({ 출처: [], 직종: [], 행: [7, 7] }), view.sourceText(undefined), ], }; })(), sheet: { at: [19, 20, 22, 24, 25, 30, 31].map((row) => sheet.hopyoAtRow(spans, row)), span: sheet.spanText([20, 24], sheet.lastColumn({ 칸: { A1: {}, N24: {} }, 열: { O: {} } })), last: [sheet.lastColumn({ 칸: { Z9: {}, AA1: {} } }), sheet.lastColumn({ 칸: {} })], rows: [sheet.rowsText(4345), sheet.rowsText([93, 101])], }, }; process.stdout.write(JSON.stringify(out)); })().catch((error) => { process.stderr.write(String(error?.stack ?? error)); process.exit(1); });