@masumdev/markforge 0.2.5 → 0.4.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.
@@ -7,132 +7,9 @@ try {
7
7
  });
8
8
  }
9
9
  } catch {}
10
- import {
11
- MARKFORGE_VERSION
12
- } from "./chunk-NGC2ZAWZ.mjs";
13
10
  import {
14
11
  DEFAULT_CONFIG
15
- } from "./chunk-IYGPJIK5.mjs";
16
- import "./chunk-YZHGBG4N.mjs";
17
-
18
- // src/ui/App.tsx
19
- import { useState, useEffect } from "react";
20
- import { Box as Box4 } from "ink";
21
-
22
- // src/ui/Header.tsx
23
- import { Box, Text } from "ink";
24
- import { jsx, jsxs } from "react/jsx-runtime";
25
- var Header = ({ inputFile, theme = "corporate" }) => {
26
- const themeLabel = typeof theme === "object" ? "custom (ThemeProps)" : String(theme || "corporate");
27
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs(
28
- Box,
29
- {
30
- borderStyle: "round",
31
- borderColor: "cyan",
32
- paddingX: 2,
33
- paddingY: 0,
34
- flexDirection: "column",
35
- children: [
36
- /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
37
- /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MARKFORGE DOCUMENT ENGINE" }),
38
- /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
39
- "v",
40
- MARKFORGE_VERSION
41
- ] })
42
- ] }),
43
- inputFile && /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
44
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "Source: " }),
45
- /* @__PURE__ */ jsx(Text, { color: "white", bold: true, children: inputFile })
46
- ] }),
47
- /* @__PURE__ */ jsxs(Box, { children: [
48
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "Theme: " }),
49
- /* @__PURE__ */ jsx(Text, { color: "blue", children: themeLabel })
50
- ] })
51
- ]
52
- }
53
- ) });
54
- };
55
-
56
- // src/ui/LiveProgress.tsx
57
- import { Box as Box2, Text as Text2 } from "ink";
58
- import Spinner from "ink-spinner";
59
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
60
- var LiveProgress = ({ status, isCompiling }) => {
61
- if (!isCompiling) return null;
62
- return /* @__PURE__ */ jsxs2(Box2, { marginY: 1, alignItems: "center", children: [
63
- /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: /* @__PURE__ */ jsx2(Spinner, { type: "dots" }) }),
64
- /* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, children: [
65
- /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "[COMPILING] " }),
66
- /* @__PURE__ */ jsx2(Text2, { color: "white", children: status })
67
- ] })
68
- ] });
69
- };
70
-
71
- // src/ui/SummaryTable.tsx
72
- import { Box as Box3, Text as Text3 } from "ink";
73
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
74
- function formatBytes(bytes) {
75
- if (bytes === 0) return "0 B";
76
- const k = 1024;
77
- const sizes = ["B", "KB", "MB", "GB"];
78
- const i = Math.floor(Math.log(bytes) / Math.log(k));
79
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
80
- }
81
- var SummaryTable = ({ result }) => {
82
- if (!result) return null;
83
- const hasErrors = result.errors.length > 0;
84
- return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs3(
85
- Box3,
86
- {
87
- borderStyle: "round",
88
- borderColor: hasErrors ? "red" : "green",
89
- paddingX: 2,
90
- paddingY: 1,
91
- flexDirection: "column",
92
- children: [
93
- /* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", children: [
94
- /* @__PURE__ */ jsx3(Text3, { bold: true, color: hasErrors ? "red" : "green", children: hasErrors ? "[COMPILATION ERRORS]" : "[COMPILATION SUCCESSFUL]" }),
95
- /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
96
- result.durationMs,
97
- "ms"
98
- ] })
99
- ] }),
100
- /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
101
- /* @__PURE__ */ jsxs3(Text3, { bold: true, color: "white", children: [
102
- "Output Documents (",
103
- result.files.length,
104
- "):"
105
- ] }),
106
- result.files.map((f, i) => /* @__PURE__ */ jsxs3(Box3, { marginLeft: 2, justifyContent: "space-between", children: [
107
- /* @__PURE__ */ jsxs3(Box3, { children: [
108
- /* @__PURE__ */ jsxs3(Text3, { color: "cyan", children: [
109
- "[",
110
- f.format.toUpperCase(),
111
- "] "
112
- ] }),
113
- /* @__PURE__ */ jsx3(Text3, { color: "gray", children: f.filePath })
114
- ] }),
115
- /* @__PURE__ */ jsxs3(Text3, { color: "yellow", children: [
116
- " ",
117
- formatBytes(f.sizeBytes)
118
- ] })
119
- ] }, i))
120
- ] }),
121
- hasErrors && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
122
- /* @__PURE__ */ jsx3(Text3, { bold: true, color: "red", children: "Errors:" }),
123
- result.errors.map((err, i) => /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
124
- "- ",
125
- err
126
- ] }) }, i))
127
- ] })
128
- ]
129
- }
130
- ) });
131
- };
132
-
133
- // src/core/engine.ts
134
- import * as fs5 from "fs";
135
- import * as path5 from "path";
12
+ } from "./chunk-BPHDY6VB.mjs";
136
13
 
137
14
  // src/core/parser.ts
138
15
  import matter from "gray-matter";
@@ -166,6 +43,26 @@ function parseInlineSpans(text) {
166
43
  remaining = remaining.slice(imgMatch[0].length);
167
44
  continue;
168
45
  }
46
+ const fnMatch = remaining.match(/^\[\^([\w-]+)\]/);
47
+ if (fnMatch) {
48
+ const fnId = fnMatch[1];
49
+ spans.push({
50
+ type: "footnoteRef",
51
+ content: fnId,
52
+ footnoteId: fnId
53
+ });
54
+ remaining = remaining.slice(fnMatch[0].length);
55
+ continue;
56
+ }
57
+ const mathMatch = remaining.match(/^\$([^$\n]+?)\$/);
58
+ if (mathMatch && !mathMatch[1].startsWith("$")) {
59
+ spans.push({
60
+ type: "mathInline",
61
+ content: mathMatch[1]
62
+ });
63
+ remaining = remaining.slice(mathMatch[0].length);
64
+ continue;
65
+ }
169
66
  const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/);
