@mermaid-js/mermaid-cli 8.13.0 → 8.13.5

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
@@ -21,6 +21,40 @@ mmdc -i input.mmd -o output.svg
21
21
  mmdc -i input.mmd -o output.png -t dark -b transparent
22
22
  ```
23
23
 
24
+ ### Transform a markdown file with mermaid diagrams
25
+
26
+ ```sh
27
+ mmdc -i readme.template.md -o readme.md
28
+ ```
29
+
30
+ This command transforms a markdown file itself. The mermaid-cli will find the mermaid diagrams, create SVG files from them and refer to those in the markdown output.
31
+
32
+ This:
33
+
34
+ ~~~md
35
+ ### Some markdown
36
+ ```mermaid
37
+ graph
38
+ [....]
39
+ ```
40
+
41
+ ### Some more markdown
42
+ ```mermaid
43
+ sequenceDiagram
44
+ [....]
45
+ ```
46
+ ~~~
47
+
48
+ Becomes:
49
+
50
+ ```md
51
+ ### Some markdown
52
+ ![diagram](./readme-1.svg)
53
+
54
+ ### Some more markdown
55
+ ![diagram](./readme-2.svg)
56
+ ```
57
+
24
58
  ### Piping from stdin
25
59
 
26
60
  You can easily pipe input from stdin. This example shows how to use a heredoc to
@@ -99,6 +133,7 @@ it installs (`mmdc`). `npx -p @mermaid-js/mermaid-cli mmdc -h`
99
133
  ## Known issues
100
134
 
101
135
  1. [Linux sandbox issue](docs/linux-sandbox-issue.md)
136
+ 2. [Docker permission denied issue](docs/docker-permission-denied.md)
102
137
 
103
138
  ## For contributors
104
139
 
package/index.bundle.js CHANGED
@@ -1,36 +1,38 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
 
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); } }
4
+ var _commander = _interopRequireDefault(require("commander"));
5
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); }); }; }
6
+ var _chalk = _interopRequireDefault(require("chalk"));
7
7
 
8
- process.title = "mmdc";
8
+ var _fs = _interopRequireDefault(require("fs"));
9
9
 
10
- const commander = require('commander');
10
+ var _path = _interopRequireDefault(require("path"));
11
11
 
12
- const chalk = require('chalk');
12
+ var _puppeteer = _interopRequireDefault(require("puppeteer"));
13
13
 
14
- const fs = require('fs');
14
+ var _package = _interopRequireDefault(require("./package.json"));
15
15
 
16
- const path = require('path');
16
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
 
18
- const puppeteer = require('puppeteer');
18
+ 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); } }
19
19
 
20
- const pkg = require('./package.json');
20
+ 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); }); }; }
21
+
22
+ process.title = "mmdc";
21
23
 
22
24
  const error = message => {
23
- console.log(chalk.red(`\n${message}\n`));
25
+ console.log(_chalk.default.red(`\n${message}\n`));
24
26
  process.exit(1);
25
27
  };
26
28
 
27
29
  const checkConfigFile = file => {
28
- if (!fs.existsSync(file)) {
30
+ if (!_fs.default.existsSync(file)) {
29
31
  error(`Configuration file "${file}" doesn't exist`);
30
32
  }
31
33
  };
32
34
 
33
- const inputPipedFromStdin = () => fs.fstatSync(0).isFIFO();
35
+ const inputPipedFromStdin = () => _fs.default.fstatSync(0).isFIFO();
34
36
 
