@mermaid-js/mermaid-cli 10.0.0 → 10.0.2

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.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.js"],"names":[],"mappings":""}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Options to pass to {@link parseMMD }
3
+ */
4
+ export type ParseMDDOptions = {
5
+ /**
6
+ * - Puppeteer viewport (e.g. `width`, `height`, `deviceScaleFactor`)
7
+ */
8
+ viewport?: puppeteer.Viewport | undefined;
9
+ /**
10
+ * - Background color.
11
+ */
12
+ backgroundColor?: string | undefined;
13
+ /**
14
+ * - Mermaid config.
15
+ */
16
+ mermaidConfig?: any;
17
+ /**
18
+ * - Optional CSS text.
19
+ */
20
+ myCSS?: string | undefined;
21
+ /**
22
+ * - If set, scale PDF to fit chart.
23
+ */
24
+ pdfFit?: boolean | undefined;
25
+ };
26
+ /**
27
+ * Markdown image properties
28
+ * Used to create an markdown image that looks like `![alt](url "title")`
29
+ */
30
+ export type MarkdownImageProps = {
31
+ /**
32
+ * - Path to image.
33
+ */
34
+ url: string;
35
+ /**
36
+ * - Image alt text, required.
37
+ */
38
+ alt: string;
39
+ /**
40
+ * - Optional image title text.
41
+ */
42
+ title?: string | null | undefined;
43
+ };
44
+ /**
45
+ * Renders a mermaid diagram or mermaid markdown file.
46
+ *
47
+ * @param {`${string}.${"md" | "markdown"}` | string | undefined} input - If this ends with `.md`/`.markdown`,
48
+ * path to a markdown file containing mermaid.
49
+ * If this is a string, loads the mermaid definition from the given file.
50
+ * If this is `undefined`, loads the mermaid definition from stdin.
51
+ * @param {`${string}.${"md" | "markdown" | "svg" | "png" | "pdf"}`} output - Path to the output file.
52
+ * @param {Object} [opts] - Options
53
+ * @param {import("puppeteer").LaunchOptions} [opts.puppeteerConfig] - Puppeteer launch options.
54
+ * @param {boolean} [opts.quiet] - If set, suppress log output.
55
+ * @param {"svg" | "png" | "pdf"} [opts.outputFormat] - Mermaid output format.
56
+ * Defaults to `output` extension. Overrides `output` extension if set.
57
+ * @param {ParseMDDOptions} [opts.parseMMDOptions] - Options to pass to {@link parseMMDOptions}.
58
+ */
59
+ export function run(input: `${string}.${"md" | "markdown"}` | string | undefined, output: `${string}.${"md" | "markdown" | "svg" | "png" | "pdf"}`, { puppeteerConfig, quiet, outputFormat, parseMMDOptions }?: {
60
+ puppeteerConfig?: puppeteer.LaunchOptions | undefined;
61
+ quiet?: boolean | undefined;
62
+ outputFormat?: "svg" | "png" | "pdf" | undefined;
63
+ parseMMDOptions?: ParseMDDOptions | undefined;
64
+ } | undefined): Promise<void>;
65
+ /**
66
+ * Render a mermaid diagram.
67
+ *
68
+ * @param {import("puppeteer").Browser} browser - Puppeteer Browser
69
+ * @param {string} definition - Mermaid diagram definition
70
+ * @param {"svg" | "png" | "pdf"} outputFormat - Mermaid output format.
71
+ * @param {ParseMDDOptions} [opt] - Options, see {@link ParseMDDOptions} for details.
72
+ * @returns {Promise<{title: string | null, desc: string | null, data: Buffer}>} The output file in bytes,
73
+ * with optional metadata.
74
+ */
75
+ export function renderMermaid(browser: import("puppeteer").Browser, definition: string, outputFormat: "svg" | "png" | "pdf", { viewport, backgroundColor, mermaidConfig, myCSS, pdfFit }?: ParseMDDOptions | undefined): Promise<{
76
+ title: string | null;
77
+ desc: string | null;
78
+ data: Buffer;
79
+ }>;
80
+ /**
81
+ * @typedef {Object} ParseMDDOptions Options to pass to {@link parseMMD}
82
+ * @property {import("puppeteer").Viewport} [viewport] - Puppeteer viewport (e.g. `width`, `height`, `deviceScaleFactor`)
83
+ * @property {string | "transparent"} [backgroundColor] - Background color.
84
+ * @property {Parameters<import("mermaid")["default"]["initialize"]>[0]} [mermaidConfig] - Mermaid config.
85
+ * @property {CSSStyleDeclaration["cssText"]} [myCSS] - Optional CSS text.
86
+ * @property {boolean} [pdfFit] - If set, scale PDF to fit chart.
87
+ */
88
+ /**
89
+ * Parse and render a mermaid diagram.
90
+ *
91
+ * @deprecated Prefer {@link renderMermaid}, as it also returns useful metadata.
92
+ *
93
+ * @param {import("puppeteer").Browser} browser - Puppeteer Browser
94
+ * @param {string} definition - Mermaid diagram definition
95
+ * @param {"svg" | "png" | "pdf"} outputFormat - Mermaid output format.
96
+ * @param {ParseMDDOptions} [opt] - Options, see {@link ParseMDDOptions} for details.
97
+ *
98
+ * @returns {Promise<Buffer>} The output file in bytes.
99
+ */
100
+ export function parseMMD(browser: import("puppeteer").Browser, definition: string, outputFormat: "svg" | "png" | "pdf", opt?: ParseMDDOptions | undefined): Promise<Buffer>;
101
+ export function cli(): Promise<void>;
102
+ /**
103
+ * Prints an error to stderr, then closes with exit code 1
104
+ *
105
+ * @param {string} message - The message to print to `stderr`.
106
+ * @returns {never} Quits Node.JS, so never returns.
107
+ */
108
+ export function error(message: string): never;
109
+ import puppeteer from 'puppeteer';
110
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA4Xc,MAAM;;;;SACN,MAAM;;;;;;AAqBpB;;;;;;;;;;;;;;GAcG;AACH,2BAZW,GAAG,MAAM,IAAI,IAAI,GAAG,UAAU,EAAE,GAAG,MAAM,GAAG,SAAS,UAIrD,GAAG,MAAM,IAAI,IAAI,GAAG,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE;;;;;8BAwGlE;AAzSD;;;;;;;;;GASG;AACH,uCAPW,OAAO,WAAW,EAAE,OAAO,cAC3B,MAAM,gBACN,KAAK,GAAG,KAAK,GAAG,KAAK,8FAEnB,QAAQ;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,CAwJ9E;AAzLD;;;;;;;GAOG;AAEH;;;;;;;;;;;GAWG;AACH,kCAPW,OAAO,WAAW,EAAE,OAAO,cAC3B,MAAM,gBACN,KAAK,GAAG,KAAK,GAAG,KAAK,sCAGnB,QAAQ,MAAM,CAAC,CAK3B;AAhHD,qCAsFC;AA9KD;;;;;GAKG;AACH,+BAHW,MAAM,GACJ,KAAK,CAKjB;sBAnBqB,WAAW"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mermaid-js/mermaid-cli",
3
- "version": "10.0.0",
3
+ "version": "10.0.2",
4
4
  "description": "Command-line interface for mermaid",