170
67
  if (linkMatch) {
171
68
  spans.push({
@@ -265,7 +162,7 @@ function parseInlineSpans(text) {
265
162
  remaining = remaining.slice(fullTag.length);
266
163
  continue;
267
164
  }
268
- const nextSpecial = remaining.search(/[\*\_\[\!`~<]/);
165
+ const nextSpecial = remaining.search(/[\*\_\[\!`~<\$]/);
269
166
  if (nextSpecial === -1) {
270
167
  spans.push({
271
168
  type: "text",
@@ -291,6 +188,35 @@ function parseInlineSpans(text) {
291
188
  function slugify(text) {
292
189
  return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
293
190
  }
191
+ function applyHeadingNumbering(nodes, tocEntries, options) {
192
+ const depth = options.depth ?? 3;
193
+ const skipH1 = options.skipH1 ?? false;
194
+ const prefix = options.prefix ?? "";
195
+ const counters = [0, 0, 0, 0, 0, 0];
196
+ for (const node of nodes) {
197
+ if (node.type === "heading" && node.level) {
198
+ const lvl = node.level;
199
+ if (lvl > depth) continue;
200
+ if (lvl === 1 && skipH1) continue;
201
+ const idx = lvl - 1;
202
+ counters[idx]++;
203
+ for (let c = idx + 1; c < counters.length; c++) {
204
+ counters[c] = 0;
205
+ }
206
+ const startIdx = skipH1 ? 1 : 0;
207
+ const parts = counters.slice(startIdx, idx + 1).filter((n) => n > 0);
208
+ const numberStr = parts.join(".") + ".";
209
+ const fullPrefix = prefix ? `${prefix} ${numberStr} ` : `${numberStr} `;
210
+ const originalText = node.text || "";
211
+ node.text = fullPrefix + originalText;
212
+ node.inlines = parseInlineSpans(node.text);
213
+ const toc = tocEntries.find((t) => t.id === node.id);
214
+ if (toc) {
215
+ toc.text = node.text;
216
+ }
217
+ }
218
+ }
219
+ }
294
220
  function parseMarkdownDocument(rawMarkdown) {
295
221
  const { data: frontmatter, content } = matter(rawMarkdown);
296
222
  const metadata = frontmatter || {};
@@ -302,6 +228,7 @@ function parseMarkdownDocument(rawMarkdown) {
302
228
  const lines = cleanContent.split(/\r?\n/);
303
229
  const nodes = [];
304
230
  const tocEntries = [];
231
+ const footnoteDefs = [];
305
232
  let i = 0;
306
233
  while (i < lines.length) {
307
234
  const line = lines[i];
@@ -330,6 +257,29 @@ function parseMarkdownDocument(rawMarkdown) {
330
257
  i++;
331
258
  continue;
332
259
  }
260
+ if (line.trim().startsWith("$$")) {
261
+ const mathLines = [];
262
+ const singleLine = line.trim().match(/^\$\$(.+)\$\$$/);
263
+ if (singleLine) {
264
+ nodes.push({
265
+ type: "mathBlock",
266
+ text: singleLine[1].trim()
267
+ });
268
+ i++;
269
+ continue;
270
+ }
271
+ i++;
272
+ while (i < lines.length && !lines[i].trim().startsWith("$$")) {
273
+ mathLines.push(lines[i]);
274
+ i++;
275
+ }
276
+ if (i < lines.length) i++;
277
+ nodes.push({
278
+ type: "mathBlock",
279
+ text: mathLines.join("\n").trim()
280
+ });
281
+ continue;
282
+ }
333
283
  const codeBlockMatch = line.match(/^```(\w+)?/);
334
284
  if (codeBlockMatch) {
335
285
  const language = (codeBlockMatch[1] || "text").trim().toLowerCase();
@@ -356,6 +306,100 @@ function parseMarkdownDocument(rawMarkdown) {
356
306
  }
357
307
  continue;
358
308
  }
309
+ const colsMatch = line.trim().match(/^:::columns(?:\s+\[?([\w\s=.-]+)\]?)?$/i);
310
+ if (colsMatch) {
311
+ const attrStr = colsMatch[1] || "";
312
+ let colsCount = 2;
313
+ let colGap = "1.5rem";
314
+ if (attrStr) {
315
+ const numMatch = attrStr.trim().match(/^(\d+)$/);
316
+ const cMatch = attrStr.match(/cols=(\d+)/i) || attrStr.match(/columns=(\d+)/i);
317
+ const gMatch = attrStr.match(/gap=([^\s]+)/i);
318
+ if (numMatch) colsCount = parseInt(numMatch[1], 10);
319
+ else if (cMatch) colsCount = parseInt(cMatch[1], 10);
320
+ if (gMatch) colGap = gMatch[1];
321
+ }
322
+ const columnNodes = [];
323
+ let currentColumnLines = [];
324
+ let inColBlock = false;
325
+ i++;
326
+ while (i < lines.length) {
327
+ const curLine = lines[i];
328
+ const trimmed = curLine.trim();
329
+ if (/^:::col(?:umn)?$/i.test(trimmed)) {
330
+ if (currentColumnLines.length > 0) {
331
+ const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
332
+ columnNodes.push({
333
+ type: "column",
334
+ children: subDoc.nodes
335
+ });
336
+ currentColumnLines = [];
337
+ }
338
+ inColBlock = true;
339
+ i++;
340
+ } else if (trimmed === ":::") {
341
+ if (inColBlock) {
342
+ if (currentColumnLines.length > 0) {
343
+ const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
344
+ columnNodes.push({
345
+ type: "column",
346
+ children: subDoc.nodes
347
+ });
348
+ currentColumnLines = [];
349
+ }
350
+ inColBlock = false;
351
+ i++;
352
+ } else {
353
+ if (currentColumnLines.length > 0) {
354
+ const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
355
+ columnNodes.push({
356
+ type: "column",
357
+ children: subDoc.nodes
358
+ });
359
+ currentColumnLines = [];
360
+ }
361
+ i++;
362
+ break;
363
+ }
364
+ } else {
365
+ currentColumnLines.push(curLine);
366
+ i++;
367
+ }
368
+ }
369
+ if (currentColumnLines.length > 0) {
370
+ const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
371
+ columnNodes.push({
372
+ type: "column",
373
+ children: subDoc.nodes
374
+ });
375
+ }
376
+ nodes.push({
377
+ type: "columns",
378
+ columnsCount: columnNodes.length > 0 ? columnNodes.length : colsCount,
379
+ columnGap: colGap,
380
+ children: columnNodes
381
+ });
382
+ continue;
383
+ }
384
+ const fnDefMatch = line.match(/^\[\^([\w-]+)\]:\s+(.+)$/);
385
+ if (fnDefMatch) {
386
+ const fnId = fnDefMatch[1];
387
+ const fnText = fnDefMatch[2].trim();
388
+ const inlines = parseInlineSpans(fnText);
389
+ footnoteDefs.push({
390
+ id: fnId,
391
+ text: fnText,
392
+ inlines
393
+ });
394
+ nodes.push({
395
+ type: "footnoteDef",
396
+ footnoteId: fnId,
397
+ text: fnText,
398
+ inlines
399
+ });
400
+ i++;
401
+ continue;
402
+ }
359
403
  const calloutMatch = line.match(/^>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/i);
360
404
  if (calloutMatch) {
361
405
  const calloutType = calloutMatch[1].toUpperCase();
@@ -479,7 +523,7 @@ function parseMarkdownDocument(rawMarkdown) {
479
523
  continue;
480
524
  }
481
525
  const paraLines = [];
482
- while (i < lines.length && lines[i].trim() && !lines[i].match(/^#{1,6}\s+/) && !lines[i].startsWith("```") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !lines[i].match(/^(\s*)([-*+]|\d+\.)\s+/)) {
526
+ while (i < lines.length && lines[i].trim() && !lines[i].match(/^#{1,6}\s+/) && !lines[i].startsWith("```") && !lines[i].startsWith("$$") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !lines[i].match(/^:::columns/) && !lines[i].match(/^\[\^[\w-]+\]:\s+/) && !lines[i].match(/^(\s*)([-*+]|\d+\.)\s+/)) {
483
527
  paraLines.push(lines[i]);
484
528
  i++;
485
529
  }
@@ -490,39 +534,25 @@ function parseMarkdownDocument(rawMarkdown) {
490
534
  inlines: parseInlineSpans(paraText)
491
535
  });
492
536
  }
537
+ if (metadata.numberHeadings) {
538
+ const opts = typeof metadata.numberHeadings === "boolean" ? { enabled: metadata.numberHeadings } : metadata.numberHeadings;
539
+ if (opts.enabled !== false) {
540
+ applyHeadingNumbering(nodes, tocEntries, opts);
541
+ }
542
+ }
493
543
  return {
494
544
  metadata,
495
545
  content: cleanContent,
496
546
  nodes,
497
547
  tocEntries,
498
- inlinedStyles
548
+ inlinedStyles,
549
+ footnoteDefs
499
550
  };
500
551
  }
501
552
 
502
- // src/core/docx/docxBuilder.ts
503
- import {
504
- Document,
505
- Paragraph,
506
- TextRun,
507
- HeadingLevel,
508
- Table,
509
- TableRow,
510
- TableCell,
511
- WidthType,
512
- BorderStyle,
513
- AlignmentType,
514
- ImageRun,
515
- Header as Header2,
516
- Footer,
517
- PageNumber,
518
- Packer,
519
- PageOrientation,
520
- convertInchesToTwip,
521
- convertMillimetersToTwip,
522
- ShadingType,
523
- ExternalHyperlink,
524
- TabStopType
525
- } from "docx";
553
+ // src/core/html/htmlBuilder.ts
554
+ import * as fs2 from "fs";
555
+ import * as path2 from "path";
526
556
 
527
557
  // src/core/imageResolver.ts
528
558
  import * as fs from "fs";
@@ -583,9 +613,14 @@ async function resolveImage(src, baseDir = process.cwd()) {
583
613
  memoryImageCache.set(cacheKey, resolved2);
584
614
  return resolved2;
585
615
  }
586
- const localPath = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
616
+ let localPath = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
587
617
  if (!fs.existsSync(localPath)) {
588
- return null;
618
+ const cwdPath = path.resolve(process.cwd(), src);
619
+ if (fs.existsSync(cwdPath)) {
620
+ localPath = cwdPath;
621
+ } else {
622
+ return null;
623
+ }
589
624
  }
590
625
  const buffer = fs.readFileSync(localPath);
591
626
  const mimeType = getMimeType(localPath);
@@ -605,6 +640,164 @@ async function resolveImage(src, baseDir = process.cwd()) {
605
640
  }
606
641
  }
607
642
 
643
+ // src/core/html/htmlThemes.ts
644
+ var THEME_COMPONENTS = `
645
+ /* Fallback CSS variables \u2014 overridden by each named theme's :root block */
646
+ :root {
647
+ --mf-bg: #ffffff;
648
+ --mf-text: #0f172a;
649
+ --mf-text-muted: #64748b;
650
+ --mf-primary: #33CDCF;
651
+ --mf-primary-dark: #009DA0;
652
+ --mf-primary-light: #ECFDFD;
653
+ --mf-border: #e2e8f0;
654
+ --mf-card-bg: #f8fafc;
655
+ --mf-code-bg: #0f172a;
656
+ --mf-code-text: #f8fafc;
657
+ --mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
658
+ --mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
659
+ }
660
+
661
+ /* Document header */
662
+ .document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
663
+ .document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
664
+ .document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
665
+ .document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
666
+
667
+ /* 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; }
669
+ .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
+ .table-of-contents ul { list-style: none; padding: 0; margin: 0; }
671
+ .table-of-contents li { padding: 0.25rem 0; }
672
+ .table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
673
+ .table-of-contents a:hover { text-decoration: underline; }
674
+
675
+ /* Links */
676
+ a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
677
+ a:hover { text-decoration: underline; }
678
+
679
+ /* Blockquote */
680
+ blockquote { border-left: 4px solid var(--mf-primary); background-color: var(--mf-card-bg); margin: 1.2rem 0; padding: 0.8rem 1.2rem; border-radius: 0 8px 8px 0; color: #334155; font-style: italic; }
681
+
682
+ /* Callout / Alert Boxes */
683
+ .callout { border-left: 4px solid var(--mf-primary); background: var(--mf-card-bg); border-radius: 6px; padding: 1rem 1.2rem; margin: 1.2rem 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
684
+ .callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
685
+ .callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
686
+ .callout-NOTE .callout-title { color: #009DA0; }
687
+ .callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
688
+ .callout-TIP .callout-title { color: #10b981; }
689
+ .callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
690
+ .callout-WARNING .callout-title { color: #f59e0b; }
691
+ .callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
692
+ .callout-CAUTION .callout-title { color: #ef4444; }
693
+ .callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
694
+ .callout-IMPORTANT .callout-title { color: #8b5cf6; }
695
+
696
+ /* Inline Code */
697
+ code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
698
+
699
+ /* Code Blocks */
700
+ pre { background-color: var(--mf-code-bg); color: var(--mf-code-text); padding: 1.2rem; border-radius: 8px; overflow-x: auto; font-family: var(--mf-font-mono); font-size: 0.9rem; line-height: 1.5; margin: 1.2rem 0; }
701
+ pre code { background-color: transparent; color: inherit; padding: 0; }
702
+
703
+ /* Tables */
704
+ table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
705
+ th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
706
+ th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
707
+ tr:nth-child(even) { background-color: var(--mf-card-bg); }
708
+
709
+ /* Images */
710
+ img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
711
+
712
+ /* Dividers */
713
+ hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
714
+
715
+ /* Print / PDF */
716
+ @media print {
717
+ body { padding: 0; }
718
+ .document-container { max-width: 100%; }
719
+ pre, table, blockquote, .callout { break-inside: avoid; }
720
+ /* Remove scrollbars \u2014 PDF has no scrolling */
721
+ pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
722
+ }
723
+ `;
724
+ var THEME_CORPORATE = `
725
+ :root {
726
+ --mf-bg: #ffffff;
727
+ --mf-text: #0f172a;
728
+ --mf-text-muted: #64748b;
729
+ --mf-primary: #33CDCF;
730
+ --mf-primary-dark: #009DA0;
731
+ --mf-primary-light: #ECFDFD;
732
+ --mf-border: #e2e8f0;
733
+ --mf-card-bg: #f8fafc;
734
+ --mf-code-bg: #0f172a;
735
+ --mf-code-text: #f8fafc;
736
+ --mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
737
+ --mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
738
+ }
739
+ 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
+ .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; }
743
+ 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; }
746
+ p { margin: 0.8rem 0; }
747
+ `;
748
+ var THEMES = {
749
+ corporate: THEME_CORPORATE,
750
+ default: THEME_CORPORATE
751
+ };
752
+ function generateThemeCss(theme) {
753
+ if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
754
+ return THEME_CORPORATE;
755
+ }
756
+ if (typeof theme === "object") {
757
+ const bg = theme.backgroundColor || "#ffffff";
758
+ const text = theme.textColor || "#0f172a";
759
+ const textMuted = theme.textMuted || "#64748b";
760
+ const primary = theme.primaryColor || "#33CDCF";
761
+ const primaryDark = theme.primaryDark || primary;
762
+ const primaryLight = theme.primaryLight || "#ECFDFD";
763
+ const border = theme.borderColor || "#e2e8f0";
764
+ const cardBg = theme.cardBackground || "#f8fafc";
765
+ const codeBg = theme.codeBackground || "#0f172a";
766
+ const codeText = theme.codeText || "#f8fafc";
767
+ const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
768
+ const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
769
+ return `
770
+ :root {
771
+ --mf-bg: ${bg};
772
+ --mf-text: ${text};
773
+ --mf-text-muted: ${textMuted};
774
+ --mf-primary: ${primary};
775
+ --mf-primary-dark: ${primaryDark};
776
+ --mf-primary-light: ${primaryLight};
777
+ --mf-border: ${border};
778
+ --mf-card-bg: ${cardBg};
779
+ --mf-code-bg: ${codeBg};
780
+ --mf-code-text: ${codeText};
781
+ --mf-font-family: ${font};
782
+ --mf-font-mono: ${fontMono};
783
+ }
784
+ 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
+ .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; }
788
+ 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; }
791
+ p { margin: 0.8rem 0; }
792
+ ${theme.customCss || ""}
793
+ `;
794
+ }
795
+ if (typeof theme === "string" && THEMES[theme]) {
796
+ return THEMES[theme];
797
+ }
798
+ return THEME_CORPORATE;
799
+ }
800
+
608
801
  // src/core/syntax/syntaxHighlighter.ts
609
802
  var SYNTAX_COLORS = {
610
803
  keyword: "FF7B72",
@@ -960,182 +1153,6 @@ function highlightCodeToHtml(code, lang = "", theme = "github-dark") {
960
1153
  return htmlLines.join("\n");
961
1154
  }
962
1155
 
963
- // src/core/mermaid/mermaidRenderer.ts
964
- import { spawnSync as spawnSync2 } from "child_process";
965
- import * as fs4 from "fs";
966
- import * as os2 from "os";
967
- import * as path4 from "path";
968
- import { pathToFileURL as pathToFileURL2 } from "url";
969
-
970
- // src/core/pdf/pdfBuilder.ts
971
- import * as fs3 from "fs";
972
- import * as path3 from "path";
973
- import * as os from "os";
974
- import { pathToFileURL } from "url";
975
- import { spawnSync } from "child_process";
976
-
977
- // src/core/html/htmlBuilder.ts
978
- import * as fs2 from "fs";
979
- import * as path2 from "path";
980
-
981
- // src/core/html/htmlThemes.ts
982
- var THEME_COMPONENTS = `
983
- /* Fallback CSS variables \u2014 overridden by each named theme's :root block */
984
- :root {
985
- --mf-bg: #ffffff;
986
- --mf-text: #0f172a;
987
- --mf-text-muted: #64748b;
988
- --mf-primary: #33CDCF;
989
- --mf-primary-dark: #009DA0;
990
- --mf-primary-light: #ECFDFD;
991
- --mf-border: #e2e8f0;
992
- --mf-card-bg: #f8fafc;
993
- --mf-code-bg: #0f172a;
994
- --mf-code-text: #f8fafc;
995
- --mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
996
- --mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
997
- }
998
-
999
- /* Document header */
1000
- .document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
1001
- .document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
1002
- .document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
1003
- .document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
1004
-
1005
- /* Table of Contents */
1006
- .table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
1007
- .table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
1008
- .table-of-contents ul { list-style: none; padding: 0; margin: 0; }
1009
- .table-of-contents li { padding: 0.25rem 0; }
1010
- .table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
1011
- .table-of-contents a:hover { text-decoration: underline; }
1012
-
1013
- /* Links */
1014
- a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
1015
- a:hover { text-decoration: underline; }
1016
-
1017
- /* Blockquote */
1018
- blockquote { border-left: 4px solid var(--mf-primary); background-color: var(--mf-card-bg); margin: 1.2rem 0; padding: 0.8rem 1.2rem; border-radius: 0 8px 8px 0; color: #334155; font-style: italic; }
1019
-
1020
- /* Callout / Alert Boxes */
1021
- .callout { border-left: 4px solid var(--mf-primary); background: var(--mf-card-bg); border-radius: 6px; padding: 1rem 1.2rem; margin: 1.2rem 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
1022
- .callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
1023
- .callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
1024
- .callout-NOTE .callout-title { color: #009DA0; }
1025
- .callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
1026
- .callout-TIP .callout-title { color: #10b981; }
1027
- .callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
1028
- .callout-WARNING .callout-title { color: #f59e0b; }
1029
- .callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
1030
- .callout-CAUTION .callout-title { color: #ef4444; }
1031
- .callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
1032
- .callout-IMPORTANT .callout-title { color: #8b5cf6; }
1033
-
1034
- /* Inline Code */
1035
- code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
1036
-
1037
- /* Code Blocks */
1038
- pre { background-color: var(--mf-code-bg); color: var(--mf-code-text); padding: 1.2rem; border-radius: 8px; overflow-x: auto; font-family: var(--mf-font-mono); font-size: 0.9rem; line-height: 1.5; margin: 1.2rem 0; }
1039
- pre code { background-color: transparent; color: inherit; padding: 0; }
1040
-
1041
- /* Tables */
1042
- table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
1043
- th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
1044
- th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
1045
- tr:nth-child(even) { background-color: var(--mf-card-bg); }
1046
-
1047
- /* Images */
1048
- img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
1049
-
1050
- /* Dividers */
1051
- hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
1052
-
1053
- /* Print / PDF */
1054
- @media print {
1055
- body { padding: 0; }
1056
- .document-container { max-width: 100%; }
1057
- pre, table, blockquote, .callout { break-inside: avoid; }
1058
- /* Remove scrollbars \u2014 PDF has no scrolling */
1059
- pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
1060
- }
1061
- `;
1062
- var THEME_CORPORATE = `
1063
- :root {
1064
- --mf-bg: #ffffff;
1065
- --mf-text: #0f172a;
1066
- --mf-text-muted: #64748b;
1067
- --mf-primary: #33CDCF;
1068
- --mf-primary-dark: #009DA0;
1069
- --mf-primary-light: #ECFDFD;
1070
- --mf-border: #e2e8f0;
1071
- --mf-card-bg: #f8fafc;
1072
- --mf-code-bg: #0f172a;
1073
- --mf-code-text: #f8fafc;
1074
- --mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
1075
- --mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
1076
- }
1077
- 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; }
1078
- .document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
1079
- 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; }
1080
- h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
1081
- h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
1082
- h3 { font-size: 1.3rem; }
1083
- h4 { font-size: 1.1rem; }
1084
- p { margin: 0.8rem 0; }
1085
- `;
1086
- var THEMES = {
1087
- corporate: THEME_CORPORATE,
1088
- default: THEME_CORPORATE
1089
- };
1090
- function generateThemeCss(theme) {
1091
- if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
1092
- return THEME_CORPORATE;
1093
- }
1094
- if (typeof theme === "object") {
1095
- const bg = theme.backgroundColor || "#ffffff";
1096
- const text = theme.textColor || "#0f172a";
1097
- const textMuted = theme.textMuted || "#64748b";
1098
- const primary = theme.primaryColor || "#33CDCF";
1099
- const primaryDark = theme.primaryDark || primary;
1100
- const primaryLight = theme.primaryLight || "#ECFDFD";
1101
- const border = theme.borderColor || "#e2e8f0";
1102
- const cardBg = theme.cardBackground || "#f8fafc";
1103
- const codeBg = theme.codeBackground || "#0f172a";
1104
- const codeText = theme.codeText || "#f8fafc";
1105
- const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
1106
- const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
1107
- return `
1108
- :root {
1109
- --mf-bg: ${bg};
1110
- --mf-text: ${text};
1111
- --mf-text-muted: ${textMuted};
1112
- --mf-primary: ${primary};
1113
- --mf-primary-dark: ${primaryDark};
1114
- --mf-primary-light: ${primaryLight};
1115
- --mf-border: ${border};
1116
- --mf-card-bg: ${cardBg};
1117
- --mf-code-bg: ${codeBg};
1118
- --mf-code-text: ${codeText};
1119
- --mf-font-family: ${font};
1120
- --mf-font-mono: ${fontMono};
1121
- }
1122
- 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; }
1123
- .document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
1124
- 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; }
1125
- h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
1126
- h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
1127
- h3 { font-size: 1.3rem; }
1128
- h4 { font-size: 1.1rem; }
1129
- p { margin: 0.8rem 0; }
1130
- ${theme.customCss || ""}
1131
- `;
1132
- }
1133
- if (typeof theme === "string" && THEMES[theme]) {
1134
- return THEMES[theme];
1135
- }
1136
- return THEME_CORPORATE;
1137
- }
1138
-
1139
1156
  // src/config/resolveConfig.ts
1140
1157
  var PAPER_DIMENSIONS_TWIP = {
1141
1158
  A4: { width: 11906, height: 16838 },
@@ -1181,7 +1198,8 @@ function formatMarginCss(margin, defaultCss = "2.5cm") {
1181
1198
  return str;
1182
1199
  }
1183
1200
  function replaceDocumentTokens(template = "", meta) {
1184
- 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(/\{company\}/gi, meta.company || "");
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 || "");
1185
1203
  }
1186
1204
  function normalizeWatermark(rawWatermark) {
1187
1205
  if (!rawWatermark) {
@@ -1257,6 +1275,190 @@ function normalizeHeaderFooter(raw, meta) {
1257
1275
  dividerColor: raw.dividerColor || "#E2E8F0"
1258
1276
  };
1259
1277
  }
1278
+ function normalizeSignatures(raw, meta = {}) {
1279
+ if (!raw) return void 0;
1280
+ let rawItems = [];
1281
+ let rawConfig = {};
1282
+ if (Array.isArray(raw)) {
1283
+ rawItems = raw;
1284
+ } else if (typeof raw === "object" && Array.isArray(raw.items)) {
1285
+ rawItems = raw.items;
1286
+ rawConfig = raw;
1287
+ }
1288
+ if (rawItems.length === 0) return void 0;
1289
+ const cappedItems = rawItems.slice(0, 4);
1290
+ const items = cappedItems.map((item) => {
1291
+ const tokenCtx = meta;
1292
+ const rawName = typeof item.name === "string" ? item.name : "";
1293
+ const name = replaceDocumentTokens(rawName, tokenCtx).trim();
1294
+ const title = item.title ? replaceDocumentTokens(item.title, tokenCtx).trim() : void 0;
1295
+ const role = item.role ? replaceDocumentTokens(item.role, tokenCtx).trim() : void 0;
1296
+ let dateStr;
1297
+ if (typeof item.date === "string") {
1298
+ dateStr = replaceDocumentTokens(item.date, tokenCtx).trim();
1299
+ } else if (item.date === true) {
1300
+ dateStr = meta.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1301
+ }
1302
+ let signatureHeight = 60;
1303
+ if (typeof item.signatureHeight === "number") {
1304
+ signatureHeight = item.signatureHeight;
1305
+ } else if (typeof item.signatureHeight === "string") {
1306
+ const parsed = parseFloat(item.signatureHeight);
1307
+ if (!isNaN(parsed)) signatureHeight = parsed;
1308
+ }
1309
+ return {
1310
+ title,
1311
+ name: name || "Authorized Signatory",
1312
+ role,
1313
+ date: dateStr,
1314
+ image: item.image,
1315
+ signatureHeight
1316
+ };
1317
+ });
1318
+ const align = rawConfig.align || (items.length === 1 ? "right" : "space-between");
1319
+ const style = rawConfig.style || "line";
1320
+ const borderColor = rawConfig.borderColor || "#CBD5E1";
1321
+ const titleColor = rawConfig.titleColor || "#64748B";
1322
+ const nameColor = rawConfig.nameColor || "#0F172A";
1323
+ const roleColor = rawConfig.roleColor || "#64748B";
1324
+ const spacingBeforeRaw = rawConfig.spacingBefore ?? "2.5rem";
1325
+ const spacingBefore = formatMarginCss(spacingBeforeRaw, "2.5rem");
1326
+ const spacingBeforeTwip = parseMarginToTwip(spacingBeforeRaw, 600);
1327
+ return {
1328
+ items,
1329
+ align,
1330
+ style,
1331
+ borderColor,
1332
+ titleColor,
1333
+ nameColor,
1334
+ roleColor,
1335
+ spacingBefore,
1336
+ spacingBeforeTwip
1337
+ };
1338
+ }
1339
+ function normalizeCoverPage(rawCover, tokenCtx = {}) {
1340
+ if (!rawCover) return void 0;
1341
+ const cfg = typeof rawCover === "object" ? rawCover : {};
1342
+ if (cfg.enabled === false) return void 0;
1343
+ 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;
1349
+ let dateStr;
1350
+ if (typeof cfg.date === "string") {
1351
+ dateStr = replaceDocumentTokens(cfg.date, tokenCtx);
1352
+ } else if (cfg.date === true) {
1353
+ dateStr = tokenCtx.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1354
+ } else {
1355
+ dateStr = tokenCtx.date;
1356
+ }
1357
+ const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
1358
+ const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
1359
+ const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
1360
+ const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
1361
+ const logoWidth = cfg.logoWidth;
1362
+ const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
1363
+ const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
1364
+ const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
1365
+ return {
1366
+ enabled: true,
1367
+ preset,
1368
+ title,
1369
+ subtitle,
1370
+ author,
1371
+ company,
1372
+ version,
1373
+ date: dateStr,
1374
+ badge,
1375
+ badgeColor,
1376
+ badgeTextColor,
1377
+ logo,
1378
+ logoWidth,
1379
+ bgGradient,
1380
+ textColor,
1381
+ footerText
1382
+ };
1383
+ }
1384
+ function normalizeBackCover(rawBack, tokenCtx = {}) {
1385
+ if (!rawBack) return void 0;
1386
+ const cfg = typeof rawBack === "object" ? rawBack : {};
1387
+ if (cfg.enabled === false) return void 0;
1388
+ const preset = cfg.preset || "modern";
1389
+ const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : "Thank You";
1390
+ const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : void 0;
1391
+ const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
1392
+ const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
1393
+ const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
1394
+ const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
1395
+ const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
1396
+ let socialMap;
1397
+ if (cfg.social && typeof cfg.social === "object") {
1398
+ socialMap = {};
1399
+ for (const [k, v] of Object.entries(cfg.social)) {
1400
+ if (typeof v === "string") {
1401
+ socialMap[k] = replaceDocumentTokens(v, tokenCtx);
1402
+ }
1403
+ }
1404
+ }
1405
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
1406
+ const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : company ? `Copyright (c) ${currentYear} ${company}. All Rights Reserved.` : void 0;
1407
+ const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
1408
+ const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
1409
+ const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
1410
+ const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
1411
+ const logoWidth = cfg.logoWidth;
1412
+ const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
1413
+ const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
1414
+ return {
1415
+ enabled: true,
1416
+ preset,
1417
+ title,
1418
+ subtitle,
1419
+ company,
1420
+ address,
1421
+ email,
1422
+ phone,
1423
+ website,
1424
+ social: socialMap,
1425
+ copyright,
1426
+ badge,
1427
+ badgeColor,
1428
+ badgeTextColor,
1429
+ logo,
1430
+ logoWidth,
1431
+ bgGradient,
1432
+ textColor
1433
+ };
1434
+ }
1435
+ function normalizeNumberHeadings(raw) {
1436
+ if (raw === void 0 || raw === false) return void 0;
1437
+ if (raw === true) {
1438
+ return { enabled: true, depth: 3, skipH1: false, prefix: "" };
1439
+ }
1440
+ if (typeof raw === "object") {
1441
+ const obj = raw;
1442
+ if (obj.enabled === false) return void 0;
1443
+ return {
1444
+ enabled: true,
1445
+ depth: obj.depth ?? 3,
1446
+ skipH1: obj.skipH1 ?? false,
1447
+ prefix: obj.prefix ?? ""
1448
+ };
1449
+ }
1450
+ return void 0;
1451
+ }
1452
+ function normalizeSecurity(raw) {
1453
+ if (!raw) return void 0;
1454
+ const sec = raw;
1455
+ if (!sec.userPassword && !sec.ownerPassword && !sec.permissions) return void 0;
1456
+ return {
1457
+ userPassword: sec.userPassword,
1458
+ ownerPassword: sec.ownerPassword,
1459
+ permissions: sec.permissions
1460
+ };
1461
+ }
1260
1462
  function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
1261
1463
  const configMeta = userConfig.metadata || {};
1262
1464
  const mergedMeta = { ...configMeta, ...frontmatter };
@@ -1297,6 +1499,17 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
1297
1499
  const toc = typeof mergedMeta.toc === "boolean" ? mergedMeta.toc : typeof userConfig.toc === "boolean" ? userConfig.toc : DEFAULT_CONFIG.toc;
1298
1500
  const rawWatermark = mergedMeta.watermark !== void 0 ? mergedMeta.watermark : userConfig.watermark !== void 0 ? userConfig.watermark : DEFAULT_CONFIG.watermark;
1299
1501
  const watermark = normalizeWatermark(rawWatermark);
1502
+ const rawSignatures = mergedMeta.signatures || userConfig.signatures;
1503
+ const signatures = normalizeSignatures(rawSignatures, tokenContext);
1504
+ const rawCover = mergedMeta.coverPage !== void 0 ? mergedMeta.coverPage : userConfig.coverPage;
1505
+ const coverPage = normalizeCoverPage(rawCover, tokenContext);
1506
+ const rawBack = mergedMeta.backCover !== void 0 ? mergedMeta.backCover : userConfig.backCover;
1507
+ const backCover = normalizeBackCover(rawBack, tokenContext);
1508
+ const rawNumberHeadings = mergedMeta.numberHeadings !== void 0 ? mergedMeta.numberHeadings : userConfig.numberHeadings;
1509
+ const numberHeadings = normalizeNumberHeadings(rawNumberHeadings);
1510
+ const rawSecurity = mergedMeta.security || userConfig.security;
1511
+ const security = normalizeSecurity(rawSecurity);
1512
+ const math = mergedMeta.math !== false && userConfig.math !== false;
1300
1513
  const cssList = [];
1301
1514
  const addCss = (item) => {
1302
1515
  if (!item) return;
@@ -1324,7 +1537,13 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
1324
1537
  header,
1325
1538
  footer,
1326
1539
  toc,
1540
+ signatures,
1327
1541
  watermark,
1542
+ coverPage,
1543
+ backCover,
1544
+ numberHeadings,
1545
+ security,
1546
+ math,
1328
1547
  css: cssList,
1329
1548
  embedImages,
1330
1549
  bundleHtml,
@@ -1332,6 +1551,45 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
1332
1551
  };
1333
1552
  }
1334
1553
 
1554
+ // src/core/math/mathRenderer.ts
1555
+ import katex from "katex";
1556
+ function renderMathToHtml(latex, displayMode = false) {
1557
+ try {
1558
+ return katex.renderToString(latex.trim(), {
1559
+ displayMode,
1560
+ throwOnError: false,
1561
+ output: "htmlAndMathml",
1562
+ strict: false
1563
+ });
1564
+ } catch {
1565
+ return `<span class="katex-fallback">${latex}</span>`;
1566
+ }
1567
+ }
1568
+ var KATEX_INLINE_CSS = `
1569
+ .katex { font: normal 1.21em KaTeX_Main, Times New Roman, serif; line-height: 1.2; text-indent: 0; text-rendering: auto; border-color: currentColor; }
1570
+ .katex * { -ms-high-contrast-adjust: none !important; }
1571
+ .katex .katex-html { display: inline-block; }
1572
+ .katex .katex-mathml { clip: rect(1px, 1px, 1px, 1px); border: 0; height: 1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
1573
+ .katex-display { display: block; margin: 1em 0; text-align: center; }
1574
+ .katex-display > .katex { display: inline-block; text-align: initial; }
1575
+ .katex .base { position: relative; white-space: nowrap; width: min-content; }
1576
+ .katex .strut { display: inline-block; }
1577
+ .katex .mord { display: inline-block; }
1578
+ .katex .mbin { display: inline-block; }
1579
+ .katex .mrel { display: inline-block; }
1580
+ .katex .mopen { display: inline-block; }
1581
+ .katex .mclose { display: inline-block; }
1582
+ .katex .mpunct { display: inline-block; }
1583
+ .katex .minner { display: inline-block; }
1584
+ .katex .mop { display: inline-block; }
1585
+ .katex .frac-line { width: 100%; border-bottom-style: solid; }
1586
+ .katex .vlist-t { display: inline-table; table-layout: fixed; }
1587
+ .katex .vlist-r { display: table-row; }
1588
+ .katex .vlist { display: table-cell; vertical-align: bottom; position: relative; }
1589
+ .katex .msupsub { text-align: left; }
1590
+ .katex .sqrt > .root { margin-left: 0.27777778em; margin-right: -0.55555556em; }
1591
+ `;
1592
+
1335
1593
  // src/core/html/htmlBuilder.ts
1336
1594
  function escapeHtml(str) {
1337
1595
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
@@ -1374,6 +1632,15 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
1374
1632
  result += `<code>${escapeHtml(span.content)}</code>`;
1375
1633
  continue;
1376
1634
  }
1635
+ if (span.type === "mathInline") {
1636
+ result += renderMathToHtml(span.content, false);
1637
+ continue;
1638
+ }
1639
+ if (span.type === "footnoteRef") {
1640
+ const id = escapeHtml(span.footnoteId || span.content);
1641
+ result += `<sup><a href="#fn-${id}" id="fnref-${id}" class="markforge-fnref">[${escapeHtml(span.content)}]</a></sup>`;
1642
+ continue;
1643
+ }
1377
1644
  if (span.type === "htmlInline") {
1378
1645
  result += span.content;
1379
1646
  continue;
@@ -1382,66 +1649,9 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
1382
1649
  }
1383
1650
  return result;
1384
1651
  }
1385
- async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
1386
- const resolved = resolveDocumentConfig(doc.metadata, config);
1387
- const baseThemeCss = generateThemeCss(resolved.theme);
1388
- let customCss = "";
1389
- for (const cssPath of resolved.css) {
1390
- const fullCssPath = path2.isAbsolute(cssPath) ? cssPath : path2.resolve(baseDir, cssPath);
1391
- if (fs2.existsSync(fullCssPath)) {
1392
- customCss += `
1393
- /* Custom CSS: ${cssPath} */
1394
- ` + fs2.readFileSync(fullCssPath, "utf-8");
1395
- }
1396
- }
1397
- const inlinedCss = doc.inlinedStyles.join("\n");
1652
+ async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
1398
1653
  let bodyHtml = "";
1399
- if (resolved.title) {
1400
- bodyHtml += ` <header class="document-header">
1401
- `;
1402
- bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
1403
- `;
1404
- if (resolved.subtitle) {
1405
- bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
1406
- `;
1407
- }
1408
- if (resolved.author || resolved.date || resolved.version) {
1409
- bodyHtml += ` <div class="document-meta">
1410
- `;
1411
- if (resolved.author) {
1412
- bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
1413
- `;
1414
- }
1415
- if (resolved.version) {
1416
- bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
1417
- `;
1418
- }
1419
- if (resolved.date) {
1420
- bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
1421
- `;
1422
- }
1423
- bodyHtml += ` </div>
1424
- `;
1425
- }
1426
- bodyHtml += ` </header>
1427
- `;
1428
- }
1429
- if (resolved.toc && doc.tocEntries.length > 0) {
1430
- bodyHtml += ` <nav class="table-of-contents">
1431
- `;
1432
- bodyHtml += ` <h2>Table of Contents</h2>
1433
- <ul>
1434
- `;
1435
- for (const entry of doc.tocEntries) {
1436
- const indent = " ".repeat(entry.level);
1437
- bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
1438
- `;
1439
- }
1440
- bodyHtml += ` </ul>
1441
- </nav>
1442
- `;
1443
- }
1444
- for (const node of doc.nodes) {
1654
+ for (const node of nodes) {
1445
1655
  if (node.type === "heading") {
1446
1656
  const inner = await renderInlinesToHtml(node.inlines, baseDir);
1447
1657
  bodyHtml += ` <h${node.level} id="${node.id}">${inner}</h${node.level}>
@@ -1451,6 +1661,26 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
1451
1661
  if (node.type === "paragraph") {
1452
1662
  const inner = await renderInlinesToHtml(node.inlines, baseDir);
1453
1663
  bodyHtml += ` <p>${inner}</p>
1664
+ `;
1665
+ continue;
1666
+ }
1667
+ if (node.type === "mathBlock") {
1668
+ bodyHtml += ` <div class="math-block">${renderMathToHtml(node.text || "", true)}</div>
1669
+ `;
1670
+ continue;
1671
+ }
1672
+ if (node.type === "columns") {
1673
+ const cols = node.columnsCount || 2;
1674
+ const gap = node.columnGap || "1.5rem";
1675
+ let colChildrenHtml = "";
1676
+ for (const col of node.children || []) {
1677
+ const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir);
1678
+ colChildrenHtml += ` <div class="markforge-col">
1679
+ ${colInner} </div>
1680
+ `;
1681
+ }
1682
+ bodyHtml += ` <div class="markforge-columns" style="--cols: ${cols}; --col-gap: ${gap};">
1683
+ ${colChildrenHtml} </div>
1454
1684
  `;
1455
1685
  continue;
1456
1686
  }
@@ -1539,6 +1769,429 @@ ${escapeHtml(node.text || "")}
1539
1769
  continue;
1540
1770
  }
1541
1771
  }
1772
+ return bodyHtml;
1773
+ }
1774
+ async function renderCoverPageHtml(cover, baseDir = process.cwd()) {
1775
+ let logoHtml = "";
1776
+ if (cover.logo) {
1777
+ const resolvedLogo = await resolveImage(cover.logo, baseDir);
1778
+ const src = resolvedLogo ? resolvedLogo.dataUri : cover.logo;
1779
+ const widthStyle = cover.logoWidth ? `max-width: ${typeof cover.logoWidth === "number" ? cover.logoWidth + "px" : cover.logoWidth}; max-height: 80px; width: auto; height: auto;` : "max-height: 60px; max-width: 180px; width: auto; height: auto;";
1780
+ logoHtml = `<div class="cover-logo"><img src="${src}" alt="Logo" style="${widthStyle} object-fit: contain;" /></div>`;
1781
+ }
1782
+ const badgeHtml = cover.badge ? `<div class="cover-badge" style="${cover.badgeColor ? `background-color: ${cover.badgeColor};` : ""}${cover.badgeTextColor ? `color: ${cover.badgeTextColor};` : ""}">${escapeHtml(cover.badge)}</div>` : "";
1783
+ const titleHtml = `<h1 class="cover-title">${escapeHtml(cover.title)}</h1>`;
1784
+ const subtitleHtml = cover.subtitle ? `<div class="cover-subtitle">${escapeHtml(cover.subtitle)}</div>` : "";
1785
+ const metaItems = [];
1786
+ if (cover.company) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Organization:</span> <span class="cover-meta-value">${escapeHtml(cover.company)}</span></div>`);
1787
+ if (cover.author) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Author:</span> <span class="cover-meta-value">${escapeHtml(cover.author)}</span></div>`);
1788
+ if (cover.version) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Version:</span> <span class="cover-meta-value">${escapeHtml(cover.version)}</span></div>`);
1789
+ if (cover.date) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Date:</span> <span class="cover-meta-value">${escapeHtml(cover.date)}</span></div>`);
1790
+ const metaHtml = metaItems.length > 0 ? `<div class="cover-meta">${metaItems.join("\n")}</div>` : "";
1791
+ const footerHtml = cover.footerText ? `<div class="cover-footer-text">${escapeHtml(cover.footerText)}</div>` : "";
1792
+ const css = `
1793
+ .markforge-cover {
1794
+ min-height: 100vh;
1795
+ box-sizing: border-box;
1796
+ display: flex;
1797
+ flex-direction: column;
1798
+ justify-content: space-between;
1799
+ padding: 4rem 3.5rem;
1800
+ page-break-after: always;
1801
+ break-after: page;
1802
+ position: relative;
1803
+ z-index: 2;
1804
+ background: ${cover.bgGradient || "#FFFFFF"};
1805
+ -webkit-print-color-adjust: exact;
1806
+ print-color-adjust: exact;
1807
+ color: ${cover.textColor || "#0F172A"};
1808
+ }
1809
+ .markforge-cover.cover-modern {
1810
+ border-top: 8px solid #0D998D;
1811
+ }
1812
+ .markforge-cover.cover-corporate-split {
1813
+ border-left: 12px solid #0D998D;
1814
+ }
1815
+ .markforge-cover.cover-card {
1816
+ background: #F8FAFC;
1817
+ }
1818
+ .cover-top {
1819
+ display: flex;
1820
+ justify-content: space-between;
1821
+ align-items: flex-start;
1822
+ width: 100%;
1823
+ }
1824
+ .cover-badge {
1825
+ display: inline-block;
1826
+ padding: 0.35rem 0.85rem;
1827
+ font-size: 0.78rem;
1828
+ font-weight: 700;
1829
+ letter-spacing: 0.08em;
1830
+ text-transform: uppercase;
1831
+ background-color: #ECFDFD;
1832
+ color: #0D998D;
1833
+ border-radius: 4px;
1834
+ border: 1px solid #33CDCF;
1835
+ }
1836
+ .cover-body {
1837
+ margin: auto 0;
1838
+ }
1839
+ .cover-title {
1840
+ font-size: 2.8rem;
1841
+ font-weight: 800;
1842
+ line-height: 1.15;
1843
+ margin: 0 0 1rem 0;
1844
+ color: inherit;
1845
+ }
1846
+ .cover-subtitle {
1847
+ font-size: 1.35rem;
1848
+ font-weight: 400;
1849
+ color: #64748B;
1850
+ margin: 0 0 2rem 0;
1851
+ line-height: 1.4;
1852
+ }
1853
+ .cover-meta {
1854
+ display: flex;
1855
+ flex-direction: column;
1856
+ gap: 0.5rem;
1857
+ border-top: 1.5px solid #E2E8F0;
1858
+ padding-top: 1.5rem;
1859
+ max-width: 480px;
1860
+ }
1861
+ .cover-meta-item {
1862
+ font-size: 0.92rem;
1863
+ display: flex;
1864
+ gap: 0.75rem;
1865
+ }
1866
+ .cover-meta-label {
1867
+ font-weight: 600;
1868
+ color: #64748B;
1869
+ min-width: 110px;
1870
+ }
1871
+ .cover-meta-value {
1872
+ font-weight: 500;
1873
+ color: #0F172A;
1874
+ }
1875
+ .cover-bottom {
1876
+ display: flex;
1877
+ justify-content: space-between;
1878
+ align-items: flex-end;
1879
+ font-size: 0.82rem;
1880
+ color: #94A3B8;
1881
+ }
1882
+ @media print {
1883
+ .markforge-cover {
1884
+ page-break-after: always;
1885
+ break-after: page;
1886
+ height: 100vh;
1887
+ min-height: 100vh;
1888
+ max-height: 100vh;
1889
+ box-sizing: border-box;
1890
+ overflow: hidden;
1891
+ margin: 0;
1892
+ -webkit-print-color-adjust: exact;
1893
+ print-color-adjust: exact;
1894
+ }
1895
+ }
1896
+ `;
1897
+ const html = ` <section class="markforge-cover cover-${cover.preset}">
1898
+ <div class="cover-top">
1899
+ ${logoHtml}
1900
+ ${badgeHtml}
1901
+ </div>
1902
+ <div class="cover-body">
1903
+ ${titleHtml}
1904
+ ${subtitleHtml}
1905
+ ${metaHtml}
1906
+ </div>
1907
+ <div class="cover-bottom">
1908
+ ${footerHtml}
1909
+ </div>
1910
+ </section>
1911
+ `;
1912
+ return { html, css };
1913
+ }
1914
+ async function renderBackCoverHtml(backCover, baseDir = process.cwd()) {
1915
+ let logoHtml = "";
1916
+ if (backCover.logo) {
1917
+ const resolved = await resolveImage(backCover.logo, baseDir);
1918
+ const src = resolved ? resolved.dataUri : backCover.logo;
1919
+ const widthStyle = backCover.logoWidth ? `style="width: ${typeof backCover.logoWidth === "number" ? `${backCover.logoWidth}px` : backCover.logoWidth}; max-width: 100%;"` : `style="max-width: 160px; height: auto;"`;
1920
+ logoHtml = `<div class="back-logo"><img src="${src}" alt="Brand Logo" ${widthStyle} /></div>`;
1921
+ }
1922
+ const badgeHtml = backCover.badge ? `<div class="back-badge" style="${backCover.badgeColor ? `background-color: ${backCover.badgeColor};` : ""}${backCover.badgeTextColor ? `color: ${backCover.badgeTextColor};` : ""}">${escapeHtml(backCover.badge)}</div>` : "";
1923
+ const titleHtml = `<h1 class="back-title">${escapeHtml(backCover.title)}</h1>`;
1924
+ const subtitleHtml = backCover.subtitle ? `<div class="back-subtitle">${escapeHtml(backCover.subtitle)}</div>` : "";
1925
+ const contactItems = [];
1926
+ if (backCover.company) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Organization:</span> <span class="back-contact-value">${escapeHtml(backCover.company)}</span></div>`);
1927
+ if (backCover.address) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Address:</span> <span class="back-contact-value">${escapeHtml(backCover.address)}</span></div>`);
1928
+ if (backCover.email) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Email:</span> <a href="mailto:${escapeHtml(backCover.email)}" class="back-contact-link">${escapeHtml(backCover.email)}</a></div>`);
1929
+ if (backCover.phone) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Phone:</span> <span class="back-contact-value">${escapeHtml(backCover.phone)}</span></div>`);
1930
+ if (backCover.website) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Website:</span> <a href="${escapeHtml(backCover.website)}" target="_blank" class="back-contact-link">${escapeHtml(backCover.website)}</a></div>`);
1931
+ if (backCover.social) {
1932
+ for (const [network, url] of Object.entries(backCover.social)) {
1933
+ if (url) {
1934
+ contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">${escapeHtml(network.toUpperCase())}:</span> <a href="${escapeHtml(url)}" target="_blank" class="back-contact-link">${escapeHtml(url)}</a></div>`);
1935
+ }
1936
+ }
1937
+ }
1938
+ const contactHtml = contactItems.length > 0 ? `<div class="back-contact-grid">${contactItems.join("\n")}</div>` : "";
1939
+ const copyrightHtml = backCover.copyright ? `<div class="back-copyright">${escapeHtml(backCover.copyright)}</div>` : "";
1940
+ const isDark = backCover.preset === "corporate";
1941
+ const css = `
1942
+ .markforge-back-cover {
1943
+ min-height: 100vh;
1944
+ box-sizing: border-box;
1945
+ display: flex;
1946
+ flex-direction: column;
1947
+ justify-content: space-between;
1948
+ padding: 4rem 3.5rem;
1949
+ page-break-before: always;
1950
+ break-before: page;
1951
+ position: relative;
1952
+ z-index: 2;
1953
+ background: ${backCover.bgGradient || (isDark ? "#0F172A" : "#FFFFFF")};
1954
+ color: ${backCover.textColor || (isDark ? "#F8FAFC" : "#0F172A")};
1955
+ }
1956
+ .markforge-back-cover.back-modern {
1957
+ border-bottom: 8px solid #0D998D;
1958
+ }
1959
+ .markforge-back-cover.back-corporate {
1960
+ border-left: 12px solid #33CDCF;
1961
+ }
1962
+ .markforge-back-cover.back-card {
1963
+ background: #F8FAFC;
1964
+ }
1965
+ .back-top {
1966
+ display: flex;
1967
+ justify-content: space-between;
1968
+ align-items: flex-start;
1969
+ width: 100%;
1970
+ }
1971
+ .back-badge {
1972
+ display: inline-block;
1973
+ padding: 0.35rem 0.85rem;
1974
+ font-size: 0.78rem;
1975
+ font-weight: 700;
1976
+ letter-spacing: 0.08em;
1977
+ text-transform: uppercase;
1978
+ background-color: #ECFDFD;
1979
+ color: #0D998D;
1980
+ border-radius: 4px;
1981
+ border: 1px solid #33CDCF;
1982
+ }
1983
+ .back-body {
1984
+ margin: auto 0;
1985
+ }
1986
+ .back-title {
1987
+ font-size: 2.6rem;
1988
+ font-weight: 800;
1989
+ line-height: 1.15;
1990
+ margin: 0 0 0.75rem 0;
1991
+ color: inherit;
1992
+ }
1993
+ .back-subtitle {
1994
+ font-size: 1.25rem;
1995
+ font-weight: 400;
1996
+ color: ${isDark ? "#94A3B8" : "#64748B"};
1997
+ margin: 0 0 2rem 0;
1998
+ line-height: 1.4;
1999
+ }
2000
+ .back-contact-grid {
2001
+ display: flex;
2002
+ flex-direction: column;
2003
+ gap: 0.6rem;
2004
+ border-top: 1.5px solid ${isDark ? "#334155" : "#E2E8F0"};
2005
+ padding-top: 1.5rem;
2006
+ max-width: 540px;
2007
+ }
2008
+ .back-contact-item {
2009
+ font-size: 0.92rem;
2010
+ display: flex;
2011
+ gap: 0.75rem;
2012
+ }
2013
+ .back-contact-label {
2014
+ font-weight: 600;
2015
+ color: ${isDark ? "#94A3B8" : "#64748B"};
2016
+ min-width: 110px;
2017
+ }
2018
+ .back-contact-link {
2019
+ color: #0D998D;
2020
+ text-decoration: none;
2021
+ font-weight: 600;
2022
+ }
2023
+ .back-contact-link:hover {
2024
+ text-decoration: underline;
2025
+ }
2026
+ .back-copyright {
2027
+ font-size: 0.82rem;
2028
+ color: ${isDark ? "#64748B" : "#94A3B8"};
2029
+ border-top: 1px solid ${isDark ? "#1E293B" : "#F1F5F9"};
2030
+ padding-top: 1rem;
2031
+ margin-top: 2rem;
2032
+ }
2033
+ @media print {
2034
+ .markforge-back-cover {
2035
+ page: back-cover-page;
2036
+ page-break-before: always;
2037
+ break-before: page;
2038
+ page-break-after: avoid;
2039
+ break-after: avoid;
2040
+ min-height: 100vh;
2041
+ height: 100vh;
2042
+ max-height: 100vh;
2043
+ margin: 0;
2044
+ box-sizing: border-box;
2045
+ overflow: hidden;
2046
+ -webkit-print-color-adjust: exact;
2047
+ print-color-adjust: exact;
2048
+ }
2049
+ }
2050
+ `;
2051
+ const html = ` <section class="markforge-back-cover back-${backCover.preset}">
2052
+ <div class="back-top">
2053
+ ${logoHtml}
2054
+ ${badgeHtml}
2055
+ </div>
2056
+ <div class="back-body">
2057
+ ${titleHtml}
2058
+ ${subtitleHtml}
2059
+ ${contactHtml}
2060
+ </div>
2061
+ ${copyrightHtml}
2062
+ </section>
2063
+ `;
2064
+ return { html, css };
2065
+ }
2066
+ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
2067
+ var _a;
2068
+ const resolved = resolveDocumentConfig(doc.metadata, config);
2069
+ const baseThemeCss = generateThemeCss(resolved.theme);
2070
+ let customCss = "";
2071
+ for (const cssPath of resolved.css) {
2072
+ const fullCssPath = path2.isAbsolute(cssPath) ? cssPath : path2.resolve(baseDir, cssPath);
2073
+ if (fs2.existsSync(fullCssPath)) {
2074
+ customCss += `
2075
+ /* Custom CSS: ${cssPath} */
2076
+ ` + fs2.readFileSync(fullCssPath, "utf-8");
2077
+ }
2078
+ }
2079
+ const inlinedCss = doc.inlinedStyles.join("\n");
2080
+ const extraCss = `
2081
+ .markforge-columns {
2082
+ display: grid;
2083
+ grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
2084
+ gap: var(--col-gap, 1.5rem);
2085
+ margin: 1.5rem 0;
2086
+ }
2087
+ .markforge-col {
2088
+ min-width: 0;
2089
+ }
2090
+ .markforge-fnref {
2091
+ text-decoration: none;
2092
+ font-size: 0.8em;
2093
+ vertical-align: super;
2094
+ color: #0D998D;
2095
+ font-weight: 700;
2096
+ }
2097
+ .markforge-footnotes {
2098
+ margin-top: 3rem;
2099
+ padding-top: 1rem;
2100
+ font-size: 0.88rem;
2101
+ color: #64748B;
2102
+ }
2103
+ .markforge-footnotes hr {
2104
+ border: 0;
2105
+ border-top: 1px solid #E2E8F0;
2106
+ margin-bottom: 1rem;
2107
+ }
2108
+ .markforge-fn-return {
2109
+ text-decoration: none;
2110
+ color: #0D998D;
2111
+ }
2112
+ .math-block {
2113
+ margin: 1.5rem 0;
2114
+ text-align: center;
2115
+ overflow-x: auto;
2116
+ }
2117
+ `;
2118
+ let coverHtml = "";
2119
+ let coverCss = "";
2120
+ if (resolved.coverPage && resolved.coverPage.enabled) {
2121
+ const coverRes = await renderCoverPageHtml(resolved.coverPage, baseDir);
2122
+ coverHtml = coverRes.html;
2123
+ coverCss = coverRes.css;
2124
+ }
2125
+ let backHtml = "";
2126
+ let backCss = "";
2127
+ if (resolved.backCover && resolved.backCover.enabled) {
2128
+ const backRes = await renderBackCoverHtml(resolved.backCover, baseDir);
2129
+ backHtml = backRes.html;
2130
+ backCss = backRes.css;
2131
+ }
2132
+ let bodyHtml = "";
2133
+ if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
2134
+ bodyHtml += ` <header class="document-header">
2135
+ `;
2136
+ bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
2137
+ `;
2138
+ if (resolved.subtitle) {
2139
+ bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
2140
+ `;
2141
+ }
2142
+ if (resolved.author || resolved.date || resolved.version) {
2143
+ bodyHtml += ` <div class="document-meta">
2144
+ `;
2145
+ if (resolved.author) {
2146
+ bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
2147
+ `;
2148
+ }
2149
+ if (resolved.version) {
2150
+ bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
2151
+ `;
2152
+ }
2153
+ if (resolved.date) {
2154
+ bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
2155
+ `;
2156
+ }
2157
+ bodyHtml += ` </div>
2158
+ `;
2159
+ }
2160
+ bodyHtml += ` </header>
2161
+ `;
2162
+ }
2163
+ if (resolved.toc && doc.tocEntries.length > 0) {
2164
+ bodyHtml += ` <nav class="table-of-contents">
2165
+ `;
2166
+ bodyHtml += ` <h2>Table of Contents</h2>
2167
+ <ul>
2168
+ `;
2169
+ for (const entry of doc.tocEntries) {
2170
+ const indent = " ".repeat(entry.level);
2171
+ bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
2172
+ `;
2173
+ }
2174
+ bodyHtml += ` </ul>
2175
+ </nav>
2176
+ `;
2177
+ }
2178
+ bodyHtml += await renderNodesToHtml(doc.nodes, resolved, baseDir);
2179
+ let footnotesHtml = "";
2180
+ if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
2181
+ let fnListHtml = "";
2182
+ for (const def of doc.footnoteDefs) {
2183
+ const defInner = await renderInlinesToHtml(def.inlines, baseDir);
2184
+ fnListHtml += ` <li id="fn-${escapeHtml(def.id)}">${defInner} <a href="#fnref-${escapeHtml(def.id)}" class="markforge-fn-return">&#8617;</a></li>
2185
+ `;
2186
+ }
2187
+ footnotesHtml = `
2188
+ <footer class="markforge-footnotes">
2189
+ <hr />
2190
+ <ol>
2191
+ ${fnListHtml} </ol>
2192
+ </footer>
2193
+ `;
2194
+ }
1542
2195
  let watermarkCss = "";
1543
2196
  let watermarkHtml = "";
1544
2197
  if (resolved.watermark) {
@@ -1546,26 +2199,164 @@ ${escapeHtml(node.text || "")}
1546
2199
  watermarkCss = `
1547
2200
  .document-watermark {
1548
2201
  position: fixed;
1549
- top: 50%;
1550
- left: 50%;
1551
- transform: translate(-50%, -50%) rotate(${wm.rotate}deg);
1552
- font-size: ${wm.fontSize}pt;
1553
- font-weight: 900;
1554
- color: ${wm.color};
1555
- opacity: ${wm.opacity};
2202
+ top: 0;
2203
+ left: 0;
2204
+ right: 0;
2205
+ bottom: 0;
2206
+ width: 100%;
2207
+ height: 100%;
1556
2208
  pointer-events: none;
1557
2209
  z-index: 0;
1558
2210
  user-select: none;
1559
- text-transform: uppercase;
1560
- letter-spacing: 0.15em;
1561
- white-space: nowrap;
2211
+ -webkit-user-select: none;
2212
+ -webkit-print-color-adjust: exact;
2213
+ print-color-adjust: exact;
1562
2214
  }
1563
2215
  .document-container {
1564
2216
  position: relative;
1565
2217
  z-index: 1;
1566
2218
  }
2219
+ @media print {
2220
+ .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;
2232
+ }
2233
+ }
2234
+ `;
2235
+ watermarkHtml = ` <div id="markforge-watermark" class="document-watermark" aria-hidden="true"></div>
2236
+ <script>
2237
+ (function() {
2238
+ try {
2239
+ var canvas = document.createElement('canvas');
2240
+ var dpr = 2;
2241
+ var width = 1200;
2242
+ var height = 1600;
2243
+ canvas.width = width * dpr;
2244
+ canvas.height = height * dpr;
2245
+ var ctx = canvas.getContext('2d');
2246
+ if (ctx) {
2247
+ ctx.scale(dpr, dpr);
2248
+ ctx.translate(width / 2, height / 2);
2249
+ ctx.rotate((-Math.abs(${wm.rotate || 45}) * Math.PI) / 180);
2250
+ ctx.textAlign = 'center';
2251
+ ctx.textBaseline = 'middle';
2252
+ ctx.font = '900 ${wm.fontSize * 1.5}px system-ui, -apple-system, sans-serif';
2253
+ ctx.fillStyle = '${wm.color}';
2254
+ ctx.globalAlpha = ${wm.opacity};
2255
+ try { ctx.letterSpacing = '0.15em'; } catch(e) {}
2256
+ ctx.fillText(${JSON.stringify(wm.text.toUpperCase())}, 0, 0);
2257
+ var dataUrl = canvas.toDataURL('image/png');
2258
+ var wmEl = document.getElementById('markforge-watermark');
2259
+ if (wmEl) {
2260
+ wmEl.style.backgroundImage = 'url("' + dataUrl + '")';
2261
+ wmEl.style.backgroundRepeat = 'no-repeat';
2262
+ wmEl.style.backgroundPosition = 'center center';
2263
+ wmEl.style.backgroundSize = 'contain';
2264
+ }
2265
+ }
2266
+ } catch(err) {}
2267
+ })();
2268
+ </script>
2269
+ `;
2270
+ }
2271
+ let signaturesHtml = "";
2272
+ let signaturesCss = "";
2273
+ if (resolved.signatures && resolved.signatures.items.length > 0) {
2274
+ const sig = resolved.signatures;
2275
+ const numItems = sig.items.length;
2276
+ signaturesCss = `
2277
+ .markforge-signatures {
2278
+ margin-top: ${sig.spacingBefore};
2279
+ display: grid;
2280
+ grid-template-columns: ${numItems === 1 ? sig.align === "left" ? "minmax(200px, 280px) 1fr" : sig.align === "center" ? "1fr minmax(200px, 280px) 1fr" : "1fr minmax(200px, 280px)" : `repeat(${numItems}, minmax(0, 1fr))`};
2281
+ gap: 2rem;
2282
+ page-break-inside: avoid;
2283
+ break-inside: avoid;
2284
+ }
2285
+ .markforge-signature-card {
2286
+ ${numItems === 1 && sig.align === "center" ? "grid-column: 2;" : ""}
2287
+ ${numItems === 1 && sig.align === "right" ? "grid-column: 2;" : ""}
2288
+ display: flex;
2289
+ flex-direction: column;
2290
+ ${sig.style === "box" ? `border: 1px solid ${sig.borderColor}; border-radius: 6px; padding: 14px 18px; background-color: var(--mf-card-bg, #F8FAFC);` : ""}
2291
+ }
2292
+ .markforge-sig-title {
2293
+ font-size: 0.85rem;
2294
+ color: ${sig.titleColor};
2295
+ font-weight: 600;
2296
+ margin-bottom: 6px;
2297
+ }
2298
+ .markforge-sig-space {
2299
+ height: var(--sig-height, 60px);
2300
+ display: flex;
2301
+ align-items: center;
2302
+ justify-content: center;
2303
+ margin-bottom: 6px;
2304
+ }
2305
+ .markforge-sig-space img {
2306
+ max-height: 100%;
2307
+ max-width: 100%;
2308
+ object-fit: contain;
2309
+ }
2310
+ .markforge-sig-line {
2311
+ ${sig.style === "line" ? `border-bottom: 1.5px solid ${sig.borderColor}; margin-bottom: 8px;` : ""}
2312
+ }
2313
+ .markforge-sig-name {
2314
+ font-size: 0.95rem;
2315
+ font-weight: 700;
2316
+ color: ${sig.nameColor};
2317
+ }
2318
+ .markforge-sig-role {
2319
+ font-size: 0.82rem;
2320
+ color: ${sig.roleColor};
2321
+ margin-top: 2px;
2322
+ }
2323
+ .markforge-sig-date {
2324
+ font-size: 0.78rem;
2325
+ color: ${sig.roleColor};
2326
+ margin-top: 2px;
2327
+ }
2328
+ @media print {
2329
+ .markforge-signatures {
2330
+ page-break-inside: avoid;
2331
+ break-inside: avoid;
2332
+ }
2333
+ }
1567
2334
  `;
1568
- watermarkHtml = ` <div class="document-watermark">${escapeHtml(wm.text)}</div>
2335
+ const itemCards = sig.items.map((item) => {
2336
+ const titleHtml = item.title ? `<div class="markforge-sig-title">${escapeHtml(item.title)}</div>` : "";
2337
+ let signSpaceHtml = "";
2338
+ if (item.image) {
2339
+ signSpaceHtml = `<div class="markforge-sig-space" style="--sig-height: ${item.signatureHeight}px;"><img src="${escapeHtml(item.image)}" alt="Signature" /></div>`;
2340
+ } else {
2341
+ signSpaceHtml = `<div class="markforge-sig-space" style="--sig-height: ${item.signatureHeight}px;"></div>`;
2342
+ }
2343
+ const lineHtml = sig.style === "line" ? `<div class="markforge-sig-line"></div>` : "";
2344
+ const nameHtml = `<div class="markforge-sig-name">${escapeHtml(item.name)}</div>`;
2345
+ const roleHtml = item.role ? `<div class="markforge-sig-role">${escapeHtml(item.role)}</div>` : "";
2346
+ const dateHtml = item.date ? `<div class="markforge-sig-date">Date: ${escapeHtml(item.date)}</div>` : "";
2347
+ return ` <div class="markforge-signature-card">
2348
+ ${titleHtml}
2349
+ ${signSpaceHtml}
2350
+ ${lineHtml}
2351
+ ${nameHtml}
2352
+ ${roleHtml}
2353
+ ${dateHtml}
2354
+ </div>`;
2355
+ }).join("\n");
2356
+ signaturesHtml = `
2357
+ <div class="markforge-signatures">
2358
+ ${itemCards}
2359
+ </div>
1569
2360
  `;
1570
2361
  }
1571
2362
  const hasMermaid = doc.nodes.some((n) => n.type === "mermaid");
@@ -1593,20 +2384,113 @@ ${escapeHtml(node.text || "")}
1593
2384
  <style>
1594
2385
  ${THEME_COMPONENTS}
1595
2386
  ${baseThemeCss}
2387
+ ${KATEX_INLINE_CSS}
2388
+ ${extraCss}
2389
+ ${coverCss}
2390
+ ${backCss}
1596
2391
  ${customCss}
1597
2392
  ${inlinedCss}
1598
2393
  ${watermarkCss}
2394
+ ${signaturesCss}
1599
2395
  </style>
1600
2396
  </head>
1601
2397
  <body>
1602
- ${watermarkHtml} <div class="document-container">
1603
- ${bodyHtml} </div>
2398
+ ${watermarkHtml}${coverHtml} <div class="document-container">
2399
+ ${bodyHtml}${footnotesHtml}${signaturesHtml} </div>
1604
2400
  ${mermaidScript}
1605
- </body>
2401
+ ${backHtml}</body>
1606
2402
  </html>`;
1607
2403
  }
1608
2404
 
1609
2405
  // src/core/pdf/pdfBuilder.ts
2406
+ import * as fs3 from "fs";
2407
+ import * as path3 from "path";
2408
+ import * as os from "os";
2409
+ import { pathToFileURL } from "url";
2410
+ import { spawnSync } from "child_process";
2411
+ import { PDFDocument } from "pdf-lib";
2412
+ import { encryptPDF } from "@pdfsmaller/pdf-encrypt";
2413
+ function escapeXml(str) {
2414
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
2415
+ }
2416
+ 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`);
2419
+ try {
2420
+ const text = escapeXml(wm.text.toUpperCase());
2421
+ const fontSize = (wm.fontSize || 52) * 1.5;
2422
+ const color = wm.color || "#E11D48";
2423
+ const opacity = wm.opacity !== void 0 ? wm.opacity : 0.12;
2424
+ const rotate = wm.rotate !== void 0 ? wm.rotate : -45;
2425
+ const html = `<!DOCTYPE html>
2426
+ <html>
2427
+ <head>
2428
+ <meta charset="utf-8">
2429
+ <style>
2430
+ html, body {
2431
+ margin: 0;
2432
+ padding: 0;
2433
+ width: 1200px;
2434
+ height: 1600px;
2435
+ background: transparent;
2436
+ overflow: hidden;
2437
+ }
2438
+ .wm-box {
2439
+ width: 1200px;
2440
+ height: 1600px;
2441
+ display: flex;
2442
+ align-items: center;
2443
+ justify-content: center;
2444
+ transform: rotate(${rotate}deg);
2445
+ }
2446
+ .wm-text {
2447
+ font-family: system-ui, -apple-system, sans-serif;
2448
+ font-weight: 900;
2449
+ font-size: ${fontSize}px;
2450
+ color: ${color};
2451
+ opacity: ${opacity};
2452
+ letter-spacing: 0.15em;
2453
+ text-transform: uppercase;
2454
+ white-space: nowrap;
2455
+ }
2456
+ </style>
2457
+ </head>
2458
+ <body>
2459
+ <div class="wm-box"><span class="wm-text">${text}</span></div>
2460
+ </body>
2461
+ </html>`;
2462
+ fs3.writeFileSync(tmpHtml, html, "utf8");
2463
+ const fileUrl = pathToFileURL(tmpHtml).href;
2464
+ const isWin = process.platform === "win32";
2465
+ spawnSync(
2466
+ chromePath,
2467
+ [
2468
+ "--headless=new",
2469
+ "--disable-gpu",
2470
+ "--disable-sync",
2471
+ "--disable-extensions",
2472
+ ...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
2473
+ `--screenshot=${tmpPng}`,
2474
+ "--window-size=1200,1600",
2475
+ "--default-background-color=00000000",
2476
+ fileUrl
2477
+ ],
2478
+ { timeout: 15e3, windowsHide: true }
2479
+ );
2480
+ if (fs3.existsSync(tmpPng) && fs3.statSync(tmpPng).size > 0) {
2481
+ return fs3.readFileSync(tmpPng);
2482
+ }
2483
+ return null;
2484
+ } catch {
2485
+ return null;
2486
+ } finally {
2487
+ try {
2488
+ if (fs3.existsSync(tmpHtml)) fs3.unlinkSync(tmpHtml);
2489
+ if (fs3.existsSync(tmpPng)) fs3.unlinkSync(tmpPng);
2490
+ } catch {
2491
+ }
2492
+ }
2493
+ }
1610
2494
  function findChromeExecutable() {
1611
2495
  if (process.env.CHROME_PATH && fs3.existsSync(process.env.CHROME_PATH)) {
1612
2496
  return process.env.CHROME_PATH;
@@ -1671,7 +2555,7 @@ function findChromeExecutable() {
1671
2555
  return null;
1672
2556
  }
1673
2557
  function injectPagedMediaStyles(html, config, metadata) {
1674
- var _a, _b, _c, _d, _e, _f;
2558
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1675
2559
  const resolved = resolveDocumentConfig(metadata || {}, config);
1676
2560
  const size = resolved.paperSize;
1677
2561
  const orientation = resolved.orientation;
@@ -1715,6 +2599,38 @@ function injectPagedMediaStyles(html, config, metadata) {
1715
2599
  ${fontStyle}
1716
2600
  }`;
1717
2601
  };
2602
+ const coverPageCss = ((_a = resolved.coverPage) == null ? void 0 : _a.enabled) ? `
2603
+ @page :first {
2604
+ margin-top: 0;
2605
+ margin-bottom: 0;
2606
+ margin-left: 0;
2607
+ margin-right: 0;
2608
+ background-image: none !important;
2609
+ @top-left { content: none; }
2610
+ @top-center { content: none; }
2611
+ @top-right { content: none; }
2612
+ @bottom-left { content: none; }
2613
+ @bottom-center { content: none; }
2614
+ @bottom-right { content: none; }
2615
+ }` : "";
2616
+ const backCoverCss = ((_b = resolved.backCover) == null ? void 0 : _b.enabled) ? `
2617
+ @page back-cover-page {
2618
+ size: ${size} ${orientation};
2619
+ margin: 0;
2620
+ background-image: none !important;
2621
+ @top-left { content: none; }
2622
+ @top-center { content: none; }
2623
+ @top-right { content: none; }
2624
+ @bottom-left { content: none; }
2625
+ @bottom-center { content: none; }
2626
+ @bottom-right { content: none; }
2627
+ }
2628
+ .markforge-back-cover {
2629
+ page: back-cover-page;
2630
+ min-height: 100vh;
2631
+ height: 100vh;
2632
+ box-sizing: border-box;
2633
+ }` : "";
1718
2634
  const pagedCss = `
1719
2635
  @page {
1720
2636
  size: ${size} ${orientation};
@@ -1722,15 +2638,18 @@ function injectPagedMediaStyles(html, config, metadata) {
1722
2638
  margin-bottom: ${bottom};
1723
2639
  margin-left: ${left};
1724
2640
  margin-right: ${right};
1725
- ${buildZoneCss("top-left", (_a = resolved.header) == null ? void 0 : _a.left)}
1726
- ${buildZoneCss("top-center", (_b = resolved.header) == null ? void 0 : _b.center)}
1727
- ${buildZoneCss("top-right", (_c = resolved.header) == null ? void 0 : _c.right)}
1728
- ${buildZoneCss("bottom-left", (_d = resolved.footer) == null ? void 0 : _d.left)}
1729
- ${buildZoneCss("bottom-center", (_e = resolved.footer) == null ? void 0 : _e.center)}
1730
- ${buildZoneCss("bottom-right", (_f = resolved.footer) == null ? void 0 : _f.right, true)}
2641
+ ${buildZoneCss("top-left", (_c = resolved.header) == null ? void 0 : _c.left)}
2642
+ ${buildZoneCss("top-center", (_d = resolved.header) == null ? void 0 : _d.center)}
2643
+ ${buildZoneCss("top-right", (_e = resolved.header) == null ? void 0 : _e.right)}
2644
+ ${buildZoneCss("bottom-left", (_f = resolved.footer) == null ? void 0 : _f.left)}
2645
+ ${buildZoneCss("bottom-center", (_g = resolved.footer) == null ? void 0 : _g.center)}
2646
+ ${buildZoneCss("bottom-right", (_h = resolved.footer) == null ? void 0 : _h.right, true)}
1731
2647
  }
2648
+ ${coverPageCss}
2649
+ ${backCoverCss}
1732
2650
  @media print {
1733
2651
  body { padding: 0; }
2652
+ .document-watermark { display: none !important; }
1734
2653
  h1, h2, h3, pre, table, blockquote, .callout {
1735
2654
  break-inside: avoid;
1736
2655
  }
@@ -1778,6 +2697,7 @@ startxref
1778
2697
  return Buffer.from(pdfBody, "utf-8");
1779
2698
  }
1780
2699
  async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
2700
+ var _a, _b, _c;
1781
2701
  const baseHtml = await buildHtmlDocument(doc, config, baseDir);
1782
2702
  const pagedHtml = injectPagedMediaStyles(baseHtml, config, doc.metadata);
1783
2703
  const chromePath = findChromeExecutable();
@@ -1787,6 +2707,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
1787
2707
  const tmpHtml = path3.join(tmpDir, `markforge_${tmpId}.html`);
1788
2708
  const tmpPdf = path3.join(tmpDir, `markforge_${tmpId}.pdf`);
1789
2709
  const tmpProfile = path3.join(tmpDir, `markforge_prof_${tmpId}`);
2710
+ const isWin = process.platform === "win32";
1790
2711
  const isolatedFlags = [
1791
2712
  `--user-data-dir=${tmpProfile}`,
1792
2713
  "--no-first-run",
@@ -1797,7 +2718,6 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
1797
2718
  "--disable-default-apps",
1798
2719
  "--disable-extensions",
1799
2720
  "--disable-domain-reliability",
1800
- "--disable-client-side-phishing-detection",
1801
2721
  "--disable-breakpad",
1802
2722
  "--disable-component-extensions-with-background-pages",
1803
2723
  "--disable-features=Translate,OptimizationHints,MediaRouter,DialMediaRouteProvider,CalculatedNewTabPage,ChromeWhatsNewUI,PrivacySandboxSettings4",
@@ -1806,12 +2726,10 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
1806
2726
  "--mute-audio",
1807
2727
  "--no-service-autorun",
1808
2728
  "--disable-gpu",
1809
- "--no-sandbox",
1810
- "--disable-setuid-sandbox",
1811
- "--allow-file-access-from-files",
1812
- "--disable-web-security",
2729
+ ...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
1813
2730
  "--force-color-profile=srgb",
1814
- "--no-pdf-header-footer"
2731
+ "--no-pdf-header-footer",
2732
+ "--window-size=1200,1600"
1815
2733
  ];
1816
2734
  try {
1817
2735
  fs3.writeFileSync(tmpHtml, pagedHtml, "utf-8");
@@ -1826,7 +2744,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
1826
2744
  `--print-to-pdf=${tmpPdf}`,
1827
2745
  fileUrl
1828
2746
  ],
1829
- { timeout: 3e4 }
2747
+ { timeout: 3e4, windowsHide: true }
1830
2748
  );
1831
2749
  if ((res.status !== 0 || !fs3.existsSync(tmpPdf)) && chromePath) {
1832
2750
  res = spawnSync(
@@ -1837,12 +2755,78 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
1837
2755
  `--print-to-pdf=${tmpPdf}`,
1838
2756
  fileUrl
1839
2757
  ],
1840
- { timeout: 3e4 }
2758
+ { timeout: 3e4, windowsHide: true }
1841
2759
  );
1842
2760
  }
1843
2761
  if (fs3.existsSync(tmpPdf) && fs3.statSync(tmpPdf).size > 0) {
1844
2762
  const pdfBuffer = fs3.readFileSync(tmpPdf);
1845
- return pdfBuffer;
2763
+ try {
2764
+ const pdfDoc = await PDFDocument.load(pdfBuffer);
2765
+ const resolved = resolveDocumentConfig(doc.metadata, config);
2766
+ if (resolved.title) pdfDoc.setTitle(resolved.title);
2767
+ if (resolved.author) pdfDoc.setAuthor(resolved.author);
2768
+ if (resolved.subtitle) pdfDoc.setSubject(resolved.subtitle);
2769
+ pdfDoc.setCreator("MarkForge Enterprise Document Generator");
2770
+ pdfDoc.setProducer("MarkForge (by Ma'sum)");
2771
+ pdfDoc.setModificationDate(/* @__PURE__ */ new Date());
2772
+ if (((_a = resolved.backCover) == null ? void 0 : _a.enabled) && pdfDoc.getPageCount() > 2) {
2773
+ pdfDoc.removePage(pdfDoc.getPageCount() - 1);
2774
+ }
2775
+ if (resolved.watermark) {
2776
+ const wmPng = generateWatermarkPngBuffer(chromePath, resolved.watermark);
2777
+ if (wmPng) {
2778
+ const embeddedPng = await pdfDoc.embedPng(wmPng);
2779
+ const pages = pdfDoc.getPages();
2780
+ 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;
2782
+ for (let i = startPageIndex; i < endPageIndex; i++) {
2783
+ const page = pages[i];
2784
+ const { width, height } = page.getSize();
2785
+ page.drawImage(embeddedPng, {
2786
+ x: 0,
2787
+ y: 0,
2788
+ width,
2789
+ height
2790
+ });
2791
+ }
2792
+ }
2793
+ }
2794
+ const savedBytes = await pdfDoc.save();
2795
+ let finalBuffer = Buffer.from(savedBytes);
2796
+ if (resolved.security) {
2797
+ const sec = resolved.security;
2798
+ const hasUserPassword = typeof sec.userPassword === "string" && sec.userPassword.length > 0;
2799
+ const hasOwnerPassword = typeof sec.ownerPassword === "string" && sec.ownerPassword.length > 0;
2800
+ if (hasUserPassword || hasOwnerPassword) {
2801
+ try {
2802
+ const userPass = sec.userPassword ?? "";
2803
+ const ownerPass = sec.ownerPassword ?? userPass;
2804
+ const perms = sec.permissions;
2805
+ const encryptedBytes = await encryptPDF(
2806
+ new Uint8Array(finalBuffer),
2807
+ userPass,
2808
+ {
2809
+ ownerPassword: ownerPass,
2810
+ algorithm: "AES-256",
2811
+ allowPrinting: (perms == null ? void 0 : perms.printing) !== "none",
2812
+ allowHighQualityPrint: (perms == null ? void 0 : perms.printing) === "highResolution",
2813
+ allowModifying: (perms == null ? void 0 : perms.modifying) ?? true,
2814
+ allowCopying: (perms == null ? void 0 : perms.copying) ?? true,
2815
+ allowAnnotating: (perms == null ? void 0 : perms.annotating) ?? true,
2816
+ allowFillingForms: (perms == null ? void 0 : perms.fillingForms) ?? true,
2817
+ allowExtraction: (perms == null ? void 0 : perms.contentAccessibility) ?? true,
2818
+ allowAssembly: (perms == null ? void 0 : perms.documentAssembly) ?? true
2819
+ }
2820
+ );
2821
+ finalBuffer = Buffer.from(encryptedBytes);
2822
+ } catch {
2823
+ }
2824
+ }
2825
+ }
2826
+ return finalBuffer;
2827
+ } catch {
2828
+ return pdfBuffer;
2829
+ }
1846
2830
  }
1847
2831
  } catch {
1848
2832
  } finally {
@@ -1857,7 +2841,37 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
1857
2841
  return createFallbackPdfBuffer(doc.metadata.title || "MarkForge Document");
1858
2842
  }
1859
2843
 
2844
+ // src/core/docx/docxBuilder.ts
2845
+ import {
2846
+ Document,
2847
+ Paragraph,
2848
+ TextRun,
2849
+ HeadingLevel,
2850
+ Table,
2851
+ TableRow,
2852
+ TableCell,
2853
+ WidthType,
2854
+ BorderStyle,
2855
+ AlignmentType,
2856
+ ImageRun,
2857
+ Header,
2858
+ Footer,
2859
+ PageNumber,
2860
+ Packer,
2861
+ PageOrientation,
2862
+ convertInchesToTwip,
2863
+ convertMillimetersToTwip,
2864
+ ShadingType,
2865
+ ExternalHyperlink,
2866
+ TabStopType
2867
+ } from "docx";
2868
+
1860
2869
  // src/core/mermaid/mermaidRenderer.ts
2870
+ import { spawnSync as spawnSync2 } from "child_process";
2871
+ import * as fs4 from "fs";
2872
+ import * as os2 from "os";
2873
+ import * as path4 from "path";
2874
+ import { pathToFileURL as pathToFileURL2 } from "url";
1861
2875
  async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
1862
2876
  const chromePath = findChromeExecutable();
1863
2877
  if (!chromePath) {
@@ -2063,13 +3077,36 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
2063
3077
  }
2064
3078
  runs.push(
2065
3079
  new TextRun({
2066
- text: span.content,
2067
- color: colorHex,
2068
- bold: isBold,
2069
- italics: isItalic,
2070
- font: options.font,
2071
- size: options.size,
2072
- shading: bgHex ? { type: ShadingType.CLEAR, fill: bgHex } : void 0
3080
+ text: span.content,
3081
+ color: colorHex,
3082
+ bold: isBold,
3083
+ italics: isItalic,
3084
+ font: options.font,
3085
+ size: options.size,
3086
+ shading: bgHex ? { type: ShadingType.CLEAR, fill: bgHex } : void 0
3087
+ })
3088
+ );
3089
+ continue;
3090
+ }
3091
+ if (span.type === "mathInline") {
3092
+ runs.push(
3093
+ new TextRun({
3094
+ text: span.content,
3095
+ font: "Cambria Math",
3096
+ italics: true,
3097
+ size: options.size,
3098
+ color: options.color || "0F172A"
3099
+ })
3100
+ );
3101
+ continue;
3102
+ }
3103
+ if (span.type === "footnoteRef") {
3104
+ runs.push(
3105
+ new TextRun({
3106
+ text: `[${span.content}]`,
3107
+ superScript: true,
3108
+ color: "009DA0",
3109
+ bold: true
2073
3110
  })
2074
3111
  );
2075
3112
  continue;
@@ -2088,7 +3125,7 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
2088
3125
  return runs;
2089
3126
  }
