@mermaid-js/mermaid-cli 8.13.4 → 8.13.8

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
package/index.bundle.js CHANGED
@@ -1,36 +1,42 @@
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
 
29
+ const warn = message => {
30
+ console.log(_chalk.default.yellow(`\n${message}\n`));
31
+ };
32
+
27
33
  const checkConfigFile = file => {
28
- if (!fs.existsSync(file)) {
34
+ if (!_fs.default.existsSync(file)) {
29
35
  error(`Configuration file "${file}" doesn't exist`);
30
36
  }
31
37
  };
32
38
 
33
- const inputPipedFromStdin = () => fs.fstatSync(0).isFIFO();
39
+ const inputPipedFromStdin = () => _fs.default.fstatSync(0).isFIFO();
34
40
 
35
41
  const getInputData = /*#__PURE__*/function () {
36
42
  var _ref = _asyncToGenerator(function* (inputFile) {
@@ -38,7 +44,7 @@ const getInputData = /*#__PURE__*/function () {
38
44
  // if an input file has been specified using '-i', it takes precedence over
39
45
  // piping from stdin
40
46
  if (typeof inputFile !== 'undefined') {
41
- return fs.readFile(inputFile, 'utf-8', (err, data) => {
47
+ return _fs.default.readFile(inputFile, 'utf-8', (err, data) => {
42
48
  if (err) {
43
49
  return reject(err);
44
50
  }
@@ -74,8 +80,10 @@ const convertToValidXML = html => {
74
80
  return html.replace(/<br>/gi, '<br/>');
75
81
  };
76
82
 
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
- const options = commander.opts();
83
+ _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);
84
+
85
+ const options = _commander.default.opts();
86
+
79
87
  let {
80
88
  theme,
81
89
  width,
@@ -92,12 +100,14 @@ let {
92
100
  } = options; // check input file
93
101
 
94
102
  if (!(input || inputPipedFromStdin())) {
95
- console.log(chalk.red(`\nPlease specify input file: -i <input>\n`));
96
- commander.help();
103
+ console.log(_chalk.default.red(`\nPlease specify input file: -i <input>\n`));
104
+
105
+ _commander.default.help();
106
+
97
107
  process.exit(1);
98
108
  }
99
109
 
100
- if (input && !fs.existsSync(input)) {
110
+ if (input && !_fs.default.existsSync(input)) {
101
111
  error(`Input file "${input}" doesn't exist`);
102
112
  } // check output file
103
113
 
@@ -109,13 +119,13 @@ if (!output) {
109
119
  output = input ? input + '.svg' : 'out.svg';
110
120
  }
111
121
 
112
- if (!/\.(?:svg|png|pdf)$/.test(output)) {
113
- error(`Output file must end with ".svg", ".png" or ".pdf"`);
122
+ if (!/\.(?:svg|png|pdf|md)$/.test(output)) {
123
+ error(`Output file must end with ".md", ".svg", ".png" or ".pdf"`);
114
124
  }
115
125
 
116
- const outputDir = path.dirname(output);
126
+ const outputDir = _path.default.dirname(output);
117
127
 
118
- if (!fs.existsSync(outputDir)) {
128
+ if (!_fs.default.existsSync(outputDir)) {
119
129
  error(`Output directory "${outputDir}/" doesn't exist`);
120
130
  } // check config files
121
131
 
@@ -126,25 +136,25 @@ let mermaidConfig = {
126
136
 
127
137
  if (configFile) {
128
138
  checkConfigFile(configFile);
129
- mermaidConfig = Object.assign(mermaidConfig, JSON.parse(fs.readFileSync(configFile, 'utf-8')));
139
+ mermaidConfig = Object.assign(mermaidConfig, JSON.parse(_fs.default.readFileSync(configFile, 'utf-8')));
130
140
  }
131
141
 
132
142
  let puppeteerConfig = {};
133
143
 
134
144
  if (puppeteerConfigFile) {
135
145
  checkConfigFile(puppeteerConfigFile);
136
- puppeteerConfig = JSON.parse(fs.readFileSync(puppeteerConfigFile, 'utf-8'));
146
+ puppeteerConfig = JSON.parse(_fs.default.readFileSync(puppeteerConfigFile, 'utf-8'));
137
147
  } // check cssFile
138
148
 
139
149
 
140
150
  let myCSS;
141
151
 
142
152
  if (cssFile) {
143
- if (!fs.existsSync(cssFile)) {
153
+ if (!_fs.default.existsSync(cssFile)) {
144
154
  error(`CSS file "${cssFile}" doesn't exist`);
145
155
  }
146
156
 
147
- myCSS = fs.readFileSync(cssFile, 'utf-8');
157
+ myCSS = _fs.default.readFileSync(cssFile, 'utf-8');
148
158
  }
149
159
 
150
160
  const info = message => {
@@ -167,7 +177,7 @@ const parseMMD = /*#__PURE__*/function () {
167
177
  height,
168
178
  deviceScaleFactor
169
179
  });
170
- yield page.goto(`file://${path.join(__dirname, 'index.html')}`);
180
+ yield page.goto(`file://${_path.default.join(__dirname, 'index.html')}`);
171
181
  yield page.evaluate(`document.body.style.background = '${backgroundColor}'`);
172
182
  const result = yield page.$eval('#container', (container, definition, mermaidConfig, myCSS) => {
173
183
  container.textContent = definition;
@@ -206,9 +216,22 @@ const parseMMD = /*#__PURE__*/function () {
206
216
  }
207
217
 
208
218
  if (output.endsWith('svg')) {
209
- const svg = yield page.$eval('#container', container => container.innerHTML);
219
+ const svg = yield page.$eval('#container', (container, backgroundColor) => {
220
+ var _container$getElement, _container$getElement2;
221
+
222
+ const svg = (_container$getElement = container.getElementsByTagName) === null || _container$getElement === void 0 ? void 0 : (_container$getElement2 = _container$getElement.call(container, 'svg')) === null || _container$getElement2 === void 0 ? void 0 : _container$getElement2[0];
223
+
224
+ if (svg.style) {
225
+ svg.style.backgroundColor = backgroundColor;
226
+ } else {
227
+ warn("svg not found. Not applying background color.");
228
+ }
229
+
230
+ return container.innerHTML;
231
+ }, backgroundColor);
210
232
  const svg_xml = convertToValidXML(svg);
211
- fs.writeFileSync(output, svg_xml);
233
+
234
+ _fs.default.writeFileSync(output, svg_xml);
212
235
  } else if (output.endsWith('png')) {
213
236
  const clip = yield page.$eval('svg', svg => {
214
237
  const react = svg.getBoundingClientRect();
@@ -263,23 +286,47 @@ const parseMMD = /*#__PURE__*/function () {
263
286
  }();
264
287
 
265
288
  _asyncToGenerator(function* () {
266
- const browser = yield puppeteer.launch(puppeteerConfig);
289
+ const mermaidChartsInMarkdown = '^```(?:mermaid)(\r?\n([\\s\\S]*?))```$';
290
+ const mermaidChartsInMarkdownRegexGlobal = new RegExp(mermaidChartsInMarkdown, 'gm');
291
+ const mermaidChartsInMarkdownRegex = new RegExp(mermaidChartsInMarkdown);
292
+ const browser = yield _puppeteer.default.launch(puppeteerConfig);
267
293
  const definition = yield getInputData(input);
268
294
 
269
295
  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
- }));
296
+ const diagrams = [];
297
+ const outDefinition = definition.replace(mermaidChartsInMarkdownRegexGlobal, mermaidMd => {
298
+ const md = mermaidChartsInMarkdownRegex.exec(mermaidMd)[1]; // Output can be either a template image file, or a `.md` output file.
299
+ // If it is a template image file, use that to created numbered diagrams
300
+ // I.e. if "out.png", use "out-1.png", "out-2.png", etc
301
+ // If it is an output `.md` file, use that to base .svg numbered diagrams on
302
+ // I.e. if "out.md". use "out-1.svg", "out-2.svg", etc
303
+
304
+ const outputFile = output.replace(/(\..*)$/, `-${diagrams.length + 1}$1`).replace(/(\.md)$/, '.svg');
305
+ const outputFileRelative = `./${_path.default.relative(_path.default.dirname(_path.default.resolve(output)), _path.default.resolve(outputFile))}`;
306
+ diagrams.push([outputFile, md]);
307
+ return `![diagram](${outputFileRelative})`;
308
+ });
309
+
310
+ if (diagrams.length) {
311
+ info(`Found ${diagrams.length} mermaid charts in Markdown input`);
312
+ yield Promise.all(diagrams.map( /*#__PURE__*/function () {
313
+ var _ref4 = _asyncToGenerator(function* ([imgFile, md]) {
314
+ yield parseMMD(browser, md, imgFile);
315
+ info(` ✅ ${imgFile}`);
316
+ });
317
+
318
+ return function (_x5) {
319
+ return _ref4.apply(this, arguments);
320
+ };
321
+ }()));
280
322
  } else {
281
323
  info(`No mermaid charts found in Markdown input`);
282
324
  }
325
+
326
+ if (/\.md$/.test(output)) {
327
+ yield _fs.default.promises.writeFile(output, outDefinition, 'utf-8');
328
+ info(` ✅ ${output}`);
329
+ }
283
330
  } else {
284
331
  info(`Generating single mermaid chart`);
285
332
  yield parseMMD(browser, definition, output);