@mermaid-js/mermaid-cli 9.4.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": "9.4.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": "^9.2.2",
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,31 +234,57 @@ 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
 
226
267
  mermaid.initialize(mermaidConfig)
227
268
  // should throw an error if mmd diagram is invalid
228
269
  try {
229
- await mermaid.initThrowsErrorsAsync(undefined, container)
270
+ await mermaid.run({
271
+ nodes: [
272
+ /**
273
+ * @type {HTMLElement} We know this is a `HTMLElement`, since we
274
+ * control the input HTML file
275
+ */ (container)
276
+ ],
277
+ suppressErrors: false
278
+ })
230
279
  } catch (error) {
231
280
  if (error instanceof Error) {
232
281
  // mermaid-js doesn't currently throws JS Errors, but let's leave this
233
282
  // here in case it does in the future
234
283
  throw error
284
+ } else if (isDetailedError(error)) {
285
+ throw new Error(error.message)
235
286
  } else {
236
- throw new Error(error?.message ?? 'Unknown mermaid render error')
287
+ throw new Error(`Unknown mermaid render error: ${error}`)
237
288
  }
238
289
  }
239
290
 
@@ -324,13 +375,18 @@ async function renderMermaid (browser, definition, outputFormat, { viewport, bac
324
375
  }
325
376
  }
326
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
+
327
386
  /**
328
387
  * Creates a markdown image syntax.
329
388
  *
330
- * @param {object} params - Parameters.
331
- * @param {string} params.url - Path to image.
332
- * @param {string} params.alt - Image alt text, required.
333
- * @param {string} [params.title] - Image title text.
389
+ * @param {MarkdownImageProps} params - Parameters.
334
390
  * @returns {`![${string}](${string})`} The markdown image text.
335
391
  */
336
392
  function markdownImage ({ url, title, alt }) {
@@ -347,19 +403,24 @@ function markdownImage ({ url, title, alt }) {
347
403
  /**
348
404
  * Renders a mermaid diagram or mermaid markdown file.
349
405
  *
350
- * @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`,
351
407
  * path to a markdown file containing mermaid.
352
408
  * If this is a string, loads the mermaid definition from the given file.
353
409
  * If this is `undefined`, loads the mermaid definition from stdin.
354
410
  * @param {`${string}.${"md" | "markdown" | "svg" | "png" | "pdf"}`} output - Path to the output file.
355
411
  * @param {Object} [opts] - Options
356
- * @param {puppeteer.LaunchOptions} [opts.puppeteerConfig] - Puppeteer launch options.
412
+ * @param {import("puppeteer").LaunchOptions} [opts.puppeteerConfig] - Puppeteer launch options.
357
413
  * @param {boolean} [opts.quiet] - If set, suppress log output.
358
414
  * @param {"svg" | "png" | "pdf"} [opts.outputFormat] - Mermaid output format.
359
415
  * Defaults to `output` extension. Overrides `output` extension if set.
360
416
  * @param {ParseMDDOptions} [opts.parseMMDOptions] - Options to pass to {@link parseMMDOptions}.
361
417
  */
362
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
+ */
363
424
  const info = message => {
364
425
  if (!quiet) {
365
426
  console.info(message)
@@ -367,32 +428,39 @@ async function run (input, output, { puppeteerConfig = {}, quiet = false, output
367
428
  }
368
429
 
369
430
  // TODO: should we use a Markdown parser like remark instead of rolling our own parser?
370
- 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]*$/
371
432
  const mermaidChartsInMarkdownRegexGlobal = new RegExp(mermaidChartsInMarkdown, 'gm')
372
433
  const browser = await puppeteer.launch(puppeteerConfig)
373
434
  try {
374
435
  if (!outputFormat) {
375
- outputFormat = path.extname(output).replace('.', '')
376
- }
377
- if (outputFormat === 'md' || outputFormat === 'markdown') {
378
- // fallback to svg in case no outputFormat is given and output file is MD
379
- 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
+ }
380
446
  }
381
447
  if (!/(?:svg|png|pdf)$/.test(outputFormat)) {
382
448
  throw new Error('Output format must be one of "svg", "png" or "pdf"')
383
449
  }
384
450
 
385
451
  const definition = await getInputData(input)
386
- if (/\.(md|markdown)$/.test(input)) {
452
+ if (input && /\.(md|markdown)$/.test(input)) {
387
453
  const imagePromises = []
388
454
  for (const mermaidCodeblockMatch of definition.matchAll(mermaidChartsInMarkdownRegexGlobal)) {
389
455
  const mermaidDefinition = mermaidCodeblockMatch[1]
390
456
 
391
- // Output can be either a template image file, or a `.md` output file.
392
- // If it is a template image file, use that to created numbered diagrams
393
- // I.e. if "out.png", use "out-1.png", "out-2.png", etc
394
- // If it is an output `.md` file, use that to base .svg numbered diagrams on
395
- // 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
+ */
396
464
  const outputFile = output.replace(
397
465
  /(\.(md|markdown|png|svg|pdf))$/,
398
466
  `-${imagePromises.length + 1}$1`
@@ -424,7 +492,12 @@ async function run (input, output, { puppeteerConfig = {}, quiet = false, output
424
492
  if (/\.(md|markdown)$/.test(output)) {
425
493
  const outDefinition = definition.replace(mermaidChartsInMarkdownRegexGlobal, (_mermaidMd) => {
426
494
  // pop first image from front of array
427
- 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())
428
501
  return markdownImage({ url, title, alt: alt || 'diagram' })
429
502
  })
430
503
  await fs.promises.writeFile(output, outDefinition, 'utf-8')