2090
3127
  async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2091
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3128
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2092
3129
  const resolved = resolveDocumentConfig(doc.metadata, config);
2093
3130
  const docElements = [];
2094
3131
  const themeProps = typeof resolved.theme === "object" ? resolved.theme : {};
@@ -2099,7 +3136,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2099
3136
  const borderHex = (themeProps.borderColor || "#E2E8F0").replace("#", "");
2100
3137
  const cardBgHex = (themeProps.cardBackground || "#F8FAFC").replace("#", "");
2101
3138
  const defaultFont = themeProps.fontFamily ? themeProps.fontFamily.split(",")[0].replace(/['"]/g, "").trim() : "Segoe UI";
2102
- if (resolved.title) {
3139
+ if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
2103
3140
  docElements.push(
2104
3141
  new Paragraph({
2105
3142
  children: [
@@ -2515,7 +3552,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2515
3552
  }
2516
3553
  if (node.type === "table" && node.children) {
2517
3554
  const tableRows = [];
2518
- const numCols = ((_b = (_a = node.children[0]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) || 1;
3555
+ const numCols = ((_c = (_b = node.children[0]) == null ? void 0 : _b.children) == null ? void 0 : _c.length) || 1;
2519
3556
  const colWidth = Math.floor(9e3 / numCols);
2520
3557
  for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
2521
3558
  const rowNode = node.children[rowIdx];
@@ -2525,7 +3562,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2525
3562
  if (rowNode.children) {
2526
3563
  for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {
2527
3564
  const cellNode = rowNode.children[colIdx];
2528
- const align = (_c = node.align) == null ? void 0 : _c[colIdx];
3565
+ const align = (_d = node.align) == null ? void 0 : _d[colIdx];
2529
3566
  let alignment = AlignmentType.LEFT;
2530
3567
  if (align === "center") alignment = AlignmentType.CENTER;
2531
3568
  if (align === "right") alignment = AlignmentType.RIGHT;
@@ -2664,6 +3701,166 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2664
3701
  }
2665
3702
  continue;
2666
3703
  }
3704
+ if (node.type === "mathBlock") {
3705
+ docElements.push(
3706
+ new Paragraph({
3707
+ alignment: AlignmentType.CENTER,
3708
+ children: [
3709
+ new TextRun({
3710
+ text: node.text || "",
3711
+ font: "Cambria Math",
3712
+ italics: true,
3713
+ size: 24,
3714
+ // 12pt
3715
+ color: textHex
3716
+ })
3717
+ ],
3718
+ spacing: { before: 180, after: 180 },
3719
+ shading: { fill: cardBgHex, type: ShadingType.CLEAR },
3720
+ border: {
3721
+ top: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
3722
+ bottom: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
3723
+ left: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
3724
+ right: { style: BorderStyle.SINGLE, size: 4, color: borderHex }
3725
+ }
3726
+ })
3727
+ );
3728
+ continue;
3729
+ }
3730
+ if (node.type === "columns") {
3731
+ const cols = node.columnsCount || 2;
3732
+ const contentWidth = Math.max(
3733
+ 1e3,
3734
+ resolved.paperDimensions.widthTwip - resolved.margins.leftTwip - resolved.margins.rightTwip
3735
+ );
3736
+ const cellWidthDxa = Math.floor(contentWidth / cols);
3737
+ const cells = [];
3738
+ for (const col of node.children || []) {
3739
+ const colParagraphs = [];
3740
+ for (const childNode of col.children || []) {
3741
+ if (childNode.type === "heading") {
3742
+ const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, bold: true, size: 24, color: primaryDarkHex });
3743
+ colParagraphs.push(new Paragraph({ children: runs, spacing: { before: 120, after: 60 } }));
3744
+ } else if (childNode.type === "paragraph") {
3745
+ const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
3746
+ colParagraphs.push(new Paragraph({ children: runs, spacing: { after: 100 } }));
3747
+ } else if (childNode.type === "list" && childNode.children) {
3748
+ for (const item of childNode.children) {
3749
+ const runs = await convertInlinesToTextRuns(item.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
3750
+ colParagraphs.push(new Paragraph({ children: [new TextRun({ text: "\u2022 ", font: defaultFont, color: primaryHex }), ...runs], spacing: { after: 40 } }));
3751
+ }
3752
+ }
3753
+ }
3754
+ if (colParagraphs.length === 0) colParagraphs.push(new Paragraph({}));
3755
+ cells.push(
3756
+ new TableCell({
3757
+ width: { size: cellWidthDxa, type: WidthType.DXA },
3758
+ borders: {
3759
+ top: { style: BorderStyle.NONE, size: 0, color: "auto" },
3760
+ bottom: { style: BorderStyle.NONE, size: 0, color: "auto" },
3761
+ left: { style: BorderStyle.NONE, size: 0, color: "auto" },
3762
+ right: { style: BorderStyle.NONE, size: 0, color: "auto" }
3763
+ },
3764
+ margins: { top: 60, bottom: 60, left: 100, right: 100 },
3765
+ children: colParagraphs
3766
+ })
3767
+ );
3768
+ }
3769
+ docElements.push(
3770
+ new Table({
3771
+ width: { size: 100, type: WidthType.PERCENTAGE },
3772
+ rows: [new TableRow({ children: cells })]
3773
+ })
3774
+ );
3775
+ docElements.push(new Paragraph({ spacing: { after: 120 } }));
3776
+ continue;
3777
+ }
3778
+ }
3779
+ if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
3780
+ docElements.push(
3781
+ new Paragraph({
3782
+ border: {
3783
+ top: { style: BorderStyle.SINGLE, size: 4, color: borderHex, space: 8 }
3784
+ },
3785
+ spacing: { before: 360, after: 120 }
3786
+ })
3787
+ );
3788
+ for (const def of doc.footnoteDefs) {
3789
+ const defRuns = await convertInlinesToTextRuns(def.inlines, baseDir, {
3790
+ font: defaultFont,
3791
+ size: 18,
3792
+ // 9pt
3793
+ color: textMutedHex
3794
+ });
3795
+ docElements.push(
3796
+ new Paragraph({
3797
+ children: [
3798
+ new TextRun({
3799
+ text: `[${def.id}] `,
3800
+ bold: true,
3801
+ color: primaryDarkHex,
3802
+ font: defaultFont,
3803
+ size: 18
3804
+ }),
3805
+ ...defRuns
3806
+ ],
3807
+ spacing: { after: 60 }
3808
+ })
3809
+ );
3810
+ }
3811
+ }
3812
+ if (resolved.signatures && resolved.signatures.items.length > 0) {
3813
+ const sig = resolved.signatures;
3814
+ const numItems = sig.items.length;
3815
+ const contentWidth = Math.max(
3816
+ 1e3,
3817
+ resolved.paperDimensions.widthTwip - resolved.margins.leftTwip - resolved.margins.rightTwip
3818
+ );
3819
+ docElements.push(new Paragraph({ spacing: { before: sig.spacingBeforeTwip } }));
3820
+ const sigCells = [];
3821
+ const colWidths = [];
3822
+ if (numItems === 1) {
3823
+ const cardWidth = Math.min(3400, Math.floor(contentWidth * 0.42));
3824
+ const spacerWidth = contentWidth - cardWidth;
3825
+ const cardCell = await buildDocxSignatureCell(sig.items[0], sig, cardWidth, defaultFont, baseDir);
3826
+ if (sig.align === "left") {
3827
+ colWidths.push(cardWidth, spacerWidth);
3828
+ sigCells.push(cardCell, createEmptyDocxCell(spacerWidth));
3829
+ } else if (sig.align === "center") {
3830
+ const sideWidth = Math.floor(spacerWidth / 2);
3831
+ colWidths.push(sideWidth, cardWidth, sideWidth);
3832
+ sigCells.push(createEmptyDocxCell(sideWidth), cardCell, createEmptyDocxCell(sideWidth));
3833
+ } else {
3834
+ colWidths.push(spacerWidth, cardWidth);
3835
+ sigCells.push(createEmptyDocxCell(spacerWidth), cardCell);
3836
+ }
3837
+ } else {
3838
+ const colWidth = Math.floor(contentWidth / numItems);
3839
+ for (let i = 0; i < numItems; i++) {
3840
+ colWidths.push(colWidth);
3841
+ const cell = await buildDocxSignatureCell(sig.items[i], sig, colWidth, defaultFont, baseDir);
3842
+ sigCells.push(cell);
3843
+ }
3844
+ }
3845
+ const sigTable = new Table({
3846
+ width: { size: 100, type: WidthType.PERCENTAGE },
3847
+ columnWidths: colWidths,
3848
+ borders: {
3849
+ top: { style: BorderStyle.NONE, size: 0, color: "auto" },
3850
+ bottom: { style: BorderStyle.NONE, size: 0, color: "auto" },
3851
+ left: { style: BorderStyle.NONE, size: 0, color: "auto" },
3852
+ right: { style: BorderStyle.NONE, size: 0, color: "auto" },
3853
+ insideHorizontal: { style: BorderStyle.NONE, size: 0, color: "auto" },
3854
+ insideVertical: { style: BorderStyle.NONE, size: 0, color: "auto" }
3855
+ },
3856
+ rows: [
3857
+ new TableRow({
3858
+ cantSplit: true,
3859
+ children: sigCells
3860
+ })
3861
+ ]
3862
+ });
3863
+ docElements.push(sigTable);
2667
3864
  }
2668
3865
  const contentWidthTwip = Math.max(
2669
3866
  1e3,
@@ -2672,7 +3869,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2672
3869
  const centerPos = Math.round(contentWidthTwip / 2);
2673
3870
  const rightPos = contentWidthTwip;
2674
3871
  const headerRuns = [];
2675
- if ((_d = resolved.header) == null ? void 0 : _d.left) {
3872
+ if ((_e = resolved.header) == null ? void 0 : _e.left) {
2676
3873
  headerRuns.push(
2677
3874
  new TextRun({
2678
3875
  text: resolved.header.left.text,
@@ -2685,7 +3882,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2685
3882
  );
2686
3883
  }
2687
3884
  headerRuns.push(new TextRun({ text: " " }));
2688
- if ((_e = resolved.header) == null ? void 0 : _e.center) {
3885
+ if ((_f = resolved.header) == null ? void 0 : _f.center) {
2689
3886
  headerRuns.push(
2690
3887
  new TextRun({
2691
3888
  text: resolved.header.center.text,
@@ -2698,7 +3895,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2698
3895
  );
2699
3896
  }
2700
3897
  headerRuns.push(new TextRun({ text: " " }));
2701
- if ((_f = resolved.header) == null ? void 0 : _f.right) {
3898
+ if ((_g = resolved.header) == null ? void 0 : _g.right) {
2702
3899
  headerRuns.push(
2703
3900
  new TextRun({
2704
3901
  text: resolved.header.right.text,
@@ -2710,7 +3907,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2710
3907
  })
2711
3908
  );
2712
3909
  }
2713
- const docHeader = resolved.header ? new Header2({
3910
+ const docHeader = resolved.header ? new Header({
2714
3911
  children: [
2715
3912
  new Paragraph({
2716
3913
  tabStops: [
@@ -2737,7 +3934,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2737
3934
  ]
2738
3935
  }) : void 0;
2739
3936
  const footerRuns = [];
2740
- if ((_g = resolved.footer) == null ? void 0 : _g.left) {
3937
+ if ((_h = resolved.footer) == null ? void 0 : _h.left) {
2741
3938
  footerRuns.push(
2742
3939
  new TextRun({
2743
3940
  text: resolved.footer.left.text,
@@ -2750,7 +3947,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2750
3947
  );
2751
3948
  }
2752
3949
  footerRuns.push(new TextRun({ text: " " }));
2753
- if ((_h = resolved.footer) == null ? void 0 : _h.center) {
3950
+ if ((_i = resolved.footer) == null ? void 0 : _i.center) {
2754
3951
  footerRuns.push(
2755
3952
  new TextRun({
2756
3953
  text: resolved.footer.center.text,
@@ -2763,7 +3960,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2763
3960
  );
2764
3961
  }
2765
3962
  footerRuns.push(new TextRun({ text: " " }));
2766
- if ((_i = resolved.footer) == null ? void 0 : _i.right) {
3963
+ if ((_j = resolved.footer) == null ? void 0 : _j.right) {
2767
3964
  const rZone = resolved.footer.right;
2768
3965
  const rColor = rZone.color.replace("#", "");
2769
3966
  const rSize = (rZone.fontSize || 9) * 2;
@@ -2848,6 +4045,91 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2848
4045
  ]
2849
4046
  }) : void 0;
2850
4047
  const isLandscape = resolved.orientation === "landscape";
4048
+ const docSections = [];
4049
+ if (resolved.coverPage && resolved.coverPage.enabled) {
4050
+ const coverElements = await buildDocxCoverPageElements(
4051
+ resolved.coverPage,
4052
+ defaultFont,
4053
+ textHex,
4054
+ primaryHex,
4055
+ primaryDarkHex,
4056
+ textMutedHex,
4057
+ baseDir
4058
+ );
4059
+ docSections.push({
4060
+ properties: {
4061
+ page: {
4062
+ size: {
4063
+ width: resolved.paperDimensions.widthTwip,
4064
+ height: resolved.paperDimensions.heightTwip,
4065
+ orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
4066
+ },
4067
+ margin: {
4068
+ top: resolved.margins.topTwip,
4069
+ bottom: resolved.margins.bottomTwip,
4070
+ left: resolved.margins.leftTwip,
4071
+ right: resolved.margins.rightTwip
4072
+ }
4073
+ }
4074
+ },
4075
+ headers: void 0,
4076
+ footers: void 0,
4077
+ children: coverElements
4078
+ });
4079
+ }
4080
+ docSections.push({
4081
+ properties: {
4082
+ page: {
4083
+ size: {
4084
+ width: resolved.paperDimensions.widthTwip,
4085
+ height: resolved.paperDimensions.heightTwip,
4086
+ orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
4087
+ },
4088
+ margin: {
4089
+ top: resolved.margins.topTwip,
4090
+ bottom: resolved.margins.bottomTwip,
4091
+ left: resolved.margins.leftTwip,
4092
+ right: resolved.margins.rightTwip,
4093
+ header: 720,
4094
+ footer: 720
4095
+ }
4096
+ }
4097
+ },
4098
+ headers: docHeader ? { default: docHeader } : void 0,
4099
+ footers: docFooter ? { default: docFooter } : void 0,
4100
+ children: docElements
4101
+ });
4102
+ if (resolved.backCover && resolved.backCover.enabled) {
4103
+ const backElements = await buildDocxBackCoverElements(
4104
+ resolved.backCover,
4105
+ defaultFont,
4106
+ textHex,
4107
+ primaryHex,
4108
+ primaryDarkHex,
4109
+ textMutedHex,
4110
+ baseDir
4111
+ );
4112
+ docSections.push({
4113
+ properties: {
4114
+ page: {
4115
+ size: {
4116
+ width: resolved.paperDimensions.widthTwip,
4117
+ height: resolved.paperDimensions.heightTwip,
4118
+ orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
4119
+ },
4120
+ margin: {
4121
+ top: resolved.margins.topTwip,
4122
+ bottom: resolved.margins.bottomTwip,
4123
+ left: resolved.margins.leftTwip,
4124
+ right: resolved.margins.rightTwip
4125
+ }
4126
+ }
4127
+ },
4128
+ headers: void 0,
4129
+ footers: void 0,
4130
+ children: backElements
4131
+ });
4132
+ }
2851
4133
  const document = new Document({
2852
4134
  styles: {
2853
4135
  default: {
@@ -2868,146 +4150,388 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
2868
4150
  }
2869
4151
  }
2870
4152
  },
2871
- sections: [
2872
- {
2873
- properties: {
2874
- page: {
2875
- size: {
2876
- width: resolved.paperDimensions.widthTwip,
2877
- height: resolved.paperDimensions.heightTwip,
2878
- orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
2879
- },
2880
- margin: {
2881
- top: resolved.margins.topTwip,
2882
- bottom: resolved.margins.bottomTwip,
2883
- left: resolved.margins.leftTwip,
2884
- right: resolved.margins.rightTwip,
2885
- header: 720,
2886
- footer: 720
2887
- }
2888
- }
2889
- },
2890
- headers: docHeader ? { default: docHeader } : void 0,
2891
- footers: docFooter ? { default: docFooter } : void 0,
2892
- children: docElements
2893
- }
2894
- ]
4153
+ sections: docSections
2895
4154
  });
2896
4155
  return await Packer.toBuffer(document);
2897
4156
  }
2898
-
2899
- // src/core/engine.ts
2900
- async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgress) {
2901
- const startTime = Date.now();
2902
- const config = { ...DEFAULT_CONFIG, ...userConfig };
2903
- let rawMarkdown = "";
2904
- let baseDir = process.cwd();
2905
- let inputFileName = "document.md";
2906
- let isFilePath = false;
2907
- if (fs5.existsSync(inputFilePathOrContent)) {
2908
- isFilePath = true;
2909
- rawMarkdown = fs5.readFileSync(inputFilePathOrContent, "utf-8");
2910
- baseDir = path5.dirname(path5.resolve(inputFilePathOrContent));
2911
- inputFileName = path5.basename(inputFilePathOrContent);
2912
- } else {
2913
- rawMarkdown = inputFilePathOrContent;
2914
- }
2915
- onProgress == null ? void 0 : onProgress(`Parsing markdown AST: ${inputFileName}...`);
2916
- const parsedDoc = parseMarkdownDocument(rawMarkdown);
2917
- const baseName = inputFileName.replace(/\.(md|mdx|markdown)$/i, "");
2918
- const outputDir = config.outputDir ? path5.isAbsolute(config.outputDir) ? config.outputDir : path5.resolve(process.cwd(), config.outputDir) : baseDir;
2919
- if (!fs5.existsSync(outputDir)) {
2920
- fs5.mkdirSync(outputDir, { recursive: true });
2921
- }
2922
- const formats = Array.isArray(config.to) ? config.to : [config.to || "docx", "pdf"];
2923
- const generatedFiles = [];
2924
- const errors = [];
2925
- for (const fmt of formats) {
2926
- try {
2927
- if (fmt === "docx") {
2928
- onProgress == null ? void 0 : onProgress(`Generating DOCX document: ${baseName}.docx...`);
2929
- const docxBuffer = await buildDocxDocument(parsedDoc, config, baseDir);
2930
- const docxPath = path5.join(outputDir, `${baseName}.docx`);
2931
- fs5.writeFileSync(docxPath, docxBuffer);
2932
- generatedFiles.push({
2933
- format: "docx",
2934
- filePath: docxPath,
2935
- fileName: `${baseName}.docx`,
2936
- sizeBytes: docxBuffer.length
2937
- });
2938
- } else if (fmt === "html") {
2939
- onProgress == null ? void 0 : onProgress(`Generating HTML document: ${baseName}.html...`);
2940
- const htmlString = await buildHtmlDocument(parsedDoc, config, baseDir);
2941
- const htmlPath = path5.join(outputDir, `${baseName}.html`);
2942
- fs5.writeFileSync(htmlPath, htmlString, "utf-8");
2943
- generatedFiles.push({
2944
- format: "html",
2945
- filePath: htmlPath,
2946
- fileName: `${baseName}.html`,
2947
- sizeBytes: Buffer.byteLength(htmlString, "utf-8")
2948
- });
2949
- } else if (fmt === "pdf") {
2950
- onProgress == null ? void 0 : onProgress(`Generating PDF document: ${baseName}.pdf...`);
2951
- const pdfBuffer = await buildPdfDocument(parsedDoc, config, baseDir);
2952
- const pdfPath = path5.join(outputDir, `${baseName}.pdf`);
2953
- fs5.writeFileSync(pdfPath, pdfBuffer);
2954
- generatedFiles.push({
2955
- format: "pdf",
2956
- filePath: pdfPath,
2957
- fileName: `${baseName}.pdf`,
2958
- sizeBytes: pdfBuffer.length
2959
- });
4157
+ async function buildDocxBackCoverElements(backCover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
4158
+ var _a;
4159
+ const elements = [];
4160
+ elements.push(new Paragraph({ spacing: { before: 1800 } }));
4161
+ if (backCover.logo) {
4162
+ const resolvedLogo = await resolveImage(backCover.logo, baseDir);
4163
+ if (resolvedLogo) {
4164
+ const logoW = typeof backCover.logoWidth === "number" ? backCover.logoWidth : 140;
4165
+ const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
4166
+ elements.push(
4167
+ new Paragraph({
4168
+ children: [
4169
+ new ImageRun({
4170
+ data: resolvedLogo.buffer,
4171
+ transformation: {
4172
+ width: logoW,
4173
+ height: Math.round(logoW * 0.75)
4174
+ },
4175
+ type: logoType
4176
+ })
4177
+ ],
4178
+ spacing: { after: 240 }
4179
+ })
4180
+ );
4181
+ }
4182
+ }
4183
+ if (backCover.badge) {
4184
+ elements.push(
4185
+ new Paragraph({
4186
+ children: [
4187
+ new TextRun({
4188
+ text: `[ ${backCover.badge.toUpperCase()} ]`,
4189
+ font: defaultFont,
4190
+ size: 20,
4191
+ bold: true,
4192
+ color: primaryDarkHex
4193
+ })
4194
+ ],
4195
+ spacing: { after: 240 }
4196
+ })
4197
+ );
4198
+ }
4199
+ elements.push(
4200
+ new Paragraph({
4201
+ children: [
4202
+ new TextRun({
4203
+ text: backCover.title,
4204
+ font: defaultFont,
4205
+ size: 52,
4206
+ // 26pt
4207
+ bold: true,
4208
+ color: textHex
4209
+ })
4210
+ ],
4211
+ spacing: { after: 140 }
4212
+ })
4213
+ );
4214
+ if (backCover.subtitle) {
4215
+ elements.push(
4216
+ new Paragraph({
4217
+ children: [
4218
+ new TextRun({
4219
+ text: backCover.subtitle,
4220
+ font: defaultFont,
4221
+ size: 24,
4222
+ // 12pt
4223
+ color: textMutedHex
4224
+ })
4225
+ ],
4226
+ spacing: { after: 480 }
4227
+ })
4228
+ );
4229
+ }
4230
+ elements.push(
4231
+ new Paragraph({
4232
+ border: {
4233
+ bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
4234
+ },
4235
+ spacing: { after: 480 }
4236
+ })
4237
+ );
4238
+ const contactRuns = [];
4239
+ if (backCover.company) contactRuns.push(new TextRun({ text: `Organization: ${backCover.company}
4240
+ `, font: defaultFont, size: 21, color: textHex }));
4241
+ if (backCover.address) contactRuns.push(new TextRun({ text: `Address: ${backCover.address}
4242
+ `, font: defaultFont, size: 21, color: textHex }));
4243
+ if (backCover.email) contactRuns.push(new TextRun({ text: `Email: ${backCover.email}
4244
+ `, font: defaultFont, size: 21, color: textHex }));
4245
+ if (backCover.phone) contactRuns.push(new TextRun({ text: `Phone: ${backCover.phone}
4246
+ `, font: defaultFont, size: 21, color: textHex }));
4247
+ if (backCover.website) contactRuns.push(new TextRun({ text: `Website: ${backCover.website}
4248
+ `, font: defaultFont, size: 21, color: textHex }));
4249
+ if (backCover.social) {
4250
+ for (const [net, url] of Object.entries(backCover.social)) {
4251
+ if (url) {
4252
+ contactRuns.push(new TextRun({ text: `${net.toUpperCase()}: ${url}
4253
+ `, font: defaultFont, size: 21, color: textHex }));
2960
4254
  }
2961
- } catch (err) {
2962
- const errMsg = err instanceof Error ? err.message : String(err);
2963
- errors.push(`Failed to generate ${fmt}: ${errMsg}`);
2964
4255
  }
2965
4256
  }
2966
- const durationMs = Date.now() - startTime;
2967
- return {
2968
- inputFile: isFilePath ? inputFilePathOrContent : "inline-string",
2969
- durationMs,
2970
- metadata: parsedDoc.metadata,
2971
- files: generatedFiles,
2972
- errors
2973
- };
4257
+ if (contactRuns.length > 0) {
4258
+ elements.push(
4259
+ new Paragraph({
4260
+ children: contactRuns,
4261
+ spacing: { before: 360, after: 360 }
4262
+ })
4263
+ );
4264
+ }
4265
+ if (backCover.copyright) {
4266
+ elements.push(
4267
+ new Paragraph({
4268
+ children: [
4269
+ new TextRun({
4270
+ text: backCover.copyright,
4271
+ font: defaultFont,
4272
+ size: 18,
4273
+ color: "94A3B8"
4274
+ })
4275
+ ],
4276
+ spacing: { before: 720 }
4277
+ })
4278
+ );
4279
+ }
4280
+ return elements;
4281
+ }
4282
+ async function buildDocxCoverPageElements(cover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
4283
+ var _a;
4284
+ const elements = [];
4285
+ elements.push(new Paragraph({ spacing: { before: 1800 } }));
4286
+ if (cover.logo) {
4287
+ const resolvedLogo = await resolveImage(cover.logo, baseDir);
4288
+ if (resolvedLogo) {
4289
+ const logoW = typeof cover.logoWidth === "number" ? cover.logoWidth : 140;
4290
+ const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
4291
+ elements.push(
4292
+ new Paragraph({
4293
+ children: [
4294
+ new ImageRun({
4295
+ data: resolvedLogo.buffer,
4296
+ transformation: {
4297
+ width: logoW,
4298
+ height: Math.round(logoW * 0.75)
4299
+ },
4300
+ type: logoType
4301
+ })
4302
+ ],
4303
+ spacing: { after: 240 }
4304
+ })
4305
+ );
4306
+ }
4307
+ }
4308
+ if (cover.badge) {
4309
+ elements.push(
4310
+ new Paragraph({
4311
+ children: [
4312
+ new TextRun({
4313
+ text: `[ ${cover.badge.toUpperCase()} ]`,
4314
+ font: defaultFont,
4315
+ size: 20,
4316
+ bold: true,
4317
+ color: primaryDarkHex
4318
+ })
4319
+ ],
4320
+ spacing: { after: 240 }
4321
+ })
4322
+ );
4323
+ }
4324
+ elements.push(
4325
+ new Paragraph({
4326
+ children: [
4327
+ new TextRun({
4328
+ text: cover.title,
4329
+ font: defaultFont,
4330
+ size: 56,
4331
+ // 28pt
4332
+ bold: true,
4333
+ color: textHex
4334
+ })
4335
+ ],
4336
+ spacing: { after: 140 }
4337
+ })
4338
+ );
4339
+ if (cover.subtitle) {
4340
+ elements.push(
4341
+ new Paragraph({
4342
+ children: [
4343
+ new TextRun({
4344
+ text: cover.subtitle,
4345
+ font: defaultFont,
4346
+ size: 26,
4347
+ // 13pt
4348
+ color: textMutedHex
4349
+ })
4350
+ ],
4351
+ spacing: { after: 480 }
4352
+ })
4353
+ );
4354
+ }
4355
+ elements.push(
4356
+ new Paragraph({
4357
+ border: {
4358
+ bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
4359
+ },
4360
+ spacing: { after: 480 }
4361
+ })
4362
+ );
4363
+ if (cover.company || cover.author || cover.version || cover.date) {
4364
+ const metaRuns = [];
4365
+ if (cover.company) metaRuns.push(new TextRun({ text: `Organization: ${cover.company}
4366
+ `, font: defaultFont, size: 21, color: textHex }));
4367
+ if (cover.author) metaRuns.push(new TextRun({ text: `Author: ${cover.author}
4368
+ `, font: defaultFont, size: 21, color: textHex }));
4369
+ if (cover.version) metaRuns.push(new TextRun({ text: `Version: ${cover.version}
4370
+ `, font: defaultFont, size: 21, color: textHex }));
4371
+ if (cover.date) metaRuns.push(new TextRun({ text: `Date: ${cover.date}
4372
+ `, font: defaultFont, size: 21, color: textHex }));
4373
+ elements.push(
4374
+ new Paragraph({
4375
+ children: metaRuns,
4376
+ spacing: { before: 360, after: 360 }
4377
+ })
4378
+ );
4379
+ }
4380
+ if (cover.footerText) {
4381
+ elements.push(
4382
+ new Paragraph({
4383
+ children: [
4384
+ new TextRun({
4385
+ text: cover.footerText,
4386
+ font: defaultFont,
4387
+ size: 18,
4388
+ color: "94A3B8"
4389
+ })
4390
+ ],
4391
+ spacing: { before: 720 }
4392
+ })
4393
+ );
4394
+ }
4395
+ return elements;
4396
+ }
4397
+ async function buildDocxSignatureCell(item, sig, widthDxa, defaultFont, baseDir) {
4398
+ const cellParagraphs = [];
4399
+ if (item.title) {
4400
+ cellParagraphs.push(
4401
+ new Paragraph({
4402
+ children: [
4403
+ new TextRun({
4404
+ text: item.title,
4405
+ font: defaultFont,
4406
+ size: 18,
4407
+ // 9pt
4408
+ color: sig.titleColor.replace("#", ""),
4409
+ bold: true
4410
+ })
4411
+ ],
4412
+ spacing: { after: 60 }
4413
+ })
4414
+ );
4415
+ }
4416
+ if (item.image) {
4417
+ const resolvedImg = await resolveImage(item.image, baseDir);
4418
+ if (resolvedImg) {
4419
+ cellParagraphs.push(
4420
+ new Paragraph({
4421
+ children: [
4422
+ new ImageRun({
4423
+ data: resolvedImg.buffer,
4424
+ transformation: {
4425
+ width: 140,
4426
+ height: 60
4427
+ },
4428
+ type: "png"
4429
+ })
4430
+ ],
4431
+ spacing: { before: 40, after: 40 }
4432
+ })
4433
+ );
4434
+ } else {
4435
+ cellParagraphs.push(new Paragraph({ spacing: { before: 240, after: 240 } }));
4436
+ }
4437
+ } else {
4438
+ cellParagraphs.push(new Paragraph({ spacing: { before: 240, after: 240 } }));
4439
+ }
4440
+ if (sig.style === "line") {
4441
+ cellParagraphs.push(
4442
+ new Paragraph({
4443
+ border: {
4444
+ bottom: {
4445
+ style: BorderStyle.SINGLE,
4446
+ size: 6,
4447
+ space: 2,
4448
+ color: sig.borderColor.replace("#", "")
4449
+ }
4450
+ },
4451
+ spacing: { after: 60 }
4452
+ })
4453
+ );
4454
+ }
4455
+ cellParagraphs.push(
4456
+ new Paragraph({
4457
+ children: [
4458
+ new TextRun({
4459
+ text: item.name,
4460
+ font: defaultFont,
4461
+ size: 21,
4462
+ // 10.5pt
4463
+ bold: true,
4464
+ color: sig.nameColor.replace("#", "")
4465
+ })
4466
+ ],
4467
+ spacing: { before: sig.style === "line" ? 40 : 20, after: 20 }
4468
+ })
4469
+ );
4470
+ if (item.role) {
4471
+ cellParagraphs.push(
4472
+ new Paragraph({
4473
+ children: [
4474
+ new TextRun({
4475
+ text: item.role,
4476
+ font: defaultFont,
4477
+ size: 18,
4478
+ // 9pt
4479
+ color: sig.roleColor.replace("#", "")
4480
+ })
4481
+ ],
4482
+ spacing: { after: 20 }
4483
+ })
4484
+ );
4485
+ }
4486
+ if (item.date) {
4487
+ cellParagraphs.push(
4488
+ new Paragraph({
4489
+ children: [
4490
+ new TextRun({
4491
+ text: `Date: ${item.date}`,
4492
+ font: defaultFont,
4493
+ size: 17,
4494
+ // 8.5pt
4495
+ color: sig.roleColor.replace("#", "")
4496
+ })
4497
+ ],
4498
+ spacing: { after: 20 }
4499
+ })
4500
+ );
4501
+ }
4502
+ const isBox = sig.style === "box";
4503
+ const boxBorder = { style: BorderStyle.SINGLE, size: 4, color: sig.borderColor.replace("#", "") };
4504
+ const noneBorder = { style: BorderStyle.NONE, size: 0, color: "auto" };
4505
+ return new TableCell({
4506
+ width: { size: widthDxa, type: WidthType.DXA },
4507
+ shading: isBox ? { fill: "F8FAFC", type: ShadingType.CLEAR } : void 0,
4508
+ margins: isBox ? { top: 140, bottom: 140, left: 160, right: 160 } : { top: 60, bottom: 60, left: 60, right: 60 },
4509
+ borders: {
4510
+ top: isBox ? boxBorder : noneBorder,
4511
+ bottom: isBox ? boxBorder : noneBorder,
4512
+ left: isBox ? boxBorder : noneBorder,
4513
+ right: isBox ? boxBorder : noneBorder
4514
+ },
4515
+ children: cellParagraphs
4516
+ });
4517
+ }
4518
+ function createEmptyDocxCell(widthDxa) {
4519
+ const noneBorder = { style: BorderStyle.NONE, size: 0, color: "auto" };
4520
+ return new TableCell({
4521
+ width: { size: widthDxa, type: WidthType.DXA },
4522
+ borders: {
4523
+ top: noneBorder,
4524
+ bottom: noneBorder,
4525
+ left: noneBorder,
4526
+ right: noneBorder
4527
+ },
4528
+ children: [new Paragraph({})]
4529
+ });
2974
4530
  }
2975
4531
 
2976
- // src/ui/App.tsx
2977
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2978
- var App = ({ inputFile, config, onComplete }) => {
2979
- const [status, setStatus] = useState("Initializing...");
2980
- const [isCompiling, setIsCompiling] = useState(true);
2981
- const [result, setResult] = useState(null);
2982
- useEffect(() => {
2983
- async function run() {
2984
- try {
2985
- const res = await compileMarkdown(inputFile, config, (msg) => setStatus(msg));
2986
- setResult(res);
2987
- setIsCompiling(false);
2988
- onComplete == null ? void 0 : onComplete(res);
2989
- } catch (err) {
2990
- const errMsg = err instanceof Error ? err.message : String(err);
2991
- const errResult = {
2992
- inputFile,
2993
- durationMs: 0,
2994
- metadata: {},
2995
- files: [],
2996
- errors: [errMsg]
2997
- };
2998
- setResult(errResult);
2999
- setIsCompiling(false);
3000
- onComplete == null ? void 0 : onComplete(errResult);
3001
- }
3002
- }
3003
- run();
3004
- }, [inputFile, config, onComplete]);
3005
- return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
3006
- /* @__PURE__ */ jsx4(Header, { inputFile, theme: config.theme }),
3007
- /* @__PURE__ */ jsx4(LiveProgress, { status, isCompiling }),
3008
- /* @__PURE__ */ jsx4(SummaryTable, { result })
3009
- ] });
3010
- };
3011
4532
  export {
3012
- App
4533
+ parseMarkdownDocument,
4534
+ buildHtmlDocument,
4535
+ buildPdfDocument,
4536
+ buildDocxDocument
3013
4537
  };