@mermaid-js/mermaid-cli 8.12.1 → 8.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,6 +99,7 @@ it installs (`mmdc`). `npx -p @mermaid-js/mermaid-cli mmdc -h`
99
99
  ## Known issues
100
100
 
101
101
  1. [Linux sandbox issue](docs/linux-sandbox-issue.md)
102
+ 2. [Docker permission denied issue](docs/docker-permission-denied.md)
102
103
 
103
104
  ## For contributors
104
105
 
package/index.bundle.js CHANGED
@@ -1,13 +1,20 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';
2
+ "use strict";
3
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"); }); }; }
4
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
5
+
6
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
5
7
 
6
8
  process.title = "mmdc";
9
+
7
10
  const commander = require('commander');
11
+
8
12
  const chalk = require('chalk');
13
+
9
14
  const fs = require('fs');
15
+
10
16
  const path = require('path');
17
+
11
18
  const puppeteer = require('puppeteer');
12
19
 
13
20
  const pkg = require('./package.json');
@@ -25,13 +32,13 @@ const checkConfigFile = file => {
25
32
 
26
33
  const inputPipedFromStdin = () => fs.fstatSync(0).isFIFO();
27
34
 
28
- const getInputData = (() => {
35
+ const getInputData = /*#__PURE__*/function () {
29
36
  var _ref = _asyncToGenerator(function* (inputFile) {
30
- return new Promise(function (resolve, reject) {
37
+ return new Promise((resolve, reject) => {
31
38
  // if an input file has been specified using '-i', it takes precedence over
32
39
  // piping from stdin
33
40
  if (typeof inputFile !== 'undefined') {
34
- return fs.readFile(inputFile, 'utf-8', function (err, data) {
41
+ return fs.readFile(inputFile, 'utf-8', (err, data) => {
35
42
  if (err) {
36
43
  return reject(err);
37
44
  }
@@ -48,11 +55,9 @@ const getInputData = (() => {
48
55
  data += chunk;
49
56
  }
50
57
  });
51
-
52
58
  process.stdin.on('error', function (err) {
53
59
  reject(err);
54
60
  });
55
-
56
61
  process.stdin.on('end', function () {
57
62
  resolve(data);
58
63
  });
@@ -62,124 +67,179 @@ const getInputData = (() => {
62
67
  return function getInputData(_x) {
63
68
  return _ref.apply(this, arguments);
64
69
  };
65
- })();
70
+ }();
66
71
 
67
72
  const convertToValidXML = html => {
68
- var xml = html;
69
-
70
73
  // <br> tags in valid HTML (from innerHTML) look like <br>, but they must look like <br/> to be valid XML (such as SVG)
71
- xml.replace(/<br>/gi, '<br/>');
72
-
73
- return xml;
74
+ return html.replace(/<br>/gi, '<br/>');
74
75
  };
75
76
 
76
- 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('-s, --scale [scale]', 'Puppeteer scale factor, default 1. Optional').option('-f, --pdfFit [pdfFit]', 'Scale PDF to fit chart').option('-p --puppeteerConfigFile [puppeteerConfigFile]', 'JSON configuration file for puppeteer. Optional').parse(process.argv);
77
-
77
+ 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. Files ending in .md will be treated as Markdown and all charts (e.g. ```mermaid (...)```) will be extracted and generated. 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('-s, --scale [scale]', 'Puppeteer scale factor, default 1. Optional').option('-f, --pdfFit [pdfFit]', 'Scale PDF to fit chart').option('-q, --quiet', 'Suppress log output').option('-p --puppeteerConfigFile [puppeteerConfigFile]', 'JSON configuration file for puppeteer. Optional').parse(process.argv);
78
78
  const options = commander.opts();
79
+ let {
80
+ theme,
81
+ width,
82
+ height,
83
+ input,
84
+ output,
85
+ backgroundColor,
86
+ configFile,
87
+ cssFile,
88
+ puppeteerConfigFile,
89
+ scale,
90
+ pdfFit,
91
+ quiet
92
+ } = options; // check input file
79
93
 
80
- let { theme, width, height, input, output, backgroundColor, configFile, cssFile, puppeteerConfigFile, scale, pdfFit } = options;
81
-
82
- // check input file
83
94
  if (!(input || inputPipedFromStdin())) {
84
- error('Please specify input file: -i <input>');
95
+ console.log(chalk.red(`\nPlease specify input file: -i <input>\n`));
96
+ commander.help();
97
+ process.exit(1);
85
98
  }
99
+
86
100
  if (input && !fs.existsSync(input)) {
87
101
  error(`Input file "${input}" doesn't exist`);
88
- }
102
+ } // check output file
103
+
89
104
 
90
- // check output file
91
105
  if (!output) {
92
106
  // if an input file is defined, it should take precedence, otherwise, input is
93
107
  // coming from stdin and just name the file out.svg, if it hasn't been
94
108
  // specified with the '-o' option
95
109
  output = input ? input + '.svg' : 'out.svg';
96
110
  }
111
+
97
112
  if (!/\.(?:svg|png|pdf)$/.test(output)) {
98
113
  error(`Output file must end with ".svg", ".png" or ".pdf"`);
99
114
  }
115
+
100
116
  const outputDir = path.dirname(output);
117
+
101
118
  if (!fs.existsSync(outputDir)) {
102
119
  error(`Output directory "${outputDir}/" doesn't exist`);
103
- }
120
+ } // check config files
121
+
122
+
123
+ let mermaidConfig = {
124
+ theme
125
+ };
104
126
 
105
- // check config files
106
- let mermaidConfig = { theme };
107
127
  if (configFile) {
108
128
  checkConfigFile(configFile);
109
129
  mermaidConfig = Object.assign(mermaidConfig, JSON.parse(fs.readFileSync(configFile, 'utf-8')));
110
130
  }
131
+
111
132
  let puppeteerConfig = {};
133
+
112
134
  if (puppeteerConfigFile) {
113
135
  checkConfigFile(puppeteerConfigFile);
114
136
  puppeteerConfig = JSON.parse(fs.readFileSync(puppeteerConfigFile, 'utf-8'));
115
- }
137
+ } // check cssFile
138
+
116
139
 
117
- // check cssFile
118
140
  let myCSS;
141
+
119
142
  if (cssFile) {
120
143
  if (!fs.existsSync(cssFile)) {
121
144
  error(`CSS file "${cssFile}" doesn't exist`);
122
145
  }
146
+
123
147
  myCSS = fs.readFileSync(cssFile, 'utf-8');
124
148
  }
125
149
 
126
- // normalize args
150
+ const info = message => {
151
+ if (!quiet) {
152
+ console.info(message);
153
+ }
154
+ }; // normalize args
155
+
156
+
127
157
  width = parseInt(width);
128
158
  height = parseInt(height);
129
159
  backgroundColor = backgroundColor || 'white';
130
160
  const deviceScaleFactor = parseInt(scale || 1, 10);
131
161
 
132
- const parseMMD = (() => {
162
+ const parseMMD = /*#__PURE__*/function () {
133
163
  var _ref2 = _asyncToGenerator(function* (browser, definition, output) {
134
164
  const page = yield browser.newPage();
135
- page.setViewport({ width, height, deviceScaleFactor });
165
+ page.setViewport({
166
+ width,
167
+ height,
168
+ deviceScaleFactor
169
+ });
136
170
  yield page.goto(`file://${path.join(__dirname, 'index.html')}`);
137
171
  yield page.evaluate(`document.body.style.background = '${backgroundColor}'`);
138
- const result = yield page.$eval('#container', function (container, definition, mermaidConfig, myCSS) {
172
+ const result = yield page.$eval('#container', (container, definition, mermaidConfig, myCSS) => {
139
173
  container.textContent = definition;
140
174
  window.mermaid.initialize(mermaidConfig);
175
+
141
176
  if (myCSS) {
142
177
  const head = window.document.head || window.document.getElementsByTagName('head')[0];
143
178
  const style = document.createElement('style');
144
179
  style.type = 'text/css';
180
+
145
181
  if (style.styleSheet) {
146
182
  style.styleSheet.cssText = myCSS;
147
183
  } else {
148
184
  style.appendChild(document.createTextNode(myCSS));
149
185
  }
186
+
150
187
  head.appendChild(style);
151
188
  }
152
189
 
153
190
  try {
154
191
  window.mermaid.init(undefined, container);
155
- return { status: 'success' };
192
+ return {
193
+ status: 'success'
194
+ };
156
195
  } catch (error) {
157
- return { status: 'error', error, message: error.message };
196
+ return {
197
+ status: 'error',
198
+ error,
199
+ message: error.message
200
+ };
158
201
  }
159
202
  }, definition, mermaidConfig, myCSS);
203
+
160
204
  if (result.status === 'error') {
161
205
  error(result.message);
162
206
  }
163
207
 
164
208
  if (output.endsWith('svg')) {
165
- const svg = yield page.$eval('#container', function (container) {
166
- return container.innerHTML;
167
- });
209
+ const svg = yield page.$eval('#container', container => container.innerHTML);
168
210
  const svg_xml = convertToValidXML(svg);
169
211
  fs.writeFileSync(output, svg_xml);
170
212
  } else if (output.endsWith('png')) {
171
- const clip = yield page.$eval('svg', function (svg) {
213
+ const clip = yield page.$eval('svg', svg => {
172
214
  const react = svg.getBoundingClientRect();
173
- return { x: Math.floor(react.left), y: Math.floor(react.top), width: Math.ceil(react.width), height: Math.ceil(react.height) };
215
+ return {
216
+ x: Math.floor(react.left),
217
+ y: Math.floor(react.top),
218
+ width: Math.ceil(react.width),
219
+ height: Math.ceil(react.height)
220
+ };
221
+ });
222
+ yield page.setViewport({
223
+ width: clip.x + clip.width,
224
+ height: clip.y + clip.height,
225
+ deviceScaleFactor
226
+ });
227
+ yield page.screenshot({
228
+ path: output,
229
+ clip,
230
+ omitBackground: backgroundColor === 'transparent'
174
231
  });
175
- yield page.setViewport({ width: clip.x + clip.width, height: clip.y + clip.height, deviceScaleFactor });
176
- yield page.screenshot({ path: output, clip, omitBackground: backgroundColor === 'transparent' });
177
232
  } else {
178
233
  // pdf
179
234
  if (pdfFit) {
180
- const clip = yield page.$eval('svg', function (svg) {
235
+ const clip = yield page.$eval('svg', svg => {
181
236
  const react = svg.getBoundingClientRect();
182
- return { x: react.left, y: react.top, width: react.width, height: react.height };
237
+ return {
238
+ x: react.left,
239
+ y: react.top,
240
+ width: react.width,
241
+ height: react.height
242
+ };
183
243
  });
184
244
  yield page.pdf({
185
245
  path: output,
@@ -200,22 +260,28 @@ const parseMMD = (() => {
200
260
  return function parseMMD(_x2, _x3, _x4) {
201
261
  return _ref2.apply(this, arguments);
202
262
  };
203
- })();
263
+ }();
204
264
 
205
265
  _asyncToGenerator(function* () {
206
266
  const browser = yield puppeteer.launch(puppeteerConfig);
207
267
  const definition = yield getInputData(input);
268
+
208
269
  if (/\.md$/.test(input)) {
209
270
  const matches = definition.match(/^```(?:mermaid)(\n([\s\S]*?))```$/gm);
210
- if (matches.length > 0) {
211
- const mmdStrings = matches.map(function (str) {
212
- return str.replace(/^```(?:mermaid)(\n([\s\S]*?))```$/, '$1').trim();
213
- });
214
- yield Promise.all(mmdStrings.map(function (mmdString, index) {
215
- return parseMMD(browser, mmdString, output.replace(/(\..*)$/, `-${index + 1}$1`));
271
+
272
+ if (matches !== null) {
273
+ info(`Found ${matches.length} mermaid charts in Markdown input`);
274
+ const mmdStrings = matches.map(str => str.replace(/^```(?:mermaid)(\n([\s\S]*?))```$/, '$1').trim());
275
+ yield Promise.all(mmdStrings.map((mmdString, index) => {
276
+ const output_file = output.replace(/(\..*)$/, `-${index + 1}$1`);
277
+ info(` - ${output_file}`);
278
+ return parseMMD(browser, mmdString, output_file);
216
279
  }));
280
+ } else {
281
+ info(`No mermaid charts found in Markdown input`);
217
282
  }
218
283
  } else {
284
+ info(`Generating single mermaid chart`);
219
285
  yield parseMMD(browser, definition, output);
220
286
  }
221
287