@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/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 fs6 = __toESM(require("fs"));
100
- var path6 = __toESM(require("path"));
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
- return spans;
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 = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
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 import_node_url3 = require("url");
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 import_node_url2 = require("url");
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-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
1262
- h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
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-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
1308
- h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
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 import_node_url = require("url");
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, import_node_url.pathToFileURL)(resolvedPath).href}?t=${Date.now()}`;
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
- const currentYear = meta.year || (/* @__PURE__ */ new Date()).getFullYear().toString();
1522
- return template.replace(/\{title\}/gi, meta.title || "").replace(/\{subtitle\}/gi, meta.subtitle || "").replace(/\{author\}/gi, meta.author || "").replace(/\{version\}/gi, meta.version || "").replace(/\{date\}/gi, meta.date || "").replace(/\{year\}/gi, currentYear).replace(/\{company\}/gi, meta.company || "");
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
- const text = rawWatermark.trim();
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: rawWatermark.text.trim(),
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 || "Document 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 || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
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
- footerText
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 company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
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
- textColor
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 = { title, subtitle, author, version, date, company };
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
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
- result += escapeHtml(span.content);
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
- bodyHtml += await renderNodesToHtml(doc.nodes, resolved, baseDir);
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">&#8617;</a></li>
2505
2671
  `;
2506
2672
  }
@@ -2538,17 +2704,7 @@ ${fnListHtml} </ol>
2538
2704
  }
2539
2705
  @media print {
2540
2706
  .document-watermark {
2541
- position: fixed;
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
2728
2884
  }
2729
2885
  function generateWatermarkPngBuffer(chromePath, wm) {
2730
- const tmpHtml = path4.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.html`);
2731
- const tmpPng = path4.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
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, import_node_url2.pathToFileURL)(tmpHtml).href;
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
- // Windows — Google Chrome
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 binPath = res.stdout.split(/\r?\n/)[0].trim();
2863
- if (fs4.existsSync(binPath)) return binPath;
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 pagedCss = `
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
- ${buildZoneCss("bottom-right", (_h = resolved.footer) == null ? void 0 : _h.right, true)}
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, import_node_url2.pathToFileURL)(tmpHtml).href;
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) ? pages.length - 1 : pages.length;
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, import_node_url3.pathToFileURL)(tmpHtml).href;
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
- "--no-sandbox",
3213
- "--disable-setuid-sandbox",
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(new import_docx.Paragraph({ spacing: { after: 200 } }));
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: textHex,
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: textHex,
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 = ((_c = (_b = node.children[0]) == null ? void 0 : _b.children) == null ? void 0 : _c.length) || 1;
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 = (_d = node.align) == null ? void 0 : _d[colIdx];
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 ((_e = resolved.header) == null ? void 0 : _e.left) {
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 ((_f = resolved.header) == null ? void 0 : _f.center) {
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 ((_g = resolved.header) == null ? void 0 : _g.right) {
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 ((_h = resolved.footer) == null ? void 0 : _h.left) {
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 ((_i = resolved.footer) == null ? void 0 : _i.center) {
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 ((_j = resolved.footer) == null ? void 0 : _j.right) {
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: void 0,
4382
- footers: void 0,
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 } : void 0,
4405
- footers: docFooter ? { default: docFooter } : void 0,
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: void 0,
4435
- footers: void 0,
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 (fs6.existsSync(inputFilePathOrContent)) {
5522
+ if (fs7.existsSync(inputFilePathOrContent)) {
4862
5523
  isFilePath = true;
4863
- rawMarkdown = fs6.readFileSync(inputFilePathOrContent, "utf-8");
4864
- baseDir = path6.dirname(path6.resolve(inputFilePathOrContent));
4865
- inputFileName = path6.basename(inputFilePathOrContent);
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 ? path6.isAbsolute(config.outputDir) ? config.outputDir : path6.resolve(process.cwd(), config.outputDir) : baseDir;
4873
- if (!fs6.existsSync(outputDir)) {
4874
- fs6.mkdirSync(outputDir, { recursive: true });
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 = path6.join(outputDir, `${baseName}.docx`);
4885
- fs6.writeFileSync(docxPath, docxBuffer);
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 = path6.join(outputDir, `${baseName}.html`);
4896
- fs6.writeFileSync(htmlPath, htmlString, "utf-8");
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 = path6.join(outputDir, `${baseName}.pdf`);
4907
- fs6.writeFileSync(pdfPath, pdfBuffer);
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 fs7 = __toESM(require("fs"));
4933
- var path7 = __toESM(require("path"));
5615
+ var fs8 = __toESM(require("fs"));
5616
+ var path8 = __toESM(require("path"));
4934
5617
  async function startPreviewServer(options) {
4935
- const absoluteFilePath = path7.resolve(process.cwd(), options.filePath);
4936
- if (!fs7.existsSync(absoluteFilePath)) {
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 = path7.dirname(absoluteFilePath);
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 = fs7.watch(baseDir, { recursive: false }, (_event, filename) => {
5640
+ const watcher = fs8.watch(baseDir, { recursive: false }, (_event, filename) => {
4958
5641
  if (!filename) return;
4959
- const changedPath = path7.resolve(baseDir, filename);
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 = fs7.readFileSync(absoluteFilePath, "utf-8");
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: path7.basename(absoluteFilePath),
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
- fs7.writeFileSync(absoluteFilePath, parsed.content, "utf-8");
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 = fs7.readFileSync(absoluteFilePath, "utf-8");
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 = path7.basename(absoluteFilePath, path7.extname(absoluteFilePath));
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 = fs7.readFileSync(absoluteFilePath, "utf-8");
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 = path7.basename(absoluteFilePath);
5103
- const initialContent = fs7.readFileSync(absoluteFilePath, "utf-8");
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 fs8 = __toESM(require("fs"));
5808
- var path8 = __toESM(require("path"));
5809
- var import_node_url4 = require("url");
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 < 6; i++) {
6516
+ for (let i = 0; i < 10; i++) {
5835
6517
  try {
5836
- const pkgJsonPath = path8.join(currentDir, "package.json");
5837
- if (fs8.existsSync(pkgJsonPath)) {
5838
- const pkg = JSON.parse(fs8.readFileSync(pkgJsonPath, "utf-8"));
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 = path8.dirname(currentDir);
6527
+ const parentDir = path9.dirname(currentDir);
5846
6528
  if (parentDir === currentDir) break;
5847
6529
  currentDir = parentDir;
5848
6530
  }
5849
- return FALLBACK_VERSION;
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 path8.dirname((0, import_node_url4.fileURLToPath)(import_meta.url));
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,