#!/usr/bin/env node import fs from "node:fs"; import path from "node:path"; import { chromium } from "playwright"; const sourcePath = path.resolve( process.argv[2] || "docs/architecture/hmm-ai-data-access-architecture.drawio", ); const outputDir = path.resolve(process.argv[3] || path.dirname(sourcePath)); const source = fs.readFileSync(sourcePath, "utf8"); const diagrams = [...source.matchAll( /]*name="([^"]+)"[^>]*>[\s\S]*?<\/diagram>/g, )]; if (diagrams.length !== 2) { throw new Error(`Expected 2 Draw.io pages, found ${diagrams.length}`); } const outputs = [ "hmm-ai-data-access-architecture-overview", "hmm-ai-data-access-architecture-security-flow", ]; const embedUrl = "https://embed.diagrams.net/?embed=1&ui=min&spin=1&proto=json"; function singlePageMxfile(diagram) { return [ '', '', diagram, "", ].join(""); } function decodeDataUrl(data, mimeType) { const base64Prefix = `data:${mimeType};base64,`; if (data.startsWith(base64Prefix)) { return Buffer.from(data.slice(base64Prefix.length), "base64"); } const utf8Prefix = `data:${mimeType},`; if (data.startsWith(utf8Prefix)) { return Buffer.from(decodeURIComponent(data.slice(utf8Prefix.length)), "utf8"); } throw new Error(`Unexpected diagrams.net export prefix: ${data.slice(0, 80)}`); } async function exportPage(browser, xml, format) { const page = await browser.newPage({ viewport: { width: 1600, height: 1000 } }); const html = ` `; await page.setContent(html, { waitUntil: "domcontentloaded" }); await page.waitForFunction( () => window.exportResult || window.exportError, null, { timeout: 120000 }, ); const result = await page.evaluate(() => ({ data: window.exportResult, error: window.exportError, })); await page.close(); if (result.error) { throw new Error(result.error); } return result.data; } fs.mkdirSync(outputDir, { recursive: true }); const browser = await chromium.launch({ headless: true }); try { for (let index = 0; index < diagrams.length; index += 1) { const xml = singlePageMxfile(diagrams[index][0]); for (const format of ["svg", "png"]) { const data = await exportPage(browser, xml, format); const mimeType = format === "svg" ? "image/svg+xml" : "image/png"; const output = path.join(outputDir, `${outputs[index]}.${format}`); fs.writeFileSync(output, decodeDataUrl(data, mimeType)); console.log(output); } } } finally { await browser.close(); }