refs #745: add OCI HMM architecture diagrams
This commit is contained in:
118
tools/architecture/export-drawio.mjs
Normal file
118
tools/architecture/export-drawio.mjs
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/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(
|
||||
/<diagram\b[^>]*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 [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<mxfile host="app.diagrams.net" compressed="false">',
|
||||
diagram,
|
||||
"</mxfile>",
|
||||
].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 = `<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
window.inputXml = ${JSON.stringify(xml)};
|
||||
window.exportResult = null;
|
||||
window.exportError = null;
|
||||
window.addEventListener("message", (event) => {
|
||||
let message = event.data;
|
||||
try {
|
||||
if (typeof message === "string") message = JSON.parse(message);
|
||||
} catch (_error) {
|
||||
return;
|
||||
}
|
||||
if (!message || !message.event) return;
|
||||
if (message.event === "init") {
|
||||
event.source.postMessage(JSON.stringify({
|
||||
action: "load",
|
||||
xml: window.inputXml,
|
||||
autosave: 0
|
||||
}), "*");
|
||||
} else if (message.event === "load") {
|
||||
event.source.postMessage(JSON.stringify({
|
||||
action: "export",
|
||||
format: ${JSON.stringify(format)},
|
||||
xml: window.inputXml,
|
||||
border: 20,
|
||||
scale: 1
|
||||
}), "*");
|
||||
} else if (message.event === "export") {
|
||||
window.exportResult = message.data;
|
||||
} else if (message.event === "error") {
|
||||
window.exportError = JSON.stringify(message);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<iframe title="diagrams.net exporter" style="width:100vw;height:100vh;border:0"
|
||||
src="${embedUrl}"></iframe>`;
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user