Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use mermaid.mermaidAPI to render #16

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2019 Thomas Biesaart
Copyright 2019 Thomas Biesaart, Dan Fallon

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

Expand Down
103 changes: 79 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,93 @@
const path = require('path');
const visit = require('unist-util-visit');
const puppeteer = require('puppeteer');

async function render(browser, definition, theme, viewport, mermaidOptions) {
const page = await browser.newPage();
page.setViewport(viewport);
await page.goto(`file://${path.join(__dirname, 'render.html')}`);
await page.addScriptTag({
path: require.resolve('mermaid/dist/mermaid.min.js')
});
return await page.$eval('#container', (container, definition, theme, mermaidOptions) => {
container.innerHTML = `<div class="mermaid">${definition}</div>`;
class HeadlessMermaidError extends Error {
constructor(message, cause) {
const m = `${message}: ${cause.message}\n${cause.stack}`
super(m)
this.name = "HeadlessMermaidError"
this.cause = cause
}
}

async function render(page, id, definition) {
const {success,svgCode,error} = await page.evaluate((id, definition) => {
try {
window.mermaid.initialize({
...mermaidOptions,
theme
});
window.mermaid.init();
return container.innerHTML;
const svgCode = window.mermaid.mermaidAPI.render(id, definition)
return {
success: true,
svgCode,
error: null
}
;
} catch (e) {
return `${e}`
return {
success: false,
svgCode: null,
error: JSON.stringify(e, Object.getOwnPropertyNames(e))
}
}
}, definition, theme, mermaidOptions);
}, id, definition);

if(success){
return svgCode
} else {
throw new HeadlessMermaidError("failed to render SVG", JSON.parse(error))
}
}

function mermaidNodes(markdownAST, language) {
const result = [];
const result = []
visit(markdownAST, 'code', node => {
if ((node.lang || '').toLowerCase() === language) {
result.push(node);
result.push(node)
}
});
return result;
}

async function getMermaidBrowser(theme, viewport, mermaidOptions) {
try{
browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
const page = await browser.newPage();
page.setViewport(viewport);
await page.goto('data:text/html,<html></html>');
await page.addScriptTag({
path: require.resolve('mermaid/dist/mermaid.min.js')
});
const {success, error} = await page.evaluate((theme, mermaidOptions) => {

try {
window.mermaid.initialize({
...mermaidOptions,
theme
})

return {
success: true,
error: null
}
} catch (e) {
return {
success: false,
error: JSON.stringify(e, Object.getOwnPropertyNames(e))
}
}
}, theme, mermaidOptions);
if(success){
return {browser,page}
} else {
throw new HeadlessMermaidError("failed to initialize mermaid", JSON.parse(error))
}
} catch(e) {
if (e instanceof HeadlessMermaidError){
throw e
} else {
throw new HeadlessMermaidError("failed to initialize browser", e)
}
}
}

module.exports = async ({markdownAST},
{
language = 'mermaid',
Expand All @@ -51,13 +104,15 @@ module.exports = async ({markdownAST},
}

// Launch virtual browser
let browser;
try {
browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
const {browser,page} = await getMermaidBrowser(theme, viewport, mermaidOptions)

console.log("browser created.")
let count = 0
try {
await Promise.all(nodes.map(async node => {
node.type = 'html';
node.value = await render(browser, node.value, theme, viewport, mermaidOptions);
const svgCode = await render(page, `mermaid${count}`, node.value);
node.value = svgCode
}));
} finally {
if (browser) {
Expand Down
Loading