@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.
@@ -183,7 +183,16 @@ function parseInlineSpans(text) {
183
183
  remaining = remaining.slice(nextSpecial);
184
184
  }
185
185
  }
186
- return spans;
186
+ const merged = [];
187
+ for (const s of spans) {
188
+ const prev = merged[merged.length - 1];
189
+ if (prev && prev.type === "text" && s.type === "text") {
190
+ prev.content += s.content;
191
+ } else {
192
+ merged.push(s);
193
+ }
194
+ }
195
+ return merged;
187
196
  }
188
197
  function slugify(text) {
189
198
  return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -195,6 +204,7 @@ function applyHeadingNumbering(nodes, tocEntries, options) {
195
204
  const counters = [0, 0, 0, 0, 0, 0];
196
205
  for (const node of nodes) {
197
206
  if (node.type === "heading" && node.level) {
207
+ if (node._numbered) continue;
198
208
  const lvl = node.level;
199
209
  if (lvl > depth) continue;
200
210
  if (lvl === 1 && skipH1) continue;
@@ -210,6 +220,7 @@ function applyHeadingNumbering(nodes, tocEntries, options) {
210
220
  const originalText = node.text || "";
211
221
  node.text = fullPrefix + originalText;
212
222
  node.inlines = parseInlineSpans(node.text);
223
+ node._numbered = true;
213
224
  const toc = tocEntries.find((t) => t.id === node.id);
214
225
  if (toc) {
215
226
  toc.text = node.text;
@@ -557,6 +568,7 @@ import * as path2 from "path";
557
568
  // src/core/imageResolver.ts
558
569
  import * as fs from "fs";
559
570
  import * as path from "path";
571
+ import { fileURLToPath } from "url";
560
572
  var memoryImageCache = /* @__PURE__ */ new Map();
561
573
  function getMimeType(filePathOrUrl) {
562
574
  const clean = filePathOrUrl.split("?")[0].toLowerCase();
@@ -613,9 +625,19 @@ async function resolveImage(src, baseDir = process.cwd()) {
613
625
  memoryImageCache.set(cacheKey, resolved2);
614
626
  return resolved2;
615
627
  }
616
- let localPath = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
628
+ let localPath = src;
629
+ if (src.startsWith("file://")) {
630
+ try {
631
+ localPath = fileURLToPath(src);
632
+ } catch {
633
+ localPath = src;
634
+ }
635
+ }
636
+ if (!path.isAbsolute(localPath)) {
637
+ localPath = path.resolve(baseDir, localPath);
638
+ }
617
639
  if (!fs.existsSync(localPath)) {
618
- const cwdPath = path.resolve(process.cwd(), src);
640
+ const cwdPath = path.resolve(process.cwd(), src.startsWith("file://") ? localPath : src);
619
641
  if (fs.existsSync(cwdPath)) {
620
642
  localPath = cwdPath;
621
643
  } else {
@@ -665,7 +687,7 @@ var THEME_COMPONENTS = `
665
687
  .document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
666
688
 
667
689
  /* Table of Contents */
668
- .table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
690
+ .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; }
669
691
  .table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
670
692
  .table-of-contents ul { list-style: none; padding: 0; margin: 0; }
671
693
  .table-of-contents li { padding: 0.25rem 0; }
@@ -738,11 +760,13 @@ var THEME_CORPORATE = `
738
760
  }
739
761
  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; }
740
762
  .document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
741
- 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; }
742
- h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
763
+ 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; }
764
+ h1 { font-size: 2.2rem; color: var(--mf-primary-dark); border-bottom: 2.5px solid var(--mf-primary); padding-bottom: 0.5rem; }
743
765
  h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
744
- h3 { font-size: 1.3rem; }
745
- h4 { font-size: 1.1rem; }
766
+ h3 { font-size: 1.3rem; color: var(--mf-primary-dark); }
767
+ h4 { font-size: 1.1rem; color: var(--mf-primary-dark); }
768
+ h5 { font-size: 1.0rem; color: var(--mf-primary-dark); }
769
+ h6 { font-size: 0.9rem; color: var(--mf-primary-dark); }
746
770
  p { margin: 0.8rem 0; }
747
771
  `;
748
772
  var THEMES = {
@@ -783,11 +807,13 @@ function generateThemeCss(theme) {
783
807
  }
784
808
  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; }
785
809
  .document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
786
- 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; }
787
- h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
810
+ 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; }
811
+ h1 { font-size: 2.2rem; color: var(--mf-primary-dark); border-bottom: 2.5px solid var(--mf-primary); padding-bottom: 0.5rem; }
788
812
  h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
789
- h3 { font-size: 1.3rem; }
790
- h4 { font-size: 1.1rem; }
813
+ h3 { font-size: 1.3rem; color: var(--mf-primary-dark); }
814
+ h4 { font-size: 1.1rem; color: var(--mf-primary-dark); }
815
+ h5 { font-size: 1.0rem; color: var(--mf-primary-dark); }
816
+ h6 { font-size: 0.9rem; color: var(--mf-primary-dark); }
791
817
  p { margin: 0.8rem 0; }
792
818
  ${theme.customCss || ""}
793
819
  `;
@@ -1197,16 +1223,45 @@ function formatMarginCss(margin, defaultCss = "2.5cm") {
1197
1223
  if (/^[0-9.]+$/.test(str)) return `${str}pt`;
1198
1224
  return str;
1199
1225
  }
1200
- function replaceDocumentTokens(template = "", meta) {
1201
- const currentYear = meta.year || (/* @__PURE__ */ new Date()).getFullYear().toString();
1202
- 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 || "");
1226
+ function replaceDocumentTokens(template = "", meta = {}) {
1227
+ if (!template) return "";
1228
+ const currentYear = meta.year ? String(meta.year) : (/* @__PURE__ */ new Date()).getFullYear().toString();
1229
+ const tokenMap = {
1230
+ title: meta.title ? String(meta.title) : "",
1231
+ subtitle: meta.subtitle ? String(meta.subtitle) : "",
1232
+ author: meta.author ? Array.isArray(meta.author) ? meta.author.join(", ") : String(meta.author) : "",
1233
+ version: meta.version ? String(meta.version) : "",
1234
+ date: meta.date ? String(meta.date) : "",
1235
+ company: meta.company ? String(meta.company) : "",
1236
+ year: currentYear
1237
+ };
1238
+ if (meta.metadata && typeof meta.metadata === "object") {
1239
+ for (const [key, val] of Object.entries(meta.metadata)) {
1240
+ if (val !== void 0 && val !== null) {
1241
+ tokenMap[key.toLowerCase()] = String(val);
1242
+ }
1243
+ }
1244
+ }
1245
+ for (const [key, val] of Object.entries(meta)) {
1246
+ if (val !== void 0 && val !== null && typeof val !== "object") {
1247
+ tokenMap[key.toLowerCase()] = String(val);
1248
+ }
1249
+ }
1250
+ return template.replace(/\{([a-zA-Z0-9_\-]+)\}/gi, (match, tokenKey) => {
1251
+ const lowerKey = tokenKey.toLowerCase();
1252
+ if (lowerKey in tokenMap) {
1253
+ return tokenMap[lowerKey];
1254
+ }
1255
+ return match;
1256
+ });
1203
1257
  }
1204
- function normalizeWatermark(rawWatermark) {
1258
+ function normalizeWatermark(rawWatermark, tokens) {
1205
1259
  if (!rawWatermark) {
1206
1260
  return void 0;
1207
1261
  }
1208
1262
  if (typeof rawWatermark === "string") {
1209
- const text = rawWatermark.trim();
1263
+ let text = rawWatermark.trim();
1264
+ if (tokens) text = replaceDocumentTokens(text, tokens);
1210
1265
  if (!text) return void 0;
1211
1266
  return {
1212
1267
  text,
@@ -1219,8 +1274,10 @@ function normalizeWatermark(rawWatermark) {
1219
1274
  }
1220
1275
  if (typeof rawWatermark === "object") {
1221
1276
  if (!rawWatermark.text || !rawWatermark.text.trim()) return void 0;
1277
+ let text = rawWatermark.text.trim();
1278
+ if (tokens) text = replaceDocumentTokens(text, tokens);
1222
1279
  return {
1223
- text: rawWatermark.text.trim(),
1280
+ text,
1224
1281
  color: rawWatermark.color || "#94a3b8",
1225
1282
  opacity: typeof rawWatermark.opacity === "number" ? rawWatermark.opacity : 0.08,
1226
1283
  fontSize: rawWatermark.fontSize || 54,
@@ -1341,27 +1398,46 @@ function normalizeCoverPage(rawCover, tokenCtx = {}) {
1341
1398
  const cfg = typeof rawCover === "object" ? rawCover : {};
1342
1399
  if (cfg.enabled === false) return void 0;
1343
1400
  const preset = cfg.preset || "modern";
1344
- const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title || "Document Title";
1345
- const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle;
1346
- const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author;
1347
- const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
1348
- const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version;
1401
+ const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title ? String(tokenCtx.title) : "Document Title";
1402
+ const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle ? String(tokenCtx.subtitle) : void 0;
1403
+ const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author ? String(tokenCtx.author) : void 0;
1404
+ const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company ? String(tokenCtx.company) : void 0;
1405
+ const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version ? String(tokenCtx.version) : void 0;
1349
1406
  let dateStr;
1350
1407
  if (typeof cfg.date === "string") {
1351
1408
  dateStr = replaceDocumentTokens(cfg.date, tokenCtx);
1352
1409
  } else if (cfg.date === true) {
1353
- dateStr = tokenCtx.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1410
+ dateStr = tokenCtx.date ? String(tokenCtx.date) : (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1354
1411
  } else {
1355
- dateStr = tokenCtx.date;
1412
+ dateStr = tokenCtx.date ? String(tokenCtx.date) : void 0;
1356
1413
  }
1357
1414
  const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
1358
1415
  const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
1359
1416
  const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
1360
1417
  const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
1361
1418
  const logoWidth = cfg.logoWidth;
1362
- const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
1419
+ const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
1420
+ const backgroundColor = typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
1363
1421
  const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
1422
+ const titleColor = typeof cfg.titleColor === "string" ? cfg.titleColor : void 0;
1423
+ const subtitleColor = typeof cfg.subtitleColor === "string" ? cfg.subtitleColor : void 0;
1424
+ const accentColor = typeof cfg.accentColor === "string" ? cfg.accentColor : void 0;
1364
1425
  const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
1426
+ const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
1427
+ const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
1428
+ const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
1429
+ const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
1430
+ let socialMap;
1431
+ if (cfg.social && typeof cfg.social === "object") {
1432
+ socialMap = {};
1433
+ for (const [k, v] of Object.entries(cfg.social)) {
1434
+ if (typeof v === "string") {
1435
+ socialMap[k] = replaceDocumentTokens(v, tokenCtx);
1436
+ }
1437
+ }
1438
+ }
1439
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
1440
+ const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : void 0;
1365
1441
  return {
1366
1442
  enabled: true,
1367
1443
  preset,
@@ -1377,8 +1453,18 @@ function normalizeCoverPage(rawCover, tokenCtx = {}) {
1377
1453
  logo,
1378
1454
  logoWidth,
1379
1455
  bgGradient,
1456
+ backgroundColor,
1380
1457
  textColor,
1381
- footerText
1458
+ titleColor,
1459
+ subtitleColor,
1460
+ accentColor,
1461
+ footerText,
1462
+ address,
1463
+ email,
1464
+ phone,
1465
+ website,
1466
+ social: socialMap,
1467
+ copyright
1382
1468
  };
1383
1469
  }
1384
1470
  function normalizeBackCover(rawBack, tokenCtx = {}) {
@@ -1388,7 +1474,10 @@ function normalizeBackCover(rawBack, tokenCtx = {}) {
1388
1474
  const preset = cfg.preset || "modern";
1389
1475
  const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : "Thank You";
1390
1476
  const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : void 0;
1391
- const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
1477
+ const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author ? String(tokenCtx.author) : void 0;
1478
+ const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company ? String(tokenCtx.company) : void 0;
1479
+ const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version ? String(tokenCtx.version) : void 0;
1480
+ const date = typeof cfg.date === "string" ? replaceDocumentTokens(cfg.date, tokenCtx) : tokenCtx.date ? String(tokenCtx.date) : void 0;
1392
1481
  const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
1393
1482
  const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
1394
1483
  const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
@@ -1404,32 +1493,45 @@ function normalizeBackCover(rawBack, tokenCtx = {}) {
1404
1493
  }
1405
1494
  const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
1406
1495
  const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : company ? `Copyright (c) ${currentYear} ${company}. All Rights Reserved.` : void 0;
1496
+ const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
1407
1497
  const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
1408
1498
  const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
1409
1499
  const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
1410
1500
  const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
1411
1501
  const logoWidth = cfg.logoWidth;
1412
- const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
1502
+ const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
1503
+ const backgroundColor = typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
1413
1504
  const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
1505
+ const titleColor = typeof cfg.titleColor === "string" ? cfg.titleColor : void 0;
1506
+ const subtitleColor = typeof cfg.subtitleColor === "string" ? cfg.subtitleColor : void 0;
1507
+ const accentColor = typeof cfg.accentColor === "string" ? cfg.accentColor : void 0;
1414
1508
  return {
1415
1509
  enabled: true,
1416
1510
  preset,
1417
1511
  title,
1418
1512
  subtitle,
1513
+ author,
1419
1514
  company,
1515
+ version,
1516
+ date,
1420
1517
  address,
1421
1518
  email,
1422
1519
  phone,
1423
1520
  website,
1424
1521
  social: socialMap,
1425
1522
  copyright,
1523
+ footerText,
1426
1524
  badge,
1427
1525
  badgeColor,
1428
1526
  badgeTextColor,
1429
1527
  logo,
1430
1528
  logoWidth,
1431
1529
  bgGradient,
1432
- textColor
1530
+ backgroundColor,
1531
+ textColor,
1532
+ titleColor,
1533
+ subtitleColor,
1534
+ accentColor
1433
1535
  };
1434
1536
  }
1435
1537
  function normalizeNumberHeadings(raw) {
@@ -1469,7 +1571,15 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
1469
1571
  const version = mergedMeta.version || void 0;
1470
1572
  const company = mergedMeta.company || void 0;
1471
1573
  const lang = mergedMeta.lang || "en";
1472
- const tokenContext = { title, subtitle, author, version, date, company };
1574
+ const tokenContext = {
1575
+ ...mergedMeta,
1576
+ title,
1577
+ subtitle,
1578
+ author,
1579
+ version,
1580
+ date,
1581
+ company
1582
+ };
1473
1583
  const theme = mergedMeta.theme || userConfig.theme || DEFAULT_CONFIG.theme;
1474
1584
  const orientation = mergedMeta.orientation || userConfig.orientation || DEFAULT_CONFIG.orientation;
1475
1585
  const paperSize = mergedMeta.paperSize || userConfig.paperSize || DEFAULT_CONFIG.paperSize;
@@ -1498,7 +1608,7 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
1498
1608
  const footer = normalizeHeaderFooter(rawFooter, tokenContext);
1499
1609
  const toc = typeof mergedMeta.toc === "boolean" ? mergedMeta.toc : typeof userConfig.toc === "boolean" ? userConfig.toc : DEFAULT_CONFIG.toc;
1500
1610
  const rawWatermark = mergedMeta.watermark !== void 0 ? mergedMeta.watermark : userConfig.watermark !== void 0 ? userConfig.watermark : DEFAULT_CONFIG.watermark;
1501
- const watermark = normalizeWatermark(rawWatermark);
1611
+ const watermark = normalizeWatermark(rawWatermark, tokenContext);
1502
1612
  const rawSignatures = mergedMeta.signatures || userConfig.signatures;
1503
1613
  const signatures = normalizeSignatures(rawSignatures, tokenContext);
1504
1614
  const rawCover = mergedMeta.coverPage !== void 0 ? mergedMeta.coverPage : userConfig.coverPage;
@@ -1594,7 +1704,7 @@ var KATEX_INLINE_CSS = `
1594
1704
  function escapeHtml(str) {
1595
1705
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1596
1706
  }
1597
- async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
1707
+ async function renderInlinesToHtml(spans = [], baseDir = process.cwd(), tokens) {
1598
1708
  let result = "";
1599
1709
  for (const span of spans) {
1600
1710
  if (span.type === "image" && span.url) {
@@ -1608,23 +1718,23 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
1608
1718
  continue;
1609
1719
  }
1610
1720
  if (span.type === "link" && span.url) {
1611
- const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
1721
+ const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
1612
1722
  const title = span.title ? ` title="${escapeHtml(span.title)}"` : "";
1613
1723
  result += `<a href="${escapeHtml(span.url)}"${title}>${inner}</a>`;
1614
1724
  continue;
1615
1725
  }
1616
1726
  if (span.type === "bold") {
1617
- const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
1727
+ const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
1618
1728
  result += `<strong>${inner}</strong>`;
1619
1729
  continue;
1620
1730
  }
1621
1731
  if (span.type === "italic") {
1622
- const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
1732
+ const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
1623
1733
  result += `<em>${inner}</em>`;
1624
1734
  continue;
1625
1735
  }
1626
1736
  if (span.type === "strikethrough") {
1627
- const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
1737
+ const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
1628
1738
  result += `<del>${inner}</del>`;
1629
1739
  continue;
1630
1740
  }
@@ -1645,21 +1755,23 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
1645
1755
  result += span.content;
1646
1756
  continue;
1647
1757
  }
1648
- result += escapeHtml(span.content);
1758
+ const content = tokens ? replaceDocumentTokens(span.content, tokens) : span.content;
1759
+ result += escapeHtml(content);
1649
1760
  }
1650
1761
  return result;
1651
1762
  }
1652
- async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
1763
+ async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd(), tokens) {
1653
1764
  let bodyHtml = "";
1765
+ const tokenCtx = tokens || resolved;
1654
1766
  for (const node of nodes) {
1655
1767
  if (node.type === "heading") {
1656
- const inner = await renderInlinesToHtml(node.inlines, baseDir);
1768
+ const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
1657
1769
  bodyHtml += ` <h${node.level} id="${node.id}">${inner}</h${node.level}>
1658
1770
  `;
1659
1771
  continue;
1660
1772
  }
1661
1773
  if (node.type === "paragraph") {
1662
- const inner = await renderInlinesToHtml(node.inlines, baseDir);
1774
+ const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
1663
1775
  bodyHtml += ` <p>${inner}</p>
1664
1776
  `;
1665
1777
  continue;
@@ -1674,7 +1786,7 @@ async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
1674
1786
  const gap = node.columnGap || "1.5rem";
1675
1787
  let colChildrenHtml = "";
1676
1788
  for (const col of node.children || []) {
1677
- const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir);
1789
+ const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir, tokenCtx);
1678
1790
  colChildrenHtml += ` <div class="markforge-col">
1679
1791
  ${colInner} </div>
1680
1792
  `;
@@ -1700,7 +1812,7 @@ ${escapeHtml(node.text || "")}
1700
1812
  continue;
1701
1813
  }
1702
1814
  if (node.type === "callout") {
1703
- const inner = await renderInlinesToHtml(node.inlines, baseDir);
1815
+ const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
1704
1816
  const CALLOUT_STYLES = {
1705
1817
  NOTE: { bg: "#ECFDFD", border: "#33CDCF", titleColor: "#009DA0" },
1706
1818
  TIP: { bg: "#ecfdf5", border: "#10b981", titleColor: "#10b981" },
@@ -1720,7 +1832,7 @@ ${escapeHtml(node.text || "")}
1720
1832
  continue;
1721
1833
  }
1722
1834
  if (node.type === "blockquote") {
1723
- const inner = await renderInlinesToHtml(node.inlines, baseDir);
1835
+ const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
1724
1836
  bodyHtml += ` <blockquote>${inner}</blockquote>
1725
1837
  `;
1726
1838
  continue;
@@ -1734,7 +1846,7 @@ ${escapeHtml(node.text || "")}
1734
1846
  for (const cell of row.children || []) {
1735
1847
  const tag = cell.isHeader ? "th" : "td";
1736
1848
  const align = cell.align ? ` align="${cell.align}"` : "";
1737
- const inner = await renderInlinesToHtml(cell.inlines, baseDir);
1849
+ const inner = await renderInlinesToHtml(cell.inlines, baseDir, tokenCtx);
1738
1850
  bodyHtml += ` <${tag}${align}>${inner}</${tag}>
1739
1851
  `;
1740
1852
  }
@@ -1750,7 +1862,7 @@ ${escapeHtml(node.text || "")}
1750
1862
  bodyHtml += ` <${tag}>
1751
1863
  `;
1752
1864
  for (const item of node.children) {
1753
- const inner = await renderInlinesToHtml(item.inlines, baseDir);
1865
+ const inner = await renderInlinesToHtml(item.inlines, baseDir, tokenCtx);
1754
1866
  bodyHtml += ` <li>${inner}</li>
1755
1867
  `;
1756
1868
  }
@@ -2063,8 +2175,8 @@ async function renderBackCoverHtml(backCover, baseDir = process.cwd()) {
2063
2175
  `;
2064
2176
  return { html, css };
2065
2177
  }
2066
- async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
2067
- var _a;
2178
+ async function buildHtmlDocument(doc, config = {}, baseDir = process.cwd()) {
2179
+ var _a, _b;
2068
2180
  const resolved = resolveDocumentConfig(doc.metadata, config);
2069
2181
  const baseThemeCss = generateThemeCss(resolved.theme);
2070
2182
  let customCss = "";
@@ -2160,6 +2272,9 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
2160
2272
  bodyHtml += ` </header>
2161
2273
  `;
2162
2274
  }
2275
+ if (((_b = resolved.numberHeadings) == null ? void 0 : _b.enabled) !== false && resolved.numberHeadings) {
2276
+ applyHeadingNumbering(doc.nodes, doc.tocEntries, resolved.numberHeadings);
2277
+ }
2163
2278
  if (resolved.toc && doc.tocEntries.length > 0) {
2164
2279
  bodyHtml += ` <nav class="table-of-contents">
2165
2280
  `;
@@ -2175,12 +2290,26 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
2175
2290
  </nav>
2176
2291
  `;
2177
2292
  }
2178
- bodyHtml += await renderNodesToHtml(doc.nodes, resolved, baseDir);
2293
+ const mergedTokens = {
2294
+ ...config.metadata,
2295
+ ...doc.metadata,
2296
+ ...resolved,
2297
+ title: resolved.title,
2298
+ subtitle: resolved.subtitle,
2299
+ author: resolved.author,
2300
+ version: resolved.version,
2301
+ date: resolved.date,
2302
+ company: resolved.company
2303
+ };
2304
+ const nodesHtml = await renderNodesToHtml(doc.nodes, resolved, baseDir, mergedTokens);
2305
+ bodyHtml += ` <main class="markforge-content-body">
2306
+ ${nodesHtml} </main>
2307
+ `;
2179
2308
  let footnotesHtml = "";
2180
2309
  if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
2181
2310
  let fnListHtml = "";
2182
2311
  for (const def of doc.footnoteDefs) {
2183
- const defInner = await renderInlinesToHtml(def.inlines, baseDir);
2312
+ const defInner = await renderInlinesToHtml(def.inlines, baseDir, mergedTokens);
2184
2313
  fnListHtml += ` <li id="fn-${escapeHtml(def.id)}">${defInner} <a href="#fnref-${escapeHtml(def.id)}" class="markforge-fn-return">&#8617;</a></li>
2185
2314
  `;
2186
2315
  }
@@ -2218,17 +2347,7 @@ ${fnListHtml} </ol>
2218
2347
  }
2219
2348
  @media print {
2220
2349
  .document-watermark {
2221
- position: fixed;
2222
- top: 0;
2223
- left: 0;
2224
- right: 0;
2225
- bottom: 0;
2226
- width: 100vw;
2227
- height: 100vh;
2228
- pointer-events: none;
2229
- z-index: 0;
2230
- -webkit-print-color-adjust: exact;
2231
- print-color-adjust: exact;
2350
+ display: none !important;
2232
2351
  }
2233
2352
  }
2234
2353
  `;
@@ -2414,8 +2533,11 @@ function escapeXml(str) {
2414
2533
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
2415
2534
  }
2416
2535
  function generateWatermarkPngBuffer(chromePath, wm) {
2417
- const tmpHtml = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.html`);
2418
- const tmpPng = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
2536
+ const tmpId = Math.random().toString(36).substring(2, 9);
2537
+ const tmpDir = os.tmpdir();
2538
+ const tmpHtml = path3.join(tmpDir, `markforge-wm-${tmpId}.html`);
2539
+ const tmpPng = path3.join(tmpDir, `markforge-wm-${tmpId}.png`);
2540
+ const tmpProfile = path3.join(tmpDir, `markforge-wm-prof-${tmpId}`);
2419
2541
  try {
2420
2542
  const text = escapeXml(wm.text.toUpperCase());
2421
2543
  const fontSize = (wm.fontSize || 52) * 1.5;
@@ -2466,6 +2588,9 @@ function generateWatermarkPngBuffer(chromePath, wm) {
2466
2588
  chromePath,
2467
2589
  [
2468
2590
  "--headless=new",
2591
+ `--user-data-dir=${tmpProfile}`,
2592
+ "--no-first-run",
2593
+ "--no-default-browser-check",
2469
2594
  "--disable-gpu",
2470
2595
  "--disable-sync",
2471
2596
  "--disable-extensions",
@@ -2487,6 +2612,7 @@ function generateWatermarkPngBuffer(chromePath, wm) {
2487
2612
  try {
2488
2613
  if (fs3.existsSync(tmpHtml)) fs3.unlinkSync(tmpHtml);
2489
2614
  if (fs3.existsSync(tmpPng)) fs3.unlinkSync(tmpPng);
2615
+ if (fs3.existsSync(tmpProfile)) fs3.rmSync(tmpProfile, { recursive: true, force: true });
2490
2616
  } catch {
2491
2617
  }
2492
2618
  }
@@ -2502,6 +2628,8 @@ function findChromeExecutable() {
2502
2628
  const winLocalAppData = process.env.LOCALAPPDATA ?? "";
2503
2629
  const winProgramFiles = process.env.PROGRAMFILES ?? "C:\\Program Files";
2504
2630
  const winProgramFilesX86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
2631
+ const winProgramW6432 = process.env.ProgramW6432 ?? "C:\\Program Files";
2632
+ const winUserProfile = process.env.USERPROFILE ?? "";
2505
2633
  const candidates = [
2506
2634
  // Linux
2507
2635
  "/usr/bin/google-chrome",
@@ -2520,17 +2648,34 @@ function findChromeExecutable() {
2520
2648
  // Windows — Microsoft Edge (Native Windows 10/11 browser, enterprise whitelist friendly)
2521
2649
  `${winProgramFiles}\\Microsoft\\Edge\\Application\\msedge.exe`,
2522
2650
  `${winProgramFilesX86}\\Microsoft\\Edge\\Application\\msedge.exe`,
2651
+ `${winProgramW6432}\\Microsoft\\Edge\\Application\\msedge.exe`,
2523
2652
  `${winLocalAppData}\\Microsoft\\Edge\\Application\\msedge.exe`,
2524
- // Windows — Google Chrome
2653
+ `${winLocalAppData}\\Microsoft\\Edge Dev\\Application\\msedge.exe`,
2654
+ `${winLocalAppData}\\Microsoft\\Edge Beta\\Application\\msedge.exe`,
2655
+ // Windows — Google Chrome & Chrome SxS (Canary)
2525
2656
  `${winProgramFiles}\\Google\\Chrome\\Application\\chrome.exe`,
2526
2657
  `${winProgramFilesX86}\\Google\\Chrome\\Application\\chrome.exe`,
2658
+ `${winProgramW6432}\\Google\\Chrome\\Application\\chrome.exe`,
2527
2659
  `${winLocalAppData}\\Google\\Chrome\\Application\\chrome.exe`,
2660
+ `${winLocalAppData}\\Google\\Chrome SxS\\Application\\chrome.exe`,
2528
2661
  // Windows — Brave Browser
2529
2662
  `${winProgramFiles}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
2530
2663
  `${winProgramFilesX86}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
2664
+ `${winProgramW6432}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
2531
2665
  `${winLocalAppData}\\BraveSoftware\\Brave-Browser\\Application\\brave.exe`,
2532
2666
  // Windows — Chromium
2533
- `${winLocalAppData}\\Chromium\\Application\\chrome.exe`
2667
+ `${winLocalAppData}\\Chromium\\Application\\chrome.exe`,
2668
+ // Windows — Scoop Package Manager
2669
+ `${winUserProfile}\\scoop\\apps\\googlechrome\\current\\chrome.exe`,
2670
+ `${winUserProfile}\\scoop\\apps\\chromium\\current\\chrome.exe`,
2671
+ `${winUserProfile}\\scoop\\apps\\brave\\current\\brave.exe`,
2672
+ `${winUserProfile}\\scoop\\apps\\msedge\\current\\msedge.exe`,
2673
+ `${winUserProfile}\\scoop\\shims\\chrome.exe`,
2674
+ `${winUserProfile}\\scoop\\shims\\msedge.exe`,
2675
+ // Windows — Chocolatey
2676
+ "C:\\ProgramData\\chocolatey\\bin\\chrome.exe",
2677
+ "C:\\ProgramData\\chocolatey\\bin\\msedge.exe",
2678
+ "C:\\ProgramData\\chocolatey\\bin\\brave.exe"
2534
2679
  ].filter(Boolean);
2535
2680
  for (const candidate of candidates) {
2536
2681
  try {
@@ -2541,13 +2686,15 @@ function findChromeExecutable() {
2541
2686
  }
2542
2687
  }
2543
2688
  try {
2544
- const cmd = isWin ? "where" : "which";
2545
- const names = isWin ? ["chrome", "msedge", "brave", "google-chrome", "chromium", "chromium-browser"] : ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser", "microsoft-edge", "brave-browser"];
2689
+ const cmd = isWin ? "where.exe" : "which";
2690
+ 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"];
2546
2691
  for (const name of names) {
2547
- const res = spawnSync(cmd, [name], { encoding: "utf-8" });
2692
+ const res = spawnSync(cmd, [name], { encoding: "utf-8", windowsHide: true });
2548
2693
  if (res.status === 0 && res.stdout.trim()) {
2549
- const binPath = res.stdout.split(/\r?\n/)[0].trim();
2550
- if (fs3.existsSync(binPath)) return binPath;
2694
+ const lines = res.stdout.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
2695
+ for (const line of lines) {
2696
+ if (fs3.existsSync(line)) return line;
2697
+ }
2551
2698
  }
2552
2699
  }
2553
2700
  } catch {
@@ -2555,7 +2702,7 @@ function findChromeExecutable() {
2555
2702
  return null;
2556
2703
  }
2557
2704
  function injectPagedMediaStyles(html, config, metadata) {
2558
- var _a, _b, _c, _d, _e, _f, _g, _h;
2705
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
2559
2706
  const resolved = resolveDocumentConfig(metadata || {}, config);
2560
2707
  const size = resolved.paperSize;
2561
2708
  const orientation = resolved.orientation;
@@ -2630,9 +2777,11 @@ function injectPagedMediaStyles(html, config, metadata) {
2630
2777
  min-height: 100vh;
2631
2778
  height: 100vh;
2632
2779
  box-sizing: border-box;
2780
+ break-before: page;
2781
+ break-after: avoid;
2633
2782
  }` : "";
2634
- const pagedCss = `
2635
- @page {
2783
+ const tocPageCss = resolved.toc ? `
2784
+ @page toc-page {
2636
2785
  size: ${size} ${orientation};
2637
2786
  margin-top: ${top};
2638
2787
  margin-bottom: ${bottom};
@@ -2643,9 +2792,36 @@ function injectPagedMediaStyles(html, config, metadata) {
2643
2792
  ${buildZoneCss("top-right", (_e = resolved.header) == null ? void 0 : _e.right)}
2644
2793
  ${buildZoneCss("bottom-left", (_f = resolved.footer) == null ? void 0 : _f.left)}
2645
2794
  ${buildZoneCss("bottom-center", (_g = resolved.footer) == null ? void 0 : _g.center)}
2646
- ${buildZoneCss("bottom-right", (_h = resolved.footer) == null ? void 0 : _h.right, true)}
2795
+ @bottom-right {
2796
+ content: counter(page, lower-roman);
2797
+ font-size: 9pt;
2798
+ color: #94a3b8;
2799
+ }
2800
+ }
2801
+ .table-of-contents {
2802
+ page: toc-page;
2803
+ page-break-after: always;
2804
+ break-after: page;
2805
+ }
2806
+ .markforge-content-body {
2807
+ counter-reset: page 1;
2808
+ }` : "";
2809
+ const pagedCss = `
2810
+ @page {
2811
+ size: ${size} ${orientation};
2812
+ margin-top: ${top};
2813
+ margin-bottom: ${bottom};
2814
+ margin-left: ${left};
2815
+ margin-right: ${right};
2816
+ ${buildZoneCss("top-left", (_h = resolved.header) == null ? void 0 : _h.left)}
2817
+ ${buildZoneCss("top-center", (_i = resolved.header) == null ? void 0 : _i.center)}
2818
+ ${buildZoneCss("top-right", (_j = resolved.header) == null ? void 0 : _j.right)}
2819
+ ${buildZoneCss("bottom-left", (_k = resolved.footer) == null ? void 0 : _k.left)}
2820
+ ${buildZoneCss("bottom-center", (_l = resolved.footer) == null ? void 0 : _l.center)}
2821
+ ${buildZoneCss("bottom-right", (_m = resolved.footer) == null ? void 0 : _m.right, true)}
2647
2822
  }
2648
2823
  ${coverPageCss}
2824
+ ${tocPageCss}
2649
2825
  ${backCoverCss}
2650
2826
  @media print {
2651
2827
  body { padding: 0; }
@@ -2776,9 +2952,10 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
2776
2952
  const wmPng = generateWatermarkPngBuffer(chromePath, resolved.watermark);
2777
2953
  if (wmPng) {
2778
2954
  const embeddedPng = await pdfDoc.embedPng(wmPng);
2955
+ const totalPages = pdfDoc.getPageCount();
2779
2956
  const pages = pdfDoc.getPages();
2780
2957
  const startPageIndex = ((_b = resolved.coverPage) == null ? void 0 : _b.enabled) ? 1 : 0;
2781
- const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ? pages.length - 1 : pages.length;
2958
+ const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ? totalPages - 1 : totalPages;
2782
2959
  for (let i = startPageIndex; i < endPageIndex; i++) {
2783
2960
  const page = pages[i];
2784
2961
  const { width, height } = page.getSize();
@@ -2863,7 +3040,10 @@ import {
2863
3040
  convertMillimetersToTwip,
2864
3041
  ShadingType,
2865
3042
  ExternalHyperlink,
2866
- TabStopType
3043
+ TabStopType,
3044
+ PageBreak,
3045
+ NumberFormat,
3046
+ SectionType
2867
3047
  } from "docx";
2868
3048
 
2869
3049
  // src/core/mermaid/mermaidRenderer.ts
@@ -2881,6 +3061,8 @@ async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
2881
3061
  const tmpDir = os2.tmpdir();
2882
3062
  const tmpHtml = path4.join(tmpDir, `mermaid_${tmpId}.html`);
2883
3063
  const tmpScreenshot = path4.join(tmpDir, `mermaid_${tmpId}.png`);
3064
+ const tmpProfile = path4.join(tmpDir, `mermaid_prof_${tmpId}`);
3065
+ const isWin = process.platform === "win32";
2884
3066
  const htmlContent = `<!DOCTYPE html>
2885
3067
  <html>
2886
3068
  <head>
@@ -2924,10 +3106,14 @@ ${mermaidCode}
2924
3106
  const res = spawnSync2(
2925
3107
  chromePath,
2926
3108
  [
2927
- "--headless",
3109
+ "--headless=new",
3110
+ `--user-data-dir=${tmpProfile}`,
3111
+ "--no-first-run",
3112
+ "--no-default-browser-check",
2928
3113
  "--disable-gpu",
2929
- "--no-sandbox",
2930
- "--disable-setuid-sandbox",
3114
+ "--disable-sync",
3115
+ "--disable-extensions",
3116
+ ...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
2931
3117
  "--allow-file-access-from-files",
2932
3118
  "--disable-web-security",
2933
3119
  "--disable-software-rasterizer",
@@ -2936,7 +3122,7 @@ ${mermaidCode}
2936
3122
  `--screenshot=${tmpScreenshot}`,
2937
3123
  fileUrl
2938
3124
  ],
2939
- { timeout: 15e3 }
3125
+ { timeout: 15e3, windowsHide: true }
2940
3126
  );
2941
3127
  if (res.status === 0 && fs4.existsSync(tmpScreenshot)) {
2942
3128
  const buffer = fs4.readFileSync(tmpScreenshot);
@@ -2947,6 +3133,7 @@ ${mermaidCode}
2947
3133
  try {
2948
3134
  if (fs4.existsSync(tmpHtml)) fs4.unlinkSync(tmpHtml);
2949
3135
  if (fs4.existsSync(tmpScreenshot)) fs4.unlinkSync(tmpScreenshot);
3136
+ if (fs4.existsSync(tmpProfile)) fs4.rmSync(tmpProfile, { recursive: true, force: true });
2950
3137
  } catch {
2951
3138
  }
2952
3139
  }
@@ -3125,7 +3312,7 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
3125
3312
  return runs;
3126
3313
  }
3127
3314
  async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3128
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3315
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
3129
3316
  const resolved = resolveDocumentConfig(doc.metadata, config);
3130
3317
  const docElements = [];
3131
3318
  const themeProps = typeof resolved.theme === "object" ? resolved.theme : {};
@@ -3197,6 +3384,9 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3197
3384
  );
3198
3385
  }
3199
3386
  }
3387
+ if (((_b = resolved.numberHeadings) == null ? void 0 : _b.enabled) !== false && resolved.numberHeadings) {
3388
+ applyHeadingNumbering(doc.nodes, doc.tocEntries, resolved.numberHeadings);
3389
+ }
3200
3390
  if (resolved.toc) {
3201
3391
  const headingNodes = doc.nodes.filter(
3202
3392
  (n) => n.type === "heading" && typeof n.level === "number" && n.level >= 1 && n.level <= 3
@@ -3266,7 +3456,11 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3266
3456
  ]
3267
3457
  });
3268
3458
  docElements.push(tocCard);
3269
- docElements.push(new Paragraph({ spacing: { after: 200 } }));
3459
+ docElements.push(
3460
+ new Paragraph({
3461
+ children: [new PageBreak()]
3462
+ })
3463
+ );
3270
3464
  }
3271
3465
  }
3272
3466
  for (const node of doc.nodes) {
@@ -3276,7 +3470,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3276
3470
  font: defaultFont,
3277
3471
  size: 34,
3278
3472
  // 17pt
3279
- color: textHex,
3473
+ color: primaryDarkHex,
3280
3474
  bold: true
3281
3475
  });
3282
3476
  docElements.push(
@@ -3322,7 +3516,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3322
3516
  font: defaultFont,
3323
3517
  size: 22,
3324
3518
  // 11pt
3325
- color: textHex,
3519
+ color: primaryDarkHex,
3326
3520
  bold: true
3327
3521
  });
3328
3522
  docElements.push(
@@ -3552,7 +3746,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3552
3746
  }
3553
3747
  if (node.type === "table" && node.children) {
3554
3748
  const tableRows = [];
3555
- const numCols = ((_c = (_b = node.children[0]) == null ? void 0 : _b.children) == null ? void 0 : _c.length) || 1;
3749
+ const numCols = ((_d = (_c = node.children[0]) == null ? void 0 : _c.children) == null ? void 0 : _d.length) || 1;
3556
3750
  const colWidth = Math.floor(9e3 / numCols);
3557
3751
  for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
3558
3752
  const rowNode = node.children[rowIdx];
@@ -3562,7 +3756,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3562
3756
  if (rowNode.children) {
3563
3757
  for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {
3564
3758
  const cellNode = rowNode.children[colIdx];
3565
- const align = (_d = node.align) == null ? void 0 : _d[colIdx];
3759
+ const align = (_e = node.align) == null ? void 0 : _e[colIdx];
3566
3760
  let alignment = AlignmentType.LEFT;
3567
3761
  if (align === "center") alignment = AlignmentType.CENTER;
3568
3762
  if (align === "right") alignment = AlignmentType.RIGHT;
@@ -3869,7 +4063,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3869
4063
  const centerPos = Math.round(contentWidthTwip / 2);
3870
4064
  const rightPos = contentWidthTwip;
3871
4065
  const headerRuns = [];
3872
- if ((_e = resolved.header) == null ? void 0 : _e.left) {
4066
+ if ((_f = resolved.header) == null ? void 0 : _f.left) {
3873
4067
  headerRuns.push(
3874
4068
  new TextRun({
3875
4069
  text: resolved.header.left.text,
@@ -3882,7 +4076,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3882
4076
  );
3883
4077
  }
3884
4078
  headerRuns.push(new TextRun({ text: " " }));
3885
- if ((_f = resolved.header) == null ? void 0 : _f.center) {
4079
+ if ((_g = resolved.header) == null ? void 0 : _g.center) {
3886
4080
  headerRuns.push(
3887
4081
  new TextRun({
3888
4082
  text: resolved.header.center.text,
@@ -3895,7 +4089,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3895
4089
  );
3896
4090
  }
3897
4091
  headerRuns.push(new TextRun({ text: " " }));
3898
- if ((_g = resolved.header) == null ? void 0 : _g.right) {
4092
+ if ((_h = resolved.header) == null ? void 0 : _h.right) {
3899
4093
  headerRuns.push(
3900
4094
  new TextRun({
3901
4095
  text: resolved.header.right.text,
@@ -3934,7 +4128,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3934
4128
  ]
3935
4129
  }) : void 0;
3936
4130
  const footerRuns = [];
3937
- if ((_h = resolved.footer) == null ? void 0 : _h.left) {
4131
+ if ((_i = resolved.footer) == null ? void 0 : _i.left) {
3938
4132
  footerRuns.push(
3939
4133
  new TextRun({
3940
4134
  text: resolved.footer.left.text,
@@ -3947,7 +4141,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3947
4141
  );
3948
4142
  }
3949
4143
  footerRuns.push(new TextRun({ text: " " }));
3950
- if ((_i = resolved.footer) == null ? void 0 : _i.center) {
4144
+ if ((_j = resolved.footer) == null ? void 0 : _j.center) {
3951
4145
  footerRuns.push(
3952
4146
  new TextRun({
3953
4147
  text: resolved.footer.center.text,
@@ -3960,7 +4154,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
3960
4154
  );
3961
4155
  }
3962
4156
  footerRuns.push(new TextRun({ text: " " }));
3963
- if ((_j = resolved.footer) == null ? void 0 : _j.right) {
4157
+ if ((_k = resolved.footer) == null ? void 0 : _k.right) {
3964
4158
  const rZone = resolved.footer.right;
3965
4159
  const rColor = rZone.color.replace("#", "");
3966
4160
  const rSize = (rZone.fontSize || 9) * 2;
@@ -4058,6 +4252,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
4058
4252
  );
4059
4253
  docSections.push({
4060
4254
  properties: {
4255
+ type: SectionType.NEXT_PAGE,
4061
4256
  page: {
4062
4257
  size: {
4063
4258
  width: resolved.paperDimensions.widthTwip,
@@ -4072,14 +4267,19 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
4072
4267
  }
4073
4268
  }
4074
4269
  },
4075
- headers: void 0,
4076
- footers: void 0,
4270
+ headers: { default: new Header({ children: [] }) },
4271
+ footers: { default: new Footer({ children: [] }) },
4077
4272
  children: coverElements
4078
4273
  });
4079
4274
  }
4080
4275
  docSections.push({
4081
4276
  properties: {
4277
+ type: SectionType.NEXT_PAGE,
4082
4278
  page: {
4279
+ pageNumbers: {
4280
+ start: 1,
4281
+ formatType: NumberFormat.DECIMAL
4282
+ },
4083
4283
  size: {
4084
4284
  width: resolved.paperDimensions.widthTwip,
4085
4285
  height: resolved.paperDimensions.heightTwip,
@@ -4095,8 +4295,8 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
4095
4295
  }
4096
4296
  }
4097
4297
  },
4098
- headers: docHeader ? { default: docHeader } : void 0,
4099
- footers: docFooter ? { default: docFooter } : void 0,
4298
+ headers: docHeader ? { default: docHeader } : { default: new Header({ children: [] }) },
4299
+ footers: docFooter ? { default: docFooter } : { default: new Footer({ children: [] }) },
4100
4300
  children: docElements
4101
4301
  });
4102
4302
  if (resolved.backCover && resolved.backCover.enabled) {
@@ -4111,6 +4311,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
4111
4311
  );
4112
4312
  docSections.push({
4113
4313
  properties: {
4314
+ type: SectionType.NEXT_PAGE,
4114
4315
  page: {
4115
4316
  size: {
4116
4317
  width: resolved.paperDimensions.widthTwip,
@@ -4125,8 +4326,8 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
4125
4326
  }
4126
4327
  }
4127
4328
  },
4128
- headers: void 0,
4129
- footers: void 0,
4329
+ headers: { default: new Header({ children: [] }) },
4330
+ footers: { default: new Footer({ children: [] }) },
4130
4331
  children: backElements
4131
4332
  });
4132
4333
  }
@@ -4530,8 +4731,12 @@ function createEmptyDocxCell(widthDxa) {
4530
4731
  }
4531
4732
 
4532
4733
  export {
4734
+ applyHeadingNumbering,
4533
4735
  parseMarkdownDocument,
4736
+ replaceDocumentTokens,
4737
+ resolveDocumentConfig,
4534
4738
  buildHtmlDocument,
4739
+ findChromeExecutable,
4535
4740
  buildPdfDocument,
4536
4741
  buildDocxDocument
4537
4742
  };