5
5
  "license": "MIT",
6
6
  "repository": "git@github.com:mermaid-js/mermaid-cli.git",
@@ -13,9 +13,10 @@
13
13
  "node": "^14.13 || >=16.0"
14
14
  },
15
15
  "exports": "./src/index.js",
16
+ "types": "./dist-types/src/index.d.ts",
16
17
  "scripts": {
17
- "prepare": "vite build",
18
- "prepack": "vite build",
18
+ "prepare": "tsc && vite build",
19
+ "prepack": "tsc && vite build",
19
20
  "test": "standard && yarn node --experimental-vm-modules $(yarn bin jest)",
20
21
  "lint": "standard",
21
22
  "lint-fix": "standard --fix"
@@ -28,9 +29,11 @@
28
29
  "devDependencies": {
29
30
  "@fortawesome/fontawesome-free-webfonts": "^1.0.9",
30
31
  "@mermaid-js/mermaid-mindmap": "^9.2.2",
31
- "mermaid": "^10.0.0",
32
+ "@tsconfig/node14": "^1.0.3",
32
33
  "jest": "^29.0.1",
34
+ "mermaid": "^10.0.0",
33
35
  "standard": "^17.0.0",
36
+ "typescript": "^5.0.1-rc",
34
37
  "vite": "^4.0.3",
35
38
  "vite-plugin-singlefile": "^0.13.1",
36
39
  "vite-svg-loader": "^4.0.0",
@@ -38,7 +41,8 @@
38
41
  },
39
42
  "files": [
40
43
  "src/",
41
- "dist/"
44
+ "dist/",
45
+ "dist-types/"
42
46
  ],
43
47
  "jest": {
44
48
  "moduleNameMapper": {
@@ -47,7 +51,8 @@
47
51
  },
48
52
  "standard": {
49
53
  "ignore": [
50
- "/dist/"
54
+ "/dist/",
55
+ "/dist-types/"
51
56
  ]
52
57
  }
53
58
  }
package/src/index.js CHANGED
@@ -10,23 +10,48 @@ import { createRequire } from 'module'
10
10
  const require = createRequire(import.meta.url)
11
11
  const pkg = require('../package.json')
12
12
  // __dirname is not available in ESM modules by default
13
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
13
+ const __dirname = url.fileURLToPath(new url.URL('.', import.meta.url))
14
14
 
15
+ /**
16
+ * Prints an error to stderr, then closes with exit code 1
17
+ *
18
+ * @param {string} message - The message to print to `stderr`.
19
+ * @returns {never} Quits Node.JS, so never returns.
20
+ */
15
21
  const error = message => {
16
22
  console.error(chalk.red(`\n${message}\n`))
17
23
  process.exit(1)
18
24
  }
19
25
 
26
+ /**
27
+ * Prints a warning to stderr.
28
+ *
29
+ * @param {string} message - The message to print to `stderr`.
30
+ */
20
31
  const warn = message => {
21
32
  console.warn(chalk.yellow(`\n${message}\n`))
22
33
  }
23
34
 
35
+ /**
36
+ * Checks if the given file exists.
37
+ *
38
+ * @param {string} file - The file to check.
39
+ * @returns {never | void} If the file doesn't exist, closes Node.JS with
40
+ * exit code 1.
41
+ */
24
42
  const checkConfigFile = file => {
25
43
  if (!fs.existsSync(file)) {
26
44
  error(`Configuration file "${file}" doesn't exist`)
27
45
  }
28
46
  }
29
47
 
48
+ /**
49
+ * Gets the data in the given file.
50
+ *
51
+ * @param {string | undefined} inputFile - The file to read.
52
+ * If `undefined`, reads from `stdin` instead.
53
+ * @returns {Promise<string>} The contents of `inputFile` parsed as `utf8`.
54
+ */
30
55
  const getInputData = async inputFile => new Promise((resolve, reject) => {
31
56
  // if an input file has been specified using '-i', it takes precedence over
32
57
  // piping from stdin
@@ -42,7 +67,7 @@ const getInputData = async inputFile => new Promise((resolve, reject) => {
42
67
 
43
68
  let data = ''
44
69
  process.stdin.on('readable', function () {
45
- const chunk = this.read()
70
+ const chunk = process.stdin.read()
46
71
 
47
72
  if (chunk !== null) {
48
73
  data += chunk
@@ -165,11 +190,11 @@ async function cli () {
165
190
 
166
191
  /**
167
192
  * @typedef {Object} ParseMDDOptions Options to pass to {@link parseMMD}
168
- * @property {puppeteer.Viewport} [viewport] - Puppeteer viewport (e.g. `width`, `height`, `deviceScaleFactor`)
193
+ * @property {import("puppeteer").Viewport} [viewport] - Puppeteer viewport (e.g. `width`, `height`, `deviceScaleFactor`)
169
194
  * @property {string | "transparent"} [backgroundColor] - Background color.
170
- * @property {Parameters<import("mermaid").Mermaid["initialize"]>[0]} [mermaidConfig] - Mermaid config.
195
+ * @property {Parameters<import("mermaid")["default"]["initialize"]>[0]} [mermaidConfig] - Mermaid config.
171
196
  * @property {CSSStyleDeclaration["cssText"]} [myCSS] - Optional CSS text.
172
- * @property {boolean} pdfFit - If set, scale PDF to fit chart.
197
+ * @property {boolean} [pdfFit] - If set, scale PDF to fit chart.
173
198
  */
174
199
 
175
200
  /**
@@ -177,26 +202,26 @@ async function cli () {
177
202
  *
178
203
  * @deprecated Prefer {@link renderMermaid}, as it also returns useful metadata.
179
204
  *
180
- * @param {puppeteer.Browser} browser - Puppeteer Browser
205
+ * @param {import("puppeteer").Browser} browser - Puppeteer Browser
181
206
  * @param {string} definition - Mermaid diagram definition
182
207
  * @param {"svg" | "png" | "pdf"} outputFormat - Mermaid output format.
183
208
  * @param {ParseMDDOptions} [opt] - Options, see {@link ParseMDDOptions} for details.
184
209
  *
185
210
  * @returns {Promise<Buffer>} The output file in bytes.
186
211
  */
187
- async function parseMMD (...args) {
188
- const { data } = await renderMermaid(...args)
212
+ async function parseMMD (browser, definition, outputFormat, opt) {
213
+ const { data } = await renderMermaid(browser, definition, outputFormat, opt)
189
214
  return data
190
215
  }
191
216
 
192
217
  /**
193
218
  * Render a mermaid diagram.
194
219
  *
195
- * @param {puppeteer.Browser} browser - Puppeteer Browser
220
+ * @param {import("puppeteer").Browser} browser - Puppeteer Browser
196
221
  * @param {string} definition - Mermaid diagram definition
197
222
  * @param {"svg" | "png" | "pdf"} outputFormat - Mermaid output format.
198
223
  * @param {ParseMDDOptions} [opt] - Options, see {@link ParseMDDOptions} for details.
199
- * @returns {Promise<{title?: string, desc?: string, data: Buffer}>} The output file in bytes,
224
+ * @returns {Promise<{title: string | null, desc: string | null, data: Buffer}>} The output file in bytes,
200
225
  * with optional metadata.
201
226
  */
202
227
  async function renderMermaid (browser, definition, outputFormat, { viewport, backgroundColor = 'white', mermaidConfig = {}, myCSS, pdfFit } = {}) {
@@ -209,17 +234,33 @@ async function renderMermaid (browser, definition, outputFormat, { viewport, bac
209
234
  await page.setViewport(viewport)
210
235
  }
211
236
  const mermaidHTMLPath = path.join(__dirname, '..', 'dist', 'index.html')
212
- await page.goto(url.pathToFileURL(mermaidHTMLPath))
237
+ await page.goto(url.pathToFileURL(mermaidHTMLPath).href)
213
238
  await page.$eval('body', (body, backgroundColor) => {
214
239
  body.style.background = backgroundColor
215
240
  }, backgroundColor)
216
241
  const metadata = await page.$eval('#container', async (container, definition, mermaidConfig, myCSS, backgroundColor) => {
242
+ /**
243
+ * Checks to see if the given object is one of Mermaid's DetailedErrors.
244
+ *
245
+ * @param {unknown} error - The error to check
246
+ * @returns {error is import("mermaid").DetailedError} Returns `true` is the `error`
247
+ * is a `Mermaid.DetailedError`.
248
+ * @see https://github.com/mermaid-js/mermaid/blob/v10.0.1/packages/mermaid/src/utils.ts#L927-L930
249
+ */
250
+ function isDetailedError (error) {
251
+ return typeof error === 'object' && error !== null && 'str' in error
252
+ }
253
+
217
254
  container.textContent = definition
218
255
 
219
- /** @type {import("mermaid")} Already imported mermaid instance */
220
- const mermaid = globalThis.mermaid
221
- /** @type {import("@mermaid-js/mermaid-mindmap")} */
222
- const mermaidMindmap = globalThis.mermaidMindmap
256
+ /**
257
+ * @typedef {Object} GlobalThisWithMermaid
258
+ * We've already imported these modules in our `index.html` file, so that they
259
+ * get correctly bundled.
260
+ * @property {import("mermaid")["default"]} mermaid Already imported mermaid instance
261
+ * @property {import("@mermaid-js/mermaid-mindmap")} mermaidMindmap Already imported mermaid-mindmap plugin
262
+ */
263
+ const { mermaid, mermaidMindmap } = /** @type {GlobalThisWithMermaid & typeof globalThis} */ (globalThis)
223
264
 
224
265
  await mermaid.registerExternalDiagrams([mermaidMindmap])
225
266
 
@@ -227,7 +268,12 @@ async function renderMermaid (browser, definition, outputFormat, { viewport, bac
227
268
  // should throw an error if mmd diagram is invalid
228
269
  try {
229
270
  await mermaid.run({
230
- nodes: [container],
271
+ nodes: [
272
+ /**
273
+ * @type {HTMLElement} We know this is a `HTMLElement`, since we
274
+ * control the input HTML file
275
+ */ (container)
276
+ ],
231
277
  suppressErrors: false
232
278
  })
233
279
  } catch (error) {
@@ -235,8 +281,10 @@ async function renderMermaid (browser, definition, outputFormat, { viewport, bac
235
281
  // mermaid-js doesn't currently throws JS Errors, but let's leave this
236
282
  // here in case it does in the future
237
283
  throw error
284
+ } else if (isDetailedError(error)) {
285
+ throw new Error(error.message)
238
286
  } else {
239
- throw new Error(error?.message ?? 'Unknown mermaid render error')
287
+ throw new Error(`Unknown mermaid render error: ${error}`)
240
288
  }
241
289
  }
242
290
 
@@ -327,13 +375,18 @@ async function renderMermaid (browser, definition, outputFormat, { viewport, bac
327
375
  }
328
376
  }
329
377
 
378
+ /**
379
+ * @typedef {object} MarkdownImageProps Markdown image properties
380
+ * Used to create an markdown image that looks like `![alt](url "title")`
381
+ * @property {string} url - Path to image.
382
+ * @property {string} alt - Image alt text, required.
383
+ * @property {string | null} [title] - Optional image title text.
384
+ */
385
+
330
386
  /**
331
387
  * Creates a markdown image syntax.
332
388
  *
333
- * @param {object} params - Parameters.
334
- * @param {string} params.url - Path to image.
335
- * @param {string} params.alt - Image alt text, required.
336
- * @param {string} [params.title] - Image title text.
389
+ * @param {MarkdownImageProps} params - Parameters.
337
390
  * @returns {`![${string}](${string})`} The markdown image text.
338
391
  */
339
392
  function markdownImage ({ url, title, alt }) {
@@ -350,19 +403,24 @@ function markdownImage ({ url, title, alt }) {
350
403
  /**
351
404
  * Renders a mermaid diagram or mermaid markdown file.
352
405
  *
353
- * @param {`${string}.${"md" | "markdown"}` | string} [input] - If this ends with `.md`/`.markdown`,
406
+ * @param {`${string}.${"md" | "markdown"}` | string | undefined} input - If this ends with `.md`/`.markdown`,
354
407
  * path to a markdown file containing mermaid.
355
408
  * If this is a string, loads the mermaid definition from the given file.
356
409
  * If this is `undefined`, loads the mermaid definition from stdin.
357
410
  * @param {`${string}.${"md" | "markdown" | "svg" | "png" | "pdf"}`} output - Path to the output file.
358
411
  * @param {Object} [opts] - Options
359
- * @param {puppeteer.LaunchOptions} [opts.puppeteerConfig] - Puppeteer launch options.
412
+ * @param {import("puppeteer").LaunchOptions} [opts.puppeteerConfig] - Puppeteer launch options.
360
413
  * @param {boolean} [opts.quiet] - If set, suppress log output.
361
414
  * @param {"svg" | "png" | "pdf"} [opts.outputFormat] - Mermaid output format.
362
415
  * Defaults to `output` extension. Overrides `output` extension if set.
363
416
  * @param {ParseMDDOptions} [opts.parseMMDOptions] - Options to pass to {@link parseMMDOptions}.
364
417
  */
365
418
  async function run (input, output, { puppeteerConfig = {}, quiet = false, outputFormat, parseMMDOptions } = {}) {
419
+ /**
420
+ * Logs the given message to stdout, unless `quiet` is set to `true`.
421
+ *
422
+ * @param {string} message - The message to maybe log.
423
+ */
366
424
  const info = message => {
367
425
  if (!quiet) {
368
426
  console.info(message)
@@ -370,32 +428,39 @@ async function run (input, output, { puppeteerConfig = {}, quiet = false, output
370
428
  }
371
429
 
372
430
  // TODO: should we use a Markdown parser like remark instead of rolling our own parser?
373
- const mermaidChartsInMarkdown = /^[^\S\n]*```(?:mermaid)(\r?\n([\s\S]*?))```[^\S\n]*$/
431
+ const mermaidChartsInMarkdown = /^[^\S\n]*```(?:mermaid)([^\S\n]*\r?\n([\s\S]*?))```[^\S\n]*$/
374
432
  const mermaidChartsInMarkdownRegexGlobal = new RegExp(mermaidChartsInMarkdown, 'gm')
375
433
  const browser = await puppeteer.launch(puppeteerConfig)
376
434
  try {
377
435
  if (!outputFormat) {
378
- outputFormat = path.extname(output).replace('.', '')
379
- }
380
- if (outputFormat === 'md' || outputFormat === 'markdown') {
381
- // fallback to svg in case no outputFormat is given and output file is MD
382
- outputFormat = 'svg'
436
+ const outputFormatFromFilename =
437
+ /**
438
+ * @type {"md" | "markdown" | "svg" | "png" | "pdf"}
439
+ */ (path.extname(output).replace('.', ''))
440
+ if (outputFormatFromFilename === 'md' || outputFormatFromFilename === 'markdown') {
441
+ // fallback to svg in case no outputFormat is given and output file is MD
442
+ outputFormat = 'svg'
443
+ } else {
444
+ outputFormat = outputFormatFromFilename
445
+ }
383
446
  }
384
447
  if (!/(?:svg|png|pdf)$/.test(outputFormat)) {
385
448
  throw new Error('Output format must be one of "svg", "png" or "pdf"')
386
449
  }
387
450
 
388
451
  const definition = await getInputData(input)
389
- if (/\.(md|markdown)$/.test(input)) {
452
+ if (input && /\.(md|markdown)$/.test(input)) {
390
453
  const imagePromises = []
391
454
  for (const mermaidCodeblockMatch of definition.matchAll(mermaidChartsInMarkdownRegexGlobal)) {
392
455
  const mermaidDefinition = mermaidCodeblockMatch[1]
393
456
 
394
- // Output can be either a template image file, or a `.md` output file.
395
- // If it is a template image file, use that to created numbered diagrams
396
- // I.e. if "out.png", use "out-1.png", "out-2.png", etc
397
- // If it is an output `.md` file, use that to base .svg numbered diagrams on
398
- // I.e. if "out.md". use "out-1.svg", "out-2.svg", etc
457
+ /** Output can be either a template image file, or a `.md` output file.
458
+ * If it is a template image file, use that to created numbered diagrams
459
+ * I.e. if "out.png", use "out-1.png", "out-2.png", etc
460
+ * If it is an output `.md` file, use that to base .svg numbered diagrams on
461
+ * I.e. if "out.md". use "out-1.svg", "out-2.svg", etc
462
+ * @type {string}
463
+ */
399
464
  const outputFile = output.replace(
400
465
  /(\.(md|markdown|png|svg|pdf))$/,
401
466
  `-${imagePromises.length + 1}$1`
@@ -427,7 +492,12 @@ async function run (input, output, { puppeteerConfig = {}, quiet = false, output
427
492
  if (/\.(md|markdown)$/.test(output)) {
428
493
  const outDefinition = definition.replace(mermaidChartsInMarkdownRegexGlobal, (_mermaidMd) => {
429
494
  // pop first image from front of array
430
- const { url, title, alt } = images.shift()
495
+ const { url, title, alt } =
496
+ /**
497
+ * @type {MarkdownImageProps} We use the same regex,
498
+ * so we will never try to get too many objects from the array.
499
+ * (aka `images.shift()` will never return `undefined`)
500
+ */ (images.shift())
431
501
  return markdownImage({ url, title, alt: alt || 'diagram' })
432
502
  })
433
503
  await fs.promises.writeFile(output, outDefinition, 'utf-8')