1 | #!/usr/bin/env node
|
2 | 'use strict';
|
3 |
|
4 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
5 |
|
6 | const commander = require('commander');
|
7 | const chalk = require('chalk');
|
8 | const fs = require('fs');
|
9 | const path = require('path');
|
10 | const puppeteer = require('puppeteer');
|
11 |
|
12 | const pkg = require('./package.json');
|
13 |
|
14 | const error = message => {
|
15 | console.log(chalk.red(`\n${message}\n`));
|
16 | process.exit(1);
|
17 | };
|
18 |
|
19 | const checkConfigFile = file => {
|
20 | if (!fs.existsSync(file)) {
|
21 | error(`Configuration file "${file}" doesn't exist`);
|
22 | } else if (!/\.(?:json)$/.test(file)) {
|
23 | error(`Config file must end with ".json"`);
|
24 | }
|
25 | };
|
26 |
|
27 | commander.version(pkg.version).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('-i, --input <input>', 'Input mermaid file. Required.').option('-o, --output [output]', 'Output file. It should be either svg, png or pdf. Optional. Default: input + ".svg"').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);
|
28 |
|
29 | let { theme, width, height, input, output, backgroundColor, configFile, cssFile, puppeteerConfigFile } = commander;
|
30 |
|
31 |
|
32 | if (!input) {
|
33 | error('Please specify input file: -i <input>');
|
34 | }
|
35 | if (!fs.existsSync(input)) {
|
36 | error(`Input file "${input}" doesn't exist`);
|
37 | }
|
38 |
|
39 |
|
40 | if (!output) {
|
41 | output = input + '.svg';
|
42 | }
|
43 | if (!/\.(?:svg|png|pdf)$/.test(output)) {
|
44 | error(`Output file must end with ".svg", ".png" or ".pdf"`);
|
45 | }
|
46 | const outputDir = path.dirname(output);
|
47 | if (!fs.existsSync(outputDir)) {
|
48 | error(`Output directory "${outputDir}/" doesn't exist`);
|
49 | }
|
50 |
|
51 |
|
52 | let mermaidConfig = { theme };
|
53 | if (configFile) {
|
54 | checkConfigFile(configFile);
|
55 | mermaidConfig = Object.assign(mermaidConfig, JSON.parse(fs.readFileSync(configFile, 'utf-8')));
|
56 | }
|
57 | let puppeteerConfig = {};
|
58 | if (puppeteerConfigFile) {
|
59 | checkConfigFile(puppeteerConfigFile);
|
60 | puppeteerConfig = JSON.parse(fs.readFileSync(puppeteerConfigFile, 'utf-8'));
|
61 | }
|
62 |
|
63 |
|
64 | let myCSS;
|
65 | if (cssFile) {
|
66 | if (!fs.existsSync(cssFile)) {
|
67 | error(`CSS file "${cssFile}" doesn't exist`);
|
68 | } else if (!/\.(?:css)$/.test(cssFile)) {
|
69 | error(`CSS file must end with ".css"`);
|
70 | }
|
71 | myCSS = fs.readFileSync(cssFile, 'utf-8');
|
72 | }
|
73 |
|
74 |
|
75 | width = parseInt(width);
|
76 | height = parseInt(height);
|
77 | backgroundColor = backgroundColor || 'white';
|
78 |
|
79 | _asyncToGenerator(function* () {
|
80 | const browser = yield puppeteer.launch(puppeteerConfig);
|
81 | const page = yield browser.newPage();
|
82 | page.setViewport({ width, height });
|
83 | yield page.goto(`file://${path.join(__dirname, 'index.html')}`);
|
84 | yield page.evaluate(`document.body.style.background = '${backgroundColor}'`);
|
85 | const definition = fs.readFileSync(input, 'utf-8');
|
86 |
|
87 | yield page.$eval('#container', function (container, definition, mermaidConfig, myCSS) {
|
88 | container.innerHTML = definition;
|
89 | window.mermaid.initialize(mermaidConfig);
|
90 |
|
91 | if (myCSS) {
|
92 | const head = window.document.head || window.document.getElementsByTagName('head')[0];
|
93 | const style = document.createElement('style');
|
94 | style.type = 'text/css';
|
95 | if (style.styleSheet) {
|
96 | style.styleSheet.cssText = myCSS;
|
97 | } else {
|
98 | style.appendChild(document.createTextNode(myCSS));
|
99 | }
|
100 | head.appendChild(style);
|
101 | }
|
102 |
|
103 | window.mermaid.init(undefined, container);
|
104 | }, definition, mermaidConfig, myCSS);
|
105 |
|
106 | if (output.endsWith('svg')) {
|
107 | const svg = yield page.$eval('#container', function (container) {
|
108 | return container.innerHTML;
|
109 | });
|
110 | fs.writeFileSync(output, svg);
|
111 | } else if (output.endsWith('png')) {
|
112 | const clip = yield page.$eval('svg', function (svg) {
|
113 | const react = svg.getBoundingClientRect();
|
114 | return { x: react.left, y: react.top, width: react.width, height: react.height };
|
115 | });
|
116 | yield page.screenshot({ path: output, clip, omitBackground: backgroundColor === 'transparent' });
|
117 | } else {
|
118 |
|
119 | yield page.pdf({ path: output, printBackground: backgroundColor !== 'transparent' });
|
120 | }
|
121 |
|
122 | browser.close();
|
123 | })();
|