35
37
  const getInputData = /*#__PURE__*/function () {
36
38
  var _ref = _asyncToGenerator(function* (inputFile) {
@@ -38,7 +40,7 @@ const getInputData = /*#__PURE__*/function () {
38
40
  // if an input file has been specified using '-i', it takes precedence over
39
41
  // piping from stdin
40
42
  if (typeof inputFile !== 'undefined') {
41
- return fs.readFile(inputFile, 'utf-8', (err, data) => {
43
+ return _fs.default.readFile(inputFile, 'utf-8', (err, data) => {
42
44
  if (err) {
43
45
  return reject(err);
44
46
  }
@@ -70,14 +72,14 @@ const getInputData = /*#__PURE__*/function () {
70
72
  }();
71
73
 
72
74
  const convertToValidXML = html => {
73
- var xml = html; // <br> tags in valid HTML (from innerHTML) look like <br>, but they must look like <br/> to be valid XML (such as SVG)
74
-
75
- xml.replace(/<br>/gi, '<br/>');
76
- return xml;
75
+ // <br> tags in valid HTML (from innerHTML) look like <br>, but they must look like <br/> to be valid XML (such as SVG)
76
+ return html.replace(/<br>/gi, '<br/>');
77
77
  };
78
78
 
79
- 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);
80
- const options = commander.opts();
79
+ _commander.default.version(_package.default.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 md, 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);
80
+
81
+ const options = _commander.default.opts();
82
+
81
83
  let {
82
84
  theme,
83
85
  width,
@@ -94,10 +96,14 @@ let {
94
96
  } = options; // check input file
95
97
 
96
98
  if (!(input || inputPipedFromStdin())) {
97
- error('Please specify input file: -i <input>');
99
+ console.log(_chalk.default.red(`\nPlease specify input file: -i <input>\n`));
100
+
101
+ _commander.default.help();
102
+
103
+ process.exit(1);
98
104
  }
99
105
 
100
- if (input && !fs.existsSync(input)) {
106
+ if (input && !_fs.default.existsSync(input)) {
101
107
  error(`Input file "${input}" doesn't exist`);
102
108
  } // check output file
103
109
 
@@ -109,13 +115,13 @@ if (!output) {
109
115
  output = input ? input + '.svg' : 'out.svg';
110
116
  }
111
117
 
112
- if (!/\.(?:svg|png|pdf)$/.test(output)) {
113
- error(`Output file must end with ".svg", ".png" or ".pdf"`);
118
+ if (!/\.(?:svg|png|pdf|md)$/.test(output)) {
119
+ error(`Output file must end with ".md", ".svg", ".png" or ".pdf"`);
114
120
  }
115
121
 
116
- const outputDir = path.dirname(output);
122
+ const outputDir = _path.default.dirname(output);
117
123
 
118
- if (!fs.existsSync(outputDir)) {
124
+ if (!_fs.default.existsSync(outputDir)) {
119
125
  error(`Output directory "${outputDir}/" doesn't exist`);
120
126
  } // check config files
121
127
 
@@ -126,25 +132,25 @@ let mermaidConfig = {
126
132
 
127
133
  if (configFile) {
128
134
  checkConfigFile(configFile);
129
- mermaidConfig = Object.assign(mermaidConfig, JSON.parse(fs.readFileSync(configFile, 'utf-8')));
135
+ mermaidConfig = Object.assign(mermaidConfig, JSON.parse(_fs.default.readFileSync(configFile, 'utf-8')));
130
136
  }
131
137
 
132
138
  let puppeteerConfig = {};
133
139
 
134
140
  if (puppeteerConfigFile) {
135
141
  checkConfigFile(puppeteerConfigFile);
136
- puppeteerConfig = JSON.parse(fs.readFileSync(puppeteerConfigFile, 'utf-8'));
142
+ puppeteerConfig = JSON.parse(_fs.default.readFileSync(puppeteerConfigFile, 'utf-8'));
137
143
  } // check cssFile
138
144
 
139
145
 
140
146
  let myCSS;
141
147
 
142
148
  if (cssFile) {
143
- if (!fs.existsSync(cssFile)) {
149
+ if (!_fs.default.existsSync(cssFile)) {
144
150
  error(`CSS file "${cssFile}" doesn't exist`);
145
151
  }
146
152
 
147
- myCSS = fs.readFileSync(cssFile, 'utf-8');
153
+ myCSS = _fs.default.readFileSync(cssFile, 'utf-8');
148
154
  }
149
155
 
150
156
  const info = message => {
@@ -167,7 +173,7 @@ const parseMMD = /*#__PURE__*/function () {
167
173
  height,
168
174
  deviceScaleFactor
169
175
  });
170
- yield page.goto(`file://${path.join(__dirname, 'index.html')}`);
176
+ yield page.goto(`file://${_path.default.join(__dirname, 'index.html')}`);
171
177
  yield page.evaluate(`document.body.style.background = '${backgroundColor}'`);
172
178
  const result = yield page.$eval('#container', (container, definition, mermaidConfig, myCSS) => {
173
179
  container.textContent = definition;
@@ -208,7 +214,8 @@ const parseMMD = /*#__PURE__*/function () {
208
214
  if (output.endsWith('svg')) {
209
215
  const svg = yield page.$eval('#container', container => container.innerHTML);
210
216
  const svg_xml = convertToValidXML(svg);
211
- fs.writeFileSync(output, svg_xml);
217
+
218
+ _fs.default.writeFileSync(output, svg_xml);
212
219
  } else if (output.endsWith('png')) {
213
220
  const clip = yield page.$eval('svg', svg => {
214
221
  const react = svg.getBoundingClientRect();
@@ -263,23 +270,47 @@ const parseMMD = /*#__PURE__*/function () {
263
270
  }();
264
271
 
265
272
  _asyncToGenerator(function* () {
266
- const browser = yield puppeteer.launch(puppeteerConfig);
273
+ const mermaidChartsInMarkdown = '^```(?:mermaid)(\r?\n([\\s\\S]*?))```$';
274
+ const mermaidChartsInMarkdownRegexGlobal = new RegExp(mermaidChartsInMarkdown, 'gm');
275
+ const mermaidChartsInMarkdownRegex = new RegExp(mermaidChartsInMarkdown);
276
+ const browser = yield _puppeteer.default.launch(puppeteerConfig);
267
277
  const definition = yield getInputData(input);
268
278
 
269
279
  if (/\.md$/.test(input)) {
270
- const matches = definition.match(/^```(?:mermaid)(\n([\s\S]*?))```$/gm);
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);
279
- }));
280
+ const diagrams = [];
281
+ const outDefinition = definition.replaceAll(mermaidChartsInMarkdownRegexGlobal, mermaidMd => {
282
+ const md = mermaidChartsInMarkdownRegex.exec(mermaidMd)[1]; // Output can be either a template image file, or a `.md` output file.
283
+ // If it is a template image file, use that to created numbered diagrams
284
+ // I.e. if "out.png", use "out-1.png", "out-2.png", etc
285
+ // If it is an output `.md` file, use that to base .svg numbered diagrams on
286
+ // I.e. if "out.md". use "out-1.svg", "out-2.svg", etc
287
+
288
+ const outputFile = output.replace(/(\..*)$/, `-${diagrams.length + 1}$1`).replace(/(\.md)$/, '.svg');
289
+ const outputFileRelative = `./${_path.default.relative(_path.default.dirname(_path.default.resolve(output)), _path.default.resolve(outputFile))}`;
290
+ diagrams.push([outputFile, md]);
291
+ return `![diagram](${outputFileRelative})`;
292
+ });
293
+
294
+ if (diagrams.length) {
295
+ info(`Found ${diagrams.length} mermaid charts in Markdown input`);
296
+ yield Promise.all(diagrams.map( /*#__PURE__*/function () {
297
+ var _ref4 = _asyncToGenerator(function* ([imgFile, md]) {
298
+ yield parseMMD(browser, md, imgFile);
299
+ info(` ✅ ${imgFile}`);
300
+ });
301
+
302
+ return function (_x5) {
303
+ return _ref4.apply(this, arguments);
304
+ };
305
+ }()));
280
306
  } else {
281
307
  info(`No mermaid charts found in Markdown input`);
282
308
  }
309
+
310
+ if (/\.md$/.test(output)) {
311
+ yield _fs.default.promises.writeFile(output, outDefinition, 'utf-8');
312
+ info(` ✅ ${output}`);
313
+ }
283
314
  } else {
284
315
  info(`Generating single mermaid chart`);
285
316
  yield parseMMD(browser, definition, output);