// 302-1 수량산출 이음매 — 영역 모으기 → 인쇄 페이지 서버 몸(pdfBody · xlsxBody) 을 node 로. // node print_quantity_seam.mjs <저장소 뿌리> // 표준입력 = { project, responses: {"/quantity/…": 응답}, image_b64 } (302-3 시험 자료 꼴) // 표준출력 끝 줄 = { pdf: {title, sheets}, xlsx: {title, sheets} } import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { pathToFileURL } from "node:url"; const root = path.resolve(process.argv[2] ?? "."); const { build } = await import( pathToFileURL(path.join(root, "config/node_modules/vite/dist/node/index.js")).href ); const input = JSON.parse(fs.readFileSync(0, "utf-8")); // 화면 · 세션만 흉내 — 이 길은 DOM 을 안 그림 class Node { constructor() { this.children = []; this.classList = { toggle() {}, add() {}, remove() {}, contains: () => false }; this.style = {}; this.dataset = {}; } append(...kids) { this.children.push(...kids); } appendChild(kid) { this.children.push(kid); return kid; } addEventListener() {} setAttribute() {} } const session = new Map(); const storage = { getItem: (k) => (session.has(k) ? session.get(k) : null), setItem: (k, v) => session.set(k, String(v)), removeItem: (k) => session.delete(k), }; globalThis.document = { createElement: () => new Node(), createElementNS: () => new Node(), createTextNode: () => new Node(), head: new Node(), body: new Node(), addEventListener() {}, documentElement: new Node(), }; globalThis.window = { sessionStorage: storage, localStorage: storage, location: { origin: "http://localhost", hash: "" }, addEventListener() {}, setTimeout: (...a) => setTimeout(...a), clearTimeout: (id) => clearTimeout(id), }; globalThis.sessionStorage = storage; globalThis.localStorage = storage; const png = Buffer.from(input.image_b64, "base64"); globalThis.fetch = async (url) => { const at = String(url) .replace(/^.*\/projects\/[^/]+/, "") .split("?")[0]; if (at === "/quantity/milestone/image") return new Response(png, { status: 200, headers: { "Content-Type": "image/png" } }); const body = input.responses[at]; return body ? new Response(JSON.stringify(body), { status: 200, headers: { "Content-Type": "application/json" }, }) : new Response(JSON.stringify({ detail: `없음 ${at}` }), { status: 404 }); }; const outDir = fs.mkdtempSync(path.join(os.tmpdir(), "aislo-302-1-")); try { await build({ configFile: false, logLevel: "silent", root, resolve: { alias: { "@ui": path.join(root, "ui_template"), "@config": path.join(root, "config"), "@util": path.join(root, "common_util"), }, }, build: { outDir, minify: false, target: "es2022", lib: { entry: path.join(root, "resources/tester/print_frame/print_quantity_entry.ts"), formats: ["es"], fileName: "entry", }, }, }); const mod = await import(pathToFileURL(path.join(outDir, "entry.js")).href); const sheets = await mod.collectQuantitySheets(input.project); console.log( JSON.stringify({ pdf: mod.pdfBody("수량산출", sheets), xlsx: mod.xlsxBody("수량산출", sheets), }), ); } finally { fs.rmSync(outDir, { recursive: true, force: true }); }