@masumdev/markforge 0.4.0 → 0.5.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 +4 -4
- package/dist/App-JOOTPDJN.mjs +847 -0
- package/dist/{chunk-CRV7R2BG.mjs → chunk-H3ZUUSHP.mjs} +303 -98
- package/dist/{chunk-TNWZ4MFS.mjs → chunk-UNWAEVDU.mjs} +4 -3
- package/dist/cli.mjs +14 -6
- package/dist/index.d.mts +117 -50
- package/dist/index.d.ts +117 -50
- package/dist/index.js +838 -145
- package/dist/index.mjs +826 -139
- package/dist/{previewServer-XAUOBNBZ.mjs → previewServer-U47WQ5FV.mjs} +1 -1
- package/package.json +1 -1
- package/dist/App-3QDKBKHG.mjs +0 -328
package/dist/index.js
CHANGED
|
@@ -38,6 +38,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
38
38
|
// src/index.ts
|
|
39
39
|
var src_exports = {};
|
|
40
40
|
__export(src_exports, {
|
|
41
|
+
BackCoverPreset: () => BackCoverPreset,
|
|
42
|
+
CoverPagePreset: () => CoverPagePreset,
|
|
41
43
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
42
44
|
KATEX_INLINE_CSS: () => KATEX_INLINE_CSS,
|
|
43
45
|
MARKFORGE_VERSION: () => MARKFORGE_VERSION,
|
|
@@ -46,15 +48,21 @@ __export(src_exports, {
|
|
|
46
48
|
PAPER_DIMENSIONS_TWIP: () => PAPER_DIMENSIONS_TWIP,
|
|
47
49
|
PaperSizeEnum: () => PaperSizeEnum,
|
|
48
50
|
SYNTAX_COLORS: () => SYNTAX_COLORS,
|
|
51
|
+
SignatureAlign: () => SignatureAlign,
|
|
52
|
+
SignatureStyle: () => SignatureStyle,
|
|
49
53
|
SyntaxTheme: () => SyntaxTheme,
|
|
50
54
|
THEMES: () => THEMES,
|
|
51
55
|
THEME_CORPORATE: () => THEME_CORPORATE,
|
|
52
56
|
THEME_DEFAULT: () => THEME_DEFAULT,
|
|
53
57
|
Theme: () => Theme,
|
|
54
58
|
WatermarkPosition: () => WatermarkPosition,
|
|
59
|
+
applyHeadingNumbering: () => applyHeadingNumbering,
|
|
55
60
|
buildDocxDocument: () => buildDocxDocument,
|
|
56
61
|
buildHtmlDocument: () => buildHtmlDocument,
|
|
57
62
|
buildPdfDocument: () => buildPdfDocument,
|
|
63
|
+
buildPngDocument: () => buildPngDocument,
|
|
64
|
+
buildTextDocument: () => buildTextDocument,
|
|
65
|
+
buildTxtDocument: () => buildTextDocument,
|
|
58
66
|
compileMarkdown: () => compileMarkdown,
|
|
59
67
|
defineConfig: () => defineConfig,
|
|
60
68
|
escapeHtml: () => escapeHtml,
|
|
@@ -83,6 +91,7 @@ __export(src_exports, {
|
|
|
83
91
|
renderBackCoverHtml: () => renderBackCoverHtml,
|
|
84
92
|
renderCoverPageHtml: () => renderCoverPageHtml,
|
|
85
93
|
renderInlinesToHtml: () => renderInlinesToHtml,
|
|
94
|
+
renderInlinesToText: () => renderInlinesToText,
|
|
86
95
|
renderMathToHtml: () => renderMathToHtml,
|
|
87
96
|
renderMermaidToPng: () => renderMermaidToPng,
|
|
88
97
|
renderNodesToHtml: () => renderNodesToHtml,
|
|
@@ -96,8 +105,8 @@ __export(src_exports, {
|
|
|
96
105
|
module.exports = __toCommonJS(src_exports);
|
|
97
106
|
|
|
98
107
|
// src/core/engine.ts
|
|
99
|
-
var
|
|
100
|
-
var
|
|
108
|
+
var fs7 = __toESM(require("fs"));
|
|
109
|
+
var path7 = __toESM(require("path"));
|
|
101
110
|
|
|
102
111
|
// src/core/parser.ts
|
|
103
112
|
var import_gray_matter = __toESM(require("gray-matter"));
|
|
@@ -271,7 +280,16 @@ function parseInlineSpans(text) {
|
|
|
271
280
|
remaining = remaining.slice(nextSpecial);
|
|
272
281
|
}
|
|
273
282
|
}
|
|
274
|
-
|
|
283
|
+
const merged = [];
|
|
284
|
+
for (const s of spans) {
|
|
285
|
+
const prev = merged[merged.length - 1];
|
|
286
|
+
if (prev && prev.type === "text" && s.type === "text") {
|
|
287
|
+
prev.content += s.content;
|
|
288
|
+
} else {
|
|
289
|
+
merged.push(s);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return merged;
|
|
275
293
|
}
|
|
276
294
|
function slugify(text) {
|
|
277
295
|
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -283,6 +301,7 @@ function applyHeadingNumbering(nodes, tocEntries, options) {
|
|
|
283
301
|
const counters = [0, 0, 0, 0, 0, 0];
|
|
284
302
|
for (const node of nodes) {
|
|
285
303
|
if (node.type === "heading" && node.level) {
|
|
304
|
+
if (node._numbered) continue;
|
|
286
305
|
const lvl = node.level;
|
|
287
306
|
if (lvl > depth) continue;
|
|
288
307
|
if (lvl === 1 && skipH1) continue;
|
|
@@ -298,6 +317,7 @@ function applyHeadingNumbering(nodes, tocEntries, options) {
|
|
|
298
317
|
const originalText = node.text || "";
|
|
299
318
|
node.text = fullPrefix + originalText;
|
|
300
319
|
node.inlines = parseInlineSpans(node.text);
|
|
320
|
+
node._numbered = true;
|
|
301
321
|
const toc = tocEntries.find((t) => t.id === node.id);
|
|
302
322
|
if (toc) {
|
|
303
323
|
toc.text = node.text;
|
|
@@ -644,6 +664,7 @@ var import_docx = require("docx");
|
|
|
644
664
|
// src/core/imageResolver.ts
|
|
645
665
|
var fs = __toESM(require("fs"));
|
|
646
666
|
var path = __toESM(require("path"));
|
|
667
|
+
var import_node_url = require("url");
|
|
647
668
|
var memoryImageCache = /* @__PURE__ */ new Map();
|
|
648
669
|
function getMimeType(filePathOrUrl) {
|
|
649
670
|
const clean = filePathOrUrl.split("?")[0].toLowerCase();
|
|
@@ -700,9 +721,19 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
700
721
|
memoryImageCache.set(cacheKey, resolved2);
|
|
701
722
|
return resolved2;
|
|
702
723
|
}
|
|
703
|
-
let localPath =
|
|
724
|
+
let localPath = src;
|
|
725
|
+
if (src.startsWith("file://")) {
|
|
726
|
+
try {
|
|
727
|
+
localPath = (0, import_node_url.fileURLToPath)(src);
|
|
728
|
+
} catch {
|
|
729
|
+
localPath = src;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
if (!path.isAbsolute(localPath)) {
|
|
733
|
+
localPath = path.resolve(baseDir, localPath);
|
|
734
|
+
}
|
|
704
735
|
if (!fs.existsSync(localPath)) {
|
|
705
|
-
const cwdPath = path.resolve(process.cwd(), src);
|
|
736
|
+
const cwdPath = path.resolve(process.cwd(), src.startsWith("file://") ? localPath : src);
|
|
706
737
|
if (fs.existsSync(cwdPath)) {
|
|
707
738
|
localPath = cwdPath;
|
|
708
739
|
} else {
|
|
@@ -1104,13 +1135,13 @@ var import_node_child_process2 = require("child_process");
|
|
|
1104
1135
|
var fs5 = __toESM(require("fs"));
|
|
1105
1136
|
var os2 = __toESM(require("os"));
|
|
1106
1137
|
var path5 = __toESM(require("path"));
|
|
1107
|
-
var
|
|
1138
|
+
var import_node_url4 = require("url");
|
|
1108
1139
|
|
|
1109
1140
|
// src/core/pdf/pdfBuilder.ts
|
|
1110
1141
|
var fs4 = __toESM(require("fs"));
|
|
1111
1142
|
var path4 = __toESM(require("path"));
|
|
1112
1143
|
var os = __toESM(require("os"));
|
|
1113
|
-
var
|
|
1144
|
+
var import_node_url3 = require("url");
|
|
1114
1145
|
var import_node_child_process = require("child_process");
|
|
1115
1146
|
var import_pdf_lib = require("pdf-lib");
|
|
1116
1147
|
var import_pdf_encrypt = require("@pdfsmaller/pdf-encrypt");
|
|
@@ -1125,6 +1156,7 @@ var OutputFormat = /* @__PURE__ */ ((OutputFormat2) => {
|
|
|
1125
1156
|
OutputFormat2["PDF"] = "pdf";
|
|
1126
1157
|
OutputFormat2["HTML"] = "html";
|
|
1127
1158
|
OutputFormat2["PNG"] = "png";
|
|
1159
|
+
OutputFormat2["TXT"] = "txt";
|
|
1128
1160
|
return OutputFormat2;
|
|
1129
1161
|
})(OutputFormat || {});
|
|
1130
1162
|
var Theme = /* @__PURE__ */ ((Theme2) => {
|
|
@@ -1159,6 +1191,33 @@ var WatermarkPosition = /* @__PURE__ */ ((WatermarkPosition2) => {
|
|
|
1159
1191
|
WatermarkPosition2["BOTTOM_RIGHT"] = "bottom-right";
|
|
1160
1192
|
return WatermarkPosition2;
|
|
1161
1193
|
})(WatermarkPosition || {});
|
|
1194
|
+
var CoverPagePreset = /* @__PURE__ */ ((CoverPagePreset2) => {
|
|
1195
|
+
CoverPagePreset2["MODERN"] = "modern";
|
|
1196
|
+
CoverPagePreset2["CORPORATE_SPLIT"] = "corporate-split";
|
|
1197
|
+
CoverPagePreset2["MINIMAL"] = "minimal";
|
|
1198
|
+
CoverPagePreset2["CARD"] = "card";
|
|
1199
|
+
return CoverPagePreset2;
|
|
1200
|
+
})(CoverPagePreset || {});
|
|
1201
|
+
var BackCoverPreset = /* @__PURE__ */ ((BackCoverPreset2) => {
|
|
1202
|
+
BackCoverPreset2["MODERN"] = "modern";
|
|
1203
|
+
BackCoverPreset2["CORPORATE"] = "corporate";
|
|
1204
|
+
BackCoverPreset2["MINIMAL"] = "minimal";
|
|
1205
|
+
BackCoverPreset2["CONTACT_CARD"] = "contact-card";
|
|
1206
|
+
return BackCoverPreset2;
|
|
1207
|
+
})(BackCoverPreset || {});
|
|
1208
|
+
var SignatureAlign = /* @__PURE__ */ ((SignatureAlign2) => {
|
|
1209
|
+
SignatureAlign2["LEFT"] = "left";
|
|
1210
|
+
SignatureAlign2["CENTER"] = "center";
|
|
1211
|
+
SignatureAlign2["RIGHT"] = "right";
|
|
1212
|
+
SignatureAlign2["SPACE_BETWEEN"] = "space-between";
|
|
1213
|
+
return SignatureAlign2;
|
|
1214
|
+
})(SignatureAlign || {});
|
|
1215
|
+
var SignatureStyle = /* @__PURE__ */ ((SignatureStyle2) => {
|
|
1216
|
+
SignatureStyle2["LINE"] = "line";
|
|
1217
|
+
SignatureStyle2["BOX"] = "box";
|
|
1218
|
+
SignatureStyle2["CLEAN"] = "clean";
|
|
1219
|
+
return SignatureStyle2;
|
|
1220
|
+
})(SignatureStyle || {});
|
|
1162
1221
|
|
|
1163
1222
|
// src/core/html/htmlThemes.ts
|
|
1164
1223
|
var THEME_COMPONENTS = `
|
|
@@ -1185,7 +1244,7 @@ var THEME_COMPONENTS = `
|
|
|
1185
1244
|
.document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
|
|
1186
1245
|
|
|
1187
1246
|
/* Table of Contents */
|
|
1188
|
-
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
|
|
1247
|
+
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; page-break-after: always; break-after: page; }
|
|
1189
1248
|
.table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
1190
1249
|
.table-of-contents ul { list-style: none; padding: 0; margin: 0; }
|
|
1191
1250
|
.table-of-contents li { padding: 0.25rem 0; }
|
|
@@ -1258,11 +1317,13 @@ var THEME_CORPORATE = `
|
|
|
1258
1317
|
}
|
|
1259
1318
|
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
1260
1319
|
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
1261
|
-
h1, h2, h3, h4, h5, h6 { color: var(--mf-
|
|
1262
|
-
h1 { font-size: 2.2rem; border-bottom:
|
|
1320
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-primary-dark); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
1321
|
+
h1 { font-size: 2.2rem; color: var(--mf-primary-dark); border-bottom: 2.5px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
1263
1322
|
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
|
|
1264
|
-
h3 { font-size: 1.3rem; }
|
|
1265
|
-
h4 { font-size: 1.1rem; }
|
|
1323
|
+
h3 { font-size: 1.3rem; color: var(--mf-primary-dark); }
|
|
1324
|
+
h4 { font-size: 1.1rem; color: var(--mf-primary-dark); }
|
|
1325
|
+
h5 { font-size: 1.0rem; color: var(--mf-primary-dark); }
|
|
1326
|
+
h6 { font-size: 0.9rem; color: var(--mf-primary-dark); }
|
|
1266
1327
|
p { margin: 0.8rem 0; }
|
|
1267
1328
|
`;
|
|
1268
1329
|
var THEME_DEFAULT = THEME_CORPORATE;
|
|
@@ -1304,11 +1365,13 @@ function generateThemeCss(theme) {
|
|
|
1304
1365
|
}
|
|
1305
1366
|
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
1306
1367
|
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
1307
|
-
h1, h2, h3, h4, h5, h6 { color: var(--mf-
|
|
1308
|
-
h1 { font-size: 2.2rem; border-bottom:
|
|
1368
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-primary-dark); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
1369
|
+
h1 { font-size: 2.2rem; color: var(--mf-primary-dark); border-bottom: 2.5px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
1309
1370
|
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
|
|
1310
|
-
h3 { font-size: 1.3rem; }
|
|
1311
|
-
h4 { font-size: 1.1rem; }
|
|
1371
|
+
h3 { font-size: 1.3rem; color: var(--mf-primary-dark); }
|
|
1372
|
+
h4 { font-size: 1.1rem; color: var(--mf-primary-dark); }
|
|
1373
|
+
h5 { font-size: 1.0rem; color: var(--mf-primary-dark); }
|
|
1374
|
+
h6 { font-size: 0.9rem; color: var(--mf-primary-dark); }
|
|
1312
1375
|
p { margin: 0.8rem 0; }
|
|
1313
1376
|
${theme.customCss || ""}
|
|
1314
1377
|
`;
|
|
@@ -1322,7 +1385,7 @@ ${theme.customCss || ""}
|
|
|
1322
1385
|
// src/config/loadConfig.ts
|
|
1323
1386
|
var fs2 = __toESM(require("fs"));
|
|
1324
1387
|
var path2 = __toESM(require("path"));
|
|
1325
|
-
var
|
|
1388
|
+
var import_node_url2 = require("url");
|
|
1326
1389
|
var YAML = __toESM(require("yaml"));
|
|
1327
1390
|
var DEFAULT_CONFIG_FILENAMES = [
|
|
1328
1391
|
"markforge.config.json",
|
|
@@ -1430,7 +1493,7 @@ async function loadConfig(customPath, startDir = process.cwd()) {
|
|
|
1430
1493
|
userConfig = YAML.parse(raw) || {};
|
|
1431
1494
|
} else if (ext === ".ts" || ext === ".js" || ext === ".mjs" || ext === ".cjs") {
|
|
1432
1495
|
try {
|
|
1433
|
-
const fileUrl = `${(0,
|
|
1496
|
+
const fileUrl = `${(0, import_node_url2.pathToFileURL)(resolvedPath).href}?t=${Date.now()}`;
|
|
1434
1497
|
const mod = await import(fileUrl);
|
|
1435
1498
|
const rawExport = mod.default ?? mod.config ?? mod;
|
|
1436
1499
|
userConfig = (typeof rawExport === "function" ? await rawExport() : rawExport) || {};
|
|
@@ -1517,16 +1580,45 @@ function formatMarginCss(margin, defaultCss = "2.5cm") {
|
|
|
1517
1580
|
if (/^[0-9.]+$/.test(str)) return `${str}pt`;
|
|
1518
1581
|
return str;
|
|
1519
1582
|
}
|
|
1520
|
-
function replaceDocumentTokens(template = "", meta) {
|
|
1521
|
-
|
|
1522
|
-
|
|
1583
|
+
function replaceDocumentTokens(template = "", meta = {}) {
|
|
1584
|
+
if (!template) return "";
|
|
1585
|
+
const currentYear = meta.year ? String(meta.year) : (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1586
|
+
const tokenMap = {
|
|
1587
|
+
title: meta.title ? String(meta.title) : "",
|
|
1588
|
+
subtitle: meta.subtitle ? String(meta.subtitle) : "",
|
|
1589
|
+
author: meta.author ? Array.isArray(meta.author) ? meta.author.join(", ") : String(meta.author) : "",
|
|
1590
|
+
version: meta.version ? String(meta.version) : "",
|
|
1591
|
+
date: meta.date ? String(meta.date) : "",
|
|
1592
|
+
company: meta.company ? String(meta.company) : "",
|
|
1593
|
+
year: currentYear
|
|
1594
|
+
};
|
|
1595
|
+
if (meta.metadata && typeof meta.metadata === "object") {
|
|
1596
|
+
for (const [key, val] of Object.entries(meta.metadata)) {
|
|
1597
|
+
if (val !== void 0 && val !== null) {
|
|
1598
|
+
tokenMap[key.toLowerCase()] = String(val);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
for (const [key, val] of Object.entries(meta)) {
|
|
1603
|
+
if (val !== void 0 && val !== null && typeof val !== "object") {
|
|
1604
|
+
tokenMap[key.toLowerCase()] = String(val);
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
return template.replace(/\{([a-zA-Z0-9_\-]+)\}/gi, (match, tokenKey) => {
|
|
1608
|
+
const lowerKey = tokenKey.toLowerCase();
|
|
1609
|
+
if (lowerKey in tokenMap) {
|
|
1610
|
+
return tokenMap[lowerKey];
|
|
1611
|
+
}
|
|
1612
|
+
return match;
|
|
1613
|
+
});
|
|
1523
1614
|
}
|
|
1524
|
-
function normalizeWatermark(rawWatermark) {
|
|
1615
|
+
function normalizeWatermark(rawWatermark, tokens) {
|
|
1525
1616
|
if (!rawWatermark) {
|
|
1526
1617
|
return void 0;
|
|
1527
1618
|
}
|
|
1528
1619
|
if (typeof rawWatermark === "string") {
|
|
1529
|
-
|
|
1620
|
+
let text = rawWatermark.trim();
|
|
1621
|
+
if (tokens) text = replaceDocumentTokens(text, tokens);
|
|
1530
1622
|
if (!text) return void 0;
|
|
1531
1623
|
return {
|
|
1532
1624
|
text,
|
|
@@ -1539,8 +1631,10 @@ function normalizeWatermark(rawWatermark) {
|
|
|
1539
1631
|
}
|
|
1540
1632
|
if (typeof rawWatermark === "object") {
|
|
1541
1633
|
if (!rawWatermark.text || !rawWatermark.text.trim()) return void 0;
|
|
1634
|
+
let text = rawWatermark.text.trim();
|
|
1635
|
+
if (tokens) text = replaceDocumentTokens(text, tokens);
|
|
1542
1636
|
return {
|
|
1543
|
-
text
|
|
1637
|
+
text,
|
|
1544
1638
|
color: rawWatermark.color || "#94a3b8",
|
|
1545
1639
|
opacity: typeof rawWatermark.opacity === "number" ? rawWatermark.opacity : 0.08,
|
|
1546
1640
|
fontSize: rawWatermark.fontSize || 54,
|
|
@@ -1661,27 +1755,46 @@ function normalizeCoverPage(rawCover, tokenCtx = {}) {
|
|
|
1661
1755
|
const cfg = typeof rawCover === "object" ? rawCover : {};
|
|
1662
1756
|
if (cfg.enabled === false) return void 0;
|
|
1663
1757
|
const preset = cfg.preset || "modern";
|
|
1664
|
-
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title
|
|
1665
|
-
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle;
|
|
1666
|
-
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author;
|
|
1667
|
-
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
|
|
1668
|
-
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version;
|
|
1758
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title ? String(tokenCtx.title) : "Document Title";
|
|
1759
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle ? String(tokenCtx.subtitle) : void 0;
|
|
1760
|
+
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author ? String(tokenCtx.author) : void 0;
|
|
1761
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company ? String(tokenCtx.company) : void 0;
|
|
1762
|
+
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version ? String(tokenCtx.version) : void 0;
|
|
1669
1763
|
let dateStr;
|
|
1670
1764
|
if (typeof cfg.date === "string") {
|
|
1671
1765
|
dateStr = replaceDocumentTokens(cfg.date, tokenCtx);
|
|
1672
1766
|
} else if (cfg.date === true) {
|
|
1673
|
-
dateStr = tokenCtx.date
|
|
1767
|
+
dateStr = tokenCtx.date ? String(tokenCtx.date) : (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1674
1768
|
} else {
|
|
1675
|
-
dateStr = tokenCtx.date;
|
|
1769
|
+
dateStr = tokenCtx.date ? String(tokenCtx.date) : void 0;
|
|
1676
1770
|
}
|
|
1677
1771
|
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1678
1772
|
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1679
1773
|
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1680
1774
|
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1681
1775
|
const logoWidth = cfg.logoWidth;
|
|
1682
|
-
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
|
|
1776
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1777
|
+
const backgroundColor = typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1683
1778
|
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1779
|
+
const titleColor = typeof cfg.titleColor === "string" ? cfg.titleColor : void 0;
|
|
1780
|
+
const subtitleColor = typeof cfg.subtitleColor === "string" ? cfg.subtitleColor : void 0;
|
|
1781
|
+
const accentColor = typeof cfg.accentColor === "string" ? cfg.accentColor : void 0;
|
|
1684
1782
|
const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
|
|
1783
|
+
const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
|
|
1784
|
+
const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
|
|
1785
|
+
const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
|
|
1786
|
+
const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
|
|
1787
|
+
let socialMap;
|
|
1788
|
+
if (cfg.social && typeof cfg.social === "object") {
|
|
1789
|
+
socialMap = {};
|
|
1790
|
+
for (const [k, v] of Object.entries(cfg.social)) {
|
|
1791
|
+
if (typeof v === "string") {
|
|
1792
|
+
socialMap[k] = replaceDocumentTokens(v, tokenCtx);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1797
|
+
const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : void 0;
|
|
1685
1798
|
return {
|
|
1686
1799
|
enabled: true,
|
|
1687
1800
|
preset,
|
|
@@ -1697,8 +1810,18 @@ function normalizeCoverPage(rawCover, tokenCtx = {}) {
|
|
|
1697
1810
|
logo,
|
|
1698
1811
|
logoWidth,
|
|
1699
1812
|
bgGradient,
|
|
1813
|
+
backgroundColor,
|
|
1700
1814
|
textColor,
|
|
1701
|
-
|
|
1815
|
+
titleColor,
|
|
1816
|
+
subtitleColor,
|
|
1817
|
+
accentColor,
|
|
1818
|
+
footerText,
|
|
1819
|
+
address,
|
|
1820
|
+
email,
|
|
1821
|
+
phone,
|
|
1822
|
+
website,
|
|
1823
|
+
social: socialMap,
|
|
1824
|
+
copyright
|
|
1702
1825
|
};
|
|
1703
1826
|
}
|
|
1704
1827
|
function normalizeBackCover(rawBack, tokenCtx = {}) {
|
|
@@ -1708,7 +1831,10 @@ function normalizeBackCover(rawBack, tokenCtx = {}) {
|
|
|
1708
1831
|
const preset = cfg.preset || "modern";
|
|
1709
1832
|
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : "Thank You";
|
|
1710
1833
|
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : void 0;
|
|
1711
|
-
const
|
|
1834
|
+
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author ? String(tokenCtx.author) : void 0;
|
|
1835
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company ? String(tokenCtx.company) : void 0;
|
|
1836
|
+
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version ? String(tokenCtx.version) : void 0;
|
|
1837
|
+
const date = typeof cfg.date === "string" ? replaceDocumentTokens(cfg.date, tokenCtx) : tokenCtx.date ? String(tokenCtx.date) : void 0;
|
|
1712
1838
|
const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
|
|
1713
1839
|
const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
|
|
1714
1840
|
const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
|
|
@@ -1724,32 +1850,45 @@ function normalizeBackCover(rawBack, tokenCtx = {}) {
|
|
|
1724
1850
|
}
|
|
1725
1851
|
const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1726
1852
|
const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : company ? `Copyright (c) ${currentYear} ${company}. All Rights Reserved.` : void 0;
|
|
1853
|
+
const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
|
|
1727
1854
|
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1728
1855
|
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1729
1856
|
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1730
1857
|
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1731
1858
|
const logoWidth = cfg.logoWidth;
|
|
1732
|
-
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
|
|
1859
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1860
|
+
const backgroundColor = typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1733
1861
|
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1862
|
+
const titleColor = typeof cfg.titleColor === "string" ? cfg.titleColor : void 0;
|
|
1863
|
+
const subtitleColor = typeof cfg.subtitleColor === "string" ? cfg.subtitleColor : void 0;
|
|
1864
|
+
const accentColor = typeof cfg.accentColor === "string" ? cfg.accentColor : void 0;
|
|
1734
1865
|
return {
|
|
1735
1866
|
enabled: true,
|
|
1736
1867
|
preset,
|
|
1737
1868
|
title,
|
|
1738
1869
|
subtitle,
|
|
1870
|
+
author,
|
|
1739
1871
|
company,
|
|
1872
|
+
version,
|
|
1873
|
+
date,
|
|
1740
1874
|
address,
|
|
1741
1875
|
email,
|
|
1742
1876
|
phone,
|
|
1743
1877
|
website,
|
|
1744
1878
|
social: socialMap,
|
|
1745
1879
|
copyright,
|
|
1880
|
+
footerText,
|
|
1746
1881
|
badge,
|
|
1747
1882
|
badgeColor,
|
|
1748
1883
|
badgeTextColor,
|
|
1749
1884
|
logo,
|
|
1750
1885
|
logoWidth,
|
|
1751
1886
|
bgGradient,
|
|
1752
|
-
|
|
1887
|
+
backgroundColor,
|
|
1888
|
+
textColor,
|
|
1889
|
+
titleColor,
|
|
1890
|
+
subtitleColor,
|
|
1891
|
+
accentColor
|
|
1753
1892
|
};
|
|
1754
1893
|
}
|
|
1755
1894
|
function normalizeNumberHeadings(raw) {
|
|
@@ -1789,7 +1928,15 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1789
1928
|
const version = mergedMeta.version || void 0;
|
|
1790
1929
|
const company = mergedMeta.company || void 0;
|
|
1791
1930
|
const lang = mergedMeta.lang || "en";
|
|
1792
|
-
const tokenContext = {
|
|
1931
|
+
const tokenContext = {
|
|
1932
|
+
...mergedMeta,
|
|
1933
|
+
title,
|
|
1934
|
+
subtitle,
|
|
1935
|
+
author,
|
|
1936
|
+
version,
|
|
1937
|
+
date,
|
|
1938
|
+
company
|
|
1939
|
+
};
|
|
1793
1940
|
const theme = mergedMeta.theme || userConfig.theme || DEFAULT_CONFIG.theme;
|
|
1794
1941
|
const orientation = mergedMeta.orientation || userConfig.orientation || DEFAULT_CONFIG.orientation;
|
|
1795
1942
|
const paperSize = mergedMeta.paperSize || userConfig.paperSize || DEFAULT_CONFIG.paperSize;
|
|
@@ -1818,7 +1965,7 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1818
1965
|
const footer = normalizeHeaderFooter(rawFooter, tokenContext);
|
|
1819
1966
|
const toc = typeof mergedMeta.toc === "boolean" ? mergedMeta.toc : typeof userConfig.toc === "boolean" ? userConfig.toc : DEFAULT_CONFIG.toc;
|
|
1820
1967
|
const rawWatermark = mergedMeta.watermark !== void 0 ? mergedMeta.watermark : userConfig.watermark !== void 0 ? userConfig.watermark : DEFAULT_CONFIG.watermark;
|
|
1821
|
-
const watermark = normalizeWatermark(rawWatermark);
|
|
1968
|
+
const watermark = normalizeWatermark(rawWatermark, tokenContext);
|
|
1822
1969
|
const rawSignatures = mergedMeta.signatures || userConfig.signatures;
|
|
1823
1970
|
const signatures = normalizeSignatures(rawSignatures, tokenContext);
|
|
1824
1971
|
const rawCover = mergedMeta.coverPage !== void 0 ? mergedMeta.coverPage : userConfig.coverPage;
|
|
@@ -1914,7 +2061,7 @@ var KATEX_INLINE_CSS = `
|
|
|
1914
2061
|
function escapeHtml(str) {
|
|
1915
2062
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1916
2063
|
}
|
|
1917
|
-
async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
2064
|
+
async function renderInlinesToHtml(spans = [], baseDir = process.cwd(), tokens) {
|
|
1918
2065
|
let result = "";
|
|
1919
2066
|
for (const span of spans) {
|
|
1920
2067
|
if (span.type === "image" && span.url) {
|
|
@@ -1928,23 +2075,23 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
|
1928
2075
|
continue;
|
|
1929
2076
|
}
|
|
1930
2077
|
if (span.type === "link" && span.url) {
|
|
1931
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
2078
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1932
2079
|
const title = span.title ? ` title="${escapeHtml(span.title)}"` : "";
|
|
1933
2080
|
result += `<a href="${escapeHtml(span.url)}"${title}>${inner}</a>`;
|
|
1934
2081
|
continue;
|
|
1935
2082
|
}
|
|
1936
2083
|
if (span.type === "bold") {
|
|
1937
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
2084
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1938
2085
|
result += `<strong>${inner}</strong>`;
|
|
1939
2086
|
continue;
|
|
1940
2087
|
}
|
|
1941
2088
|
if (span.type === "italic") {
|
|
1942
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
2089
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1943
2090
|
result += `<em>${inner}</em>`;
|
|
1944
2091
|
continue;
|
|
1945
2092
|
}
|
|
1946
2093
|
if (span.type === "strikethrough") {
|
|
1947
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
2094
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1948
2095
|
result += `<del>${inner}</del>`;
|
|
1949
2096
|
continue;
|
|
1950
2097
|
}
|
|
@@ -1965,21 +2112,23 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
|
1965
2112
|
result += span.content;
|
|
1966
2113
|
continue;
|
|
1967
2114
|
}
|
|
1968
|
-
|
|
2115
|
+
const content = tokens ? replaceDocumentTokens(span.content, tokens) : span.content;
|
|
2116
|
+
result += escapeHtml(content);
|
|
1969
2117
|
}
|
|
1970
2118
|
return result;
|
|
1971
2119
|
}
|
|
1972
|
-
async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
|
|
2120
|
+
async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd(), tokens) {
|
|
1973
2121
|
let bodyHtml = "";
|
|
2122
|
+
const tokenCtx = tokens || resolved;
|
|
1974
2123
|
for (const node of nodes) {
|
|
1975
2124
|
if (node.type === "heading") {
|
|
1976
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
2125
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
1977
2126
|
bodyHtml += ` <h${node.level} id="${node.id}">${inner}</h${node.level}>
|
|
1978
2127
|
`;
|
|
1979
2128
|
continue;
|
|
1980
2129
|
}
|
|
1981
2130
|
if (node.type === "paragraph") {
|
|
1982
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
2131
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
1983
2132
|
bodyHtml += ` <p>${inner}</p>
|
|
1984
2133
|
`;
|
|
1985
2134
|
continue;
|
|
@@ -1994,7 +2143,7 @@ async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
|
|
|
1994
2143
|
const gap = node.columnGap || "1.5rem";
|
|
1995
2144
|
let colChildrenHtml = "";
|
|
1996
2145
|
for (const col of node.children || []) {
|
|
1997
|
-
const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir);
|
|
2146
|
+
const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir, tokenCtx);
|
|
1998
2147
|
colChildrenHtml += ` <div class="markforge-col">
|
|
1999
2148
|
${colInner} </div>
|
|
2000
2149
|
`;
|
|
@@ -2020,7 +2169,7 @@ ${escapeHtml(node.text || "")}
|
|
|
2020
2169
|
continue;
|
|
2021
2170
|
}
|
|
2022
2171
|
if (node.type === "callout") {
|
|
2023
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
2172
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
2024
2173
|
const CALLOUT_STYLES = {
|
|
2025
2174
|
NOTE: { bg: "#ECFDFD", border: "#33CDCF", titleColor: "#009DA0" },
|
|
2026
2175
|
TIP: { bg: "#ecfdf5", border: "#10b981", titleColor: "#10b981" },
|
|
@@ -2040,7 +2189,7 @@ ${escapeHtml(node.text || "")}
|
|
|
2040
2189
|
continue;
|
|
2041
2190
|
}
|
|
2042
2191
|
if (node.type === "blockquote") {
|
|
2043
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
2192
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
2044
2193
|
bodyHtml += ` <blockquote>${inner}</blockquote>
|
|
2045
2194
|
`;
|
|
2046
2195
|
continue;
|
|
@@ -2054,7 +2203,7 @@ ${escapeHtml(node.text || "")}
|
|
|
2054
2203
|
for (const cell of row.children || []) {
|
|
2055
2204
|
const tag = cell.isHeader ? "th" : "td";
|
|
2056
2205
|
const align = cell.align ? ` align="${cell.align}"` : "";
|
|
2057
|
-
const inner = await renderInlinesToHtml(cell.inlines, baseDir);
|
|
2206
|
+
const inner = await renderInlinesToHtml(cell.inlines, baseDir, tokenCtx);
|
|
2058
2207
|
bodyHtml += ` <${tag}${align}>${inner}</${tag}>
|
|
2059
2208
|
`;
|
|
2060
2209
|
}
|
|
@@ -2070,7 +2219,7 @@ ${escapeHtml(node.text || "")}
|
|
|
2070
2219
|
bodyHtml += ` <${tag}>
|
|
2071
2220
|
`;
|
|
2072
2221
|
for (const item of node.children) {
|
|
2073
|
-
const inner = await renderInlinesToHtml(item.inlines, baseDir);
|
|
2222
|
+
const inner = await renderInlinesToHtml(item.inlines, baseDir, tokenCtx);
|
|
2074
2223
|
bodyHtml += ` <li>${inner}</li>
|
|
2075
2224
|
`;
|
|
2076
2225
|
}
|
|
@@ -2383,8 +2532,8 @@ async function renderBackCoverHtml(backCover, baseDir = process.cwd()) {
|
|
|
2383
2532
|
`;
|
|
2384
2533
|
return { html, css };
|
|
2385
2534
|
}
|
|
2386
|
-
async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
2387
|
-
var _a;
|
|
2535
|
+
async function buildHtmlDocument(doc, config = {}, baseDir = process.cwd()) {
|
|
2536
|
+
var _a, _b;
|
|
2388
2537
|
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2389
2538
|
const baseThemeCss = generateThemeCss(resolved.theme);
|
|
2390
2539
|
let customCss = "";
|
|
@@ -2480,6 +2629,9 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2480
2629
|
bodyHtml += ` </header>
|
|
2481
2630
|
`;
|
|
2482
2631
|
}
|
|
2632
|
+
if (((_b = resolved.numberHeadings) == null ? void 0 : _b.enabled) !== false && resolved.numberHeadings) {
|
|
2633
|
+
applyHeadingNumbering(doc.nodes, doc.tocEntries, resolved.numberHeadings);
|
|
2634
|
+
}
|
|
2483
2635
|
if (resolved.toc && doc.tocEntries.length > 0) {
|
|
2484
2636
|
bodyHtml += ` <nav class="table-of-contents">
|
|
2485
2637
|
`;
|
|
@@ -2495,12 +2647,26 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2495
2647
|
</nav>
|
|
2496
2648
|
`;
|
|
2497
2649
|
}
|
|
2498
|
-
|
|
2650
|
+
const mergedTokens = {
|
|
2651
|
+
...config.metadata,
|
|
2652
|
+
...doc.metadata,
|
|
2653
|
+
...resolved,
|
|
2654
|
+
title: resolved.title,
|
|
2655
|
+
subtitle: resolved.subtitle,
|
|
2656
|
+
author: resolved.author,
|
|
2657
|
+
version: resolved.version,
|
|
2658
|
+
date: resolved.date,
|
|
2659
|
+
company: resolved.company
|
|
2660
|
+
};
|
|
2661
|
+
const nodesHtml = await renderNodesToHtml(doc.nodes, resolved, baseDir, mergedTokens);
|
|
2662
|
+
bodyHtml += ` <main class="markforge-content-body">
|
|
2663
|
+
${nodesHtml} </main>
|
|
2664
|
+
`;
|
|
2499
2665
|
let footnotesHtml = "";
|
|
2500
2666
|
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
2501
2667
|
let fnListHtml = "";
|
|
2502
2668
|
for (const def of doc.footnoteDefs) {
|
|
2503
|
-
const defInner = await renderInlinesToHtml(def.inlines, baseDir);
|
|
2669
|
+
const defInner = await renderInlinesToHtml(def.inlines, baseDir, mergedTokens);
|
|
2504
2670
|
fnListHtml += ` <li id="fn-${escapeHtml(def.id)}">${defInner} <a href="#fnref-${escapeHtml(def.id)}" class="markforge-fn-return">↩</a></li>
|
|
2505
2671
|
`;
|
|
2506
2672
|
}
|
|
@@ -2538,17 +2704,7 @@ ${fnListHtml} </ol>
|
|
|
2538
2704
|
}
|
|
2539
2705
|
@media print {
|
|
2540
2706
|
.document-watermark {
|
|
2541
|
-
|
|
2542
|
-
top: 0;
|
|
2543
|
-
left: 0;
|
|
2544
|
-
right: 0;
|
|
2545
|
-
bottom: 0;
|
|
2546
|
-
width: 100vw;
|
|
2547
|
-
height: 100vh;
|
|
2548
|
-
pointer-events: none;
|
|
2549
|
-
z-index: 0;
|
|
2550
|
-
-webkit-print-color-adjust: exact;
|
|
2551
|
-
print-color-adjust: exact;
|
|
2707
|
+
display: none !important;
|
|
2552
2708
|
}
|
|
2553
2709
|
}
|
|
2554
2710
|
`;
|
|
@@ -2727,8 +2883,11 @@ function escapeXml(str) {
|
|
|
2727
2883
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2728
2884
|
}
|
|
2729
2885
|
function generateWatermarkPngBuffer(chromePath, wm) {
|
|
2730
|
-
const
|
|
2731
|
-
const
|
|
2886
|
+
const tmpId = Math.random().toString(36).substring(2, 9);
|
|
2887
|
+
const tmpDir = os.tmpdir();
|
|
2888
|
+
const tmpHtml = path4.join(tmpDir, `markforge-wm-${tmpId}.html`);
|
|
2889
|
+
const tmpPng = path4.join(tmpDir, `markforge-wm-${tmpId}.png`);
|
|
2890
|
+
const tmpProfile = path4.join(tmpDir, `markforge-wm-prof-${tmpId}`);
|
|
2732
2891
|
try {
|
|
2733
2892
|
const text = escapeXml(wm.text.toUpperCase());
|
|
2734
2893
|
const fontSize = (wm.fontSize || 52) * 1.5;
|
|
@@ -2773,12 +2932,15 @@ function generateWatermarkPngBuffer(chromePath, wm) {
|
|
|
2773
2932
|
</body>
|
|
2774
2933
|
</html>`;
|
|
2775
2934
|
fs4.writeFileSync(tmpHtml, html, "utf8");
|
|
2776
|
-
const fileUrl = (0,
|
|
2935
|
+
const fileUrl = (0, import_node_url3.pathToFileURL)(tmpHtml).href;
|
|
2777
2936
|
const isWin = process.platform === "win32";
|
|
2778
2937
|
(0, import_node_child_process.spawnSync)(
|
|
2779
2938
|
chromePath,
|
|
2780
2939
|
[
|
|
2781
2940
|
"--headless=new",
|
|
2941
|
+
`--user-data-dir=${tmpProfile}`,
|
|
2942
|
+
"--no-first-run",
|
|
2943
|
+
"--no-default-browser-check",
|
|
2782
2944
|
"--disable-gpu",
|
|
2783
2945
|
"--disable-sync",
|
|
2784
2946
|
"--disable-extensions",
|
|
@@ -2800,6 +2962,7 @@ function generateWatermarkPngBuffer(chromePath, wm) {
|
|
|
2800
2962
|
try {
|
|
2801
2963
|
if (fs4.existsSync(tmpHtml)) fs4.unlinkSync(tmpHtml);
|
|
2802
2964
|
if (fs4.existsSync(tmpPng)) fs4.unlinkSync(tmpPng);
|
|
2965
|
+
if (fs4.existsSync(tmpProfile)) fs4.rmSync(tmpProfile, { recursive: true, force: true });
|
|
2803
2966
|
} catch {
|
|
2804
2967
|
}
|
|
2805
2968
|
}
|
|
@@ -2815,6 +2978,8 @@ function findChromeExecutable() {
|
|
|
2815
2978
|
const winLocalAppData = process.env.LOCALAPPDATA ?? "";
|
|
2816
2979
|
const winProgramFiles = process.env.PROGRAMFILES ?? "C:\\Program Files";
|
|
2817
2980
|
const winProgramFilesX86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
|
|
2981
|
+
const winProgramW6432 = process.env.ProgramW6432 ?? "C:\\Program Files";
|
|
2982
|
+
const winUserProfile = process.env.USERPROFILE ?? "";
|
|
2818
2983
|
const candidates = [
|
|
2819
2984
|
// Linux
|
|
2820
2985
|
"/usr/bin/google-chrome",
|
|
@@ -2833,17 +2998,34 @@ function findChromeExecutable() {
|
|
|
2833
2998
|
// Windows — Microsoft Edge (Native Windows 10/11 browser, enterprise whitelist friendly)
|
|
2834
2999
|
`${winProgramFiles}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
|
2835
3000
|
`${winProgramFilesX86}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
|
3001
|
+
`${winProgramW6432}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
|
2836
3002
|
`${winLocalAppData}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
|
2837
|
-
|
|
3003
|
+
`${winLocalAppData}\\Microsoft\\Edge Dev\\Application\\msedge.exe`,
|
|
3004
|
+
`${winLocalAppData}\\Microsoft\\Edge Beta\\Application\\msedge.exe`,
|
|
3005
|
+
// Windows — Google Chrome & Chrome SxS (Canary)
|
|
2838
3006
|
`${winProgramFiles}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
2839
3007
|
`${winProgramFilesX86}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
3008
|
+
`${winProgramW6432}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
2840
3009
|
`${winLocalAppData}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
3010
|
+
`${winLocalAppData}\\Google\\Chrome SxS\\Application\\chrome.exe`,
|
|
2841
3011
|
// Windows — Brave Browser
|
|
2842
3012
|
`${winProgramFiles}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
2843
3013
|
`${winProgramFilesX86}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
3014
|
+
`${winProgramW6432}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
2844
3015
|
`${winLocalAppData}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
|
|
2845
3016
|
// Windows — Chromium
|
|
2846
|
-
`${winLocalAppData}\\Chromium\\Application\\chrome.exe
|
|
3017
|
+
`${winLocalAppData}\\Chromium\\Application\\chrome.exe`,
|
|
3018
|
+
// Windows — Scoop Package Manager
|
|
3019
|
+
`${winUserProfile}\\scoop\\apps\\googlechrome\\current\\chrome.exe`,
|
|
3020
|
+
`${winUserProfile}\\scoop\\apps\\chromium\\current\\chrome.exe`,
|
|
3021
|
+
`${winUserProfile}\\scoop\\apps\\brave\\current\\brave.exe`,
|
|
3022
|
+
`${winUserProfile}\\scoop\\apps\\msedge\\current\\msedge.exe`,
|
|
3023
|
+
`${winUserProfile}\\scoop\\shims\\chrome.exe`,
|
|
3024
|
+
`${winUserProfile}\\scoop\\shims\\msedge.exe`,
|
|
3025
|
+
// Windows — Chocolatey
|
|
3026
|
+
"C:\\ProgramData\\chocolatey\\bin\\chrome.exe",
|
|
3027
|
+
"C:\\ProgramData\\chocolatey\\bin\\msedge.exe",
|
|
3028
|
+
"C:\\ProgramData\\chocolatey\\bin\\brave.exe"
|
|
2847
3029
|
].filter(Boolean);
|
|
2848
3030
|
for (const candidate of candidates) {
|
|
2849
3031
|
try {
|
|
@@ -2854,13 +3036,15 @@ function findChromeExecutable() {
|
|
|
2854
3036
|
}
|
|
2855
3037
|
}
|
|
2856
3038
|
try {
|
|
2857
|
-
const cmd = isWin ? "where" : "which";
|
|
2858
|
-
const names = isWin ? ["chrome", "msedge", "brave", "google-chrome", "chromium", "chromium-browser"] : ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser", "microsoft-edge", "brave-browser"];
|
|
3039
|
+
const cmd = isWin ? "where.exe" : "which";
|
|
3040
|
+
const names = isWin ? ["chrome.exe", "msedge.exe", "brave.exe", "chrome", "msedge", "brave", "google-chrome", "chromium", "chromium-browser"] : ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser", "microsoft-edge", "brave-browser"];
|
|
2859
3041
|
for (const name of names) {
|
|
2860
|
-
const res = (0, import_node_child_process.spawnSync)(cmd, [name], { encoding: "utf-8" });
|
|
3042
|
+
const res = (0, import_node_child_process.spawnSync)(cmd, [name], { encoding: "utf-8", windowsHide: true });
|
|
2861
3043
|
if (res.status === 0 && res.stdout.trim()) {
|
|
2862
|
-
const
|
|
2863
|
-
|
|
3044
|
+
const lines = res.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
3045
|
+
for (const line of lines) {
|
|
3046
|
+
if (fs4.existsSync(line)) return line;
|
|
3047
|
+
}
|
|
2864
3048
|
}
|
|
2865
3049
|
}
|
|
2866
3050
|
} catch {
|
|
@@ -2868,7 +3052,7 @@ function findChromeExecutable() {
|
|
|
2868
3052
|
return null;
|
|
2869
3053
|
}
|
|
2870
3054
|
function injectPagedMediaStyles(html, config, metadata) {
|
|
2871
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3055
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
2872
3056
|
const resolved = resolveDocumentConfig(metadata || {}, config);
|
|
2873
3057
|
const size = resolved.paperSize;
|
|
2874
3058
|
const orientation = resolved.orientation;
|
|
@@ -2943,9 +3127,11 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
2943
3127
|
min-height: 100vh;
|
|
2944
3128
|
height: 100vh;
|
|
2945
3129
|
box-sizing: border-box;
|
|
3130
|
+
break-before: page;
|
|
3131
|
+
break-after: avoid;
|
|
2946
3132
|
}` : "";
|
|
2947
|
-
const
|
|
2948
|
-
@page {
|
|
3133
|
+
const tocPageCss = resolved.toc ? `
|
|
3134
|
+
@page toc-page {
|
|
2949
3135
|
size: ${size} ${orientation};
|
|
2950
3136
|
margin-top: ${top};
|
|
2951
3137
|
margin-bottom: ${bottom};
|
|
@@ -2956,9 +3142,36 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
2956
3142
|
${buildZoneCss("top-right", (_e = resolved.header) == null ? void 0 : _e.right)}
|
|
2957
3143
|
${buildZoneCss("bottom-left", (_f = resolved.footer) == null ? void 0 : _f.left)}
|
|
2958
3144
|
${buildZoneCss("bottom-center", (_g = resolved.footer) == null ? void 0 : _g.center)}
|
|
2959
|
-
|
|
3145
|
+
@bottom-right {
|
|
3146
|
+
content: counter(page, lower-roman);
|
|
3147
|
+
font-size: 9pt;
|
|
3148
|
+
color: #94a3b8;
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
.table-of-contents {
|
|
3152
|
+
page: toc-page;
|
|
3153
|
+
page-break-after: always;
|
|
3154
|
+
break-after: page;
|
|
3155
|
+
}
|
|
3156
|
+
.markforge-content-body {
|
|
3157
|
+
counter-reset: page 1;
|
|
3158
|
+
}` : "";
|
|
3159
|
+
const pagedCss = `
|
|
3160
|
+
@page {
|
|
3161
|
+
size: ${size} ${orientation};
|
|
3162
|
+
margin-top: ${top};
|
|
3163
|
+
margin-bottom: ${bottom};
|
|
3164
|
+
margin-left: ${left};
|
|
3165
|
+
margin-right: ${right};
|
|
3166
|
+
${buildZoneCss("top-left", (_h = resolved.header) == null ? void 0 : _h.left)}
|
|
3167
|
+
${buildZoneCss("top-center", (_i = resolved.header) == null ? void 0 : _i.center)}
|
|
3168
|
+
${buildZoneCss("top-right", (_j = resolved.header) == null ? void 0 : _j.right)}
|
|
3169
|
+
${buildZoneCss("bottom-left", (_k = resolved.footer) == null ? void 0 : _k.left)}
|
|
3170
|
+
${buildZoneCss("bottom-center", (_l = resolved.footer) == null ? void 0 : _l.center)}
|
|
3171
|
+
${buildZoneCss("bottom-right", (_m = resolved.footer) == null ? void 0 : _m.right, true)}
|
|
2960
3172
|
}
|
|
2961
3173
|
${coverPageCss}
|
|
3174
|
+
${tocPageCss}
|
|
2962
3175
|
${backCoverCss}
|
|
2963
3176
|
@media print {
|
|
2964
3177
|
body { padding: 0; }
|
|
@@ -3046,7 +3259,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3046
3259
|
];
|
|
3047
3260
|
try {
|
|
3048
3261
|
fs4.writeFileSync(tmpHtml, pagedHtml, "utf-8");
|
|
3049
|
-
const fileUrl = (0,
|
|
3262
|
+
const fileUrl = (0, import_node_url3.pathToFileURL)(tmpHtml).href;
|
|
3050
3263
|
let res = (0, import_node_child_process.spawnSync)(
|
|
3051
3264
|
chromePath,
|
|
3052
3265
|
[
|
|
@@ -3089,9 +3302,10 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3089
3302
|
const wmPng = generateWatermarkPngBuffer(chromePath, resolved.watermark);
|
|
3090
3303
|
if (wmPng) {
|
|
3091
3304
|
const embeddedPng = await pdfDoc.embedPng(wmPng);
|
|
3305
|
+
const totalPages = pdfDoc.getPageCount();
|
|
3092
3306
|
const pages = pdfDoc.getPages();
|
|
3093
3307
|
const startPageIndex = ((_b = resolved.coverPage) == null ? void 0 : _b.enabled) ? 1 : 0;
|
|
3094
|
-
const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ?
|
|
3308
|
+
const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ? totalPages - 1 : totalPages;
|
|
3095
3309
|
for (let i = startPageIndex; i < endPageIndex; i++) {
|
|
3096
3310
|
const page = pages[i];
|
|
3097
3311
|
const { width, height } = page.getSize();
|
|
@@ -3164,6 +3378,8 @@ async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
|
|
|
3164
3378
|
const tmpDir = os2.tmpdir();
|
|
3165
3379
|
const tmpHtml = path5.join(tmpDir, `mermaid_${tmpId}.html`);
|
|
3166
3380
|
const tmpScreenshot = path5.join(tmpDir, `mermaid_${tmpId}.png`);
|
|
3381
|
+
const tmpProfile = path5.join(tmpDir, `mermaid_prof_${tmpId}`);
|
|
3382
|
+
const isWin = process.platform === "win32";
|
|
3167
3383
|
const htmlContent = `<!DOCTYPE html>
|
|
3168
3384
|
<html>
|
|
3169
3385
|
<head>
|
|
@@ -3203,14 +3419,18 @@ ${mermaidCode}
|
|
|
3203
3419
|
</html>`;
|
|
3204
3420
|
try {
|
|
3205
3421
|
fs5.writeFileSync(tmpHtml, htmlContent, "utf-8");
|
|
3206
|
-
const fileUrl = (0,
|
|
3422
|
+
const fileUrl = (0, import_node_url4.pathToFileURL)(tmpHtml).href;
|
|
3207
3423
|
const res = (0, import_node_child_process2.spawnSync)(
|
|
3208
3424
|
chromePath,
|
|
3209
3425
|
[
|
|
3210
|
-
"--headless",
|
|
3426
|
+
"--headless=new",
|
|
3427
|
+
`--user-data-dir=${tmpProfile}`,
|
|
3428
|
+
"--no-first-run",
|
|
3429
|
+
"--no-default-browser-check",
|
|
3211
3430
|
"--disable-gpu",
|
|
3212
|
-
"--
|
|
3213
|
-
"--disable-
|
|
3431
|
+
"--disable-sync",
|
|
3432
|
+
"--disable-extensions",
|
|
3433
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
3214
3434
|
"--allow-file-access-from-files",
|
|
3215
3435
|
"--disable-web-security",
|
|
3216
3436
|
"--disable-software-rasterizer",
|
|
@@ -3219,7 +3439,7 @@ ${mermaidCode}
|
|
|
3219
3439
|
`--screenshot=${tmpScreenshot}`,
|
|
3220
3440
|
fileUrl
|
|
3221
3441
|
],
|
|
3222
|
-
{ timeout: 15e3 }
|
|
3442
|
+
{ timeout: 15e3, windowsHide: true }
|
|
3223
3443
|
);
|
|
3224
3444
|
if (res.status === 0 && fs5.existsSync(tmpScreenshot)) {
|
|
3225
3445
|
const buffer = fs5.readFileSync(tmpScreenshot);
|
|
@@ -3230,6 +3450,7 @@ ${mermaidCode}
|
|
|
3230
3450
|
try {
|
|
3231
3451
|
if (fs5.existsSync(tmpHtml)) fs5.unlinkSync(tmpHtml);
|
|
3232
3452
|
if (fs5.existsSync(tmpScreenshot)) fs5.unlinkSync(tmpScreenshot);
|
|
3453
|
+
if (fs5.existsSync(tmpProfile)) fs5.rmSync(tmpProfile, { recursive: true, force: true });
|
|
3233
3454
|
} catch {
|
|
3234
3455
|
}
|
|
3235
3456
|
}
|
|
@@ -3431,7 +3652,7 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
3431
3652
|
return runs;
|
|
3432
3653
|
}
|
|
3433
3654
|
async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
3434
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
3655
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
3435
3656
|
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
3436
3657
|
const docElements = [];
|
|
3437
3658
|
const themeProps = typeof resolved.theme === "object" ? resolved.theme : {};
|
|
@@ -3503,6 +3724,9 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3503
3724
|
);
|
|
3504
3725
|
}
|
|
3505
3726
|
}
|
|
3727
|
+
if (((_b = resolved.numberHeadings) == null ? void 0 : _b.enabled) !== false && resolved.numberHeadings) {
|
|
3728
|
+
applyHeadingNumbering(doc.nodes, doc.tocEntries, resolved.numberHeadings);
|
|
3729
|
+
}
|
|
3506
3730
|
if (resolved.toc) {
|
|
3507
3731
|
const headingNodes = doc.nodes.filter(
|
|
3508
3732
|
(n) => n.type === "heading" && typeof n.level === "number" && n.level >= 1 && n.level <= 3
|
|
@@ -3572,7 +3796,11 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3572
3796
|
]
|
|
3573
3797
|
});
|
|
3574
3798
|
docElements.push(tocCard);
|
|
3575
|
-
docElements.push(
|
|
3799
|
+
docElements.push(
|
|
3800
|
+
new import_docx.Paragraph({
|
|
3801
|
+
children: [new import_docx.PageBreak()]
|
|
3802
|
+
})
|
|
3803
|
+
);
|
|
3576
3804
|
}
|
|
3577
3805
|
}
|
|
3578
3806
|
for (const node of doc.nodes) {
|
|
@@ -3582,7 +3810,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3582
3810
|
font: defaultFont,
|
|
3583
3811
|
size: 34,
|
|
3584
3812
|
// 17pt
|
|
3585
|
-
color:
|
|
3813
|
+
color: primaryDarkHex,
|
|
3586
3814
|
bold: true
|
|
3587
3815
|
});
|
|
3588
3816
|
docElements.push(
|
|
@@ -3628,7 +3856,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3628
3856
|
font: defaultFont,
|
|
3629
3857
|
size: 22,
|
|
3630
3858
|
// 11pt
|
|
3631
|
-
color:
|
|
3859
|
+
color: primaryDarkHex,
|
|
3632
3860
|
bold: true
|
|
3633
3861
|
});
|
|
3634
3862
|
docElements.push(
|
|
@@ -3858,7 +4086,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3858
4086
|
}
|
|
3859
4087
|
if (node.type === "table" && node.children) {
|
|
3860
4088
|
const tableRows = [];
|
|
3861
|
-
const numCols = ((
|
|
4089
|
+
const numCols = ((_d = (_c = node.children[0]) == null ? void 0 : _c.children) == null ? void 0 : _d.length) || 1;
|
|
3862
4090
|
const colWidth = Math.floor(9e3 / numCols);
|
|
3863
4091
|
for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
|
|
3864
4092
|
const rowNode = node.children[rowIdx];
|
|
@@ -3868,7 +4096,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3868
4096
|
if (rowNode.children) {
|
|
3869
4097
|
for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {
|
|
3870
4098
|
const cellNode = rowNode.children[colIdx];
|
|
3871
|
-
const align = (
|
|
4099
|
+
const align = (_e = node.align) == null ? void 0 : _e[colIdx];
|
|
3872
4100
|
let alignment = import_docx.AlignmentType.LEFT;
|
|
3873
4101
|
if (align === "center") alignment = import_docx.AlignmentType.CENTER;
|
|
3874
4102
|
if (align === "right") alignment = import_docx.AlignmentType.RIGHT;
|
|
@@ -4175,7 +4403,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4175
4403
|
const centerPos = Math.round(contentWidthTwip / 2);
|
|
4176
4404
|
const rightPos = contentWidthTwip;
|
|
4177
4405
|
const headerRuns = [];
|
|
4178
|
-
if ((
|
|
4406
|
+
if ((_f = resolved.header) == null ? void 0 : _f.left) {
|
|
4179
4407
|
headerRuns.push(
|
|
4180
4408
|
new import_docx.TextRun({
|
|
4181
4409
|
text: resolved.header.left.text,
|
|
@@ -4188,7 +4416,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4188
4416
|
);
|
|
4189
4417
|
}
|
|
4190
4418
|
headerRuns.push(new import_docx.TextRun({ text: " " }));
|
|
4191
|
-
if ((
|
|
4419
|
+
if ((_g = resolved.header) == null ? void 0 : _g.center) {
|
|
4192
4420
|
headerRuns.push(
|
|
4193
4421
|
new import_docx.TextRun({
|
|
4194
4422
|
text: resolved.header.center.text,
|
|
@@ -4201,7 +4429,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4201
4429
|
);
|
|
4202
4430
|
}
|
|
4203
4431
|
headerRuns.push(new import_docx.TextRun({ text: " " }));
|
|
4204
|
-
if ((
|
|
4432
|
+
if ((_h = resolved.header) == null ? void 0 : _h.right) {
|
|
4205
4433
|
headerRuns.push(
|
|
4206
4434
|
new import_docx.TextRun({
|
|
4207
4435
|
text: resolved.header.right.text,
|
|
@@ -4240,7 +4468,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4240
4468
|
]
|
|
4241
4469
|
}) : void 0;
|
|
4242
4470
|
const footerRuns = [];
|
|
4243
|
-
if ((
|
|
4471
|
+
if ((_i = resolved.footer) == null ? void 0 : _i.left) {
|
|
4244
4472
|
footerRuns.push(
|
|
4245
4473
|
new import_docx.TextRun({
|
|
4246
4474
|
text: resolved.footer.left.text,
|
|
@@ -4253,7 +4481,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4253
4481
|
);
|
|
4254
4482
|
}
|
|
4255
4483
|
footerRuns.push(new import_docx.TextRun({ text: " " }));
|
|
4256
|
-
if ((
|
|
4484
|
+
if ((_j = resolved.footer) == null ? void 0 : _j.center) {
|
|
4257
4485
|
footerRuns.push(
|
|
4258
4486
|
new import_docx.TextRun({
|
|
4259
4487
|
text: resolved.footer.center.text,
|
|
@@ -4266,7 +4494,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4266
4494
|
);
|
|
4267
4495
|
}
|
|
4268
4496
|
footerRuns.push(new import_docx.TextRun({ text: " " }));
|
|
4269
|
-
if ((
|
|
4497
|
+
if ((_k = resolved.footer) == null ? void 0 : _k.right) {
|
|
4270
4498
|
const rZone = resolved.footer.right;
|
|
4271
4499
|
const rColor = rZone.color.replace("#", "");
|
|
4272
4500
|
const rSize = (rZone.fontSize || 9) * 2;
|
|
@@ -4364,6 +4592,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4364
4592
|
);
|
|
4365
4593
|
docSections.push({
|
|
4366
4594
|
properties: {
|
|
4595
|
+
type: import_docx.SectionType.NEXT_PAGE,
|
|
4367
4596
|
page: {
|
|
4368
4597
|
size: {
|
|
4369
4598
|
width: resolved.paperDimensions.widthTwip,
|
|
@@ -4378,14 +4607,19 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4378
4607
|
}
|
|
4379
4608
|
}
|
|
4380
4609
|
},
|
|
4381
|
-
headers:
|
|
4382
|
-
footers:
|
|
4610
|
+
headers: { default: new import_docx.Header({ children: [] }) },
|
|
4611
|
+
footers: { default: new import_docx.Footer({ children: [] }) },
|
|
4383
4612
|
children: coverElements
|
|
4384
4613
|
});
|
|
4385
4614
|
}
|
|
4386
4615
|
docSections.push({
|
|
4387
4616
|
properties: {
|
|
4617
|
+
type: import_docx.SectionType.NEXT_PAGE,
|
|
4388
4618
|
page: {
|
|
4619
|
+
pageNumbers: {
|
|
4620
|
+
start: 1,
|
|
4621
|
+
formatType: import_docx.NumberFormat.DECIMAL
|
|
4622
|
+
},
|
|
4389
4623
|
size: {
|
|
4390
4624
|
width: resolved.paperDimensions.widthTwip,
|
|
4391
4625
|
height: resolved.paperDimensions.heightTwip,
|
|
@@ -4401,8 +4635,8 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4401
4635
|
}
|
|
4402
4636
|
}
|
|
4403
4637
|
},
|
|
4404
|
-
headers: docHeader ? { default: docHeader } :
|
|
4405
|
-
footers: docFooter ? { default: docFooter } :
|
|
4638
|
+
headers: docHeader ? { default: docHeader } : { default: new import_docx.Header({ children: [] }) },
|
|
4639
|
+
footers: docFooter ? { default: docFooter } : { default: new import_docx.Footer({ children: [] }) },
|
|
4406
4640
|
children: docElements
|
|
4407
4641
|
});
|
|
4408
4642
|
if (resolved.backCover && resolved.backCover.enabled) {
|
|
@@ -4417,6 +4651,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4417
4651
|
);
|
|
4418
4652
|
docSections.push({
|
|
4419
4653
|
properties: {
|
|
4654
|
+
type: import_docx.SectionType.NEXT_PAGE,
|
|
4420
4655
|
page: {
|
|
4421
4656
|
size: {
|
|
4422
4657
|
width: resolved.paperDimensions.widthTwip,
|
|
@@ -4431,8 +4666,8 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
4431
4666
|
}
|
|
4432
4667
|
}
|
|
4433
4668
|
},
|
|
4434
|
-
headers:
|
|
4435
|
-
footers:
|
|
4669
|
+
headers: { default: new import_docx.Header({ children: [] }) },
|
|
4670
|
+
footers: { default: new import_docx.Footer({ children: [] }) },
|
|
4436
4671
|
children: backElements
|
|
4437
4672
|
});
|
|
4438
4673
|
}
|
|
@@ -4835,6 +5070,432 @@ function createEmptyDocxCell(widthDxa) {
|
|
|
4835
5070
|
});
|
|
4836
5071
|
}
|
|
4837
5072
|
|
|
5073
|
+
// src/core/text/textBuilder.ts
|
|
5074
|
+
var LINE_WIDTH = 80;
|
|
5075
|
+
var HR_DOUBLE = "=".repeat(LINE_WIDTH);
|
|
5076
|
+
var HR_SINGLE = "-".repeat(LINE_WIDTH);
|
|
5077
|
+
function centerText(text, width = LINE_WIDTH) {
|
|
5078
|
+
if (text.length >= width) return text;
|
|
5079
|
+
const leftPad = Math.floor((width - text.length) / 2);
|
|
5080
|
+
return " ".repeat(leftPad) + text;
|
|
5081
|
+
}
|
|
5082
|
+
function renderInlinesToText(spans = [], meta = {}) {
|
|
5083
|
+
let result = "";
|
|
5084
|
+
for (const span of spans) {
|
|
5085
|
+
switch (span.type) {
|
|
5086
|
+
case "text": {
|
|
5087
|
+
const content = replaceDocumentTokens(span.content, meta);
|
|
5088
|
+
result += content;
|
|
5089
|
+
break;
|
|
5090
|
+
}
|
|
5091
|
+
case "bold": {
|
|
5092
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
5093
|
+
result += `**${inner}**`;
|
|
5094
|
+
break;
|
|
5095
|
+
}
|
|
5096
|
+
case "italic": {
|
|
5097
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
5098
|
+
result += `*${inner}*`;
|
|
5099
|
+
break;
|
|
5100
|
+
}
|
|
5101
|
+
case "code": {
|
|
5102
|
+
result += `\`${span.content}\``;
|
|
5103
|
+
break;
|
|
5104
|
+
}
|
|
5105
|
+
case "link": {
|
|
5106
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
5107
|
+
result += span.url && span.url !== inner ? `${inner} (${span.url})` : inner;
|
|
5108
|
+
break;
|
|
5109
|
+
}
|
|
5110
|
+
case "image": {
|
|
5111
|
+
result += `[Image: ${span.alt || "image"} (${span.url || ""})]`;
|
|
5112
|
+
break;
|
|
5113
|
+
}
|
|
5114
|
+
case "strikethrough": {
|
|
5115
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
5116
|
+
result += `~${inner}~`;
|
|
5117
|
+
break;
|
|
5118
|
+
}
|
|
5119
|
+
case "mathInline": {
|
|
5120
|
+
result += `$${span.content}$`;
|
|
5121
|
+
break;
|
|
5122
|
+
}
|
|
5123
|
+
case "footnoteRef": {
|
|
5124
|
+
const id = span.footnoteId || span.content;
|
|
5125
|
+
result += `[${id}]`;
|
|
5126
|
+
break;
|
|
5127
|
+
}
|
|
5128
|
+
case "htmlInline": {
|
|
5129
|
+
result += span.content.replace(/<[^>]+>/g, "");
|
|
5130
|
+
break;
|
|
5131
|
+
}
|
|
5132
|
+
default: {
|
|
5133
|
+
result += span.content || "";
|
|
5134
|
+
break;
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
return result;
|
|
5139
|
+
}
|
|
5140
|
+
async function buildTextDocument(doc, config = {}, _baseDir = process.cwd()) {
|
|
5141
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
5142
|
+
const meta = {
|
|
5143
|
+
...doc.metadata,
|
|
5144
|
+
...config.metadata,
|
|
5145
|
+
title: resolved.title,
|
|
5146
|
+
subtitle: resolved.subtitle,
|
|
5147
|
+
author: resolved.author,
|
|
5148
|
+
company: resolved.company,
|
|
5149
|
+
version: resolved.version,
|
|
5150
|
+
date: resolved.date
|
|
5151
|
+
};
|
|
5152
|
+
const nodes = JSON.parse(JSON.stringify(doc.nodes));
|
|
5153
|
+
const tocEntries = JSON.parse(JSON.stringify(doc.tocEntries));
|
|
5154
|
+
if (resolved.numberHeadings && resolved.numberHeadings.enabled) {
|
|
5155
|
+
applyHeadingNumbering(nodes, tocEntries, resolved.numberHeadings);
|
|
5156
|
+
}
|
|
5157
|
+
const lines = [];
|
|
5158
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
5159
|
+
const cover = resolved.coverPage;
|
|
5160
|
+
const coverTitle = (cover.title || meta.title || "DOCUMENT").toUpperCase();
|
|
5161
|
+
const coverSubtitle = cover.subtitle || meta.subtitle || "";
|
|
5162
|
+
const coverAuthor = cover.author || meta.author || "";
|
|
5163
|
+
const coverCompany = cover.company || meta.company || "";
|
|
5164
|
+
const coverDate = cover.date || meta.date || "";
|
|
5165
|
+
const coverVersion = cover.version || meta.version || "";
|
|
5166
|
+
const coverBadge = cover.badge || "";
|
|
5167
|
+
const coverFooter = cover.footerText || "";
|
|
5168
|
+
lines.push(HR_DOUBLE);
|
|
5169
|
+
lines.push(centerText(coverTitle));
|
|
5170
|
+
if (coverSubtitle) {
|
|
5171
|
+
lines.push(centerText(coverSubtitle));
|
|
5172
|
+
}
|
|
5173
|
+
lines.push(HR_DOUBLE);
|
|
5174
|
+
if (coverBadge) {
|
|
5175
|
+
lines.push(`[${coverBadge}]`);
|
|
5176
|
+
lines.push("");
|
|
5177
|
+
}
|
|
5178
|
+
if (coverAuthor) lines.push(`Author: ${coverAuthor}`);
|
|
5179
|
+
if (coverCompany) lines.push(`Company: ${coverCompany}`);
|
|
5180
|
+
if (coverDate) lines.push(`Date: ${coverDate}`);
|
|
5181
|
+
if (coverVersion) lines.push(`Version: ${coverVersion}`);
|
|
5182
|
+
if (coverFooter) lines.push(`Notice: ${coverFooter}`);
|
|
5183
|
+
lines.push(HR_DOUBLE);
|
|
5184
|
+
lines.push("");
|
|
5185
|
+
lines.push("");
|
|
5186
|
+
}
|
|
5187
|
+
if (resolved.toc) {
|
|
5188
|
+
const headings = nodes.filter(
|
|
5189
|
+
(n) => n.type === "heading" && (n.level || 1) <= 3
|
|
5190
|
+
);
|
|
5191
|
+
if (headings.length > 0) {
|
|
5192
|
+
const tocTitle = "TABLE OF CONTENTS";
|
|
5193
|
+
lines.push(HR_DOUBLE);
|
|
5194
|
+
lines.push(centerText(tocTitle));
|
|
5195
|
+
lines.push(HR_DOUBLE);
|
|
5196
|
+
for (const h of headings) {
|
|
5197
|
+
const level = h.level || 1;
|
|
5198
|
+
const indent = " ".repeat(level - 1);
|
|
5199
|
+
const headingText = renderInlinesToText(h.inlines, meta);
|
|
5200
|
+
const prefix = level === 1 ? "* " : "- ";
|
|
5201
|
+
lines.push(`${indent}${prefix}${headingText}`);
|
|
5202
|
+
}
|
|
5203
|
+
lines.push(HR_DOUBLE);
|
|
5204
|
+
lines.push("");
|
|
5205
|
+
lines.push("");
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
function renderNode(node, listLevel = 0) {
|
|
5209
|
+
var _a;
|
|
5210
|
+
switch (node.type) {
|
|
5211
|
+
case "heading": {
|
|
5212
|
+
const level = node.level || 1;
|
|
5213
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
5214
|
+
lines.push("");
|
|
5215
|
+
if (level === 1) {
|
|
5216
|
+
lines.push(HR_DOUBLE);
|
|
5217
|
+
lines.push(text.toUpperCase());
|
|
5218
|
+
lines.push(HR_DOUBLE);
|
|
5219
|
+
} else if (level === 2) {
|
|
5220
|
+
lines.push(HR_SINGLE);
|
|
5221
|
+
lines.push(text);
|
|
5222
|
+
lines.push(HR_SINGLE);
|
|
5223
|
+
} else {
|
|
5224
|
+
const hashes = "#".repeat(level);
|
|
5225
|
+
lines.push(`${hashes} ${text}`);
|
|
5226
|
+
}
|
|
5227
|
+
lines.push("");
|
|
5228
|
+
break;
|
|
5229
|
+
}
|
|
5230
|
+
case "paragraph": {
|
|
5231
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
5232
|
+
if (text.trim()) {
|
|
5233
|
+
lines.push(text);
|
|
5234
|
+
lines.push("");
|
|
5235
|
+
}
|
|
5236
|
+
break;
|
|
5237
|
+
}
|
|
5238
|
+
case "callout": {
|
|
5239
|
+
const calloutType = (node.calloutType || "NOTE").toUpperCase();
|
|
5240
|
+
lines.push(`| [${calloutType}]`);
|
|
5241
|
+
if (node.inlines && node.inlines.length > 0) {
|
|
5242
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
5243
|
+
text.split("\n").forEach((l) => lines.push(`| ${l}`));
|
|
5244
|
+
}
|
|
5245
|
+
lines.push("");
|
|
5246
|
+
break;
|
|
5247
|
+
}
|
|
5248
|
+
case "blockquote": {
|
|
5249
|
+
if (node.inlines && node.inlines.length > 0) {
|
|
5250
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
5251
|
+
text.split("\n").forEach((l) => lines.push(`> ${l}`));
|
|
5252
|
+
lines.push("");
|
|
5253
|
+
}
|
|
5254
|
+
break;
|
|
5255
|
+
}
|
|
5256
|
+
case "codeBlock": {
|
|
5257
|
+
const lang = node.language ? `[Language: ${node.language}]` : "[Code]";
|
|
5258
|
+
lines.push(HR_SINGLE);
|
|
5259
|
+
lines.push(lang);
|
|
5260
|
+
lines.push(HR_SINGLE);
|
|
5261
|
+
const codeText = node.text || "";
|
|
5262
|
+
lines.push(codeText);
|
|
5263
|
+
lines.push(HR_SINGLE);
|
|
5264
|
+
lines.push("");
|
|
5265
|
+
break;
|
|
5266
|
+
}
|
|
5267
|
+
case "list": {
|
|
5268
|
+
if (node.children) {
|
|
5269
|
+
let itemIndex = 1;
|
|
5270
|
+
for (const item of node.children) {
|
|
5271
|
+
const indent = " ".repeat(listLevel);
|
|
5272
|
+
let prefix = node.ordered ? `${itemIndex}. ` : "* ";
|
|
5273
|
+
itemIndex++;
|
|
5274
|
+
if (item.checked !== void 0) {
|
|
5275
|
+
prefix = item.checked ? "[x] " : "[ ] ";
|
|
5276
|
+
}
|
|
5277
|
+
if (item.inlines && item.inlines.length > 0) {
|
|
5278
|
+
const text = renderInlinesToText(item.inlines, meta);
|
|
5279
|
+
lines.push(`${indent}${prefix}${text}`);
|
|
5280
|
+
}
|
|
5281
|
+
if (item.children && item.children.length > 0) {
|
|
5282
|
+
for (const subChild of item.children) {
|
|
5283
|
+
if (subChild.type === "list") {
|
|
5284
|
+
renderNode(subChild, listLevel + 1);
|
|
5285
|
+
} else if (subChild.type === "paragraph") {
|
|
5286
|
+
const text = renderInlinesToText(subChild.inlines, meta);
|
|
5287
|
+
lines.push(`${indent} ${text}`);
|
|
5288
|
+
} else {
|
|
5289
|
+
renderNode(subChild, listLevel + 1);
|
|
5290
|
+
}
|
|
5291
|
+
}
|
|
5292
|
+
}
|
|
5293
|
+
}
|
|
5294
|
+
lines.push("");
|
|
5295
|
+
}
|
|
5296
|
+
break;
|
|
5297
|
+
}
|
|
5298
|
+
case "table": {
|
|
5299
|
+
const rows = node.children || [];
|
|
5300
|
+
if (rows.length === 0) break;
|
|
5301
|
+
const rowCells = [];
|
|
5302
|
+
let maxCols = 0;
|
|
5303
|
+
for (const row of rows) {
|
|
5304
|
+
const cells = row.children || [];
|
|
5305
|
+
const texts = cells.map((c) => renderInlinesToText(c.inlines, meta));
|
|
5306
|
+
const isHeader = cells.some((c) => c.isHeader);
|
|
5307
|
+
maxCols = Math.max(maxCols, texts.length);
|
|
5308
|
+
rowCells.push({ isHeader, texts });
|
|
5309
|
+
}
|
|
5310
|
+
if (maxCols === 0) break;
|
|
5311
|
+
const colWidths = new Array(maxCols).fill(3);
|
|
5312
|
+
for (const r of rowCells) {
|
|
5313
|
+
for (let col = 0; col < maxCols; col++) {
|
|
5314
|
+
const cellText = r.texts[col] || "";
|
|
5315
|
+
colWidths[col] = Math.max(colWidths[col] ?? 3, cellText.length);
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
const separatorLine = "+" + colWidths.map((w) => "-".repeat(w + 2)).join("+") + "+";
|
|
5319
|
+
const formatRow = (texts) => {
|
|
5320
|
+
const paddedCells = colWidths.map((width, colIdx) => {
|
|
5321
|
+
const text = texts[colIdx] || "";
|
|
5322
|
+
return " " + text.padEnd(width, " ") + " ";
|
|
5323
|
+
});
|
|
5324
|
+
return "|" + paddedCells.join("|") + "|";
|
|
5325
|
+
};
|
|
5326
|
+
lines.push(separatorLine);
|
|
5327
|
+
for (const r of rowCells) {
|
|
5328
|
+
lines.push(formatRow(r.texts));
|
|
5329
|
+
if (r.isHeader) {
|
|
5330
|
+
lines.push(separatorLine);
|
|
5331
|
+
}
|
|
5332
|
+
}
|
|
5333
|
+
if (!((_a = rowCells[rowCells.length - 1]) == null ? void 0 : _a.isHeader)) {
|
|
5334
|
+
lines.push(separatorLine);
|
|
5335
|
+
}
|
|
5336
|
+
lines.push("");
|
|
5337
|
+
break;
|
|
5338
|
+
}
|
|
5339
|
+
case "mathBlock": {
|
|
5340
|
+
lines.push("[Equation]");
|
|
5341
|
+
lines.push(` $$${node.text || ""} $$`);
|
|
5342
|
+
lines.push("");
|
|
5343
|
+
break;
|
|
5344
|
+
}
|
|
5345
|
+
case "mermaid": {
|
|
5346
|
+
lines.push("[Diagram: Mermaid]");
|
|
5347
|
+
lines.push(node.text || "");
|
|
5348
|
+
lines.push("");
|
|
5349
|
+
break;
|
|
5350
|
+
}
|
|
5351
|
+
case "thematicBreak": {
|
|
5352
|
+
lines.push(HR_SINGLE);
|
|
5353
|
+
lines.push("");
|
|
5354
|
+
break;
|
|
5355
|
+
}
|
|
5356
|
+
case "columns": {
|
|
5357
|
+
if (node.children) {
|
|
5358
|
+
for (const col of node.children) {
|
|
5359
|
+
if (col.children) {
|
|
5360
|
+
for (const child of col.children) {
|
|
5361
|
+
renderNode(child, listLevel);
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
break;
|
|
5367
|
+
}
|
|
5368
|
+
default: {
|
|
5369
|
+
if (node.children && node.children.length > 0) {
|
|
5370
|
+
for (const child of node.children) {
|
|
5371
|
+
renderNode(child, listLevel);
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
break;
|
|
5375
|
+
}
|
|
5376
|
+
}
|
|
5377
|
+
}
|
|
5378
|
+
for (const node of nodes) {
|
|
5379
|
+
renderNode(node);
|
|
5380
|
+
}
|
|
5381
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
5382
|
+
lines.push(HR_SINGLE);
|
|
5383
|
+
lines.push("FOOTNOTES");
|
|
5384
|
+
lines.push(HR_SINGLE);
|
|
5385
|
+
for (const fn of doc.footnoteDefs) {
|
|
5386
|
+
const text = renderInlinesToText(fn.inlines, meta);
|
|
5387
|
+
lines.push(`[${fn.id}] ${text}`);
|
|
5388
|
+
}
|
|
5389
|
+
lines.push("");
|
|
5390
|
+
}
|
|
5391
|
+
if (resolved.signatures && resolved.signatures.items && resolved.signatures.items.length > 0) {
|
|
5392
|
+
lines.push(HR_SINGLE);
|
|
5393
|
+
lines.push("SIGNATURES & APPROVALS");
|
|
5394
|
+
lines.push(HR_SINGLE);
|
|
5395
|
+
lines.push("");
|
|
5396
|
+
for (const item of resolved.signatures.items) {
|
|
5397
|
+
const title = item.title || "Signatory";
|
|
5398
|
+
const name = item.name ? replaceDocumentTokens(item.name, meta) : "";
|
|
5399
|
+
const role = item.role ? replaceDocumentTokens(item.role, meta) : "";
|
|
5400
|
+
const date = item.date ? replaceDocumentTokens(item.date, meta) : "";
|
|
5401
|
+
lines.push(`[${title}]`);
|
|
5402
|
+
lines.push("____________________________________");
|
|
5403
|
+
if (name) lines.push(`Name: ${name}`);
|
|
5404
|
+
if (role) lines.push(`Role: ${role}`);
|
|
5405
|
+
if (date) lines.push(`Date: ${date}`);
|
|
5406
|
+
lines.push("");
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
5410
|
+
const back = resolved.backCover;
|
|
5411
|
+
const backTitle = (back.title || "THANK YOU").toUpperCase();
|
|
5412
|
+
const backSubtitle = back.subtitle || "";
|
|
5413
|
+
const backCompany = back.company ? replaceDocumentTokens(back.company, meta) : "";
|
|
5414
|
+
const backAddress = back.address ? replaceDocumentTokens(back.address, meta) : "";
|
|
5415
|
+
const backEmail = back.email ? replaceDocumentTokens(back.email, meta) : "";
|
|
5416
|
+
const backPhone = back.phone ? replaceDocumentTokens(back.phone, meta) : "";
|
|
5417
|
+
const backWebsite = back.website ? replaceDocumentTokens(back.website, meta) : "";
|
|
5418
|
+
const backCopyright = back.copyright ? replaceDocumentTokens(back.copyright, meta) : "";
|
|
5419
|
+
lines.push(HR_DOUBLE);
|
|
5420
|
+
lines.push(centerText(backTitle));
|
|
5421
|
+
if (backSubtitle) {
|
|
5422
|
+
lines.push(centerText(backSubtitle));
|
|
5423
|
+
}
|
|
5424
|
+
lines.push(HR_DOUBLE);
|
|
5425
|
+
if (backCompany) lines.push(`Company: ${backCompany}`);
|
|
5426
|
+
if (backAddress) lines.push(`Address: ${backAddress}`);
|
|
5427
|
+
if (backEmail) lines.push(`Email: ${backEmail}`);
|
|
5428
|
+
if (backPhone) lines.push(`Phone: ${backPhone}`);
|
|
5429
|
+
if (backWebsite) lines.push(`Website: ${backWebsite}`);
|
|
5430
|
+
if (back.social && back.social.github) {
|
|
5431
|
+
lines.push(`GitHub: ${back.social.github}`);
|
|
5432
|
+
}
|
|
5433
|
+
if (backCopyright) {
|
|
5434
|
+
lines.push("");
|
|
5435
|
+
lines.push(backCopyright);
|
|
5436
|
+
}
|
|
5437
|
+
lines.push(HR_DOUBLE);
|
|
5438
|
+
lines.push("");
|
|
5439
|
+
}
|
|
5440
|
+
return lines.join("\n").trim() + "\n";
|
|
5441
|
+
}
|
|
5442
|
+
|
|
5443
|
+
// src/core/png/pngBuilder.ts
|
|
5444
|
+
var fs6 = __toESM(require("fs"));
|
|
5445
|
+
var path6 = __toESM(require("path"));
|
|
5446
|
+
var os3 = __toESM(require("os"));
|
|
5447
|
+
var import_node_url5 = require("url");
|
|
5448
|
+
var import_node_child_process3 = require("child_process");
|
|
5449
|
+
async function buildPngDocument(doc, config, baseDir) {
|
|
5450
|
+
const htmlContent = await buildHtmlDocument(doc, config, baseDir);
|
|
5451
|
+
const chromePath = findChromeExecutable();
|
|
5452
|
+
if (!chromePath) {
|
|
5453
|
+
throw new Error(
|
|
5454
|
+
"Headless Chrome / Chromium / Edge executable not found for PNG document export. Please install Google Chrome, Chromium, or Microsoft Edge, or set CHROME_PATH environment variable."
|
|
5455
|
+
);
|
|
5456
|
+
}
|
|
5457
|
+
const tmpHtml = path6.join(
|
|
5458
|
+
os3.tmpdir(),
|
|
5459
|
+
`markforge-png-${Date.now()}-${Math.random().toString(36).slice(2)}.html`
|
|
5460
|
+
);
|
|
5461
|
+
const tmpPng = path6.join(
|
|
5462
|
+
os3.tmpdir(),
|
|
5463
|
+
`markforge-png-${Date.now()}-${Math.random().toString(36).slice(2)}.png`
|
|
5464
|
+
);
|
|
5465
|
+
try {
|
|
5466
|
+
fs6.writeFileSync(tmpHtml, htmlContent, "utf-8");
|
|
5467
|
+
const fileUrl = (0, import_node_url5.pathToFileURL)(tmpHtml).href;
|
|
5468
|
+
const spawnResult = (0, import_node_child_process3.spawnSync)(
|
|
5469
|
+
chromePath,
|
|
5470
|
+
[
|
|
5471
|
+
"--headless=new",
|
|
5472
|
+
"--disable-gpu",
|
|
5473
|
+
"--no-sandbox",
|
|
5474
|
+
"--disable-setuid-sandbox",
|
|
5475
|
+
"--hide-scrollbars",
|
|
5476
|
+
"--force-device-scale-factor=2",
|
|
5477
|
+
"--window-size=1200,1600",
|
|
5478
|
+
`--screenshot=${tmpPng}`,
|
|
5479
|
+
fileUrl
|
|
5480
|
+
],
|
|
5481
|
+
{ timeout: 3e4, windowsHide: true }
|
|
5482
|
+
);
|
|
5483
|
+
if (spawnResult.error) {
|
|
5484
|
+
throw new Error(`Failed to execute Chromium for PNG export: ${spawnResult.error.message}`);
|
|
5485
|
+
}
|
|
5486
|
+
if (!fs6.existsSync(tmpPng) || fs6.statSync(tmpPng).size === 0) {
|
|
5487
|
+
throw new Error("Chromium PNG export failed to generate output screenshot file.");
|
|
5488
|
+
}
|
|
5489
|
+
return fs6.readFileSync(tmpPng);
|
|
5490
|
+
} finally {
|
|
5491
|
+
try {
|
|
5492
|
+
if (fs6.existsSync(tmpHtml)) fs6.unlinkSync(tmpHtml);
|
|
5493
|
+
if (fs6.existsSync(tmpPng)) fs6.unlinkSync(tmpPng);
|
|
5494
|
+
} catch {
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5497
|
+
}
|
|
5498
|
+
|
|
4838
5499
|
// src/core/engine.ts
|
|
4839
5500
|
function formatServerTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
4840
5501
|
const pad = (n) => String(n).padStart(2, "0");
|
|
@@ -4858,20 +5519,20 @@ async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgre
|
|
|
4858
5519
|
let baseDir = process.cwd();
|
|
4859
5520
|
let inputFileName = "document.md";
|
|
4860
5521
|
let isFilePath = false;
|
|
4861
|
-
if (
|
|
5522
|
+
if (fs7.existsSync(inputFilePathOrContent)) {
|
|
4862
5523
|
isFilePath = true;
|
|
4863
|
-
rawMarkdown =
|
|
4864
|
-
baseDir =
|
|
4865
|
-
inputFileName =
|
|
5524
|
+
rawMarkdown = fs7.readFileSync(inputFilePathOrContent, "utf-8");
|
|
5525
|
+
baseDir = path7.dirname(path7.resolve(inputFilePathOrContent));
|
|
5526
|
+
inputFileName = path7.basename(inputFilePathOrContent);
|
|
4866
5527
|
} else {
|
|
4867
5528
|
rawMarkdown = inputFilePathOrContent;
|
|
4868
5529
|
}
|
|
4869
5530
|
onProgress == null ? void 0 : onProgress(`Parsing markdown AST: ${inputFileName}...`);
|
|
4870
5531
|
const parsedDoc = parseMarkdownDocument(rawMarkdown);
|
|
4871
5532
|
const baseName = inputFileName.replace(/\.(md|mdx|markdown)$/i, "");
|
|
4872
|
-
const outputDir = config.outputDir ?
|
|
4873
|
-
if (!
|
|
4874
|
-
|
|
5533
|
+
const outputDir = config.outputDir ? path7.isAbsolute(config.outputDir) ? config.outputDir : path7.resolve(process.cwd(), config.outputDir) : baseDir;
|
|
5534
|
+
if (!fs7.existsSync(outputDir)) {
|
|
5535
|
+
fs7.mkdirSync(outputDir, { recursive: true });
|
|
4875
5536
|
}
|
|
4876
5537
|
const formats = Array.isArray(config.to) ? config.to : [config.to || "docx", "pdf"];
|
|
4877
5538
|
const generatedFiles = [];
|
|
@@ -4881,8 +5542,8 @@ async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgre
|
|
|
4881
5542
|
if (fmt === "docx") {
|
|
4882
5543
|
onProgress == null ? void 0 : onProgress(`Generating DOCX document: ${baseName}.docx...`);
|
|
4883
5544
|
const docxBuffer = await buildDocxDocument(parsedDoc, config, baseDir);
|
|
4884
|
-
const docxPath =
|
|
4885
|
-
|
|
5545
|
+
const docxPath = path7.join(outputDir, `${baseName}.docx`);
|
|
5546
|
+
fs7.writeFileSync(docxPath, docxBuffer);
|
|
4886
5547
|
generatedFiles.push({
|
|
4887
5548
|
format: "docx",
|
|
4888
5549
|
filePath: docxPath,
|
|
@@ -4892,8 +5553,8 @@ async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgre
|
|
|
4892
5553
|
} else if (fmt === "html") {
|
|
4893
5554
|
onProgress == null ? void 0 : onProgress(`Generating HTML document: ${baseName}.html...`);
|
|
4894
5555
|
const htmlString = await buildHtmlDocument(parsedDoc, config, baseDir);
|
|
4895
|
-
const htmlPath =
|
|
4896
|
-
|
|
5556
|
+
const htmlPath = path7.join(outputDir, `${baseName}.html`);
|
|
5557
|
+
fs7.writeFileSync(htmlPath, htmlString, "utf-8");
|
|
4897
5558
|
generatedFiles.push({
|
|
4898
5559
|
format: "html",
|
|
4899
5560
|
filePath: htmlPath,
|
|
@@ -4903,14 +5564,36 @@ async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgre
|
|
|
4903
5564
|
} else if (fmt === "pdf") {
|
|
4904
5565
|
onProgress == null ? void 0 : onProgress(`Generating PDF document: ${baseName}.pdf...`);
|
|
4905
5566
|
const pdfBuffer = await buildPdfDocument(parsedDoc, config, baseDir);
|
|
4906
|
-
const pdfPath =
|
|
4907
|
-
|
|
5567
|
+
const pdfPath = path7.join(outputDir, `${baseName}.pdf`);
|
|
5568
|
+
fs7.writeFileSync(pdfPath, pdfBuffer);
|
|
4908
5569
|
generatedFiles.push({
|
|
4909
5570
|
format: "pdf",
|
|
4910
5571
|
filePath: pdfPath,
|
|
4911
5572
|
fileName: `${baseName}.pdf`,
|
|
4912
5573
|
sizeBytes: pdfBuffer.length
|
|
4913
5574
|
});
|
|
5575
|
+
} else if (fmt === "txt") {
|
|
5576
|
+
onProgress == null ? void 0 : onProgress(`Generating Plain Text document: ${baseName}.txt...`);
|
|
5577
|
+
const textContent = await buildTextDocument(parsedDoc, config, baseDir);
|
|
5578
|
+
const textPath = path7.join(outputDir, `${baseName}.txt`);
|
|
5579
|
+
fs7.writeFileSync(textPath, textContent, "utf-8");
|
|
5580
|
+
generatedFiles.push({
|
|
5581
|
+
format: "txt",
|
|
5582
|
+
filePath: textPath,
|
|
5583
|
+
fileName: `${baseName}.txt`,
|
|
5584
|
+
sizeBytes: Buffer.byteLength(textContent, "utf-8")
|
|
5585
|
+
});
|
|
5586
|
+
} else if (fmt === "png") {
|
|
5587
|
+
onProgress == null ? void 0 : onProgress(`Generating PNG document: ${baseName}.png...`);
|
|
5588
|
+
const pngBuffer = await buildPngDocument(parsedDoc, config, baseDir);
|
|
5589
|
+
const pngPath = path7.join(outputDir, `${baseName}.png`);
|
|
5590
|
+
fs7.writeFileSync(pngPath, pngBuffer);
|
|
5591
|
+
generatedFiles.push({
|
|
5592
|
+
format: "png",
|
|
5593
|
+
filePath: pngPath,
|
|
5594
|
+
fileName: `${baseName}.png`,
|
|
5595
|
+
sizeBytes: pngBuffer.length
|
|
5596
|
+
});
|
|
4914
5597
|
}
|
|
4915
5598
|
} catch (err) {
|
|
4916
5599
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -4929,14 +5612,14 @@ async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgre
|
|
|
4929
5612
|
|
|
4930
5613
|
// src/server/previewServer.ts
|
|
4931
5614
|
var http = __toESM(require("http"));
|
|
4932
|
-
var
|
|
4933
|
-
var
|
|
5615
|
+
var fs8 = __toESM(require("fs"));
|
|
5616
|
+
var path8 = __toESM(require("path"));
|
|
4934
5617
|
async function startPreviewServer(options) {
|
|
4935
|
-
const absoluteFilePath =
|
|
4936
|
-
if (!
|
|
5618
|
+
const absoluteFilePath = path8.resolve(process.cwd(), options.filePath);
|
|
5619
|
+
if (!fs8.existsSync(absoluteFilePath)) {
|
|
4937
5620
|
throw new Error(`MarkForge preview error: File not found at "${absoluteFilePath}"`);
|
|
4938
5621
|
}
|
|
4939
|
-
const baseDir =
|
|
5622
|
+
const baseDir = path8.dirname(absoluteFilePath);
|
|
4940
5623
|
const { config: fileConfig } = await loadConfig(void 0, baseDir);
|
|
4941
5624
|
const baseConfig = options.config || fileConfig;
|
|
4942
5625
|
const port = options.port || 3e3;
|
|
@@ -4954,9 +5637,9 @@ data: ${Date.now()}
|
|
|
4954
5637
|
});
|
|
4955
5638
|
};
|
|
4956
5639
|
let debounceTimer = null;
|
|
4957
|
-
const watcher =
|
|
5640
|
+
const watcher = fs8.watch(baseDir, { recursive: false }, (_event, filename) => {
|
|
4958
5641
|
if (!filename) return;
|
|
4959
|
-
const changedPath =
|
|
5642
|
+
const changedPath = path8.resolve(baseDir, filename);
|
|
4960
5643
|
if (changedPath === absoluteFilePath || filename.includes("markforge") || filename.endsWith(".css")) {
|
|
4961
5644
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
4962
5645
|
debounceTimer = setTimeout(() => {
|
|
@@ -4983,12 +5666,12 @@ data: ${Date.now()}
|
|
|
4983
5666
|
}
|
|
4984
5667
|
if (url.pathname === "/api/file-content" && req.method === "GET") {
|
|
4985
5668
|
try {
|
|
4986
|
-
const content =
|
|
5669
|
+
const content = fs8.readFileSync(absoluteFilePath, "utf-8");
|
|
4987
5670
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
4988
5671
|
res.end(
|
|
4989
5672
|
JSON.stringify({
|
|
4990
5673
|
content,
|
|
4991
|
-
fileName:
|
|
5674
|
+
fileName: path8.basename(absoluteFilePath),
|
|
4992
5675
|
filePath: absoluteFilePath
|
|
4993
5676
|
})
|
|
4994
5677
|
);
|
|
@@ -5008,7 +5691,7 @@ data: ${Date.now()}
|
|
|
5008
5691
|
try {
|
|
5009
5692
|
const parsed = JSON.parse(body);
|
|
5010
5693
|
if (typeof parsed.content === "string") {
|
|
5011
|
-
|
|
5694
|
+
fs8.writeFileSync(absoluteFilePath, parsed.content, "utf-8");
|
|
5012
5695
|
broadcastReload();
|
|
5013
5696
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5014
5697
|
res.end(JSON.stringify({ success: true, savedAt: Date.now() }));
|
|
@@ -5027,11 +5710,11 @@ data: ${Date.now()}
|
|
|
5027
5710
|
if (url.pathname === "/api/export" && (req.method === "GET" || req.method === "POST")) {
|
|
5028
5711
|
const format = url.searchParams.get("format") || "docx";
|
|
5029
5712
|
try {
|
|
5030
|
-
const mdContent =
|
|
5713
|
+
const mdContent = fs8.readFileSync(absoluteFilePath, "utf-8");
|
|
5031
5714
|
const doc = parseMarkdownDocument(mdContent);
|
|
5032
5715
|
const { config: resolvedConfig } = await loadConfig(void 0, baseDir);
|
|
5033
5716
|
const mergedConfig = { ...baseConfig, ...resolvedConfig };
|
|
5034
|
-
const fileBase =
|
|
5717
|
+
const fileBase = path8.basename(absoluteFilePath, path8.extname(absoluteFilePath));
|
|
5035
5718
|
if (format === "docx") {
|
|
5036
5719
|
const buffer = await buildDocxDocument(doc, mergedConfig, baseDir);
|
|
5037
5720
|
res.writeHead(200, {
|
|
@@ -5066,7 +5749,7 @@ data: ${Date.now()}
|
|
|
5066
5749
|
}
|
|
5067
5750
|
if (url.pathname === "/document-content") {
|
|
5068
5751
|
try {
|
|
5069
|
-
const mdContent =
|
|
5752
|
+
const mdContent = fs8.readFileSync(absoluteFilePath, "utf-8");
|
|
5070
5753
|
const doc = parseMarkdownDocument(mdContent);
|
|
5071
5754
|
const { config: resolvedConfig } = await loadConfig(void 0, baseDir);
|
|
5072
5755
|
const html = await buildHtmlDocument(doc, { ...baseConfig, ...resolvedConfig }, baseDir);
|
|
@@ -5099,8 +5782,8 @@ data: ${Date.now()}
|
|
|
5099
5782
|
return;
|
|
5100
5783
|
}
|
|
5101
5784
|
if (url.pathname === "/" || url.pathname === "/index.html") {
|
|
5102
|
-
const fileName =
|
|
5103
|
-
const initialContent =
|
|
5785
|
+
const fileName = path8.basename(absoluteFilePath);
|
|
5786
|
+
const initialContent = fs8.readFileSync(absoluteFilePath, "utf-8");
|
|
5104
5787
|
const appHtml = `<!DOCTYPE html>
|
|
5105
5788
|
<html lang="en">
|
|
5106
5789
|
<head>
|
|
@@ -5804,9 +6487,9 @@ function defineConfig(config) {
|
|
|
5804
6487
|
}
|
|
5805
6488
|
|
|
5806
6489
|
// src/version.ts
|
|
5807
|
-
var
|
|
5808
|
-
var
|
|
5809
|
-
var
|
|
6490
|
+
var fs9 = __toESM(require("fs"));
|
|
6491
|
+
var path9 = __toESM(require("path"));
|
|
6492
|
+
var import_node_url6 = require("url");
|
|
5810
6493
|
var import_meta = {};
|
|
5811
6494
|
try {
|
|
5812
6495
|
if (typeof globalThis !== "undefined" && (!globalThis.localStorage || typeof globalThis.localStorage.getItem !== "function")) {
|
|
@@ -5828,32 +6511,33 @@ try {
|
|
|
5828
6511
|
}
|
|
5829
6512
|
} catch {
|
|
5830
6513
|
}
|
|
5831
|
-
var FALLBACK_VERSION = "0.4.0";
|
|
5832
6514
|
function readVersionFromPackageJson(fromDir) {
|
|
5833
6515
|
let currentDir = fromDir;
|
|
5834
|
-
for (let i = 0; i <
|
|
6516
|
+
for (let i = 0; i < 10; i++) {
|
|
5835
6517
|
try {
|
|
5836
|
-
const pkgJsonPath =
|
|
5837
|
-
if (
|
|
5838
|
-
const pkg = JSON.parse(
|
|
6518
|
+
const pkgJsonPath = path9.join(currentDir, "package.json");
|
|
6519
|
+
if (fs9.existsSync(pkgJsonPath)) {
|
|
6520
|
+
const pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
|
|
5839
6521
|
if (pkg.name === "@masumdev/markforge" && pkg.version) {
|
|
5840
6522
|
return pkg.version;
|
|
5841
6523
|
}
|
|
5842
6524
|
}
|
|
5843
6525
|
} catch {
|
|
5844
6526
|
}
|
|
5845
|
-
const parentDir =
|
|
6527
|
+
const parentDir = path9.dirname(currentDir);
|
|
5846
6528
|
if (parentDir === currentDir) break;
|
|
5847
6529
|
currentDir = parentDir;
|
|
5848
6530
|
}
|
|
5849
|
-
|
|
6531
|
+
throw new Error(
|
|
6532
|
+
"Failed to resolve '@masumdev/markforge' package version: package.json was not found or is missing a valid 'version' field."
|
|
6533
|
+
);
|
|
5850
6534
|
}
|
|
5851
6535
|
function getPackageDir() {
|
|
5852
6536
|
if (typeof __dirname !== "undefined") {
|
|
5853
6537
|
return __dirname;
|
|
5854
6538
|
}
|
|
5855
6539
|
try {
|
|
5856
|
-
return
|
|
6540
|
+
return path9.dirname((0, import_node_url6.fileURLToPath)(import_meta.url));
|
|
5857
6541
|
} catch {
|
|
5858
6542
|
return process.cwd();
|
|
5859
6543
|
}
|
|
@@ -5864,6 +6548,8 @@ function getMarkforgeVersion(fromDir = getPackageDir()) {
|
|
|
5864
6548
|
}
|
|
5865
6549
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5866
6550
|
0 && (module.exports = {
|
|
6551
|
+
BackCoverPreset,
|
|
6552
|
+
CoverPagePreset,
|
|
5867
6553
|
DEFAULT_CONFIG,
|
|
5868
6554
|
KATEX_INLINE_CSS,
|
|
5869
6555
|
MARKFORGE_VERSION,
|
|
@@ -5872,15 +6558,21 @@ function getMarkforgeVersion(fromDir = getPackageDir()) {
|
|
|
5872
6558
|
PAPER_DIMENSIONS_TWIP,
|
|
5873
6559
|
PaperSizeEnum,
|
|
5874
6560
|
SYNTAX_COLORS,
|
|
6561
|
+
SignatureAlign,
|
|
6562
|
+
SignatureStyle,
|
|
5875
6563
|
SyntaxTheme,
|
|
5876
6564
|
THEMES,
|
|
5877
6565
|
THEME_CORPORATE,
|
|
5878
6566
|
THEME_DEFAULT,
|
|
5879
6567
|
Theme,
|
|
5880
6568
|
WatermarkPosition,
|
|
6569
|
+
applyHeadingNumbering,
|
|
5881
6570
|
buildDocxDocument,
|
|
5882
6571
|
buildHtmlDocument,
|
|
5883
6572
|
buildPdfDocument,
|
|
6573
|
+
buildPngDocument,
|
|
6574
|
+
buildTextDocument,
|
|
6575
|
+
buildTxtDocument,
|
|
5884
6576
|
compileMarkdown,
|
|
5885
6577
|
defineConfig,
|
|
5886
6578
|
escapeHtml,
|
|
@@ -5909,6 +6601,7 @@ function getMarkforgeVersion(fromDir = getPackageDir()) {
|
|
|
5909
6601
|
renderBackCoverHtml,
|
|
5910
6602
|
renderCoverPageHtml,
|
|
5911
6603
|
renderInlinesToHtml,
|
|
6604
|
+
renderInlinesToText,
|
|
5912
6605
|
renderMathToHtml,
|
|
5913
6606
|
renderMermaidToPng,
|
|
5914
6607
|
renderNodesToHtml,
|