-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathupdate_mermaid_diagrams.js
executable file
·145 lines (127 loc) · 5.58 KB
/
update_mermaid_diagrams.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env node
const commander = require('commander')
const chalk = require('chalk')
const fs = require('fs')
const path = require('path')
const puppeteer = require('puppeteer')
const error = message => {
console.log(chalk.red(`\n${message}\n`))
process.exit(1)
}
const checkConfigFile = file => {
if (!fs.existsSync(file)) {
error(`Configuration file "${file}" doesn't exist`)
}
}
commander
.option('-t, --theme [theme]', 'Theme of the chart, could be default, forest, dark or neutral. Optional. Default: default', /^default|forest|dark|neutral$/, 'default')
.option('-w, --width [width]', 'Width of the page. Optional. Default: 800', /^\d+$/, '800')
.option('-H, --height [height]', 'Height of the page. Optional. Default: 600', /^\d+$/, '600')
.option('-b, --backgroundColor [backgroundColor]', 'Background color. Example: transparent, red, \'#F0F0F0\'. Optional. Default: white')
.option('-c, --configFile [configFile]', 'JSON configuration file for mermaid. Optional')
.option('-C, --cssFile [cssFile]', 'CSS file for the page. Optional')
.option('-p --puppeteerConfigFile [puppeteerConfigFile]', 'JSON configuration file for puppeteer. Optional')
.parse(process.argv)
let { theme, width, height, backgroundColor, configFile, cssFile, puppeteerConfigFile } = commander
// check config files
let mermaidConfig = { theme }
if (configFile) {
checkConfigFile(configFile)
mermaidConfig = Object.assign(mermaidConfig, JSON.parse(fs.readFileSync(configFile, 'utf-8')))
}
let puppeteerConfig = {}
if (puppeteerConfigFile) {
checkConfigFile(puppeteerConfigFile)
puppeteerConfig = JSON.parse(fs.readFileSync(puppeteerConfigFile, 'utf-8'))
}
// check cssFile
let myCSS
if (cssFile) {
if (!fs.existsSync(cssFile)) {
error(`CSS file "${cssFile}" doesn't exist`)
}
myCSS = fs.readFileSync(cssFile, 'utf-8')
} else {
myCSS = ".node rect, rect.actor, .node polygon, polygon.labelBox, line.loopLine { fill: #ff8a65; stroke: #ff8a65; } text.actor, text.labelText>tspan {fill: white;font-size: large;} .label { color: white; } .edgeLabel { color: black; background-color: white; font-size: small } .label foreignObject { overflow: visible; }";
}
mermaidConfig = Object.assign(mermaidConfig, { themeCSS: myCSS });
// normalize args
width = parseInt(width)
height = parseInt(height)
backgroundColor = backgroundColor || 'transparent';
const outputDir = "./static/img/diagrams/";
if (!fs.existsSync(outputDir)) {
error(`Output directory "${outputDir}/" doesn't exist`)
}
async function processDef(browser, definition, output, config = {}) {
const page = await browser.newPage()
page.setViewport({ width, height })
await page.goto(`file://${path.join(__dirname, 'node_modules/mermaid.cli/index.html')}`)
if (backgroundColor)
await page.evaluate(`document.body.style.background = '${backgroundColor}'`)
page.on('console', consoleObj => console.log(consoleObj.text()));
await page.$eval('#container', (container, definition, config) => {
container.innerHTML = definition
window.mermaid.initialize(config)
window.mermaid.init(undefined, container)
}, definition, config)
if (output.endsWith('svg')) {
const svg = await page.$eval('#container', container => container.innerHTML)
fs.writeFileSync(output, svg)
} else if (output.endsWith('png')) {
const clip = await page.$eval('svg', svg => {
const react = svg.getBoundingClientRect()
return { x: react.left, y: react.top, width: react.width, height: react.height }
})
await page.screenshot({ path: output, clip, omitBackground: backgroundColor === 'transparent' })
} else { // pdf
await page.pdf({ path: output, printBackground: backgroundColor !== 'transparent' })
}
await page.close();
}
function* walk(dir) {
var list = fs.readdirSync(dir);
for (let file of list) {
file = dir + '/' + file;
var stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
yield* walk(file);
} else {
yield file;
}
};
}
let regex = /\{\{<\ mermaid([^>]*)>\}\}(.+?)(?=\{\{)/gs
let regexContext = /context="([^"]*)"/
let regexOptions = /options="([^"]*)"/
async function* getDefinitions() {
for (let file of walk("./content/en")) {
const content = fs.readFileSync(file, 'utf-8');
while (result = regex.exec(content)) {
if (result && result.length > 2) {
let context = regexContext.exec(result[1]) || "";
if (context) context = context.length > 1 ? context[1] : "";
let options = regexOptions.exec(result[1]);
if (options && options.length > 1) {
// Add quotes around json field keys: {abc:true} -> {"abc":true}
options = options[1].replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ');
// Parse options
options = options && options.length > 1 ? JSON.parse(options) : {};
}
yield { file: path.basename(file), options, context, definition: result[2] }
}
}
}
}
async function main() {
const browser = await puppeteer.launch(puppeteerConfig);
for await (let d of getDefinitions()) {
const out = outputDir + d.file.replace(".md", "_") + d.context + ".svg";
console.log("Render file", d.file, d.context);
let config = Object.assign(mermaidConfig, d.options);
config.themeCSS = myCSS;
await processDef(browser, d.definition, out, config);
}
browser.close();
}
main();