@helping-ai-workflow/md2doc 2.2.0 → 2.3.0
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 +6 -1
- package/bin/md2doc.js +7 -2
- package/lib/md2doc.js +137 -58
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ A single global CLI (`md2doc`) you can call from any directory.
|
|
|
8
8
|
|
|
9
9
|
Requires Node.js 18 or higher. The first install pulls puppeteer (≈ 170 MB Chromium download); subsequent installs reuse it.
|
|
10
10
|
|
|
11
|
+
Chromium is only needed for **PDF export** and the optional `--bake-svg` flag. HTML diagram rendering needs nothing extra — Graphviz runs in-process via WebAssembly, and Mermaid / WaveDrom are bundled and inlined, so diagrams render **offline with no system Graphviz and no CDN**.
|
|
12
|
+
|
|
11
13
|
### Recommended: install via nvm
|
|
12
14
|
|
|
13
15
|
If you do not yet have Node.js — or your system Node lives under `/usr/local` and `npm install -g` fails with `EACCES` — install Node through [nvm](https://github.com/nvm-sh/nvm) first. nvm puts Node under `~/.nvm`, so global packages never need `sudo`.
|
|
@@ -69,6 +71,7 @@ also pass `--open`.
|
|
|
69
71
|
| `--open` | Launch the platform viewer (`xdg-open` / `open` / `start`) after render. Default when `--out` is absent. |
|
|
70
72
|
| `--no-open` | Skip the viewer launch. |
|
|
71
73
|
| `--quiet` | Suppress per-file progress messages. |
|
|
74
|
+
| `--bake-svg` | Pre-render Mermaid / WaveDrom to inert SVG at generation time (HTML output only; needs Chromium). The output then contains no diagram JavaScript. |
|
|
72
75
|
| `--version`, `-v` | Print version. |
|
|
73
76
|
| `--help`, `-h` | Print help. |
|
|
74
77
|
|
|
@@ -101,7 +104,9 @@ digraph G { A -> B }
|
|
|
101
104
|
```
|
|
102
105
|
````
|
|
103
106
|
|
|
104
|
-
|
|
107
|
+
All three render directly in the output (HTML or PDF), **offline and with no system dependencies**: Graphviz `dot` runs in-process via WebAssembly (no system `dot` binary required), and Mermaid / WaveDrom are bundled and inlined (no CDN). Each engine's runtime is embedded only when the document actually uses that diagram type.
|
|
108
|
+
|
|
109
|
+
By default, Mermaid and WaveDrom render in the browser when the HTML is opened; pass `--bake-svg` to pre-render them to inert SVG at generation time instead (Graphviz is always pre-rendered to SVG).
|
|
105
110
|
|
|
106
111
|
## Why a global CLI
|
|
107
112
|
|
package/bin/md2doc.js
CHANGED
|
@@ -32,6 +32,7 @@ function printHelp() {
|
|
|
32
32
|
' --open Launch the platform viewer after render (default when --out is absent).',
|
|
33
33
|
' --no-open Skip the viewer launch.',
|
|
34
34
|
' --quiet Suppress per-file progress messages.',
|
|
35
|
+
' --bake-svg Pre-render mermaid/wavedrom to inert SVG (HTML output only; needs Chromium).',
|
|
35
36
|
' --version, -v Print version.',
|
|
36
37
|
' --help, -h Print this help.',
|
|
37
38
|
''
|
|
@@ -45,6 +46,7 @@ function parseArgs(argv) {
|
|
|
45
46
|
let out = null;
|
|
46
47
|
let openExplicit = null; // null = unset; true/false = user-specified
|
|
47
48
|
let quiet = false;
|
|
49
|
+
let bakeSvg = false;
|
|
48
50
|
|
|
49
51
|
for (let i = 0; i < argv.length; i++) {
|
|
50
52
|
const a = argv[i];
|
|
@@ -61,6 +63,7 @@ function parseArgs(argv) {
|
|
|
61
63
|
if (a === '--open') { openExplicit = true; continue; }
|
|
62
64
|
if (a === '--no-open') { openExplicit = false; continue; }
|
|
63
65
|
if (a === '--quiet') { quiet = true; continue; }
|
|
66
|
+
if (a === '--bake-svg') { bakeSvg = true; continue; }
|
|
64
67
|
if (a === '--out') {
|
|
65
68
|
if (out !== null) {
|
|
66
69
|
process.stderr.write('error: --out specified more than once\n');
|
|
@@ -102,7 +105,7 @@ function parseArgs(argv) {
|
|
|
102
105
|
open = (out === null);
|
|
103
106
|
}
|
|
104
107
|
|
|
105
|
-
return { inputs, formats, formatsExplicit, out, open, quiet };
|
|
108
|
+
return { inputs, formats, formatsExplicit, out, open, quiet, bakeSvg };
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
function shortHash(absPath) {
|
|
@@ -244,7 +247,9 @@ function main() {
|
|
|
244
247
|
const outputs = [];
|
|
245
248
|
for (const { input, output } of pairs) {
|
|
246
249
|
const stdio = args.quiet ? ['inherit', 'ignore', 'inherit'] : 'inherit';
|
|
247
|
-
const
|
|
250
|
+
const childArgs = [LIB, input, output];
|
|
251
|
+
if (args.bakeSvg) childArgs.push('--bake-svg');
|
|
252
|
+
const r = spawnSync(process.execPath, childArgs, { stdio });
|
|
248
253
|
if (r.status !== 0) {
|
|
249
254
|
process.stderr.write('error: render failed for ' + input + ' (exit ' + r.status + ')\n');
|
|
250
255
|
process.exit(r.status || 1);
|
package/lib/md2doc.js
CHANGED
|
@@ -20,9 +20,13 @@
|
|
|
20
20
|
|
|
21
21
|
const fs = require('fs');
|
|
22
22
|
const path = require('path');
|
|
23
|
-
const { spawnSync } = require('child_process');
|
|
24
23
|
|
|
25
24
|
const [,, src, dst] = process.argv;
|
|
25
|
+
const BAKE_SVG = process.argv.slice(4).includes('--bake-svg');
|
|
26
|
+
|
|
27
|
+
// How long to let client-side WaveDrom / Mermaid scripts render before we
|
|
28
|
+
// snapshot the DOM (PDF print, or --bake-svg inert-SVG bake).
|
|
29
|
+
const DIAGRAM_RENDER_WAIT_MS = 2500;
|
|
26
30
|
if (!src || !dst) {
|
|
27
31
|
console.error('Usage: node md2doc.js <input.md> <output.html|pdf>');
|
|
28
32
|
process.exit(1);
|
|
@@ -55,56 +59,57 @@ function safeResolve(modulePath) {
|
|
|
55
59
|
}
|
|
56
60
|
}
|
|
57
61
|
|
|
58
|
-
function inlineScriptTag(sourcePath) {
|
|
62
|
+
function inlineScriptTag(sourcePath, engine) {
|
|
59
63
|
if (!sourcePath) {
|
|
60
64
|
return null;
|
|
61
65
|
}
|
|
62
|
-
|
|
66
|
+
const marker = engine ? ` data-md2doc-diagram-engine="${engine}"` : '';
|
|
67
|
+
return `<script type="text/javascript"${marker}>\n${fs.readFileSync(sourcePath, 'utf8')}\n</script>`;
|
|
63
68
|
}
|
|
64
69
|
|
|
70
|
+
// wavedrom is pinned to 3.5.0 in package.json: 3.6.1+ adds an `exports` map
|
|
71
|
+
// that no longer exposes the `wavedrom/wavedrom.min.js` / `wavedrom/skins/default.js`
|
|
72
|
+
// subpaths resolved below, so a bump past 3.5.x must switch to an exports-blessed
|
|
73
|
+
// entry (or a vendored copy) or these safeResolve() calls return null and the
|
|
74
|
+
// hard guard further down exits 1.
|
|
65
75
|
const localWaveDromSkin = firstExistingPath([
|
|
66
76
|
process.env.WAVEDROM_SKIN_JS,
|
|
67
77
|
safeResolve('wavedrom/skins/default.js'),
|
|
68
|
-
'/home/user/.vscode-server/extensions/shd101wyy.markdown-preview-enhanced-0.8.22/crossnote/dependencies/wavedrom/skins/default.js',
|
|
69
78
|
]);
|
|
70
79
|
|
|
71
80
|
const localWaveDromJs = firstExistingPath([
|
|
72
81
|
process.env.WAVEDROM_JS,
|
|
73
82
|
safeResolve('wavedrom/wavedrom.min.js'),
|
|
74
|
-
'/home/user/.vscode-server/extensions/shd101wyy.markdown-preview-enhanced-0.8.22/crossnote/dependencies/wavedrom/wavedrom.min.js',
|
|
75
83
|
]);
|
|
76
84
|
|
|
77
85
|
const localMermaidJs = firstExistingPath([
|
|
78
86
|
process.env.MERMAID_JS,
|
|
79
87
|
safeResolve('mermaid/dist/mermaid.min.js'),
|
|
80
|
-
'/home/user/.vscode-server/extensions/shd101wyy.markdown-preview-enhanced-0.8.22/crossnote/dependencies/mermaid/mermaid.min.js',
|
|
81
88
|
]);
|
|
82
89
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|| '<script src="https://cdn.jsdelivr.net/npm/wavedrom/wavedrom.min.js" type="text/javascript"></script>';
|
|
90
|
+
if (!localMermaidJs || !localWaveDromJs || !localWaveDromSkin) {
|
|
91
|
+
console.error('[ERROR] bundled diagram runtime missing — reinstall dependencies with `npm install`');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
88
94
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
mermaid.initialize({ startOnLoad: true, theme: 'default' });
|
|
93
|
-
</script>`;
|
|
95
|
+
const waveDromSkinTag = inlineScriptTag(localWaveDromSkin, 'wavedrom');
|
|
96
|
+
const waveDromTag = inlineScriptTag(localWaveDromJs, 'wavedrom');
|
|
97
|
+
const mermaidScriptTag = inlineScriptTag(localMermaidJs, 'mermaid');
|
|
94
98
|
|
|
95
|
-
const mermaidInitTag =
|
|
96
|
-
? `<script type="text/javascript">
|
|
99
|
+
const mermaidInitTag = `<script type="text/javascript" data-md2doc-diagram-engine="mermaid">
|
|
97
100
|
if (typeof mermaid !== 'undefined') {
|
|
98
101
|
mermaid.initialize({ startOnLoad: true, theme: 'default' });
|
|
99
102
|
}
|
|
100
|
-
</script
|
|
101
|
-
: '';
|
|
103
|
+
</script>`;
|
|
102
104
|
|
|
103
105
|
// ── Markdown → HTML body ─────────────────────────────────────────────────────
|
|
104
106
|
// Use a custom renderer to intercept fenced code blocks before marked escapes
|
|
105
107
|
// their content. This is the correct approach — pre-processing the raw markdown
|
|
106
108
|
// string causes marked to re-parse the injected HTML and mangle indented lines.
|
|
107
109
|
|
|
110
|
+
let usesMermaid = false;
|
|
111
|
+
let usesWaveDrom = false;
|
|
112
|
+
|
|
108
113
|
let bodyHtml;
|
|
109
114
|
let tocHtml = '';
|
|
110
115
|
let serializedSections = '[]';
|
|
@@ -306,9 +311,11 @@ ${itemsHtml}
|
|
|
306
311
|
const code = (typeof token === 'object') ? token.text : token;
|
|
307
312
|
|
|
308
313
|
if (lang === 'wavedrom') {
|
|
314
|
+
usesWaveDrom = true;
|
|
309
315
|
return `\n<script type="WaveDrom">\n${code}\n</script>\n`;
|
|
310
316
|
}
|
|
311
317
|
if (lang === 'mermaid') {
|
|
318
|
+
usesMermaid = true;
|
|
312
319
|
// Escape so the browser delivers the literal source to mermaid. Raw
|
|
313
320
|
// injection lets the HTML parser consume entities and tags first —
|
|
314
321
|
// an author's <IP> became an <IP> element mermaid sanitized
|
|
@@ -316,19 +323,12 @@ ${itemsHtml}
|
|
|
316
323
|
return `\n<div class="mermaid">\n${escapeHtml(code)}\n</div>\n`;
|
|
317
324
|
}
|
|
318
325
|
if (lang === 'dot' || lang === 'graphviz') {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
.replace(/<\?xml[^>]*\?>/g, '')
|
|
326
|
-
.replace(/<!DOCTYPE[^>]*>/g, '')
|
|
327
|
-
.trim();
|
|
328
|
-
return `\n<div class="graphviz">${svg}</div>\n`;
|
|
329
|
-
}
|
|
330
|
-
console.error('[WARN] dot render failed:', r.stderr);
|
|
331
|
-
// Fall through to default code block
|
|
326
|
+
// Defer rendering to the async bakeGraphviz() post-pass so the
|
|
327
|
+
// synchronous marked() pass stays sync. The dot source is carried as
|
|
328
|
+
// base64 in a data attribute — safe for arbitrary dot syntax (quotes,
|
|
329
|
+
// angle brackets, newlines) inside an HTML attribute.
|
|
330
|
+
const b64 = Buffer.from(code, 'utf8').toString('base64');
|
|
331
|
+
return `\n<div class="graphviz" data-graphviz-src="${b64}"></div>\n`;
|
|
332
332
|
}
|
|
333
333
|
// Default: syntax-highlighted code block
|
|
334
334
|
const escaped = code.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
@@ -1054,9 +1054,9 @@ ${bodyHtml}
|
|
|
1054
1054
|
</div>
|
|
1055
1055
|
|
|
1056
1056
|
<!-- WaveDrom -->
|
|
1057
|
-
${waveDromSkinTag}
|
|
1057
|
+
${usesWaveDrom ? `${waveDromSkinTag}
|
|
1058
1058
|
${waveDromTag}
|
|
1059
|
-
<script type="text/javascript">
|
|
1059
|
+
<script type="text/javascript" data-md2doc-diagram-engine="wavedrom">
|
|
1060
1060
|
function renderWaveDrom() {
|
|
1061
1061
|
if (typeof WaveDrom !== 'undefined') {
|
|
1062
1062
|
WaveDrom.ProcessAll();
|
|
@@ -1066,11 +1066,11 @@ ${waveDromTag}
|
|
|
1066
1066
|
window.addEventListener('load', renderWaveDrom);
|
|
1067
1067
|
setTimeout(renderWaveDrom, 250);
|
|
1068
1068
|
setTimeout(renderWaveDrom, 1000);
|
|
1069
|
-
</script
|
|
1069
|
+
</script>` : ''}
|
|
1070
1070
|
|
|
1071
1071
|
<!-- Mermaid -->
|
|
1072
|
-
${mermaidScriptTag}
|
|
1073
|
-
${mermaidInitTag}
|
|
1072
|
+
${usesMermaid ? `${mermaidScriptTag}
|
|
1073
|
+
${mermaidInitTag}` : ''}
|
|
1074
1074
|
|
|
1075
1075
|
<!-- Reader runtime -->
|
|
1076
1076
|
<script id="reader-section-data" type="application/json">${serializedSections}</script>
|
|
@@ -1540,13 +1540,90 @@ ${mermaidInitTag}
|
|
|
1540
1540
|
</body>
|
|
1541
1541
|
</html>`;
|
|
1542
1542
|
|
|
1543
|
+
// Render every deferred dot/graphviz placeholder to inline SVG using the
|
|
1544
|
+
// in-process WASM engine. Loads the WASM module only when at least one dot
|
|
1545
|
+
// block exists, so text-only docs pay nothing.
|
|
1546
|
+
async function bakeGraphviz(htmlStr) {
|
|
1547
|
+
if (!/data-graphviz-src=/.test(htmlStr)) return htmlStr;
|
|
1548
|
+
let Graphviz;
|
|
1549
|
+
try {
|
|
1550
|
+
({ Graphviz } = require('@hpcc-js/wasm-graphviz'));
|
|
1551
|
+
} catch (e) {
|
|
1552
|
+
console.error('[ERROR] @hpcc-js/wasm-graphviz not installed — run `npm install`:', e.message);
|
|
1553
|
+
return htmlStr;
|
|
1554
|
+
}
|
|
1555
|
+
const gv = await Graphviz.load();
|
|
1556
|
+
return htmlStr.replace(/<div class="graphviz" data-graphviz-src="([^"]*)"><\/div>/g, (m, b64) => {
|
|
1557
|
+
const dotSrc = Buffer.from(b64, 'base64').toString('utf8');
|
|
1558
|
+
try {
|
|
1559
|
+
const svg = gv.dot(dotSrc)
|
|
1560
|
+
.replace(/<\?xml[^>]*\?>/g, '')
|
|
1561
|
+
.replace(/<!DOCTYPE[\s\S]*?>/g, '')
|
|
1562
|
+
// drop graphviz's "Generated by graphviz" banner comment so the div and <svg> are adjacent
|
|
1563
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
1564
|
+
.trim();
|
|
1565
|
+
return `<div class="graphviz">${svg}</div>`;
|
|
1566
|
+
} catch (e) {
|
|
1567
|
+
console.error('[WARN] graphviz render failed:', e.message);
|
|
1568
|
+
const escaped = dotSrc.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1569
|
+
return `<pre><code class="language-dot">${escaped}</code></pre>\n`;
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
function launchBrowser(puppeteer) {
|
|
1575
|
+
return puppeteer.launch({
|
|
1576
|
+
headless: 'new',
|
|
1577
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-crash-reporter', '--disable-dev-shm-usage'],
|
|
1578
|
+
});
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// Pre-render mermaid/wavedrom to inert SVG using headless Chromium, then strip
|
|
1582
|
+
// the diagram-engine runtime scripts so the output HTML carries no diagram JS.
|
|
1583
|
+
async function bakeDiagrams(htmlStr) {
|
|
1584
|
+
if (!/data-md2doc-diagram-engine/.test(htmlStr)) return htmlStr;
|
|
1585
|
+
let puppeteer;
|
|
1586
|
+
try {
|
|
1587
|
+
puppeteer = require('puppeteer');
|
|
1588
|
+
} catch (e) {
|
|
1589
|
+
console.error('[ERROR] --bake-svg requires puppeteer/Chromium — install it, or drop --bake-svg:', e.message);
|
|
1590
|
+
process.exit(1);
|
|
1591
|
+
}
|
|
1592
|
+
const tmp = dst.replace(/\.html$/i, '._bake.html');
|
|
1593
|
+
fs.writeFileSync(tmp, htmlStr, 'utf8');
|
|
1594
|
+
let browser;
|
|
1595
|
+
try {
|
|
1596
|
+
browser = await launchBrowser(puppeteer);
|
|
1597
|
+
} catch (e) {
|
|
1598
|
+
fs.unlinkSync(tmp);
|
|
1599
|
+
console.error('[ERROR] --bake-svg requires Chromium but it failed to launch — drop --bake-svg or install Chromium:', e.message);
|
|
1600
|
+
process.exit(1);
|
|
1601
|
+
}
|
|
1602
|
+
try {
|
|
1603
|
+
const page = await browser.newPage();
|
|
1604
|
+
await page.goto('file://' + path.resolve(tmp), { waitUntil: 'load' });
|
|
1605
|
+
await new Promise(r => setTimeout(r, DIAGRAM_RENDER_WAIT_MS));
|
|
1606
|
+
await page.evaluate(() => {
|
|
1607
|
+
document.querySelectorAll('script[data-md2doc-diagram-engine]').forEach((s) => s.remove());
|
|
1608
|
+
});
|
|
1609
|
+
return await page.content();
|
|
1610
|
+
} finally {
|
|
1611
|
+
await browser.close();
|
|
1612
|
+
fs.unlinkSync(tmp);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1543
1616
|
// ── Output ───────────────────────────────────────────────────────────────────
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
console.log(`[HTML] ${src} → ${dst}`);
|
|
1617
|
+
(async () => {
|
|
1618
|
+
let finalHtml = await bakeGraphviz(html);
|
|
1547
1619
|
|
|
1548
|
-
|
|
1549
|
-
|
|
1620
|
+
if (ext === '.html') {
|
|
1621
|
+
if (BAKE_SVG) finalHtml = await bakeDiagrams(finalHtml);
|
|
1622
|
+
fs.writeFileSync(dst, finalHtml, 'utf8');
|
|
1623
|
+
console.log(`[HTML] ${src} → ${dst}`);
|
|
1624
|
+
|
|
1625
|
+
} else if (ext === '.pdf') {
|
|
1626
|
+
if (BAKE_SVG) console.log('[INFO] --bake-svg is redundant for PDF output (already static); ignoring');
|
|
1550
1627
|
let puppeteer;
|
|
1551
1628
|
try {
|
|
1552
1629
|
puppeteer = require('puppeteer');
|
|
@@ -1555,26 +1632,25 @@ if (ext === '.html') {
|
|
|
1555
1632
|
process.exit(1);
|
|
1556
1633
|
}
|
|
1557
1634
|
|
|
1558
|
-
// Write temporary HTML, launch headless Chromium, export PDF
|
|
1635
|
+
// Write temporary HTML, launch headless Chromium, export PDF.
|
|
1559
1636
|
// Case-insensitive: an uppercase .PDF dst must not make tmp === dst, or the
|
|
1560
1637
|
// unlinkSync below deletes the freshly written PDF.
|
|
1561
1638
|
const tmp = dst.replace(/\.pdf$/i, '._tmp.html');
|
|
1562
|
-
fs.writeFileSync(tmp,
|
|
1639
|
+
fs.writeFileSync(tmp, finalHtml, 'utf8');
|
|
1563
1640
|
|
|
1564
|
-
const browser = await puppeteer
|
|
1565
|
-
|
|
1566
|
-
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-crash-reporter', '--disable-dev-shm-usage'],
|
|
1567
|
-
});
|
|
1568
|
-
const page = await browser.newPage();
|
|
1641
|
+
const browser = await launchBrowser(puppeteer);
|
|
1642
|
+
const page = await browser.newPage();
|
|
1569
1643
|
|
|
1570
1644
|
await page.goto('file://' + path.resolve(tmp), { waitUntil: 'load' });
|
|
1571
1645
|
|
|
1572
|
-
// Allow WaveDrom / Mermaid scripts time to render diagrams
|
|
1573
|
-
|
|
1646
|
+
// Allow WaveDrom / Mermaid scripts time to render diagrams.
|
|
1647
|
+
// NOTE: this sleep is load-bearing for the DEFAULT (view-time) render path.
|
|
1648
|
+
// It is only safe to drop under --bake-svg, where the DOM is already final SVG.
|
|
1649
|
+
await new Promise(r => setTimeout(r, DIAGRAM_RENDER_WAIT_MS));
|
|
1574
1650
|
|
|
1575
1651
|
await page.pdf({
|
|
1576
|
-
path:
|
|
1577
|
-
format:
|
|
1652
|
+
path: dst,
|
|
1653
|
+
format: 'A4',
|
|
1578
1654
|
printBackground: true,
|
|
1579
1655
|
outline: true,
|
|
1580
1656
|
tagged: true,
|
|
@@ -1584,9 +1660,12 @@ if (ext === '.html') {
|
|
|
1584
1660
|
await browser.close();
|
|
1585
1661
|
fs.unlinkSync(tmp);
|
|
1586
1662
|
console.log(`[PDF] ${src} → ${dst}`);
|
|
1587
|
-
})();
|
|
1588
1663
|
|
|
1589
|
-
} else {
|
|
1590
|
-
|
|
1664
|
+
} else {
|
|
1665
|
+
console.error('[ERROR] Output extension must be .html or .pdf');
|
|
1666
|
+
process.exit(1);
|
|
1667
|
+
}
|
|
1668
|
+
})().catch((e) => {
|
|
1669
|
+
console.error('[ERROR]', (e && e.stack) || e);
|
|
1591
1670
|
process.exit(1);
|
|
1592
|
-
}
|
|
1671
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helping-ai-workflow/md2doc",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Markdown → HTML / PDF renderer with WaveDrom, Mermaid, and Graphviz support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -26,8 +26,11 @@
|
|
|
26
26
|
"node": ">=18"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@hpcc-js/wasm-graphviz": "1.22.0",
|
|
29
30
|
"marked": "^14.1.0",
|
|
30
|
-
"
|
|
31
|
+
"mermaid": "11.15.0",
|
|
32
|
+
"puppeteer": "^24.15.0",
|
|
33
|
+
"wavedrom": "3.5.0"
|
|
31
34
|
},
|
|
32
35
|
"scripts": {
|
|
33
36
|
"preinstall": "node scripts/preinstall.js",
|