@masumdev/markforge 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -140
- package/dist/App-TPDCT2VL.mjs +393 -0
- package/dist/{chunk-IYGPJIK5.mjs → chunk-BPHDY6VB.mjs} +6 -0
- package/dist/{App-AM2CWXHJ.mjs → chunk-R6DT335C.mjs} +2140 -924
- package/dist/{chunk-HKB4CSPZ.mjs → chunk-UNWAEVDU.mjs} +4 -3
- package/dist/cli.mjs +38 -8
- package/dist/index.d.mts +554 -136
- package/dist/index.d.ts +554 -136
- package/dist/index.js +2652 -227
- package/dist/index.mjs +2643 -228
- package/dist/{loadConfig-PD6ENMAM.mjs → loadConfig-PGJKPE6G.mjs} +1 -1
- package/dist/previewServer-4EELOUAV.mjs +893 -0
- package/package.json +5 -1
- package/schema.json +142 -0
|
@@ -7,197 +7,9 @@ try {
|
|
|
7
7
|
});
|
|
8
8
|
}
|
|
9
9
|
} catch {}
|
|
10
|
-
import {
|
|
11
|
-
MARKFORGE_VERSION
|
|
12
|
-
} from "./chunk-HKB4CSPZ.mjs";
|
|
13
10
|
import {
|
|
14
11
|
DEFAULT_CONFIG
|
|
15
|
-
} from "./chunk-
|
|
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 * as path from "path";
|
|
24
|
-
import { Box, Text } from "ink";
|
|
25
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
26
|
-
function formatDisplayPath(p) {
|
|
27
|
-
if (!p) return "";
|
|
28
|
-
try {
|
|
29
|
-
const rel = path.relative(process.cwd(), p);
|
|
30
|
-
return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p;
|
|
31
|
-
} catch {
|
|
32
|
-
return p;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
var Header = ({
|
|
36
|
-
inputFile,
|
|
37
|
-
theme = "corporate",
|
|
38
|
-
targetFormats = ["docx", "pdf"]
|
|
39
|
-
}) => {
|
|
40
|
-
const themeLabel = typeof theme === "object" ? "Custom (ThemeProps)" : String(theme || "corporate");
|
|
41
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs(
|
|
42
|
-
Box,
|
|
43
|
-
{
|
|
44
|
-
borderStyle: "round",
|
|
45
|
-
borderColor: "cyan",
|
|
46
|
-
paddingX: 2,
|
|
47
|
-
paddingY: 1,
|
|
48
|
-
flexDirection: "column",
|
|
49
|
-
children: [
|
|
50
|
-
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", alignItems: "center", children: [
|
|
51
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
52
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MARKFORGE" }),
|
|
53
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: " | Document Publishing Engine" })
|
|
54
|
-
] }),
|
|
55
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "black", backgroundColor: "cyan", bold: true, children: [
|
|
56
|
-
" ",
|
|
57
|
-
"v",
|
|
58
|
-
MARKFORGE_VERSION,
|
|
59
|
-
" "
|
|
60
|
-
] }) })
|
|
61
|
-
] }),
|
|
62
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
63
|
-
inputFile && /* @__PURE__ */ jsxs(Box, { children: [
|
|
64
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Source: " }),
|
|
65
|
-
/* @__PURE__ */ jsx(Text, { color: "white", bold: true, children: formatDisplayPath(inputFile) })
|
|
66
|
-
] }),
|
|
67
|
-
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginTop: 0, children: [
|
|
68
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
69
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Theme: " }),
|
|
70
|
-
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: themeLabel })
|
|
71
|
-
] }),
|
|
72
|
-
targetFormats && targetFormats.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
|
|
73
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Targets: " }),
|
|
74
|
-
/* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: targetFormats.map((f) => f.toUpperCase()).join(", ") })
|
|
75
|
-
] })
|
|
76
|
-
] })
|
|
77
|
-
] }),
|
|
78
|
-
/* @__PURE__ */ jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [
|
|
79
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
80
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Author: " }),
|
|
81
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "Ma'sum" }),
|
|
82
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: " (@masumrpg)" })
|
|
83
|
-
] }),
|
|
84
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
85
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "GitHub: " }),
|
|
86
|
-
/* @__PURE__ */ jsx(Text, { color: "blue", underline: true, children: "https://github.com/masumrpg" })
|
|
87
|
-
] })
|
|
88
|
-
] })
|
|
89
|
-
]
|
|
90
|
-
}
|
|
91
|
-
) });
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
// src/ui/LiveProgress.tsx
|
|
95
|
-
import { Box as Box2, Text as Text2 } from "ink";
|
|
96
|
-
import Spinner from "ink-spinner";
|
|
97
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
98
|
-
var LiveProgress = ({ status, isCompiling }) => {
|
|
99
|
-
if (!isCompiling) return null;
|
|
100
|
-
return /* @__PURE__ */ jsxs2(Box2, { marginY: 1, alignItems: "center", children: [
|
|
101
|
-
/* @__PURE__ */ jsx2(Text2, { color: "cyan", children: /* @__PURE__ */ jsx2(Spinner, { type: "dots" }) }),
|
|
102
|
-
/* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, children: [
|
|
103
|
-
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "[COMPILING] " }),
|
|
104
|
-
/* @__PURE__ */ jsx2(Text2, { color: "white", children: status })
|
|
105
|
-
] })
|
|
106
|
-
] });
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// src/ui/SummaryTable.tsx
|
|
110
|
-
import * as path2 from "path";
|
|
111
|
-
import { Box as Box3, Text as Text3 } from "ink";
|
|
112
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
113
|
-
function formatBytes(bytes) {
|
|
114
|
-
if (bytes === 0) return "0 B";
|
|
115
|
-
const k = 1024;
|
|
116
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
117
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
118
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
119
|
-
}
|
|
120
|
-
function formatDisplayPath2(p) {
|
|
121
|
-
if (!p) return "";
|
|
122
|
-
try {
|
|
123
|
-
const rel = path2.relative(process.cwd(), p);
|
|
124
|
-
return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p;
|
|
125
|
-
} catch {
|
|
126
|
-
return p;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
var SummaryTable = ({ result }) => {
|
|
130
|
-
if (!result) return null;
|
|
131
|
-
const hasErrors = result.errors.length > 0;
|
|
132
|
-
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs3(
|
|
133
|
-
Box3,
|
|
134
|
-
{
|
|
135
|
-
borderStyle: "round",
|
|
136
|
-
borderColor: hasErrors ? "red" : "green",
|
|
137
|
-
paddingX: 2,
|
|
138
|
-
paddingY: 1,
|
|
139
|
-
flexDirection: "column",
|
|
140
|
-
children: [
|
|
141
|
-
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", alignItems: "center", children: [
|
|
142
|
-
/* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: hasErrors ? "red" : "green", children: hasErrors ? "[COMPILATION FAILED]" : "[COMPILATION SUCCESSFUL]" }) }),
|
|
143
|
-
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
144
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Duration: " }),
|
|
145
|
-
/* @__PURE__ */ jsxs3(Text3, { color: "yellow", bold: true, children: [
|
|
146
|
-
result.durationMs,
|
|
147
|
-
"ms"
|
|
148
|
-
] })
|
|
149
|
-
] })
|
|
150
|
-
] }),
|
|
151
|
-
result.files.length > 0 && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
152
|
-
/* @__PURE__ */ jsxs3(Text3, { bold: true, color: "white", children: [
|
|
153
|
-
"Generated Documents (",
|
|
154
|
-
result.files.length,
|
|
155
|
-
"):"
|
|
156
|
-
] }),
|
|
157
|
-
result.files.map((f, i) => {
|
|
158
|
-
const formatColor = f.format === "docx" ? "blue" : f.format === "pdf" ? "red" : "yellow";
|
|
159
|
-
const paddedBadge = `[${f.format.toUpperCase()}]`.padEnd(7, " ");
|
|
160
|
-
return /* @__PURE__ */ jsxs3(Box3, { marginTop: 0, flexDirection: "column", marginLeft: 1, children: [
|
|
161
|
-
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", alignItems: "center", children: [
|
|
162
|
-
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
163
|
-
/* @__PURE__ */ jsx3(Text3, { color: formatColor, bold: true, children: paddedBadge }),
|
|
164
|
-
/* @__PURE__ */ jsx3(Text3, { color: "white", bold: true, children: f.fileName })
|
|
165
|
-
] }),
|
|
166
|
-
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: formatBytes(f.sizeBytes) })
|
|
167
|
-
] }),
|
|
168
|
-
/* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
169
|
-
"\u2514\u2500 ",
|
|
170
|
-
formatDisplayPath2(f.filePath)
|
|
171
|
-
] }) })
|
|
172
|
-
] }, i);
|
|
173
|
-
})
|
|
174
|
-
] }),
|
|
175
|
-
hasErrors && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
176
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "red", children: "Errors:" }),
|
|
177
|
-
result.errors.map((err, i) => /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
|
|
178
|
-
"- ",
|
|
179
|
-
err
|
|
180
|
-
] }) }, i))
|
|
181
|
-
] }),
|
|
182
|
-
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, justifyContent: "space-between", alignItems: "center", children: [
|
|
183
|
-
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
184
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Author: " }),
|
|
185
|
-
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "Ma'sum" }),
|
|
186
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: " (@masumrpg)" })
|
|
187
|
-
] }),
|
|
188
|
-
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
189
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "GitHub: " }),
|
|
190
|
-
/* @__PURE__ */ jsx3(Text3, { color: "blue", underline: true, children: "https://github.com/masumrpg" })
|
|
191
|
-
] })
|
|
192
|
-
] })
|
|
193
|
-
]
|
|
194
|
-
}
|
|
195
|
-
) });
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
// src/core/engine.ts
|
|
199
|
-
import * as fs5 from "fs";
|
|
200
|
-
import * as path7 from "path";
|
|
12
|
+
} from "./chunk-BPHDY6VB.mjs";
|
|
201
13
|
|
|
202
14
|
// src/core/parser.ts
|
|
203
15
|
import matter from "gray-matter";
|
|
@@ -231,6 +43,26 @@ function parseInlineSpans(text) {
|
|
|
231
43
|
remaining = remaining.slice(imgMatch[0].length);
|
|
232
44
|
continue;
|
|
233
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
|
+
}
|
|
234
66
|
const linkMatch = remaining.match(/^\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]+)")?\)/);
|
|
235
67
|
if (linkMatch) {
|
|
236
68
|
spans.push({
|
|
@@ -330,7 +162,7 @@ function parseInlineSpans(text) {
|
|
|
330
162
|
remaining = remaining.slice(fullTag.length);
|
|
331
163
|
continue;
|
|
332
164
|
}
|
|
333
|
-
const nextSpecial = remaining.search(/[\*\_\[
|
|
165
|
+
const nextSpecial = remaining.search(/[\*\_\[\!`~<\$]/);
|
|
334
166
|
if (nextSpecial === -1) {
|
|
335
167
|
spans.push({
|
|
336
168
|
type: "text",
|
|
@@ -351,11 +183,51 @@ function parseInlineSpans(text) {
|
|
|
351
183
|
remaining = remaining.slice(nextSpecial);
|
|
352
184
|
}
|
|
353
185
|
}
|
|
354
|
-
|
|
186
|
+
const merged = [];
|
|
187
|
+
for (const s of spans) {
|
|
188
|
+
const prev = merged[merged.length - 1];
|
|
189
|
+
if (prev && prev.type === "text" && s.type === "text") {
|
|
190
|
+
prev.content += s.content;
|
|
191
|
+
} else {
|
|
192
|
+
merged.push(s);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return merged;
|
|
355
196
|
}
|
|
356
197
|
function slugify(text) {
|
|
357
198
|
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
358
199
|
}
|
|
200
|
+
function applyHeadingNumbering(nodes, tocEntries, options) {
|
|
201
|
+
const depth = options.depth ?? 3;
|
|
202
|
+
const skipH1 = options.skipH1 ?? false;
|
|
203
|
+
const prefix = options.prefix ?? "";
|
|
204
|
+
const counters = [0, 0, 0, 0, 0, 0];
|
|
205
|
+
for (const node of nodes) {
|
|
206
|
+
if (node.type === "heading" && node.level) {
|
|
207
|
+
if (node._numbered) continue;
|
|
208
|
+
const lvl = node.level;
|
|
209
|
+
if (lvl > depth) continue;
|
|
210
|
+
if (lvl === 1 && skipH1) continue;
|
|
211
|
+
const idx = lvl - 1;
|
|
212
|
+
counters[idx]++;
|
|
213
|
+
for (let c = idx + 1; c < counters.length; c++) {
|
|
214
|
+
counters[c] = 0;
|
|
215
|
+
}
|
|
216
|
+
const startIdx = skipH1 ? 1 : 0;
|
|
217
|
+
const parts = counters.slice(startIdx, idx + 1).filter((n) => n > 0);
|
|
218
|
+
const numberStr = parts.join(".") + ".";
|
|
219
|
+
const fullPrefix = prefix ? `${prefix} ${numberStr} ` : `${numberStr} `;
|
|
220
|
+
const originalText = node.text || "";
|
|
221
|
+
node.text = fullPrefix + originalText;
|
|
222
|
+
node.inlines = parseInlineSpans(node.text);
|
|
223
|
+
node._numbered = true;
|
|
224
|
+
const toc = tocEntries.find((t) => t.id === node.id);
|
|
225
|
+
if (toc) {
|
|
226
|
+
toc.text = node.text;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
359
231
|
function parseMarkdownDocument(rawMarkdown) {
|
|
360
232
|
const { data: frontmatter, content } = matter(rawMarkdown);
|
|
361
233
|
const metadata = frontmatter || {};
|
|
@@ -367,6 +239,7 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
367
239
|
const lines = cleanContent.split(/\r?\n/);
|
|
368
240
|
const nodes = [];
|
|
369
241
|
const tocEntries = [];
|
|
242
|
+
const footnoteDefs = [];
|
|
370
243
|
let i = 0;
|
|
371
244
|
while (i < lines.length) {
|
|
372
245
|
const line = lines[i];
|
|
@@ -395,6 +268,29 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
395
268
|
i++;
|
|
396
269
|
continue;
|
|
397
270
|
}
|
|
271
|
+
if (line.trim().startsWith("$$")) {
|
|
272
|
+
const mathLines = [];
|
|
273
|
+
const singleLine = line.trim().match(/^\$\$(.+)\$\$$/);
|
|
274
|
+
if (singleLine) {
|
|
275
|
+
nodes.push({
|
|
276
|
+
type: "mathBlock",
|
|
277
|
+
text: singleLine[1].trim()
|
|
278
|
+
});
|
|
279
|
+
i++;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
i++;
|
|
283
|
+
while (i < lines.length && !lines[i].trim().startsWith("$$")) {
|
|
284
|
+
mathLines.push(lines[i]);
|
|
285
|
+
i++;
|
|
286
|
+
}
|
|
287
|
+
if (i < lines.length) i++;
|
|
288
|
+
nodes.push({
|
|
289
|
+
type: "mathBlock",
|
|
290
|
+
text: mathLines.join("\n").trim()
|
|
291
|
+
});
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
398
294
|
const codeBlockMatch = line.match(/^```(\w+)?/);
|
|
399
295
|
if (codeBlockMatch) {
|
|
400
296
|
const language = (codeBlockMatch[1] || "text").trim().toLowerCase();
|
|
@@ -421,6 +317,100 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
421
317
|
}
|
|
422
318
|
continue;
|
|
423
319
|
}
|
|
320
|
+
const colsMatch = line.trim().match(/^:::columns(?:\s+\[?([\w\s=.-]+)\]?)?$/i);
|
|
321
|
+
if (colsMatch) {
|
|
322
|
+
const attrStr = colsMatch[1] || "";
|
|
323
|
+
let colsCount = 2;
|
|
324
|
+
let colGap = "1.5rem";
|
|
325
|
+
if (attrStr) {
|
|
326
|
+
const numMatch = attrStr.trim().match(/^(\d+)$/);
|
|
327
|
+
const cMatch = attrStr.match(/cols=(\d+)/i) || attrStr.match(/columns=(\d+)/i);
|
|
328
|
+
const gMatch = attrStr.match(/gap=([^\s]+)/i);
|
|
329
|
+
if (numMatch) colsCount = parseInt(numMatch[1], 10);
|
|
330
|
+
else if (cMatch) colsCount = parseInt(cMatch[1], 10);
|
|
331
|
+
if (gMatch) colGap = gMatch[1];
|
|
332
|
+
}
|
|
333
|
+
const columnNodes = [];
|
|
334
|
+
let currentColumnLines = [];
|
|
335
|
+
let inColBlock = false;
|
|
336
|
+
i++;
|
|
337
|
+
while (i < lines.length) {
|
|
338
|
+
const curLine = lines[i];
|
|
339
|
+
const trimmed = curLine.trim();
|
|
340
|
+
if (/^:::col(?:umn)?$/i.test(trimmed)) {
|
|
341
|
+
if (currentColumnLines.length > 0) {
|
|
342
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
343
|
+
columnNodes.push({
|
|
344
|
+
type: "column",
|
|
345
|
+
children: subDoc.nodes
|
|
346
|
+
});
|
|
347
|
+
currentColumnLines = [];
|
|
348
|
+
}
|
|
349
|
+
inColBlock = true;
|
|
350
|
+
i++;
|
|
351
|
+
} else if (trimmed === ":::") {
|
|
352
|
+
if (inColBlock) {
|
|
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
|
+
inColBlock = false;
|
|
362
|
+
i++;
|
|
363
|
+
} else {
|
|
364
|
+
if (currentColumnLines.length > 0) {
|
|
365
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
366
|
+
columnNodes.push({
|
|
367
|
+
type: "column",
|
|
368
|
+
children: subDoc.nodes
|
|
369
|
+
});
|
|
370
|
+
currentColumnLines = [];
|
|
371
|
+
}
|
|
372
|
+
i++;
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
currentColumnLines.push(curLine);
|
|
377
|
+
i++;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (currentColumnLines.length > 0) {
|
|
381
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
382
|
+
columnNodes.push({
|
|
383
|
+
type: "column",
|
|
384
|
+
children: subDoc.nodes
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
nodes.push({
|
|
388
|
+
type: "columns",
|
|
389
|
+
columnsCount: columnNodes.length > 0 ? columnNodes.length : colsCount,
|
|
390
|
+
columnGap: colGap,
|
|
391
|
+
children: columnNodes
|
|
392
|
+
});
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
const fnDefMatch = line.match(/^\[\^([\w-]+)\]:\s+(.+)$/);
|
|
396
|
+
if (fnDefMatch) {
|
|
397
|
+
const fnId = fnDefMatch[1];
|
|
398
|
+
const fnText = fnDefMatch[2].trim();
|
|
399
|
+
const inlines = parseInlineSpans(fnText);
|
|
400
|
+
footnoteDefs.push({
|
|
401
|
+
id: fnId,
|
|
402
|
+
text: fnText,
|
|
403
|
+
inlines
|
|
404
|
+
});
|
|
405
|
+
nodes.push({
|
|
406
|
+
type: "footnoteDef",
|
|
407
|
+
footnoteId: fnId,
|
|
408
|
+
text: fnText,
|
|
409
|
+
inlines
|
|
410
|
+
});
|
|
411
|
+
i++;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
424
414
|
const calloutMatch = line.match(/^>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/i);
|
|
425
415
|
if (calloutMatch) {
|
|
426
416
|
const calloutType = calloutMatch[1].toUpperCase();
|
|
@@ -544,7 +534,7 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
544
534
|
continue;
|
|
545
535
|
}
|
|
546
536
|
const paraLines = [];
|
|
547
|
-
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+/)) {
|
|
537
|
+
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+/)) {
|
|
548
538
|
paraLines.push(lines[i]);
|
|
549
539
|
i++;
|
|
550
540
|
}
|
|
@@ -555,43 +545,29 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
555
545
|
inlines: parseInlineSpans(paraText)
|
|
556
546
|
});
|
|
557
547
|
}
|
|
548
|
+
if (metadata.numberHeadings) {
|
|
549
|
+
const opts = typeof metadata.numberHeadings === "boolean" ? { enabled: metadata.numberHeadings } : metadata.numberHeadings;
|
|
550
|
+
if (opts.enabled !== false) {
|
|
551
|
+
applyHeadingNumbering(nodes, tocEntries, opts);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
558
554
|
return {
|
|
559
555
|
metadata,
|
|
560
556
|
content: cleanContent,
|
|
561
557
|
nodes,
|
|
562
558
|
tocEntries,
|
|
563
|
-
inlinedStyles
|
|
559
|
+
inlinedStyles,
|
|
560
|
+
footnoteDefs
|
|
564
561
|
};
|
|
565
562
|
}
|
|
566
563
|
|
|
567
|
-
// src/core/
|
|
568
|
-
import
|
|
569
|
-
|
|
570
|
-
Paragraph,
|
|
571
|
-
TextRun,
|
|
572
|
-
HeadingLevel,
|
|
573
|
-
Table,
|
|
574
|
-
TableRow,
|
|
575
|
-
TableCell,
|
|
576
|
-
WidthType,
|
|
577
|
-
BorderStyle,
|
|
578
|
-
AlignmentType,
|
|
579
|
-
ImageRun,
|
|
580
|
-
Header as Header2,
|
|
581
|
-
Footer,
|
|
582
|
-
PageNumber,
|
|
583
|
-
Packer,
|
|
584
|
-
PageOrientation,
|
|
585
|
-
convertInchesToTwip,
|
|
586
|
-
convertMillimetersToTwip,
|
|
587
|
-
ShadingType,
|
|
588
|
-
ExternalHyperlink,
|
|
589
|
-
TabStopType
|
|
590
|
-
} from "docx";
|
|
564
|
+
// src/core/html/htmlBuilder.ts
|
|
565
|
+
import * as fs2 from "fs";
|
|
566
|
+
import * as path2 from "path";
|
|
591
567
|
|
|
592
568
|
// src/core/imageResolver.ts
|
|
593
569
|
import * as fs from "fs";
|
|
594
|
-
import * as
|
|
570
|
+
import * as path from "path";
|
|
595
571
|
var memoryImageCache = /* @__PURE__ */ new Map();
|
|
596
572
|
function getMimeType(filePathOrUrl) {
|
|
597
573
|
const clean = filePathOrUrl.split("?")[0].toLowerCase();
|
|
@@ -648,9 +624,14 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
648
624
|
memoryImageCache.set(cacheKey, resolved2);
|
|
649
625
|
return resolved2;
|
|
650
626
|
}
|
|
651
|
-
|
|
627
|
+
let localPath = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
|
|
652
628
|
if (!fs.existsSync(localPath)) {
|
|
653
|
-
|
|
629
|
+
const cwdPath = path.resolve(process.cwd(), src);
|
|
630
|
+
if (fs.existsSync(cwdPath)) {
|
|
631
|
+
localPath = cwdPath;
|
|
632
|
+
} else {
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
654
635
|
}
|
|
655
636
|
const buffer = fs.readFileSync(localPath);
|
|
656
637
|
const mimeType = getMimeType(localPath);
|
|
@@ -670,135 +651,297 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
670
651
|
}
|
|
671
652
|
}
|
|
672
653
|
|
|
673
|
-
// src/core/
|
|
674
|
-
var
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
operator: "FF7B72",
|
|
690
|
-
// Same as keyword — = + - * / > <
|
|
691
|
-
punctuation: "8B9AC0",
|
|
692
|
-
// Steel blue-gray — () [] {} , . ;
|
|
693
|
-
plain: "E2E8F0"
|
|
694
|
-
// Light gray — identifiers / plain text
|
|
695
|
-
};
|
|
696
|
-
var SYNTAX_COLORS_LIGHT = {
|
|
697
|
-
keyword: "D73A49",
|
|
698
|
-
// Crimson red — keywords
|
|
699
|
-
string: "0A7E5C",
|
|
700
|
-
// Forest teal — strings (readable on white)
|
|
701
|
-
comment: "6A737D",
|
|
702
|
-
// Muted gray — comments
|
|
703
|
-
number: "005CC5",
|
|
704
|
-
// Cobalt blue — numbers
|
|
705
|
-
boolean: "D73A49",
|
|
706
|
-
// Crimson — true/false/None
|
|
707
|
-
function: "6F42C1",
|
|
708
|
-
// Purple — function names
|
|
709
|
-
type: "22863A",
|
|
710
|
-
// Forest green — Types / Classes
|
|
711
|
-
operator: "D73A49",
|
|
712
|
-
// Crimson — operators
|
|
713
|
-
punctuation: "586069",
|
|
714
|
-
// Dark gray — punctuation
|
|
715
|
-
plain: "24292E"
|
|
716
|
-
// Near-black — identifiers
|
|
717
|
-
};
|
|
718
|
-
var SYNTAX_THEMES = {
|
|
719
|
-
"github-dark": SYNTAX_COLORS,
|
|
720
|
-
"dark": SYNTAX_COLORS,
|
|
721
|
-
"github-light": SYNTAX_COLORS_LIGHT,
|
|
722
|
-
"light": SYNTAX_COLORS_LIGHT,
|
|
723
|
-
"dracula": {
|
|
724
|
-
keyword: "FF79C6",
|
|
725
|
-
string: "F1FA8C",
|
|
726
|
-
comment: "6272A4",
|
|
727
|
-
number: "BD93F9",
|
|
728
|
-
boolean: "BD93F9",
|
|
729
|
-
function: "50FA7B",
|
|
730
|
-
type: "8BE9FD",
|
|
731
|
-
operator: "FF79C6",
|
|
732
|
-
punctuation: "F8F8F2",
|
|
733
|
-
plain: "F8F8F2"
|
|
734
|
-
},
|
|
735
|
-
"monokai": {
|
|
736
|
-
keyword: "F92672",
|
|
737
|
-
string: "E6DB74",
|
|
738
|
-
comment: "75715E",
|
|
739
|
-
number: "AE81FF",
|
|
740
|
-
boolean: "AE81FF",
|
|
741
|
-
function: "A6E22E",
|
|
742
|
-
type: "66D9EF",
|
|
743
|
-
operator: "F92672",
|
|
744
|
-
punctuation: "F8F8F2",
|
|
745
|
-
plain: "F8F8F2"
|
|
746
|
-
},
|
|
747
|
-
"nord": {
|
|
748
|
-
keyword: "81A1C1",
|
|
749
|
-
string: "A3BE8C",
|
|
750
|
-
comment: "616E88",
|
|
751
|
-
number: "B48EAD",
|
|
752
|
-
boolean: "81A1C1",
|
|
753
|
-
function: "88C0D0",
|
|
754
|
-
type: "8FBCBB",
|
|
755
|
-
operator: "81A1C1",
|
|
756
|
-
punctuation: "ECEFF4",
|
|
757
|
-
plain: "D8DEE9"
|
|
758
|
-
}
|
|
759
|
-
};
|
|
760
|
-
function getSyntaxPalette(themeName = "github-dark") {
|
|
761
|
-
return SYNTAX_THEMES[themeName.toLowerCase()] || SYNTAX_THEMES["github-dark"];
|
|
654
|
+
// src/core/html/htmlThemes.ts
|
|
655
|
+
var THEME_COMPONENTS = `
|
|
656
|
+
/* Fallback CSS variables \u2014 overridden by each named theme's :root block */
|
|
657
|
+
:root {
|
|
658
|
+
--mf-bg: #ffffff;
|
|
659
|
+
--mf-text: #0f172a;
|
|
660
|
+
--mf-text-muted: #64748b;
|
|
661
|
+
--mf-primary: #33CDCF;
|
|
662
|
+
--mf-primary-dark: #009DA0;
|
|
663
|
+
--mf-primary-light: #ECFDFD;
|
|
664
|
+
--mf-border: #e2e8f0;
|
|
665
|
+
--mf-card-bg: #f8fafc;
|
|
666
|
+
--mf-code-bg: #0f172a;
|
|
667
|
+
--mf-code-text: #f8fafc;
|
|
668
|
+
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
669
|
+
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
762
670
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
671
|
+
|
|
672
|
+
/* Document header */
|
|
673
|
+
.document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
|
|
674
|
+
.document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
|
|
675
|
+
.document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
676
|
+
.document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
|
|
677
|
+
|
|
678
|
+
/* Table of Contents */
|
|
679
|
+
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; page-break-after: always; break-after: page; }
|
|
680
|
+
.table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
681
|
+
.table-of-contents ul { list-style: none; padding: 0; margin: 0; }
|
|
682
|
+
.table-of-contents li { padding: 0.25rem 0; }
|
|
683
|
+
.table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
|
|
684
|
+
.table-of-contents a:hover { text-decoration: underline; }
|
|
685
|
+
|
|
686
|
+
/* Links */
|
|
687
|
+
a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
|
|
688
|
+
a:hover { text-decoration: underline; }
|
|
689
|
+
|
|
690
|
+
/* Blockquote */
|
|
691
|
+
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; }
|
|
692
|
+
|
|
693
|
+
/* Callout / Alert Boxes */
|
|
694
|
+
.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; }
|
|
695
|
+
.callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
|
|
696
|
+
.callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
697
|
+
.callout-NOTE .callout-title { color: #009DA0; }
|
|
698
|
+
.callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
699
|
+
.callout-TIP .callout-title { color: #10b981; }
|
|
700
|
+
.callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
701
|
+
.callout-WARNING .callout-title { color: #f59e0b; }
|
|
702
|
+
.callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
703
|
+
.callout-CAUTION .callout-title { color: #ef4444; }
|
|
704
|
+
.callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
705
|
+
.callout-IMPORTANT .callout-title { color: #8b5cf6; }
|
|
706
|
+
|
|
707
|
+
/* Inline Code */
|
|
708
|
+
code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
|
|
709
|
+
|
|
710
|
+
/* Code Blocks */
|
|
711
|
+
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; }
|
|
712
|
+
pre code { background-color: transparent; color: inherit; padding: 0; }
|
|
713
|
+
|
|
714
|
+
/* Tables */
|
|
715
|
+
table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
|
|
716
|
+
th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
|
|
717
|
+
th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
|
|
718
|
+
tr:nth-child(even) { background-color: var(--mf-card-bg); }
|
|
719
|
+
|
|
720
|
+
/* Images */
|
|
721
|
+
img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
|
|
722
|
+
|
|
723
|
+
/* Dividers */
|
|
724
|
+
hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
|
|
725
|
+
|
|
726
|
+
/* Print / PDF */
|
|
727
|
+
@media print {
|
|
728
|
+
body { padding: 0; }
|
|
729
|
+
.document-container { max-width: 100%; }
|
|
730
|
+
pre, table, blockquote, .callout { break-inside: avoid; }
|
|
731
|
+
/* Remove scrollbars \u2014 PDF has no scrolling */
|
|
732
|
+
pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
|
|
733
|
+
}
|
|
734
|
+
`;
|
|
735
|
+
var THEME_CORPORATE = `
|
|
736
|
+
:root {
|
|
737
|
+
--mf-bg: #ffffff;
|
|
738
|
+
--mf-text: #0f172a;
|
|
739
|
+
--mf-text-muted: #64748b;
|
|
740
|
+
--mf-primary: #33CDCF;
|
|
741
|
+
--mf-primary-dark: #009DA0;
|
|
742
|
+
--mf-primary-light: #ECFDFD;
|
|
743
|
+
--mf-border: #e2e8f0;
|
|
744
|
+
--mf-card-bg: #f8fafc;
|
|
745
|
+
--mf-code-bg: #0f172a;
|
|
746
|
+
--mf-code-text: #f8fafc;
|
|
747
|
+
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
748
|
+
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
749
|
+
}
|
|
750
|
+
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; }
|
|
751
|
+
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
752
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-primary-dark); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
753
|
+
h1 { font-size: 2.2rem; color: var(--mf-primary-dark); border-bottom: 2.5px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
754
|
+
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
|
|
755
|
+
h3 { font-size: 1.3rem; color: var(--mf-primary-dark); }
|
|
756
|
+
h4 { font-size: 1.1rem; color: var(--mf-primary-dark); }
|
|
757
|
+
h5 { font-size: 1.0rem; color: var(--mf-primary-dark); }
|
|
758
|
+
h6 { font-size: 0.9rem; color: var(--mf-primary-dark); }
|
|
759
|
+
p { margin: 0.8rem 0; }
|
|
760
|
+
`;
|
|
761
|
+
var THEMES = {
|
|
762
|
+
corporate: THEME_CORPORATE,
|
|
763
|
+
default: THEME_CORPORATE
|
|
764
|
+
};
|
|
765
|
+
function generateThemeCss(theme) {
|
|
766
|
+
if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
|
|
767
|
+
return THEME_CORPORATE;
|
|
768
|
+
}
|
|
769
|
+
if (typeof theme === "object") {
|
|
770
|
+
const bg = theme.backgroundColor || "#ffffff";
|
|
771
|
+
const text = theme.textColor || "#0f172a";
|
|
772
|
+
const textMuted = theme.textMuted || "#64748b";
|
|
773
|
+
const primary = theme.primaryColor || "#33CDCF";
|
|
774
|
+
const primaryDark = theme.primaryDark || primary;
|
|
775
|
+
const primaryLight = theme.primaryLight || "#ECFDFD";
|
|
776
|
+
const border = theme.borderColor || "#e2e8f0";
|
|
777
|
+
const cardBg = theme.cardBackground || "#f8fafc";
|
|
778
|
+
const codeBg = theme.codeBackground || "#0f172a";
|
|
779
|
+
const codeText = theme.codeText || "#f8fafc";
|
|
780
|
+
const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
781
|
+
const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
|
|
782
|
+
return `
|
|
783
|
+
:root {
|
|
784
|
+
--mf-bg: ${bg};
|
|
785
|
+
--mf-text: ${text};
|
|
786
|
+
--mf-text-muted: ${textMuted};
|
|
787
|
+
--mf-primary: ${primary};
|
|
788
|
+
--mf-primary-dark: ${primaryDark};
|
|
789
|
+
--mf-primary-light: ${primaryLight};
|
|
790
|
+
--mf-border: ${border};
|
|
791
|
+
--mf-card-bg: ${cardBg};
|
|
792
|
+
--mf-code-bg: ${codeBg};
|
|
793
|
+
--mf-code-text: ${codeText};
|
|
794
|
+
--mf-font-family: ${font};
|
|
795
|
+
--mf-font-mono: ${fontMono};
|
|
796
|
+
}
|
|
797
|
+
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; }
|
|
798
|
+
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
799
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-primary-dark); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
800
|
+
h1 { font-size: 2.2rem; color: var(--mf-primary-dark); border-bottom: 2.5px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
801
|
+
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
|
|
802
|
+
h3 { font-size: 1.3rem; color: var(--mf-primary-dark); }
|
|
803
|
+
h4 { font-size: 1.1rem; color: var(--mf-primary-dark); }
|
|
804
|
+
h5 { font-size: 1.0rem; color: var(--mf-primary-dark); }
|
|
805
|
+
h6 { font-size: 0.9rem; color: var(--mf-primary-dark); }
|
|
806
|
+
p { margin: 0.8rem 0; }
|
|
807
|
+
${theme.customCss || ""}
|
|
808
|
+
`;
|
|
809
|
+
}
|
|
810
|
+
if (typeof theme === "string" && THEMES[theme]) {
|
|
811
|
+
return THEMES[theme];
|
|
812
|
+
}
|
|
813
|
+
return THEME_CORPORATE;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// src/core/syntax/syntaxHighlighter.ts
|
|
817
|
+
var SYNTAX_COLORS = {
|
|
818
|
+
keyword: "FF7B72",
|
|
819
|
+
// Bright coral-red — keywords (import, def, return...)
|
|
820
|
+
string: "E07C4F",
|
|
821
|
+
// Warm orange — strings (visible on dark bg)
|
|
822
|
+
comment: "8B949E",
|
|
823
|
+
// Muted gray — comments (italic)
|
|
824
|
+
number: "79C0FF",
|
|
825
|
+
// Sky blue — numbers
|
|
826
|
+
boolean: "FF9580",
|
|
827
|
+
// Salmon — true / false / None
|
|
828
|
+
function: "D2A8FF",
|
|
829
|
+
// Soft purple — function names
|
|
830
|
+
type: "7EE787",
|
|
831
|
+
// Bright green — Types / Classes
|
|
832
|
+
operator: "FF7B72",
|
|
833
|
+
// Same as keyword — = + - * / > <
|
|
834
|
+
punctuation: "8B9AC0",
|
|
835
|
+
// Steel blue-gray — () [] {} , . ;
|
|
836
|
+
plain: "E2E8F0"
|
|
837
|
+
// Light gray — identifiers / plain text
|
|
838
|
+
};
|
|
839
|
+
var SYNTAX_COLORS_LIGHT = {
|
|
840
|
+
keyword: "D73A49",
|
|
841
|
+
// Crimson red — keywords
|
|
842
|
+
string: "0A7E5C",
|
|
843
|
+
// Forest teal — strings (readable on white)
|
|
844
|
+
comment: "6A737D",
|
|
845
|
+
// Muted gray — comments
|
|
846
|
+
number: "005CC5",
|
|
847
|
+
// Cobalt blue — numbers
|
|
848
|
+
boolean: "D73A49",
|
|
849
|
+
// Crimson — true/false/None
|
|
850
|
+
function: "6F42C1",
|
|
851
|
+
// Purple — function names
|
|
852
|
+
type: "22863A",
|
|
853
|
+
// Forest green — Types / Classes
|
|
854
|
+
operator: "D73A49",
|
|
855
|
+
// Crimson — operators
|
|
856
|
+
punctuation: "586069",
|
|
857
|
+
// Dark gray — punctuation
|
|
858
|
+
plain: "24292E"
|
|
859
|
+
// Near-black — identifiers
|
|
860
|
+
};
|
|
861
|
+
var SYNTAX_THEMES = {
|
|
862
|
+
"github-dark": SYNTAX_COLORS,
|
|
863
|
+
"dark": SYNTAX_COLORS,
|
|
864
|
+
"github-light": SYNTAX_COLORS_LIGHT,
|
|
865
|
+
"light": SYNTAX_COLORS_LIGHT,
|
|
866
|
+
"dracula": {
|
|
867
|
+
keyword: "FF79C6",
|
|
868
|
+
string: "F1FA8C",
|
|
869
|
+
comment: "6272A4",
|
|
870
|
+
number: "BD93F9",
|
|
871
|
+
boolean: "BD93F9",
|
|
872
|
+
function: "50FA7B",
|
|
873
|
+
type: "8BE9FD",
|
|
874
|
+
operator: "FF79C6",
|
|
875
|
+
punctuation: "F8F8F2",
|
|
876
|
+
plain: "F8F8F2"
|
|
877
|
+
},
|
|
878
|
+
"monokai": {
|
|
879
|
+
keyword: "F92672",
|
|
880
|
+
string: "E6DB74",
|
|
881
|
+
comment: "75715E",
|
|
882
|
+
number: "AE81FF",
|
|
883
|
+
boolean: "AE81FF",
|
|
884
|
+
function: "A6E22E",
|
|
885
|
+
type: "66D9EF",
|
|
886
|
+
operator: "F92672",
|
|
887
|
+
punctuation: "F8F8F2",
|
|
888
|
+
plain: "F8F8F2"
|
|
889
|
+
},
|
|
890
|
+
"nord": {
|
|
891
|
+
keyword: "81A1C1",
|
|
892
|
+
string: "A3BE8C",
|
|
893
|
+
comment: "616E88",
|
|
894
|
+
number: "B48EAD",
|
|
895
|
+
boolean: "81A1C1",
|
|
896
|
+
function: "88C0D0",
|
|
897
|
+
type: "8FBCBB",
|
|
898
|
+
operator: "81A1C1",
|
|
899
|
+
punctuation: "ECEFF4",
|
|
900
|
+
plain: "D8DEE9"
|
|
901
|
+
}
|
|
902
|
+
};
|
|
903
|
+
function getSyntaxPalette(themeName = "github-dark") {
|
|
904
|
+
return SYNTAX_THEMES[themeName.toLowerCase()] || SYNTAX_THEMES["github-dark"];
|
|
905
|
+
}
|
|
906
|
+
var JS_KEYWORDS = /* @__PURE__ */ new Set([
|
|
907
|
+
"import",
|
|
908
|
+
"from",
|
|
909
|
+
"export",
|
|
910
|
+
"default",
|
|
911
|
+
"const",
|
|
912
|
+
"let",
|
|
913
|
+
"var",
|
|
914
|
+
"function",
|
|
915
|
+
"async",
|
|
916
|
+
"await",
|
|
917
|
+
"return",
|
|
918
|
+
"if",
|
|
919
|
+
"else",
|
|
920
|
+
"for",
|
|
921
|
+
"while",
|
|
922
|
+
"switch",
|
|
923
|
+
"case",
|
|
924
|
+
"break",
|
|
925
|
+
"continue",
|
|
926
|
+
"new",
|
|
927
|
+
"this",
|
|
928
|
+
"typeof",
|
|
929
|
+
"instanceof",
|
|
930
|
+
"class",
|
|
931
|
+
"extends",
|
|
932
|
+
"implements",
|
|
933
|
+
"interface",
|
|
934
|
+
"type",
|
|
935
|
+
"enum",
|
|
936
|
+
"as",
|
|
937
|
+
"try",
|
|
938
|
+
"catch",
|
|
939
|
+
"finally",
|
|
940
|
+
"throw",
|
|
941
|
+
"void",
|
|
942
|
+
"yield",
|
|
943
|
+
"static",
|
|
944
|
+
"readonly",
|
|
802
945
|
"private",
|
|
803
946
|
"public",
|
|
804
947
|
"protected"
|
|
@@ -907,298 +1050,122 @@ function tokenizeCodeLine(line, lang = "", theme = "github-dark") {
|
|
|
907
1050
|
var _a;
|
|
908
1051
|
const COLORS = getSyntaxPalette(theme);
|
|
909
1052
|
if (!line) {
|
|
910
|
-
return [{ text: " ", type: "plain", colorHex: COLORS.plain }];
|
|
911
|
-
}
|
|
912
|
-
const normalizedLang = (lang || "").toLowerCase().trim();
|
|
913
|
-
const tokens = [];
|
|
914
|
-
let pos = 0;
|
|
915
|
-
if (line.trimStart().startsWith("//") || line.trimStart().startsWith("#") || line.trimStart().startsWith("--")) {
|
|
916
|
-
const leadWs = ((_a = line.match(/^\s*/)) == null ? void 0 : _a[0]) || "";
|
|
917
|
-
if (leadWs) {
|
|
918
|
-
tokens.push({ text: leadWs, type: "plain", colorHex: COLORS.plain });
|
|
919
|
-
}
|
|
920
|
-
tokens.push({
|
|
921
|
-
text: line.slice(leadWs.length),
|
|
922
|
-
type: "comment",
|
|
923
|
-
colorHex: COLORS.comment,
|
|
924
|
-
italic: true
|
|
925
|
-
});
|
|
926
|
-
return tokens;
|
|
927
|
-
}
|
|
928
|
-
while (pos < line.length) {
|
|
929
|
-
if (/\s/.test(line[pos])) {
|
|
930
|
-
let ws = "";
|
|
931
|
-
while (pos < line.length && /\s/.test(line[pos])) {
|
|
932
|
-
ws += line[pos++];
|
|
933
|
-
}
|
|
934
|
-
tokens.push({ text: ws, type: "plain", colorHex: COLORS.plain });
|
|
935
|
-
continue;
|
|
936
|
-
}
|
|
937
|
-
if (line.slice(pos, pos + 2) === "//") {
|
|
938
|
-
tokens.push({
|
|
939
|
-
text: line.slice(pos),
|
|
940
|
-
type: "comment",
|
|
941
|
-
colorHex: COLORS.comment,
|
|
942
|
-
italic: true
|
|
943
|
-
});
|
|
944
|
-
break;
|
|
945
|
-
}
|
|
946
|
-
if (line[pos] === '"' || line[pos] === "'" || line[pos] === "`") {
|
|
947
|
-
const quote = line[pos];
|
|
948
|
-
let str = quote;
|
|
949
|
-
pos++;
|
|
950
|
-
while (pos < line.length) {
|
|
951
|
-
if (line[pos] === "\\" && pos + 1 < line.length) {
|
|
952
|
-
str += line[pos] + line[pos + 1];
|
|
953
|
-
pos += 2;
|
|
954
|
-
continue;
|
|
955
|
-
}
|
|
956
|
-
str += line[pos];
|
|
957
|
-
if (line[pos] === quote) {
|
|
958
|
-
pos++;
|
|
959
|
-
break;
|
|
960
|
-
}
|
|
961
|
-
pos++;
|
|
962
|
-
}
|
|
963
|
-
tokens.push({ text: str, type: "string", colorHex: COLORS.string });
|
|
964
|
-
continue;
|
|
965
|
-
}
|
|
966
|
-
if (/\d/.test(line[pos])) {
|
|
967
|
-
let num = "";
|
|
968
|
-
while (pos < line.length && /[\d.a-fA-FxX]/.test(line[pos])) {
|
|
969
|
-
num += line[pos++];
|
|
970
|
-
}
|
|
971
|
-
tokens.push({ text: num, type: "number", colorHex: COLORS.number });
|
|
972
|
-
continue;
|
|
973
|
-
}
|
|
974
|
-
if (/[a-zA-Z_$]/.test(line[pos])) {
|
|
975
|
-
let word = "";
|
|
976
|
-
while (pos < line.length && /[a-zA-Z0-9_$]/.test(line[pos])) {
|
|
977
|
-
word += line[pos++];
|
|
978
|
-
}
|
|
979
|
-
if (word === "true" || word === "false" || word === "null" || word === "undefined" || word === "True" || word === "False" || word === "None") {
|
|
980
|
-
tokens.push({ text: word, type: "boolean", colorHex: COLORS.boolean, bold: true });
|
|
981
|
-
continue;
|
|
982
|
-
}
|
|
983
|
-
const isJsKeyword = (!normalizedLang || ["ts", "typescript", "js", "javascript", "tsx", "jsx"].includes(normalizedLang)) && JS_KEYWORDS.has(word);
|
|
984
|
-
const isPyKeyword = ["py", "python"].includes(normalizedLang) && PYTHON_KEYWORDS.has(word);
|
|
985
|
-
const isBashKeyword = ["sh", "bash", "shell", "zsh"].includes(normalizedLang) && BASH_KEYWORDS.has(word);
|
|
986
|
-
const isSqlKeyword = ["sql"].includes(normalizedLang) && SQL_KEYWORDS.has(word.toLowerCase());
|
|
987
|
-
if (isJsKeyword || isPyKeyword || isBashKeyword || isSqlKeyword) {
|
|
988
|
-
tokens.push({ text: word, type: "keyword", colorHex: COLORS.keyword, bold: true });
|
|
989
|
-
continue;
|
|
990
|
-
}
|
|
991
|
-
if (/^[A-Z][a-zA-Z0-9_$]*$/.test(word)) {
|
|
992
|
-
tokens.push({ text: word, type: "type", colorHex: COLORS.type });
|
|
993
|
-
continue;
|
|
994
|
-
}
|
|
995
|
-
let nextNonWs = pos;
|
|
996
|
-
while (nextNonWs < line.length && /\s/.test(line[nextNonWs])) {
|
|
997
|
-
nextNonWs++;
|
|
998
|
-
}
|
|
999
|
-
if (line[nextNonWs] === "(") {
|
|
1000
|
-
tokens.push({ text: word, type: "function", colorHex: COLORS.function });
|
|
1001
|
-
continue;
|
|
1002
|
-
}
|
|
1003
|
-
tokens.push({ text: word, type: "plain", colorHex: COLORS.plain });
|
|
1004
|
-
continue;
|
|
1005
|
-
}
|
|
1006
|
-
const char = line[pos++];
|
|
1007
|
-
if (["=", "+", "-", "*", "/", "!", ">", "<", "&", "|", "?", ":"].includes(char)) {
|
|
1008
|
-
tokens.push({ text: char, type: "operator", colorHex: COLORS.operator });
|
|
1009
|
-
} else {
|
|
1010
|
-
tokens.push({ text: char, type: "punctuation", colorHex: COLORS.punctuation });
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
return tokens;
|
|
1014
|
-
}
|
|
1015
|
-
function highlightCodeToHtml(code, lang = "", theme = "github-dark") {
|
|
1016
|
-
const lines = (code || "").split("\n");
|
|
1017
|
-
const htmlLines = lines.map((line) => {
|
|
1018
|
-
const tokens = tokenizeCodeLine(line, lang, theme);
|
|
1019
|
-
return tokens.map((t) => {
|
|
1020
|
-
const escaped = t.text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1021
|
-
if (t.type === "plain") return escaped;
|
|
1022
|
-
return `<span style="color: #${t.colorHex};${t.bold ? " font-weight: bold;" : ""}${t.italic ? " font-style: italic;" : ""}">${escaped}</span>`;
|
|
1023
|
-
}).join("");
|
|
1024
|
-
});
|
|
1025
|
-
return htmlLines.join("\n");
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
// src/core/mermaid/mermaidRenderer.ts
|
|
1029
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
1030
|
-
import * as fs4 from "fs";
|
|
1031
|
-
import * as os2 from "os";
|
|
1032
|
-
import * as path6 from "path";
|
|
1033
|
-
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1034
|
-
|
|
1035
|
-
// src/core/pdf/pdfBuilder.ts
|
|
1036
|
-
import * as fs3 from "fs";
|
|
1037
|
-
import * as path5 from "path";
|
|
1038
|
-
import * as os from "os";
|
|
1039
|
-
import { pathToFileURL } from "url";
|
|
1040
|
-
import { spawnSync } from "child_process";
|
|
1041
|
-
|
|
1042
|
-
// src/core/html/htmlBuilder.ts
|
|
1043
|
-
import * as fs2 from "fs";
|
|
1044
|
-
import * as path4 from "path";
|
|
1045
|
-
|
|
1046
|
-
// src/core/html/htmlThemes.ts
|
|
1047
|
-
var THEME_COMPONENTS = `
|
|
1048
|
-
/* Fallback CSS variables \u2014 overridden by each named theme's :root block */
|
|
1049
|
-
:root {
|
|
1050
|
-
--mf-bg: #ffffff;
|
|
1051
|
-
--mf-text: #0f172a;
|
|
1052
|
-
--mf-text-muted: #64748b;
|
|
1053
|
-
--mf-primary: #33CDCF;
|
|
1054
|
-
--mf-primary-dark: #009DA0;
|
|
1055
|
-
--mf-primary-light: #ECFDFD;
|
|
1056
|
-
--mf-border: #e2e8f0;
|
|
1057
|
-
--mf-card-bg: #f8fafc;
|
|
1058
|
-
--mf-code-bg: #0f172a;
|
|
1059
|
-
--mf-code-text: #f8fafc;
|
|
1060
|
-
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1061
|
-
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
/* Document header */
|
|
1065
|
-
.document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
|
|
1066
|
-
.document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
|
|
1067
|
-
.document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
1068
|
-
.document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
|
|
1069
|
-
|
|
1070
|
-
/* Table of Contents */
|
|
1071
|
-
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
|
|
1072
|
-
.table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
1073
|
-
.table-of-contents ul { list-style: none; padding: 0; margin: 0; }
|
|
1074
|
-
.table-of-contents li { padding: 0.25rem 0; }
|
|
1075
|
-
.table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
|
|
1076
|
-
.table-of-contents a:hover { text-decoration: underline; }
|
|
1077
|
-
|
|
1078
|
-
/* Links */
|
|
1079
|
-
a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
|
|
1080
|
-
a:hover { text-decoration: underline; }
|
|
1081
|
-
|
|
1082
|
-
/* Blockquote */
|
|
1083
|
-
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; }
|
|
1084
|
-
|
|
1085
|
-
/* Callout / Alert Boxes */
|
|
1086
|
-
.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; }
|
|
1087
|
-
.callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
|
|
1088
|
-
.callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1089
|
-
.callout-NOTE .callout-title { color: #009DA0; }
|
|
1090
|
-
.callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1091
|
-
.callout-TIP .callout-title { color: #10b981; }
|
|
1092
|
-
.callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1093
|
-
.callout-WARNING .callout-title { color: #f59e0b; }
|
|
1094
|
-
.callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1095
|
-
.callout-CAUTION .callout-title { color: #ef4444; }
|
|
1096
|
-
.callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
1097
|
-
.callout-IMPORTANT .callout-title { color: #8b5cf6; }
|
|
1098
|
-
|
|
1099
|
-
/* Inline Code */
|
|
1100
|
-
code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
|
|
1101
|
-
|
|
1102
|
-
/* Code Blocks */
|
|
1103
|
-
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; }
|
|
1104
|
-
pre code { background-color: transparent; color: inherit; padding: 0; }
|
|
1105
|
-
|
|
1106
|
-
/* Tables */
|
|
1107
|
-
table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
|
|
1108
|
-
th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
|
|
1109
|
-
th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
|
|
1110
|
-
tr:nth-child(even) { background-color: var(--mf-card-bg); }
|
|
1111
|
-
|
|
1112
|
-
/* Images */
|
|
1113
|
-
img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
|
|
1114
|
-
|
|
1115
|
-
/* Dividers */
|
|
1116
|
-
hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
|
|
1117
|
-
|
|
1118
|
-
/* Print / PDF */
|
|
1119
|
-
@media print {
|
|
1120
|
-
body { padding: 0; }
|
|
1121
|
-
.document-container { max-width: 100%; }
|
|
1122
|
-
pre, table, blockquote, .callout { break-inside: avoid; }
|
|
1123
|
-
/* Remove scrollbars \u2014 PDF has no scrolling */
|
|
1124
|
-
pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
|
|
1125
|
-
}
|
|
1126
|
-
`;
|
|
1127
|
-
var THEME_CORPORATE = `
|
|
1128
|
-
:root {
|
|
1129
|
-
--mf-bg: #ffffff;
|
|
1130
|
-
--mf-text: #0f172a;
|
|
1131
|
-
--mf-text-muted: #64748b;
|
|
1132
|
-
--mf-primary: #33CDCF;
|
|
1133
|
-
--mf-primary-dark: #009DA0;
|
|
1134
|
-
--mf-primary-light: #ECFDFD;
|
|
1135
|
-
--mf-border: #e2e8f0;
|
|
1136
|
-
--mf-card-bg: #f8fafc;
|
|
1137
|
-
--mf-code-bg: #0f172a;
|
|
1138
|
-
--mf-code-text: #f8fafc;
|
|
1139
|
-
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1140
|
-
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
1141
|
-
}
|
|
1142
|
-
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; }
|
|
1143
|
-
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
1144
|
-
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; }
|
|
1145
|
-
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
1146
|
-
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
|
|
1147
|
-
h3 { font-size: 1.3rem; }
|
|
1148
|
-
h4 { font-size: 1.1rem; }
|
|
1149
|
-
p { margin: 0.8rem 0; }
|
|
1150
|
-
`;
|
|
1151
|
-
var THEMES = {
|
|
1152
|
-
corporate: THEME_CORPORATE,
|
|
1153
|
-
default: THEME_CORPORATE
|
|
1154
|
-
};
|
|
1155
|
-
function generateThemeCss(theme) {
|
|
1156
|
-
if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
|
|
1157
|
-
return THEME_CORPORATE;
|
|
1053
|
+
return [{ text: " ", type: "plain", colorHex: COLORS.plain }];
|
|
1158
1054
|
}
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
--mf-bg: ${bg};
|
|
1175
|
-
--mf-text: ${text};
|
|
1176
|
-
--mf-text-muted: ${textMuted};
|
|
1177
|
-
--mf-primary: ${primary};
|
|
1178
|
-
--mf-primary-dark: ${primaryDark};
|
|
1179
|
-
--mf-primary-light: ${primaryLight};
|
|
1180
|
-
--mf-border: ${border};
|
|
1181
|
-
--mf-card-bg: ${cardBg};
|
|
1182
|
-
--mf-code-bg: ${codeBg};
|
|
1183
|
-
--mf-code-text: ${codeText};
|
|
1184
|
-
--mf-font-family: ${font};
|
|
1185
|
-
--mf-font-mono: ${fontMono};
|
|
1186
|
-
}
|
|
1187
|
-
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; }
|
|
1188
|
-
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
1189
|
-
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; }
|
|
1190
|
-
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
1191
|
-
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
|
|
1192
|
-
h3 { font-size: 1.3rem; }
|
|
1193
|
-
h4 { font-size: 1.1rem; }
|
|
1194
|
-
p { margin: 0.8rem 0; }
|
|
1195
|
-
${theme.customCss || ""}
|
|
1196
|
-
`;
|
|
1055
|
+
const normalizedLang = (lang || "").toLowerCase().trim();
|
|
1056
|
+
const tokens = [];
|
|
1057
|
+
let pos = 0;
|
|
1058
|
+
if (line.trimStart().startsWith("//") || line.trimStart().startsWith("#") || line.trimStart().startsWith("--")) {
|
|
1059
|
+
const leadWs = ((_a = line.match(/^\s*/)) == null ? void 0 : _a[0]) || "";
|
|
1060
|
+
if (leadWs) {
|
|
1061
|
+
tokens.push({ text: leadWs, type: "plain", colorHex: COLORS.plain });
|
|
1062
|
+
}
|
|
1063
|
+
tokens.push({
|
|
1064
|
+
text: line.slice(leadWs.length),
|
|
1065
|
+
type: "comment",
|
|
1066
|
+
colorHex: COLORS.comment,
|
|
1067
|
+
italic: true
|
|
1068
|
+
});
|
|
1069
|
+
return tokens;
|
|
1197
1070
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1071
|
+
while (pos < line.length) {
|
|
1072
|
+
if (/\s/.test(line[pos])) {
|
|
1073
|
+
let ws = "";
|
|
1074
|
+
while (pos < line.length && /\s/.test(line[pos])) {
|
|
1075
|
+
ws += line[pos++];
|
|
1076
|
+
}
|
|
1077
|
+
tokens.push({ text: ws, type: "plain", colorHex: COLORS.plain });
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
if (line.slice(pos, pos + 2) === "//") {
|
|
1081
|
+
tokens.push({
|
|
1082
|
+
text: line.slice(pos),
|
|
1083
|
+
type: "comment",
|
|
1084
|
+
colorHex: COLORS.comment,
|
|
1085
|
+
italic: true
|
|
1086
|
+
});
|
|
1087
|
+
break;
|
|
1088
|
+
}
|
|
1089
|
+
if (line[pos] === '"' || line[pos] === "'" || line[pos] === "`") {
|
|
1090
|
+
const quote = line[pos];
|
|
1091
|
+
let str = quote;
|
|
1092
|
+
pos++;
|
|
1093
|
+
while (pos < line.length) {
|
|
1094
|
+
if (line[pos] === "\\" && pos + 1 < line.length) {
|
|
1095
|
+
str += line[pos] + line[pos + 1];
|
|
1096
|
+
pos += 2;
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
str += line[pos];
|
|
1100
|
+
if (line[pos] === quote) {
|
|
1101
|
+
pos++;
|
|
1102
|
+
break;
|
|
1103
|
+
}
|
|
1104
|
+
pos++;
|
|
1105
|
+
}
|
|
1106
|
+
tokens.push({ text: str, type: "string", colorHex: COLORS.string });
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1109
|
+
if (/\d/.test(line[pos])) {
|
|
1110
|
+
let num = "";
|
|
1111
|
+
while (pos < line.length && /[\d.a-fA-FxX]/.test(line[pos])) {
|
|
1112
|
+
num += line[pos++];
|
|
1113
|
+
}
|
|
1114
|
+
tokens.push({ text: num, type: "number", colorHex: COLORS.number });
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
1117
|
+
if (/[a-zA-Z_$]/.test(line[pos])) {
|
|
1118
|
+
let word = "";
|
|
1119
|
+
while (pos < line.length && /[a-zA-Z0-9_$]/.test(line[pos])) {
|
|
1120
|
+
word += line[pos++];
|
|
1121
|
+
}
|
|
1122
|
+
if (word === "true" || word === "false" || word === "null" || word === "undefined" || word === "True" || word === "False" || word === "None") {
|
|
1123
|
+
tokens.push({ text: word, type: "boolean", colorHex: COLORS.boolean, bold: true });
|
|
1124
|
+
continue;
|
|
1125
|
+
}
|
|
1126
|
+
const isJsKeyword = (!normalizedLang || ["ts", "typescript", "js", "javascript", "tsx", "jsx"].includes(normalizedLang)) && JS_KEYWORDS.has(word);
|
|
1127
|
+
const isPyKeyword = ["py", "python"].includes(normalizedLang) && PYTHON_KEYWORDS.has(word);
|
|
1128
|
+
const isBashKeyword = ["sh", "bash", "shell", "zsh"].includes(normalizedLang) && BASH_KEYWORDS.has(word);
|
|
1129
|
+
const isSqlKeyword = ["sql"].includes(normalizedLang) && SQL_KEYWORDS.has(word.toLowerCase());
|
|
1130
|
+
if (isJsKeyword || isPyKeyword || isBashKeyword || isSqlKeyword) {
|
|
1131
|
+
tokens.push({ text: word, type: "keyword", colorHex: COLORS.keyword, bold: true });
|
|
1132
|
+
continue;
|
|
1133
|
+
}
|
|
1134
|
+
if (/^[A-Z][a-zA-Z0-9_$]*$/.test(word)) {
|
|
1135
|
+
tokens.push({ text: word, type: "type", colorHex: COLORS.type });
|
|
1136
|
+
continue;
|
|
1137
|
+
}
|
|
1138
|
+
let nextNonWs = pos;
|
|
1139
|
+
while (nextNonWs < line.length && /\s/.test(line[nextNonWs])) {
|
|
1140
|
+
nextNonWs++;
|
|
1141
|
+
}
|
|
1142
|
+
if (line[nextNonWs] === "(") {
|
|
1143
|
+
tokens.push({ text: word, type: "function", colorHex: COLORS.function });
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
tokens.push({ text: word, type: "plain", colorHex: COLORS.plain });
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
const char = line[pos++];
|
|
1150
|
+
if (["=", "+", "-", "*", "/", "!", ">", "<", "&", "|", "?", ":"].includes(char)) {
|
|
1151
|
+
tokens.push({ text: char, type: "operator", colorHex: COLORS.operator });
|
|
1152
|
+
} else {
|
|
1153
|
+
tokens.push({ text: char, type: "punctuation", colorHex: COLORS.punctuation });
|
|
1154
|
+
}
|
|
1200
1155
|
}
|
|
1201
|
-
return
|
|
1156
|
+
return tokens;
|
|
1157
|
+
}
|
|
1158
|
+
function highlightCodeToHtml(code, lang = "", theme = "github-dark") {
|
|
1159
|
+
const lines = (code || "").split("\n");
|
|
1160
|
+
const htmlLines = lines.map((line) => {
|
|
1161
|
+
const tokens = tokenizeCodeLine(line, lang, theme);
|
|
1162
|
+
return tokens.map((t) => {
|
|
1163
|
+
const escaped = t.text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1164
|
+
if (t.type === "plain") return escaped;
|
|
1165
|
+
return `<span style="color: #${t.colorHex};${t.bold ? " font-weight: bold;" : ""}${t.italic ? " font-style: italic;" : ""}">${escaped}</span>`;
|
|
1166
|
+
}).join("");
|
|
1167
|
+
});
|
|
1168
|
+
return htmlLines.join("\n");
|
|
1202
1169
|
}
|
|
1203
1170
|
|
|
1204
1171
|
// src/config/resolveConfig.ts
|
|
@@ -1245,15 +1212,45 @@ function formatMarginCss(margin, defaultCss = "2.5cm") {
|
|
|
1245
1212
|
if (/^[0-9.]+$/.test(str)) return `${str}pt`;
|
|
1246
1213
|
return str;
|
|
1247
1214
|
}
|
|
1248
|
-
function replaceDocumentTokens(template = "", meta) {
|
|
1249
|
-
|
|
1215
|
+
function replaceDocumentTokens(template = "", meta = {}) {
|
|
1216
|
+
if (!template) return "";
|
|
1217
|
+
const currentYear = meta.year ? String(meta.year) : (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1218
|
+
const tokenMap = {
|
|
1219
|
+
title: meta.title ? String(meta.title) : "",
|
|
1220
|
+
subtitle: meta.subtitle ? String(meta.subtitle) : "",
|
|
1221
|
+
author: meta.author ? Array.isArray(meta.author) ? meta.author.join(", ") : String(meta.author) : "",
|
|
1222
|
+
version: meta.version ? String(meta.version) : "",
|
|
1223
|
+
date: meta.date ? String(meta.date) : "",
|
|
1224
|
+
company: meta.company ? String(meta.company) : "",
|
|
1225
|
+
year: currentYear
|
|
1226
|
+
};
|
|
1227
|
+
if (meta.metadata && typeof meta.metadata === "object") {
|
|
1228
|
+
for (const [key, val] of Object.entries(meta.metadata)) {
|
|
1229
|
+
if (val !== void 0 && val !== null) {
|
|
1230
|
+
tokenMap[key.toLowerCase()] = String(val);
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
for (const [key, val] of Object.entries(meta)) {
|
|
1235
|
+
if (val !== void 0 && val !== null && typeof val !== "object") {
|
|
1236
|
+
tokenMap[key.toLowerCase()] = String(val);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
return template.replace(/\{([a-zA-Z0-9_\-]+)\}/gi, (match, tokenKey) => {
|
|
1240
|
+
const lowerKey = tokenKey.toLowerCase();
|
|
1241
|
+
if (lowerKey in tokenMap) {
|
|
1242
|
+
return tokenMap[lowerKey];
|
|
1243
|
+
}
|
|
1244
|
+
return match;
|
|
1245
|
+
});
|
|
1250
1246
|
}
|
|
1251
|
-
function normalizeWatermark(rawWatermark) {
|
|
1247
|
+
function normalizeWatermark(rawWatermark, tokens) {
|
|
1252
1248
|
if (!rawWatermark) {
|
|
1253
1249
|
return void 0;
|
|
1254
1250
|
}
|
|
1255
1251
|
if (typeof rawWatermark === "string") {
|
|
1256
|
-
|
|
1252
|
+
let text = rawWatermark.trim();
|
|
1253
|
+
if (tokens) text = replaceDocumentTokens(text, tokens);
|
|
1257
1254
|
if (!text) return void 0;
|
|
1258
1255
|
return {
|
|
1259
1256
|
text,
|
|
@@ -1266,8 +1263,10 @@ function normalizeWatermark(rawWatermark) {
|
|
|
1266
1263
|
}
|
|
1267
1264
|
if (typeof rawWatermark === "object") {
|
|
1268
1265
|
if (!rawWatermark.text || !rawWatermark.text.trim()) return void 0;
|
|
1266
|
+
let text = rawWatermark.text.trim();
|
|
1267
|
+
if (tokens) text = replaceDocumentTokens(text, tokens);
|
|
1269
1268
|
return {
|
|
1270
|
-
text
|
|
1269
|
+
text,
|
|
1271
1270
|
color: rawWatermark.color || "#94a3b8",
|
|
1272
1271
|
opacity: typeof rawWatermark.opacity === "number" ? rawWatermark.opacity : 0.08,
|
|
1273
1272
|
fontSize: rawWatermark.fontSize || 54,
|
|
@@ -1383,6 +1382,174 @@ function normalizeSignatures(raw, meta = {}) {
|
|
|
1383
1382
|
spacingBeforeTwip
|
|
1384
1383
|
};
|
|
1385
1384
|
}
|
|
1385
|
+
function normalizeCoverPage(rawCover, tokenCtx = {}) {
|
|
1386
|
+
if (!rawCover) return void 0;
|
|
1387
|
+
const cfg = typeof rawCover === "object" ? rawCover : {};
|
|
1388
|
+
if (cfg.enabled === false) return void 0;
|
|
1389
|
+
const preset = cfg.preset || "modern";
|
|
1390
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title ? String(tokenCtx.title) : "Document Title";
|
|
1391
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle ? String(tokenCtx.subtitle) : void 0;
|
|
1392
|
+
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author ? String(tokenCtx.author) : void 0;
|
|
1393
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company ? String(tokenCtx.company) : void 0;
|
|
1394
|
+
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version ? String(tokenCtx.version) : void 0;
|
|
1395
|
+
let dateStr;
|
|
1396
|
+
if (typeof cfg.date === "string") {
|
|
1397
|
+
dateStr = replaceDocumentTokens(cfg.date, tokenCtx);
|
|
1398
|
+
} else if (cfg.date === true) {
|
|
1399
|
+
dateStr = tokenCtx.date ? String(tokenCtx.date) : (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1400
|
+
} else {
|
|
1401
|
+
dateStr = tokenCtx.date ? String(tokenCtx.date) : void 0;
|
|
1402
|
+
}
|
|
1403
|
+
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1404
|
+
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1405
|
+
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1406
|
+
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1407
|
+
const logoWidth = cfg.logoWidth;
|
|
1408
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1409
|
+
const backgroundColor = typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1410
|
+
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1411
|
+
const titleColor = typeof cfg.titleColor === "string" ? cfg.titleColor : void 0;
|
|
1412
|
+
const subtitleColor = typeof cfg.subtitleColor === "string" ? cfg.subtitleColor : void 0;
|
|
1413
|
+
const accentColor = typeof cfg.accentColor === "string" ? cfg.accentColor : void 0;
|
|
1414
|
+
const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
|
|
1415
|
+
const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
|
|
1416
|
+
const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
|
|
1417
|
+
const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
|
|
1418
|
+
const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
|
|
1419
|
+
let socialMap;
|
|
1420
|
+
if (cfg.social && typeof cfg.social === "object") {
|
|
1421
|
+
socialMap = {};
|
|
1422
|
+
for (const [k, v] of Object.entries(cfg.social)) {
|
|
1423
|
+
if (typeof v === "string") {
|
|
1424
|
+
socialMap[k] = replaceDocumentTokens(v, tokenCtx);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1429
|
+
const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : void 0;
|
|
1430
|
+
return {
|
|
1431
|
+
enabled: true,
|
|
1432
|
+
preset,
|
|
1433
|
+
title,
|
|
1434
|
+
subtitle,
|
|
1435
|
+
author,
|
|
1436
|
+
company,
|
|
1437
|
+
version,
|
|
1438
|
+
date: dateStr,
|
|
1439
|
+
badge,
|
|
1440
|
+
badgeColor,
|
|
1441
|
+
badgeTextColor,
|
|
1442
|
+
logo,
|
|
1443
|
+
logoWidth,
|
|
1444
|
+
bgGradient,
|
|
1445
|
+
backgroundColor,
|
|
1446
|
+
textColor,
|
|
1447
|
+
titleColor,
|
|
1448
|
+
subtitleColor,
|
|
1449
|
+
accentColor,
|
|
1450
|
+
footerText,
|
|
1451
|
+
address,
|
|
1452
|
+
email,
|
|
1453
|
+
phone,
|
|
1454
|
+
website,
|
|
1455
|
+
social: socialMap,
|
|
1456
|
+
copyright
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
function normalizeBackCover(rawBack, tokenCtx = {}) {
|
|
1460
|
+
if (!rawBack) return void 0;
|
|
1461
|
+
const cfg = typeof rawBack === "object" ? rawBack : {};
|
|
1462
|
+
if (cfg.enabled === false) return void 0;
|
|
1463
|
+
const preset = cfg.preset || "modern";
|
|
1464
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : "Thank You";
|
|
1465
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : void 0;
|
|
1466
|
+
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author ? String(tokenCtx.author) : void 0;
|
|
1467
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company ? String(tokenCtx.company) : void 0;
|
|
1468
|
+
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version ? String(tokenCtx.version) : void 0;
|
|
1469
|
+
const date = typeof cfg.date === "string" ? replaceDocumentTokens(cfg.date, tokenCtx) : tokenCtx.date ? String(tokenCtx.date) : void 0;
|
|
1470
|
+
const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
|
|
1471
|
+
const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
|
|
1472
|
+
const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
|
|
1473
|
+
const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
|
|
1474
|
+
let socialMap;
|
|
1475
|
+
if (cfg.social && typeof cfg.social === "object") {
|
|
1476
|
+
socialMap = {};
|
|
1477
|
+
for (const [k, v] of Object.entries(cfg.social)) {
|
|
1478
|
+
if (typeof v === "string") {
|
|
1479
|
+
socialMap[k] = replaceDocumentTokens(v, tokenCtx);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1484
|
+
const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : company ? `Copyright (c) ${currentYear} ${company}. All Rights Reserved.` : void 0;
|
|
1485
|
+
const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
|
|
1486
|
+
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1487
|
+
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1488
|
+
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1489
|
+
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1490
|
+
const logoWidth = cfg.logoWidth;
|
|
1491
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1492
|
+
const backgroundColor = typeof cfg.backgroundColor === "string" ? cfg.backgroundColor : void 0;
|
|
1493
|
+
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1494
|
+
const titleColor = typeof cfg.titleColor === "string" ? cfg.titleColor : void 0;
|
|
1495
|
+
const subtitleColor = typeof cfg.subtitleColor === "string" ? cfg.subtitleColor : void 0;
|
|
1496
|
+
const accentColor = typeof cfg.accentColor === "string" ? cfg.accentColor : void 0;
|
|
1497
|
+
return {
|
|
1498
|
+
enabled: true,
|
|
1499
|
+
preset,
|
|
1500
|
+
title,
|
|
1501
|
+
subtitle,
|
|
1502
|
+
author,
|
|
1503
|
+
company,
|
|
1504
|
+
version,
|
|
1505
|
+
date,
|
|
1506
|
+
address,
|
|
1507
|
+
email,
|
|
1508
|
+
phone,
|
|
1509
|
+
website,
|
|
1510
|
+
social: socialMap,
|
|
1511
|
+
copyright,
|
|
1512
|
+
footerText,
|
|
1513
|
+
badge,
|
|
1514
|
+
badgeColor,
|
|
1515
|
+
badgeTextColor,
|
|
1516
|
+
logo,
|
|
1517
|
+
logoWidth,
|
|
1518
|
+
bgGradient,
|
|
1519
|
+
backgroundColor,
|
|
1520
|
+
textColor,
|
|
1521
|
+
titleColor,
|
|
1522
|
+
subtitleColor,
|
|
1523
|
+
accentColor
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
function normalizeNumberHeadings(raw) {
|
|
1527
|
+
if (raw === void 0 || raw === false) return void 0;
|
|
1528
|
+
if (raw === true) {
|
|
1529
|
+
return { enabled: true, depth: 3, skipH1: false, prefix: "" };
|
|
1530
|
+
}
|
|
1531
|
+
if (typeof raw === "object") {
|
|
1532
|
+
const obj = raw;
|
|
1533
|
+
if (obj.enabled === false) return void 0;
|
|
1534
|
+
return {
|
|
1535
|
+
enabled: true,
|
|
1536
|
+
depth: obj.depth ?? 3,
|
|
1537
|
+
skipH1: obj.skipH1 ?? false,
|
|
1538
|
+
prefix: obj.prefix ?? ""
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
return void 0;
|
|
1542
|
+
}
|
|
1543
|
+
function normalizeSecurity(raw) {
|
|
1544
|
+
if (!raw) return void 0;
|
|
1545
|
+
const sec = raw;
|
|
1546
|
+
if (!sec.userPassword && !sec.ownerPassword && !sec.permissions) return void 0;
|
|
1547
|
+
return {
|
|
1548
|
+
userPassword: sec.userPassword,
|
|
1549
|
+
ownerPassword: sec.ownerPassword,
|
|
1550
|
+
permissions: sec.permissions
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1386
1553
|
function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
1387
1554
|
const configMeta = userConfig.metadata || {};
|
|
1388
1555
|
const mergedMeta = { ...configMeta, ...frontmatter };
|
|
@@ -1393,7 +1560,15 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1393
1560
|
const version = mergedMeta.version || void 0;
|
|
1394
1561
|
const company = mergedMeta.company || void 0;
|
|
1395
1562
|
const lang = mergedMeta.lang || "en";
|
|
1396
|
-
const tokenContext = {
|
|
1563
|
+
const tokenContext = {
|
|
1564
|
+
...mergedMeta,
|
|
1565
|
+
title,
|
|
1566
|
+
subtitle,
|
|
1567
|
+
author,
|
|
1568
|
+
version,
|
|
1569
|
+
date,
|
|
1570
|
+
company
|
|
1571
|
+
};
|
|
1397
1572
|
const theme = mergedMeta.theme || userConfig.theme || DEFAULT_CONFIG.theme;
|
|
1398
1573
|
const orientation = mergedMeta.orientation || userConfig.orientation || DEFAULT_CONFIG.orientation;
|
|
1399
1574
|
const paperSize = mergedMeta.paperSize || userConfig.paperSize || DEFAULT_CONFIG.paperSize;
|
|
@@ -1422,9 +1597,18 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1422
1597
|
const footer = normalizeHeaderFooter(rawFooter, tokenContext);
|
|
1423
1598
|
const toc = typeof mergedMeta.toc === "boolean" ? mergedMeta.toc : typeof userConfig.toc === "boolean" ? userConfig.toc : DEFAULT_CONFIG.toc;
|
|
1424
1599
|
const rawWatermark = mergedMeta.watermark !== void 0 ? mergedMeta.watermark : userConfig.watermark !== void 0 ? userConfig.watermark : DEFAULT_CONFIG.watermark;
|
|
1425
|
-
const watermark = normalizeWatermark(rawWatermark);
|
|
1600
|
+
const watermark = normalizeWatermark(rawWatermark, tokenContext);
|
|
1426
1601
|
const rawSignatures = mergedMeta.signatures || userConfig.signatures;
|
|
1427
1602
|
const signatures = normalizeSignatures(rawSignatures, tokenContext);
|
|
1603
|
+
const rawCover = mergedMeta.coverPage !== void 0 ? mergedMeta.coverPage : userConfig.coverPage;
|
|
1604
|
+
const coverPage = normalizeCoverPage(rawCover, tokenContext);
|
|
1605
|
+
const rawBack = mergedMeta.backCover !== void 0 ? mergedMeta.backCover : userConfig.backCover;
|
|
1606
|
+
const backCover = normalizeBackCover(rawBack, tokenContext);
|
|
1607
|
+
const rawNumberHeadings = mergedMeta.numberHeadings !== void 0 ? mergedMeta.numberHeadings : userConfig.numberHeadings;
|
|
1608
|
+
const numberHeadings = normalizeNumberHeadings(rawNumberHeadings);
|
|
1609
|
+
const rawSecurity = mergedMeta.security || userConfig.security;
|
|
1610
|
+
const security = normalizeSecurity(rawSecurity);
|
|
1611
|
+
const math = mergedMeta.math !== false && userConfig.math !== false;
|
|
1428
1612
|
const cssList = [];
|
|
1429
1613
|
const addCss = (item) => {
|
|
1430
1614
|
if (!item) return;
|
|
@@ -1454,6 +1638,11 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1454
1638
|
toc,
|
|
1455
1639
|
signatures,
|
|
1456
1640
|
watermark,
|
|
1641
|
+
coverPage,
|
|
1642
|
+
backCover,
|
|
1643
|
+
numberHeadings,
|
|
1644
|
+
security,
|
|
1645
|
+
math,
|
|
1457
1646
|
css: cssList,
|
|
1458
1647
|
embedImages,
|
|
1459
1648
|
bundleHtml,
|
|
@@ -1461,11 +1650,50 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1461
1650
|
};
|
|
1462
1651
|
}
|
|
1463
1652
|
|
|
1653
|
+
// src/core/math/mathRenderer.ts
|
|
1654
|
+
import katex from "katex";
|
|
1655
|
+
function renderMathToHtml(latex, displayMode = false) {
|
|
1656
|
+
try {
|
|
1657
|
+
return katex.renderToString(latex.trim(), {
|
|
1658
|
+
displayMode,
|
|
1659
|
+
throwOnError: false,
|
|
1660
|
+
output: "htmlAndMathml",
|
|
1661
|
+
strict: false
|
|
1662
|
+
});
|
|
1663
|
+
} catch {
|
|
1664
|
+
return `<span class="katex-fallback">${latex}</span>`;
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
var KATEX_INLINE_CSS = `
|
|
1668
|
+
.katex { font: normal 1.21em KaTeX_Main, Times New Roman, serif; line-height: 1.2; text-indent: 0; text-rendering: auto; border-color: currentColor; }
|
|
1669
|
+
.katex * { -ms-high-contrast-adjust: none !important; }
|
|
1670
|
+
.katex .katex-html { display: inline-block; }
|
|
1671
|
+
.katex .katex-mathml { clip: rect(1px, 1px, 1px, 1px); border: 0; height: 1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
|
|
1672
|
+
.katex-display { display: block; margin: 1em 0; text-align: center; }
|
|
1673
|
+
.katex-display > .katex { display: inline-block; text-align: initial; }
|
|
1674
|
+
.katex .base { position: relative; white-space: nowrap; width: min-content; }
|
|
1675
|
+
.katex .strut { display: inline-block; }
|
|
1676
|
+
.katex .mord { display: inline-block; }
|
|
1677
|
+
.katex .mbin { display: inline-block; }
|
|
1678
|
+
.katex .mrel { display: inline-block; }
|
|
1679
|
+
.katex .mopen { display: inline-block; }
|
|
1680
|
+
.katex .mclose { display: inline-block; }
|
|
1681
|
+
.katex .mpunct { display: inline-block; }
|
|
1682
|
+
.katex .minner { display: inline-block; }
|
|
1683
|
+
.katex .mop { display: inline-block; }
|
|
1684
|
+
.katex .frac-line { width: 100%; border-bottom-style: solid; }
|
|
1685
|
+
.katex .vlist-t { display: inline-table; table-layout: fixed; }
|
|
1686
|
+
.katex .vlist-r { display: table-row; }
|
|
1687
|
+
.katex .vlist { display: table-cell; vertical-align: bottom; position: relative; }
|
|
1688
|
+
.katex .msupsub { text-align: left; }
|
|
1689
|
+
.katex .sqrt > .root { margin-left: 0.27777778em; margin-right: -0.55555556em; }
|
|
1690
|
+
`;
|
|
1691
|
+
|
|
1464
1692
|
// src/core/html/htmlBuilder.ts
|
|
1465
1693
|
function escapeHtml(str) {
|
|
1466
1694
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1467
1695
|
}
|
|
1468
|
-
async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
1696
|
+
async function renderInlinesToHtml(spans = [], baseDir = process.cwd(), tokens) {
|
|
1469
1697
|
let result = "";
|
|
1470
1698
|
for (const span of spans) {
|
|
1471
1699
|
if (span.type === "image" && span.url) {
|
|
@@ -1479,107 +1707,81 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
|
1479
1707
|
continue;
|
|
1480
1708
|
}
|
|
1481
1709
|
if (span.type === "link" && span.url) {
|
|
1482
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
1710
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1483
1711
|
const title = span.title ? ` title="${escapeHtml(span.title)}"` : "";
|
|
1484
1712
|
result += `<a href="${escapeHtml(span.url)}"${title}>${inner}</a>`;
|
|
1485
1713
|
continue;
|
|
1486
1714
|
}
|
|
1487
1715
|
if (span.type === "bold") {
|
|
1488
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
1716
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1489
1717
|
result += `<strong>${inner}</strong>`;
|
|
1490
1718
|
continue;
|
|
1491
1719
|
}
|
|
1492
1720
|
if (span.type === "italic") {
|
|
1493
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
1721
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1494
1722
|
result += `<em>${inner}</em>`;
|
|
1495
1723
|
continue;
|
|
1496
1724
|
}
|
|
1497
1725
|
if (span.type === "strikethrough") {
|
|
1498
|
-
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir) : escapeHtml(span.content);
|
|
1726
|
+
const inner = span.children ? await renderInlinesToHtml(span.children, baseDir, tokens) : escapeHtml(tokens ? replaceDocumentTokens(span.content, tokens) : span.content);
|
|
1499
1727
|
result += `<del>${inner}</del>`;
|
|
1500
1728
|
continue;
|
|
1501
1729
|
}
|
|
1502
1730
|
if (span.type === "code") {
|
|
1503
1731
|
result += `<code>${escapeHtml(span.content)}</code>`;
|
|
1504
|
-
continue;
|
|
1505
|
-
}
|
|
1506
|
-
if (span.type === "htmlInline") {
|
|
1507
|
-
result += span.content;
|
|
1508
|
-
continue;
|
|
1509
|
-
}
|
|
1510
|
-
result += escapeHtml(span.content);
|
|
1511
|
-
}
|
|
1512
|
-
return result;
|
|
1513
|
-
}
|
|
1514
|
-
async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
1515
|
-
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
1516
|
-
const baseThemeCss = generateThemeCss(resolved.theme);
|
|
1517
|
-
let customCss = "";
|
|
1518
|
-
for (const cssPath of resolved.css) {
|
|
1519
|
-
const fullCssPath = path4.isAbsolute(cssPath) ? cssPath : path4.resolve(baseDir, cssPath);
|
|
1520
|
-
if (fs2.existsSync(fullCssPath)) {
|
|
1521
|
-
customCss += `
|
|
1522
|
-
/* Custom CSS: ${cssPath} */
|
|
1523
|
-
` + fs2.readFileSync(fullCssPath, "utf-8");
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
const inlinedCss = doc.inlinedStyles.join("\n");
|
|
1527
|
-
let bodyHtml = "";
|
|
1528
|
-
if (resolved.title) {
|
|
1529
|
-
bodyHtml += ` <header class="document-header">
|
|
1530
|
-
`;
|
|
1531
|
-
bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
|
|
1532
|
-
`;
|
|
1533
|
-
if (resolved.subtitle) {
|
|
1534
|
-
bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
|
|
1535
|
-
`;
|
|
1536
|
-
}
|
|
1537
|
-
if (resolved.author || resolved.date || resolved.version) {
|
|
1538
|
-
bodyHtml += ` <div class="document-meta">
|
|
1539
|
-
`;
|
|
1540
|
-
if (resolved.author) {
|
|
1541
|
-
bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
|
|
1542
|
-
`;
|
|
1543
|
-
}
|
|
1544
|
-
if (resolved.version) {
|
|
1545
|
-
bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
|
|
1546
|
-
`;
|
|
1547
|
-
}
|
|
1548
|
-
if (resolved.date) {
|
|
1549
|
-
bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
|
|
1550
|
-
`;
|
|
1551
|
-
}
|
|
1552
|
-
bodyHtml += ` </div>
|
|
1553
|
-
`;
|
|
1732
|
+
continue;
|
|
1554
1733
|
}
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
if (resolved.toc && doc.tocEntries.length > 0) {
|
|
1559
|
-
bodyHtml += ` <nav class="table-of-contents">
|
|
1560
|
-
`;
|
|
1561
|
-
bodyHtml += ` <h2>Table of Contents</h2>
|
|
1562
|
-
<ul>
|
|
1563
|
-
`;
|
|
1564
|
-
for (const entry of doc.tocEntries) {
|
|
1565
|
-
const indent = " ".repeat(entry.level);
|
|
1566
|
-
bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
|
|
1567
|
-
`;
|
|
1734
|
+
if (span.type === "mathInline") {
|
|
1735
|
+
result += renderMathToHtml(span.content, false);
|
|
1736
|
+
continue;
|
|
1568
1737
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1738
|
+
if (span.type === "footnoteRef") {
|
|
1739
|
+
const id = escapeHtml(span.footnoteId || span.content);
|
|
1740
|
+
result += `<sup><a href="#fn-${id}" id="fnref-${id}" class="markforge-fnref">[${escapeHtml(span.content)}]</a></sup>`;
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
if (span.type === "htmlInline") {
|
|
1744
|
+
result += span.content;
|
|
1745
|
+
continue;
|
|
1746
|
+
}
|
|
1747
|
+
const content = tokens ? replaceDocumentTokens(span.content, tokens) : span.content;
|
|
1748
|
+
result += escapeHtml(content);
|
|
1572
1749
|
}
|
|
1573
|
-
|
|
1750
|
+
return result;
|
|
1751
|
+
}
|
|
1752
|
+
async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd(), tokens) {
|
|
1753
|
+
let bodyHtml = "";
|
|
1754
|
+
const tokenCtx = tokens || resolved;
|
|
1755
|
+
for (const node of nodes) {
|
|
1574
1756
|
if (node.type === "heading") {
|
|
1575
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1757
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
1576
1758
|
bodyHtml += ` <h${node.level} id="${node.id}">${inner}</h${node.level}>
|
|
1577
1759
|
`;
|
|
1578
1760
|
continue;
|
|
1579
1761
|
}
|
|
1580
1762
|
if (node.type === "paragraph") {
|
|
1581
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1763
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
1582
1764
|
bodyHtml += ` <p>${inner}</p>
|
|
1765
|
+
`;
|
|
1766
|
+
continue;
|
|
1767
|
+
}
|
|
1768
|
+
if (node.type === "mathBlock") {
|
|
1769
|
+
bodyHtml += ` <div class="math-block">${renderMathToHtml(node.text || "", true)}</div>
|
|
1770
|
+
`;
|
|
1771
|
+
continue;
|
|
1772
|
+
}
|
|
1773
|
+
if (node.type === "columns") {
|
|
1774
|
+
const cols = node.columnsCount || 2;
|
|
1775
|
+
const gap = node.columnGap || "1.5rem";
|
|
1776
|
+
let colChildrenHtml = "";
|
|
1777
|
+
for (const col of node.children || []) {
|
|
1778
|
+
const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir, tokenCtx);
|
|
1779
|
+
colChildrenHtml += ` <div class="markforge-col">
|
|
1780
|
+
${colInner} </div>
|
|
1781
|
+
`;
|
|
1782
|
+
}
|
|
1783
|
+
bodyHtml += ` <div class="markforge-columns" style="--cols: ${cols}; --col-gap: ${gap};">
|
|
1784
|
+
${colChildrenHtml} </div>
|
|
1583
1785
|
`;
|
|
1584
1786
|
continue;
|
|
1585
1787
|
}
|
|
@@ -1599,7 +1801,7 @@ ${escapeHtml(node.text || "")}
|
|
|
1599
1801
|
continue;
|
|
1600
1802
|
}
|
|
1601
1803
|
if (node.type === "callout") {
|
|
1602
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1804
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
1603
1805
|
const CALLOUT_STYLES = {
|
|
1604
1806
|
NOTE: { bg: "#ECFDFD", border: "#33CDCF", titleColor: "#009DA0" },
|
|
1605
1807
|
TIP: { bg: "#ecfdf5", border: "#10b981", titleColor: "#10b981" },
|
|
@@ -1619,7 +1821,7 @@ ${escapeHtml(node.text || "")}
|
|
|
1619
1821
|
continue;
|
|
1620
1822
|
}
|
|
1621
1823
|
if (node.type === "blockquote") {
|
|
1622
|
-
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1824
|
+
const inner = await renderInlinesToHtml(node.inlines, baseDir, tokenCtx);
|
|
1623
1825
|
bodyHtml += ` <blockquote>${inner}</blockquote>
|
|
1624
1826
|
`;
|
|
1625
1827
|
continue;
|
|
@@ -1633,7 +1835,7 @@ ${escapeHtml(node.text || "")}
|
|
|
1633
1835
|
for (const cell of row.children || []) {
|
|
1634
1836
|
const tag = cell.isHeader ? "th" : "td";
|
|
1635
1837
|
const align = cell.align ? ` align="${cell.align}"` : "";
|
|
1636
|
-
const inner = await renderInlinesToHtml(cell.inlines, baseDir);
|
|
1838
|
+
const inner = await renderInlinesToHtml(cell.inlines, baseDir, tokenCtx);
|
|
1637
1839
|
bodyHtml += ` <${tag}${align}>${inner}</${tag}>
|
|
1638
1840
|
`;
|
|
1639
1841
|
}
|
|
@@ -1649,7 +1851,7 @@ ${escapeHtml(node.text || "")}
|
|
|
1649
1851
|
bodyHtml += ` <${tag}>
|
|
1650
1852
|
`;
|
|
1651
1853
|
for (const item of node.children) {
|
|
1652
|
-
const inner = await renderInlinesToHtml(item.inlines, baseDir);
|
|
1854
|
+
const inner = await renderInlinesToHtml(item.inlines, baseDir, tokenCtx);
|
|
1653
1855
|
bodyHtml += ` <li>${inner}</li>
|
|
1654
1856
|
`;
|
|
1655
1857
|
}
|
|
@@ -1668,6 +1870,446 @@ ${escapeHtml(node.text || "")}
|
|
|
1668
1870
|
continue;
|
|
1669
1871
|
}
|
|
1670
1872
|
}
|
|
1873
|
+
return bodyHtml;
|
|
1874
|
+
}
|
|
1875
|
+
async function renderCoverPageHtml(cover, baseDir = process.cwd()) {
|
|
1876
|
+
let logoHtml = "";
|
|
1877
|
+
if (cover.logo) {
|
|
1878
|
+
const resolvedLogo = await resolveImage(cover.logo, baseDir);
|
|
1879
|
+
const src = resolvedLogo ? resolvedLogo.dataUri : cover.logo;
|
|
1880
|
+
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;";
|
|
1881
|
+
logoHtml = `<div class="cover-logo"><img src="${src}" alt="Logo" style="${widthStyle} object-fit: contain;" /></div>`;
|
|
1882
|
+
}
|
|
1883
|
+
const badgeHtml = cover.badge ? `<div class="cover-badge" style="${cover.badgeColor ? `background-color: ${cover.badgeColor};` : ""}${cover.badgeTextColor ? `color: ${cover.badgeTextColor};` : ""}">${escapeHtml(cover.badge)}</div>` : "";
|
|
1884
|
+
const titleHtml = `<h1 class="cover-title">${escapeHtml(cover.title)}</h1>`;
|
|
1885
|
+
const subtitleHtml = cover.subtitle ? `<div class="cover-subtitle">${escapeHtml(cover.subtitle)}</div>` : "";
|
|
1886
|
+
const metaItems = [];
|
|
1887
|
+
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>`);
|
|
1888
|
+
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>`);
|
|
1889
|
+
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>`);
|
|
1890
|
+
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>`);
|
|
1891
|
+
const metaHtml = metaItems.length > 0 ? `<div class="cover-meta">${metaItems.join("\n")}</div>` : "";
|
|
1892
|
+
const footerHtml = cover.footerText ? `<div class="cover-footer-text">${escapeHtml(cover.footerText)}</div>` : "";
|
|
1893
|
+
const css = `
|
|
1894
|
+
.markforge-cover {
|
|
1895
|
+
min-height: 100vh;
|
|
1896
|
+
box-sizing: border-box;
|
|
1897
|
+
display: flex;
|
|
1898
|
+
flex-direction: column;
|
|
1899
|
+
justify-content: space-between;
|
|
1900
|
+
padding: 4rem 3.5rem;
|
|
1901
|
+
page-break-after: always;
|
|
1902
|
+
break-after: page;
|
|
1903
|
+
position: relative;
|
|
1904
|
+
z-index: 2;
|
|
1905
|
+
background: ${cover.bgGradient || "#FFFFFF"};
|
|
1906
|
+
-webkit-print-color-adjust: exact;
|
|
1907
|
+
print-color-adjust: exact;
|
|
1908
|
+
color: ${cover.textColor || "#0F172A"};
|
|
1909
|
+
}
|
|
1910
|
+
.markforge-cover.cover-modern {
|
|
1911
|
+
border-top: 8px solid #0D998D;
|
|
1912
|
+
}
|
|
1913
|
+
.markforge-cover.cover-corporate-split {
|
|
1914
|
+
border-left: 12px solid #0D998D;
|
|
1915
|
+
}
|
|
1916
|
+
.markforge-cover.cover-card {
|
|
1917
|
+
background: #F8FAFC;
|
|
1918
|
+
}
|
|
1919
|
+
.cover-top {
|
|
1920
|
+
display: flex;
|
|
1921
|
+
justify-content: space-between;
|
|
1922
|
+
align-items: flex-start;
|
|
1923
|
+
width: 100%;
|
|
1924
|
+
}
|
|
1925
|
+
.cover-badge {
|
|
1926
|
+
display: inline-block;
|
|
1927
|
+
padding: 0.35rem 0.85rem;
|
|
1928
|
+
font-size: 0.78rem;
|
|
1929
|
+
font-weight: 700;
|
|
1930
|
+
letter-spacing: 0.08em;
|
|
1931
|
+
text-transform: uppercase;
|
|
1932
|
+
background-color: #ECFDFD;
|
|
1933
|
+
color: #0D998D;
|
|
1934
|
+
border-radius: 4px;
|
|
1935
|
+
border: 1px solid #33CDCF;
|
|
1936
|
+
}
|
|
1937
|
+
.cover-body {
|
|
1938
|
+
margin: auto 0;
|
|
1939
|
+
}
|
|
1940
|
+
.cover-title {
|
|
1941
|
+
font-size: 2.8rem;
|
|
1942
|
+
font-weight: 800;
|
|
1943
|
+
line-height: 1.15;
|
|
1944
|
+
margin: 0 0 1rem 0;
|
|
1945
|
+
color: inherit;
|
|
1946
|
+
}
|
|
1947
|
+
.cover-subtitle {
|
|
1948
|
+
font-size: 1.35rem;
|
|
1949
|
+
font-weight: 400;
|
|
1950
|
+
color: #64748B;
|
|
1951
|
+
margin: 0 0 2rem 0;
|
|
1952
|
+
line-height: 1.4;
|
|
1953
|
+
}
|
|
1954
|
+
.cover-meta {
|
|
1955
|
+
display: flex;
|
|
1956
|
+
flex-direction: column;
|
|
1957
|
+
gap: 0.5rem;
|
|
1958
|
+
border-top: 1.5px solid #E2E8F0;
|
|
1959
|
+
padding-top: 1.5rem;
|
|
1960
|
+
max-width: 480px;
|
|
1961
|
+
}
|
|
1962
|
+
.cover-meta-item {
|
|
1963
|
+
font-size: 0.92rem;
|
|
1964
|
+
display: flex;
|
|
1965
|
+
gap: 0.75rem;
|
|
1966
|
+
}
|
|
1967
|
+
.cover-meta-label {
|
|
1968
|
+
font-weight: 600;
|
|
1969
|
+
color: #64748B;
|
|
1970
|
+
min-width: 110px;
|
|
1971
|
+
}
|
|
1972
|
+
.cover-meta-value {
|
|
1973
|
+
font-weight: 500;
|
|
1974
|
+
color: #0F172A;
|
|
1975
|
+
}
|
|
1976
|
+
.cover-bottom {
|
|
1977
|
+
display: flex;
|
|
1978
|
+
justify-content: space-between;
|
|
1979
|
+
align-items: flex-end;
|
|
1980
|
+
font-size: 0.82rem;
|
|
1981
|
+
color: #94A3B8;
|
|
1982
|
+
}
|
|
1983
|
+
@media print {
|
|
1984
|
+
.markforge-cover {
|
|
1985
|
+
page-break-after: always;
|
|
1986
|
+
break-after: page;
|
|
1987
|
+
height: 100vh;
|
|
1988
|
+
min-height: 100vh;
|
|
1989
|
+
max-height: 100vh;
|
|
1990
|
+
box-sizing: border-box;
|
|
1991
|
+
overflow: hidden;
|
|
1992
|
+
margin: 0;
|
|
1993
|
+
-webkit-print-color-adjust: exact;
|
|
1994
|
+
print-color-adjust: exact;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
`;
|
|
1998
|
+
const html = ` <section class="markforge-cover cover-${cover.preset}">
|
|
1999
|
+
<div class="cover-top">
|
|
2000
|
+
${logoHtml}
|
|
2001
|
+
${badgeHtml}
|
|
2002
|
+
</div>
|
|
2003
|
+
<div class="cover-body">
|
|
2004
|
+
${titleHtml}
|
|
2005
|
+
${subtitleHtml}
|
|
2006
|
+
${metaHtml}
|
|
2007
|
+
</div>
|
|
2008
|
+
<div class="cover-bottom">
|
|
2009
|
+
${footerHtml}
|
|
2010
|
+
</div>
|
|
2011
|
+
</section>
|
|
2012
|
+
`;
|
|
2013
|
+
return { html, css };
|
|
2014
|
+
}
|
|
2015
|
+
async function renderBackCoverHtml(backCover, baseDir = process.cwd()) {
|
|
2016
|
+
let logoHtml = "";
|
|
2017
|
+
if (backCover.logo) {
|
|
2018
|
+
const resolved = await resolveImage(backCover.logo, baseDir);
|
|
2019
|
+
const src = resolved ? resolved.dataUri : backCover.logo;
|
|
2020
|
+
const widthStyle = backCover.logoWidth ? `style="width: ${typeof backCover.logoWidth === "number" ? `${backCover.logoWidth}px` : backCover.logoWidth}; max-width: 100%;"` : `style="max-width: 160px; height: auto;"`;
|
|
2021
|
+
logoHtml = `<div class="back-logo"><img src="${src}" alt="Brand Logo" ${widthStyle} /></div>`;
|
|
2022
|
+
}
|
|
2023
|
+
const badgeHtml = backCover.badge ? `<div class="back-badge" style="${backCover.badgeColor ? `background-color: ${backCover.badgeColor};` : ""}${backCover.badgeTextColor ? `color: ${backCover.badgeTextColor};` : ""}">${escapeHtml(backCover.badge)}</div>` : "";
|
|
2024
|
+
const titleHtml = `<h1 class="back-title">${escapeHtml(backCover.title)}</h1>`;
|
|
2025
|
+
const subtitleHtml = backCover.subtitle ? `<div class="back-subtitle">${escapeHtml(backCover.subtitle)}</div>` : "";
|
|
2026
|
+
const contactItems = [];
|
|
2027
|
+
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>`);
|
|
2028
|
+
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>`);
|
|
2029
|
+
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>`);
|
|
2030
|
+
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>`);
|
|
2031
|
+
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>`);
|
|
2032
|
+
if (backCover.social) {
|
|
2033
|
+
for (const [network, url] of Object.entries(backCover.social)) {
|
|
2034
|
+
if (url) {
|
|
2035
|
+
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>`);
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
const contactHtml = contactItems.length > 0 ? `<div class="back-contact-grid">${contactItems.join("\n")}</div>` : "";
|
|
2040
|
+
const copyrightHtml = backCover.copyright ? `<div class="back-copyright">${escapeHtml(backCover.copyright)}</div>` : "";
|
|
2041
|
+
const isDark = backCover.preset === "corporate";
|
|
2042
|
+
const css = `
|
|
2043
|
+
.markforge-back-cover {
|
|
2044
|
+
min-height: 100vh;
|
|
2045
|
+
box-sizing: border-box;
|
|
2046
|
+
display: flex;
|
|
2047
|
+
flex-direction: column;
|
|
2048
|
+
justify-content: space-between;
|
|
2049
|
+
padding: 4rem 3.5rem;
|
|
2050
|
+
page-break-before: always;
|
|
2051
|
+
break-before: page;
|
|
2052
|
+
position: relative;
|
|
2053
|
+
z-index: 2;
|
|
2054
|
+
background: ${backCover.bgGradient || (isDark ? "#0F172A" : "#FFFFFF")};
|
|
2055
|
+
color: ${backCover.textColor || (isDark ? "#F8FAFC" : "#0F172A")};
|
|
2056
|
+
}
|
|
2057
|
+
.markforge-back-cover.back-modern {
|
|
2058
|
+
border-bottom: 8px solid #0D998D;
|
|
2059
|
+
}
|
|
2060
|
+
.markforge-back-cover.back-corporate {
|
|
2061
|
+
border-left: 12px solid #33CDCF;
|
|
2062
|
+
}
|
|
2063
|
+
.markforge-back-cover.back-card {
|
|
2064
|
+
background: #F8FAFC;
|
|
2065
|
+
}
|
|
2066
|
+
.back-top {
|
|
2067
|
+
display: flex;
|
|
2068
|
+
justify-content: space-between;
|
|
2069
|
+
align-items: flex-start;
|
|
2070
|
+
width: 100%;
|
|
2071
|
+
}
|
|
2072
|
+
.back-badge {
|
|
2073
|
+
display: inline-block;
|
|
2074
|
+
padding: 0.35rem 0.85rem;
|
|
2075
|
+
font-size: 0.78rem;
|
|
2076
|
+
font-weight: 700;
|
|
2077
|
+
letter-spacing: 0.08em;
|
|
2078
|
+
text-transform: uppercase;
|
|
2079
|
+
background-color: #ECFDFD;
|
|
2080
|
+
color: #0D998D;
|
|
2081
|
+
border-radius: 4px;
|
|
2082
|
+
border: 1px solid #33CDCF;
|
|
2083
|
+
}
|
|
2084
|
+
.back-body {
|
|
2085
|
+
margin: auto 0;
|
|
2086
|
+
}
|
|
2087
|
+
.back-title {
|
|
2088
|
+
font-size: 2.6rem;
|
|
2089
|
+
font-weight: 800;
|
|
2090
|
+
line-height: 1.15;
|
|
2091
|
+
margin: 0 0 0.75rem 0;
|
|
2092
|
+
color: inherit;
|
|
2093
|
+
}
|
|
2094
|
+
.back-subtitle {
|
|
2095
|
+
font-size: 1.25rem;
|
|
2096
|
+
font-weight: 400;
|
|
2097
|
+
color: ${isDark ? "#94A3B8" : "#64748B"};
|
|
2098
|
+
margin: 0 0 2rem 0;
|
|
2099
|
+
line-height: 1.4;
|
|
2100
|
+
}
|
|
2101
|
+
.back-contact-grid {
|
|
2102
|
+
display: flex;
|
|
2103
|
+
flex-direction: column;
|
|
2104
|
+
gap: 0.6rem;
|
|
2105
|
+
border-top: 1.5px solid ${isDark ? "#334155" : "#E2E8F0"};
|
|
2106
|
+
padding-top: 1.5rem;
|
|
2107
|
+
max-width: 540px;
|
|
2108
|
+
}
|
|
2109
|
+
.back-contact-item {
|
|
2110
|
+
font-size: 0.92rem;
|
|
2111
|
+
display: flex;
|
|
2112
|
+
gap: 0.75rem;
|
|
2113
|
+
}
|
|
2114
|
+
.back-contact-label {
|
|
2115
|
+
font-weight: 600;
|
|
2116
|
+
color: ${isDark ? "#94A3B8" : "#64748B"};
|
|
2117
|
+
min-width: 110px;
|
|
2118
|
+
}
|
|
2119
|
+
.back-contact-link {
|
|
2120
|
+
color: #0D998D;
|
|
2121
|
+
text-decoration: none;
|
|
2122
|
+
font-weight: 600;
|
|
2123
|
+
}
|
|
2124
|
+
.back-contact-link:hover {
|
|
2125
|
+
text-decoration: underline;
|
|
2126
|
+
}
|
|
2127
|
+
.back-copyright {
|
|
2128
|
+
font-size: 0.82rem;
|
|
2129
|
+
color: ${isDark ? "#64748B" : "#94A3B8"};
|
|
2130
|
+
border-top: 1px solid ${isDark ? "#1E293B" : "#F1F5F9"};
|
|
2131
|
+
padding-top: 1rem;
|
|
2132
|
+
margin-top: 2rem;
|
|
2133
|
+
}
|
|
2134
|
+
@media print {
|
|
2135
|
+
.markforge-back-cover {
|
|
2136
|
+
page: back-cover-page;
|
|
2137
|
+
page-break-before: always;
|
|
2138
|
+
break-before: page;
|
|
2139
|
+
page-break-after: avoid;
|
|
2140
|
+
break-after: avoid;
|
|
2141
|
+
min-height: 100vh;
|
|
2142
|
+
height: 100vh;
|
|
2143
|
+
max-height: 100vh;
|
|
2144
|
+
margin: 0;
|
|
2145
|
+
box-sizing: border-box;
|
|
2146
|
+
overflow: hidden;
|
|
2147
|
+
-webkit-print-color-adjust: exact;
|
|
2148
|
+
print-color-adjust: exact;
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
`;
|
|
2152
|
+
const html = ` <section class="markforge-back-cover back-${backCover.preset}">
|
|
2153
|
+
<div class="back-top">
|
|
2154
|
+
${logoHtml}
|
|
2155
|
+
${badgeHtml}
|
|
2156
|
+
</div>
|
|
2157
|
+
<div class="back-body">
|
|
2158
|
+
${titleHtml}
|
|
2159
|
+
${subtitleHtml}
|
|
2160
|
+
${contactHtml}
|
|
2161
|
+
</div>
|
|
2162
|
+
${copyrightHtml}
|
|
2163
|
+
</section>
|
|
2164
|
+
`;
|
|
2165
|
+
return { html, css };
|
|
2166
|
+
}
|
|
2167
|
+
async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
2168
|
+
var _a, _b;
|
|
2169
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2170
|
+
const baseThemeCss = generateThemeCss(resolved.theme);
|
|
2171
|
+
let customCss = "";
|
|
2172
|
+
for (const cssPath of resolved.css) {
|
|
2173
|
+
const fullCssPath = path2.isAbsolute(cssPath) ? cssPath : path2.resolve(baseDir, cssPath);
|
|
2174
|
+
if (fs2.existsSync(fullCssPath)) {
|
|
2175
|
+
customCss += `
|
|
2176
|
+
/* Custom CSS: ${cssPath} */
|
|
2177
|
+
` + fs2.readFileSync(fullCssPath, "utf-8");
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
const inlinedCss = doc.inlinedStyles.join("\n");
|
|
2181
|
+
const extraCss = `
|
|
2182
|
+
.markforge-columns {
|
|
2183
|
+
display: grid;
|
|
2184
|
+
grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
|
|
2185
|
+
gap: var(--col-gap, 1.5rem);
|
|
2186
|
+
margin: 1.5rem 0;
|
|
2187
|
+
}
|
|
2188
|
+
.markforge-col {
|
|
2189
|
+
min-width: 0;
|
|
2190
|
+
}
|
|
2191
|
+
.markforge-fnref {
|
|
2192
|
+
text-decoration: none;
|
|
2193
|
+
font-size: 0.8em;
|
|
2194
|
+
vertical-align: super;
|
|
2195
|
+
color: #0D998D;
|
|
2196
|
+
font-weight: 700;
|
|
2197
|
+
}
|
|
2198
|
+
.markforge-footnotes {
|
|
2199
|
+
margin-top: 3rem;
|
|
2200
|
+
padding-top: 1rem;
|
|
2201
|
+
font-size: 0.88rem;
|
|
2202
|
+
color: #64748B;
|
|
2203
|
+
}
|
|
2204
|
+
.markforge-footnotes hr {
|
|
2205
|
+
border: 0;
|
|
2206
|
+
border-top: 1px solid #E2E8F0;
|
|
2207
|
+
margin-bottom: 1rem;
|
|
2208
|
+
}
|
|
2209
|
+
.markforge-fn-return {
|
|
2210
|
+
text-decoration: none;
|
|
2211
|
+
color: #0D998D;
|
|
2212
|
+
}
|
|
2213
|
+
.math-block {
|
|
2214
|
+
margin: 1.5rem 0;
|
|
2215
|
+
text-align: center;
|
|
2216
|
+
overflow-x: auto;
|
|
2217
|
+
}
|
|
2218
|
+
`;
|
|
2219
|
+
let coverHtml = "";
|
|
2220
|
+
let coverCss = "";
|
|
2221
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
2222
|
+
const coverRes = await renderCoverPageHtml(resolved.coverPage, baseDir);
|
|
2223
|
+
coverHtml = coverRes.html;
|
|
2224
|
+
coverCss = coverRes.css;
|
|
2225
|
+
}
|
|
2226
|
+
let backHtml = "";
|
|
2227
|
+
let backCss = "";
|
|
2228
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
2229
|
+
const backRes = await renderBackCoverHtml(resolved.backCover, baseDir);
|
|
2230
|
+
backHtml = backRes.html;
|
|
2231
|
+
backCss = backRes.css;
|
|
2232
|
+
}
|
|
2233
|
+
let bodyHtml = "";
|
|
2234
|
+
if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
|
|
2235
|
+
bodyHtml += ` <header class="document-header">
|
|
2236
|
+
`;
|
|
2237
|
+
bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
|
|
2238
|
+
`;
|
|
2239
|
+
if (resolved.subtitle) {
|
|
2240
|
+
bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
|
|
2241
|
+
`;
|
|
2242
|
+
}
|
|
2243
|
+
if (resolved.author || resolved.date || resolved.version) {
|
|
2244
|
+
bodyHtml += ` <div class="document-meta">
|
|
2245
|
+
`;
|
|
2246
|
+
if (resolved.author) {
|
|
2247
|
+
bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
|
|
2248
|
+
`;
|
|
2249
|
+
}
|
|
2250
|
+
if (resolved.version) {
|
|
2251
|
+
bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
|
|
2252
|
+
`;
|
|
2253
|
+
}
|
|
2254
|
+
if (resolved.date) {
|
|
2255
|
+
bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
|
|
2256
|
+
`;
|
|
2257
|
+
}
|
|
2258
|
+
bodyHtml += ` </div>
|
|
2259
|
+
`;
|
|
2260
|
+
}
|
|
2261
|
+
bodyHtml += ` </header>
|
|
2262
|
+
`;
|
|
2263
|
+
}
|
|
2264
|
+
if (((_b = resolved.numberHeadings) == null ? void 0 : _b.enabled) !== false && resolved.numberHeadings) {
|
|
2265
|
+
applyHeadingNumbering(doc.nodes, doc.tocEntries, resolved.numberHeadings);
|
|
2266
|
+
}
|
|
2267
|
+
if (resolved.toc && doc.tocEntries.length > 0) {
|
|
2268
|
+
bodyHtml += ` <nav class="table-of-contents">
|
|
2269
|
+
`;
|
|
2270
|
+
bodyHtml += ` <h2>Table of Contents</h2>
|
|
2271
|
+
<ul>
|
|
2272
|
+
`;
|
|
2273
|
+
for (const entry of doc.tocEntries) {
|
|
2274
|
+
const indent = " ".repeat(entry.level);
|
|
2275
|
+
bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
|
|
2276
|
+
`;
|
|
2277
|
+
}
|
|
2278
|
+
bodyHtml += ` </ul>
|
|
2279
|
+
</nav>
|
|
2280
|
+
`;
|
|
2281
|
+
}
|
|
2282
|
+
const mergedTokens = {
|
|
2283
|
+
...config.metadata,
|
|
2284
|
+
...doc.metadata,
|
|
2285
|
+
...resolved,
|
|
2286
|
+
title: resolved.title,
|
|
2287
|
+
subtitle: resolved.subtitle,
|
|
2288
|
+
author: resolved.author,
|
|
2289
|
+
version: resolved.version,
|
|
2290
|
+
date: resolved.date,
|
|
2291
|
+
company: resolved.company
|
|
2292
|
+
};
|
|
2293
|
+
const nodesHtml = await renderNodesToHtml(doc.nodes, resolved, baseDir, mergedTokens);
|
|
2294
|
+
bodyHtml += ` <main class="markforge-content-body">
|
|
2295
|
+
${nodesHtml} </main>
|
|
2296
|
+
`;
|
|
2297
|
+
let footnotesHtml = "";
|
|
2298
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
2299
|
+
let fnListHtml = "";
|
|
2300
|
+
for (const def of doc.footnoteDefs) {
|
|
2301
|
+
const defInner = await renderInlinesToHtml(def.inlines, baseDir, mergedTokens);
|
|
2302
|
+
fnListHtml += ` <li id="fn-${escapeHtml(def.id)}">${defInner} <a href="#fnref-${escapeHtml(def.id)}" class="markforge-fn-return">↩</a></li>
|
|
2303
|
+
`;
|
|
2304
|
+
}
|
|
2305
|
+
footnotesHtml = `
|
|
2306
|
+
<footer class="markforge-footnotes">
|
|
2307
|
+
<hr />
|
|
2308
|
+
<ol>
|
|
2309
|
+
${fnListHtml} </ol>
|
|
2310
|
+
</footer>
|
|
2311
|
+
`;
|
|
2312
|
+
}
|
|
1671
2313
|
let watermarkCss = "";
|
|
1672
2314
|
let watermarkHtml = "";
|
|
1673
2315
|
if (resolved.watermark) {
|
|
@@ -1677,12 +2319,16 @@ ${escapeHtml(node.text || "")}
|
|
|
1677
2319
|
position: fixed;
|
|
1678
2320
|
top: 0;
|
|
1679
2321
|
left: 0;
|
|
1680
|
-
|
|
1681
|
-
|
|
2322
|
+
right: 0;
|
|
2323
|
+
bottom: 0;
|
|
2324
|
+
width: 100%;
|
|
2325
|
+
height: 100%;
|
|
1682
2326
|
pointer-events: none;
|
|
1683
2327
|
z-index: 0;
|
|
1684
2328
|
user-select: none;
|
|
1685
2329
|
-webkit-user-select: none;
|
|
2330
|
+
-webkit-print-color-adjust: exact;
|
|
2331
|
+
print-color-adjust: exact;
|
|
1686
2332
|
}
|
|
1687
2333
|
.document-container {
|
|
1688
2334
|
position: relative;
|
|
@@ -1690,13 +2336,7 @@ ${escapeHtml(node.text || "")}
|
|
|
1690
2336
|
}
|
|
1691
2337
|
@media print {
|
|
1692
2338
|
.document-watermark {
|
|
1693
|
-
|
|
1694
|
-
top: 0;
|
|
1695
|
-
left: 0;
|
|
1696
|
-
width: 100vw;
|
|
1697
|
-
height: 100vh;
|
|
1698
|
-
-webkit-print-color-adjust: exact;
|
|
1699
|
-
print-color-adjust: exact;
|
|
2339
|
+
display: none !important;
|
|
1700
2340
|
}
|
|
1701
2341
|
}
|
|
1702
2342
|
`;
|
|
@@ -1705,16 +2345,16 @@ ${escapeHtml(node.text || "")}
|
|
|
1705
2345
|
(function() {
|
|
1706
2346
|
try {
|
|
1707
2347
|
var canvas = document.createElement('canvas');
|
|
1708
|
-
var dpr =
|
|
1709
|
-
var width =
|
|
1710
|
-
var height =
|
|
1711
|
-
canvas.width =
|
|
1712
|
-
canvas.height =
|
|
2348
|
+
var dpr = 2;
|
|
2349
|
+
var width = 1200;
|
|
2350
|
+
var height = 1600;
|
|
2351
|
+
canvas.width = width * dpr;
|
|
2352
|
+
canvas.height = height * dpr;
|
|
1713
2353
|
var ctx = canvas.getContext('2d');
|
|
1714
2354
|
if (ctx) {
|
|
1715
2355
|
ctx.scale(dpr, dpr);
|
|
1716
2356
|
ctx.translate(width / 2, height / 2);
|
|
1717
|
-
ctx.rotate((${wm.rotate} * Math.PI) / 180);
|
|
2357
|
+
ctx.rotate((-Math.abs(${wm.rotate || 45}) * Math.PI) / 180);
|
|
1718
2358
|
ctx.textAlign = 'center';
|
|
1719
2359
|
ctx.textBaseline = 'middle';
|
|
1720
2360
|
ctx.font = '900 ${wm.fontSize * 1.5}px system-ui, -apple-system, sans-serif';
|
|
@@ -1741,10 +2381,6 @@ ${escapeHtml(node.text || "")}
|
|
|
1741
2381
|
if (resolved.signatures && resolved.signatures.items.length > 0) {
|
|
1742
2382
|
const sig = resolved.signatures;
|
|
1743
2383
|
const numItems = sig.items.length;
|
|
1744
|
-
let justifyCss = "flex-end";
|
|
1745
|
-
if (sig.align === "left") justifyCss = "flex-start";
|
|
1746
|
-
else if (sig.align === "center") justifyCss = "center";
|
|
1747
|
-
else if (sig.align === "space-between") justifyCss = "space-between";
|
|
1748
2384
|
signaturesCss = `
|
|
1749
2385
|
.markforge-signatures {
|
|
1750
2386
|
margin-top: ${sig.spacingBefore};
|
|
@@ -1856,6 +2492,10 @@ ${itemCards}
|
|
|
1856
2492
|
<style>
|
|
1857
2493
|
${THEME_COMPONENTS}
|
|
1858
2494
|
${baseThemeCss}
|
|
2495
|
+
${KATEX_INLINE_CSS}
|
|
2496
|
+
${extraCss}
|
|
2497
|
+
${coverCss}
|
|
2498
|
+
${backCss}
|
|
1859
2499
|
${customCss}
|
|
1860
2500
|
${inlinedCss}
|
|
1861
2501
|
${watermarkCss}
|
|
@@ -1863,14 +2503,102 @@ ${signaturesCss}
|
|
|
1863
2503
|
</style>
|
|
1864
2504
|
</head>
|
|
1865
2505
|
<body>
|
|
1866
|
-
${watermarkHtml} <div class="document-container">
|
|
1867
|
-
${bodyHtml}${signaturesHtml} </div>
|
|
2506
|
+
${watermarkHtml}${coverHtml} <div class="document-container">
|
|
2507
|
+
${bodyHtml}${footnotesHtml}${signaturesHtml} </div>
|
|
1868
2508
|
${mermaidScript}
|
|
1869
|
-
</body>
|
|
2509
|
+
${backHtml}</body>
|
|
1870
2510
|
</html>`;
|
|
1871
2511
|
}
|
|
1872
2512
|
|
|
1873
2513
|
// src/core/pdf/pdfBuilder.ts
|
|
2514
|
+
import * as fs3 from "fs";
|
|
2515
|
+
import * as path3 from "path";
|
|
2516
|
+
import * as os from "os";
|
|
2517
|
+
import { pathToFileURL } from "url";
|
|
2518
|
+
import { spawnSync } from "child_process";
|
|
2519
|
+
import { PDFDocument } from "pdf-lib";
|
|
2520
|
+
import { encryptPDF } from "@pdfsmaller/pdf-encrypt";
|
|
2521
|
+
function escapeXml(str) {
|
|
2522
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2523
|
+
}
|
|
2524
|
+
function generateWatermarkPngBuffer(chromePath, wm) {
|
|
2525
|
+
const tmpHtml = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.html`);
|
|
2526
|
+
const tmpPng = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
|
|
2527
|
+
try {
|
|
2528
|
+
const text = escapeXml(wm.text.toUpperCase());
|
|
2529
|
+
const fontSize = (wm.fontSize || 52) * 1.5;
|
|
2530
|
+
const color = wm.color || "#E11D48";
|
|
2531
|
+
const opacity = wm.opacity !== void 0 ? wm.opacity : 0.12;
|
|
2532
|
+
const rotate = wm.rotate !== void 0 ? wm.rotate : -45;
|
|
2533
|
+
const html = `<!DOCTYPE html>
|
|
2534
|
+
<html>
|
|
2535
|
+
<head>
|
|
2536
|
+
<meta charset="utf-8">
|
|
2537
|
+
<style>
|
|
2538
|
+
html, body {
|
|
2539
|
+
margin: 0;
|
|
2540
|
+
padding: 0;
|
|
2541
|
+
width: 1200px;
|
|
2542
|
+
height: 1600px;
|
|
2543
|
+
background: transparent;
|
|
2544
|
+
overflow: hidden;
|
|
2545
|
+
}
|
|
2546
|
+
.wm-box {
|
|
2547
|
+
width: 1200px;
|
|
2548
|
+
height: 1600px;
|
|
2549
|
+
display: flex;
|
|
2550
|
+
align-items: center;
|
|
2551
|
+
justify-content: center;
|
|
2552
|
+
transform: rotate(${rotate}deg);
|
|
2553
|
+
}
|
|
2554
|
+
.wm-text {
|
|
2555
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
2556
|
+
font-weight: 900;
|
|
2557
|
+
font-size: ${fontSize}px;
|
|
2558
|
+
color: ${color};
|
|
2559
|
+
opacity: ${opacity};
|
|
2560
|
+
letter-spacing: 0.15em;
|
|
2561
|
+
text-transform: uppercase;
|
|
2562
|
+
white-space: nowrap;
|
|
2563
|
+
}
|
|
2564
|
+
</style>
|
|
2565
|
+
</head>
|
|
2566
|
+
<body>
|
|
2567
|
+
<div class="wm-box"><span class="wm-text">${text}</span></div>
|
|
2568
|
+
</body>
|
|
2569
|
+
</html>`;
|
|
2570
|
+
fs3.writeFileSync(tmpHtml, html, "utf8");
|
|
2571
|
+
const fileUrl = pathToFileURL(tmpHtml).href;
|
|
2572
|
+
const isWin = process.platform === "win32";
|
|
2573
|
+
spawnSync(
|
|
2574
|
+
chromePath,
|
|
2575
|
+
[
|
|
2576
|
+
"--headless=new",
|
|
2577
|
+
"--disable-gpu",
|
|
2578
|
+
"--disable-sync",
|
|
2579
|
+
"--disable-extensions",
|
|
2580
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
2581
|
+
`--screenshot=${tmpPng}`,
|
|
2582
|
+
"--window-size=1200,1600",
|
|
2583
|
+
"--default-background-color=00000000",
|
|
2584
|
+
fileUrl
|
|
2585
|
+
],
|
|
2586
|
+
{ timeout: 15e3, windowsHide: true }
|
|
2587
|
+
);
|
|
2588
|
+
if (fs3.existsSync(tmpPng) && fs3.statSync(tmpPng).size > 0) {
|
|
2589
|
+
return fs3.readFileSync(tmpPng);
|
|
2590
|
+
}
|
|
2591
|
+
return null;
|
|
2592
|
+
} catch {
|
|
2593
|
+
return null;
|
|
2594
|
+
} finally {
|
|
2595
|
+
try {
|
|
2596
|
+
if (fs3.existsSync(tmpHtml)) fs3.unlinkSync(tmpHtml);
|
|
2597
|
+
if (fs3.existsSync(tmpPng)) fs3.unlinkSync(tmpPng);
|
|
2598
|
+
} catch {
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
1874
2602
|
function findChromeExecutable() {
|
|
1875
2603
|
if (process.env.CHROME_PATH && fs3.existsSync(process.env.CHROME_PATH)) {
|
|
1876
2604
|
return process.env.CHROME_PATH;
|
|
@@ -1935,7 +2663,7 @@ function findChromeExecutable() {
|
|
|
1935
2663
|
return null;
|
|
1936
2664
|
}
|
|
1937
2665
|
function injectPagedMediaStyles(html, config, metadata) {
|
|
1938
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2666
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1939
2667
|
const resolved = resolveDocumentConfig(metadata || {}, config);
|
|
1940
2668
|
const size = resolved.paperSize;
|
|
1941
2669
|
const orientation = resolved.orientation;
|
|
@@ -1979,6 +2707,66 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
1979
2707
|
${fontStyle}
|
|
1980
2708
|
}`;
|
|
1981
2709
|
};
|
|
2710
|
+
const coverPageCss = ((_a = resolved.coverPage) == null ? void 0 : _a.enabled) ? `
|
|
2711
|
+
@page :first {
|
|
2712
|
+
margin-top: 0;
|
|
2713
|
+
margin-bottom: 0;
|
|
2714
|
+
margin-left: 0;
|
|
2715
|
+
margin-right: 0;
|
|
2716
|
+
background-image: none !important;
|
|
2717
|
+
@top-left { content: none; }
|
|
2718
|
+
@top-center { content: none; }
|
|
2719
|
+
@top-right { content: none; }
|
|
2720
|
+
@bottom-left { content: none; }
|
|
2721
|
+
@bottom-center { content: none; }
|
|
2722
|
+
@bottom-right { content: none; }
|
|
2723
|
+
}` : "";
|
|
2724
|
+
const backCoverCss = ((_b = resolved.backCover) == null ? void 0 : _b.enabled) ? `
|
|
2725
|
+
@page back-cover-page {
|
|
2726
|
+
size: ${size} ${orientation};
|
|
2727
|
+
margin: 0;
|
|
2728
|
+
background-image: none !important;
|
|
2729
|
+
@top-left { content: none; }
|
|
2730
|
+
@top-center { content: none; }
|
|
2731
|
+
@top-right { content: none; }
|
|
2732
|
+
@bottom-left { content: none; }
|
|
2733
|
+
@bottom-center { content: none; }
|
|
2734
|
+
@bottom-right { content: none; }
|
|
2735
|
+
}
|
|
2736
|
+
.markforge-back-cover {
|
|
2737
|
+
page: back-cover-page;
|
|
2738
|
+
min-height: 100vh;
|
|
2739
|
+
height: 100vh;
|
|
2740
|
+
box-sizing: border-box;
|
|
2741
|
+
break-before: page;
|
|
2742
|
+
break-after: avoid;
|
|
2743
|
+
}` : "";
|
|
2744
|
+
const tocPageCss = resolved.toc ? `
|
|
2745
|
+
@page toc-page {
|
|
2746
|
+
size: ${size} ${orientation};
|
|
2747
|
+
margin-top: ${top};
|
|
2748
|
+
margin-bottom: ${bottom};
|
|
2749
|
+
margin-left: ${left};
|
|
2750
|
+
margin-right: ${right};
|
|
2751
|
+
${buildZoneCss("top-left", (_c = resolved.header) == null ? void 0 : _c.left)}
|
|
2752
|
+
${buildZoneCss("top-center", (_d = resolved.header) == null ? void 0 : _d.center)}
|
|
2753
|
+
${buildZoneCss("top-right", (_e = resolved.header) == null ? void 0 : _e.right)}
|
|
2754
|
+
${buildZoneCss("bottom-left", (_f = resolved.footer) == null ? void 0 : _f.left)}
|
|
2755
|
+
${buildZoneCss("bottom-center", (_g = resolved.footer) == null ? void 0 : _g.center)}
|
|
2756
|
+
@bottom-right {
|
|
2757
|
+
content: counter(page, lower-roman);
|
|
2758
|
+
font-size: 9pt;
|
|
2759
|
+
color: #94a3b8;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
.table-of-contents {
|
|
2763
|
+
page: toc-page;
|
|
2764
|
+
page-break-after: always;
|
|
2765
|
+
break-after: page;
|
|
2766
|
+
}
|
|
2767
|
+
.markforge-content-body {
|
|
2768
|
+
counter-reset: page 1;
|
|
2769
|
+
}` : "";
|
|
1982
2770
|
const pagedCss = `
|
|
1983
2771
|
@page {
|
|
1984
2772
|
size: ${size} ${orientation};
|
|
@@ -1986,15 +2774,19 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
1986
2774
|
margin-bottom: ${bottom};
|
|
1987
2775
|
margin-left: ${left};
|
|
1988
2776
|
margin-right: ${right};
|
|
1989
|
-
${buildZoneCss("top-left", (
|
|
1990
|
-
${buildZoneCss("top-center", (
|
|
1991
|
-
${buildZoneCss("top-right", (
|
|
1992
|
-
${buildZoneCss("bottom-left", (
|
|
1993
|
-
${buildZoneCss("bottom-center", (
|
|
1994
|
-
${buildZoneCss("bottom-right", (
|
|
2777
|
+
${buildZoneCss("top-left", (_h = resolved.header) == null ? void 0 : _h.left)}
|
|
2778
|
+
${buildZoneCss("top-center", (_i = resolved.header) == null ? void 0 : _i.center)}
|
|
2779
|
+
${buildZoneCss("top-right", (_j = resolved.header) == null ? void 0 : _j.right)}
|
|
2780
|
+
${buildZoneCss("bottom-left", (_k = resolved.footer) == null ? void 0 : _k.left)}
|
|
2781
|
+
${buildZoneCss("bottom-center", (_l = resolved.footer) == null ? void 0 : _l.center)}
|
|
2782
|
+
${buildZoneCss("bottom-right", (_m = resolved.footer) == null ? void 0 : _m.right, true)}
|
|
1995
2783
|
}
|
|
2784
|
+
${coverPageCss}
|
|
2785
|
+
${tocPageCss}
|
|
2786
|
+
${backCoverCss}
|
|
1996
2787
|
@media print {
|
|
1997
2788
|
body { padding: 0; }
|
|
2789
|
+
.document-watermark { display: none !important; }
|
|
1998
2790
|
h1, h2, h3, pre, table, blockquote, .callout {
|
|
1999
2791
|
break-inside: avoid;
|
|
2000
2792
|
}
|
|
@@ -2042,15 +2834,17 @@ startxref
|
|
|
2042
2834
|
return Buffer.from(pdfBody, "utf-8");
|
|
2043
2835
|
}
|
|
2044
2836
|
async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
2837
|
+
var _a, _b, _c;
|
|
2045
2838
|
const baseHtml = await buildHtmlDocument(doc, config, baseDir);
|
|
2046
2839
|
const pagedHtml = injectPagedMediaStyles(baseHtml, config, doc.metadata);
|
|
2047
2840
|
const chromePath = findChromeExecutable();
|
|
2048
2841
|
if (chromePath) {
|
|
2049
2842
|
const tmpId = Math.random().toString(36).substring(2, 9);
|
|
2050
2843
|
const tmpDir = os.tmpdir();
|
|
2051
|
-
const tmpHtml =
|
|
2052
|
-
const tmpPdf =
|
|
2053
|
-
const tmpProfile =
|
|
2844
|
+
const tmpHtml = path3.join(tmpDir, `markforge_${tmpId}.html`);
|
|
2845
|
+
const tmpPdf = path3.join(tmpDir, `markforge_${tmpId}.pdf`);
|
|
2846
|
+
const tmpProfile = path3.join(tmpDir, `markforge_prof_${tmpId}`);
|
|
2847
|
+
const isWin = process.platform === "win32";
|
|
2054
2848
|
const isolatedFlags = [
|
|
2055
2849
|
`--user-data-dir=${tmpProfile}`,
|
|
2056
2850
|
"--no-first-run",
|
|
@@ -2061,7 +2855,6 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2061
2855
|
"--disable-default-apps",
|
|
2062
2856
|
"--disable-extensions",
|
|
2063
2857
|
"--disable-domain-reliability",
|
|
2064
|
-
"--disable-client-side-phishing-detection",
|
|
2065
2858
|
"--disable-breakpad",
|
|
2066
2859
|
"--disable-component-extensions-with-background-pages",
|
|
2067
2860
|
"--disable-features=Translate,OptimizationHints,MediaRouter,DialMediaRouteProvider,CalculatedNewTabPage,ChromeWhatsNewUI,PrivacySandboxSettings4",
|
|
@@ -2070,12 +2863,10 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2070
2863
|
"--mute-audio",
|
|
2071
2864
|
"--no-service-autorun",
|
|
2072
2865
|
"--disable-gpu",
|
|
2073
|
-
"--no-sandbox",
|
|
2074
|
-
"--disable-setuid-sandbox",
|
|
2075
|
-
"--allow-file-access-from-files",
|
|
2076
|
-
"--disable-web-security",
|
|
2866
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
2077
2867
|
"--force-color-profile=srgb",
|
|
2078
|
-
"--no-pdf-header-footer"
|
|
2868
|
+
"--no-pdf-header-footer",
|
|
2869
|
+
"--window-size=1200,1600"
|
|
2079
2870
|
];
|
|
2080
2871
|
try {
|
|
2081
2872
|
fs3.writeFileSync(tmpHtml, pagedHtml, "utf-8");
|
|
@@ -2090,7 +2881,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2090
2881
|
`--print-to-pdf=${tmpPdf}`,
|
|
2091
2882
|
fileUrl
|
|
2092
2883
|
],
|
|
2093
|
-
{ timeout: 3e4 }
|
|
2884
|
+
{ timeout: 3e4, windowsHide: true }
|
|
2094
2885
|
);
|
|
2095
2886
|
if ((res.status !== 0 || !fs3.existsSync(tmpPdf)) && chromePath) {
|
|
2096
2887
|
res = spawnSync(
|
|
@@ -2101,12 +2892,79 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2101
2892
|
`--print-to-pdf=${tmpPdf}`,
|
|
2102
2893
|
fileUrl
|
|
2103
2894
|
],
|
|
2104
|
-
{ timeout: 3e4 }
|
|
2895
|
+
{ timeout: 3e4, windowsHide: true }
|
|
2105
2896
|
);
|
|
2106
2897
|
}
|
|
2107
2898
|
if (fs3.existsSync(tmpPdf) && fs3.statSync(tmpPdf).size > 0) {
|
|
2108
2899
|
const pdfBuffer = fs3.readFileSync(tmpPdf);
|
|
2109
|
-
|
|
2900
|
+
try {
|
|
2901
|
+
const pdfDoc = await PDFDocument.load(pdfBuffer);
|
|
2902
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2903
|
+
if (resolved.title) pdfDoc.setTitle(resolved.title);
|
|
2904
|
+
if (resolved.author) pdfDoc.setAuthor(resolved.author);
|
|
2905
|
+
if (resolved.subtitle) pdfDoc.setSubject(resolved.subtitle);
|
|
2906
|
+
pdfDoc.setCreator("MarkForge Enterprise Document Generator");
|
|
2907
|
+
pdfDoc.setProducer("MarkForge (by Ma'sum)");
|
|
2908
|
+
pdfDoc.setModificationDate(/* @__PURE__ */ new Date());
|
|
2909
|
+
if (((_a = resolved.backCover) == null ? void 0 : _a.enabled) && pdfDoc.getPageCount() > 2) {
|
|
2910
|
+
pdfDoc.removePage(pdfDoc.getPageCount() - 1);
|
|
2911
|
+
}
|
|
2912
|
+
if (resolved.watermark) {
|
|
2913
|
+
const wmPng = generateWatermarkPngBuffer(chromePath, resolved.watermark);
|
|
2914
|
+
if (wmPng) {
|
|
2915
|
+
const embeddedPng = await pdfDoc.embedPng(wmPng);
|
|
2916
|
+
const totalPages = pdfDoc.getPageCount();
|
|
2917
|
+
const pages = pdfDoc.getPages();
|
|
2918
|
+
const startPageIndex = ((_b = resolved.coverPage) == null ? void 0 : _b.enabled) ? 1 : 0;
|
|
2919
|
+
const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ? totalPages - 1 : totalPages;
|
|
2920
|
+
for (let i = startPageIndex; i < endPageIndex; i++) {
|
|
2921
|
+
const page = pages[i];
|
|
2922
|
+
const { width, height } = page.getSize();
|
|
2923
|
+
page.drawImage(embeddedPng, {
|
|
2924
|
+
x: 0,
|
|
2925
|
+
y: 0,
|
|
2926
|
+
width,
|
|
2927
|
+
height
|
|
2928
|
+
});
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
const savedBytes = await pdfDoc.save();
|
|
2933
|
+
let finalBuffer = Buffer.from(savedBytes);
|
|
2934
|
+
if (resolved.security) {
|
|
2935
|
+
const sec = resolved.security;
|
|
2936
|
+
const hasUserPassword = typeof sec.userPassword === "string" && sec.userPassword.length > 0;
|
|
2937
|
+
const hasOwnerPassword = typeof sec.ownerPassword === "string" && sec.ownerPassword.length > 0;
|
|
2938
|
+
if (hasUserPassword || hasOwnerPassword) {
|
|
2939
|
+
try {
|
|
2940
|
+
const userPass = sec.userPassword ?? "";
|
|
2941
|
+
const ownerPass = sec.ownerPassword ?? userPass;
|
|
2942
|
+
const perms = sec.permissions;
|
|
2943
|
+
const encryptedBytes = await encryptPDF(
|
|
2944
|
+
new Uint8Array(finalBuffer),
|
|
2945
|
+
userPass,
|
|
2946
|
+
{
|
|
2947
|
+
ownerPassword: ownerPass,
|
|
2948
|
+
algorithm: "AES-256",
|
|
2949
|
+
allowPrinting: (perms == null ? void 0 : perms.printing) !== "none",
|
|
2950
|
+
allowHighQualityPrint: (perms == null ? void 0 : perms.printing) === "highResolution",
|
|
2951
|
+
allowModifying: (perms == null ? void 0 : perms.modifying) ?? true,
|
|
2952
|
+
allowCopying: (perms == null ? void 0 : perms.copying) ?? true,
|
|
2953
|
+
allowAnnotating: (perms == null ? void 0 : perms.annotating) ?? true,
|
|
2954
|
+
allowFillingForms: (perms == null ? void 0 : perms.fillingForms) ?? true,
|
|
2955
|
+
allowExtraction: (perms == null ? void 0 : perms.contentAccessibility) ?? true,
|
|
2956
|
+
allowAssembly: (perms == null ? void 0 : perms.documentAssembly) ?? true
|
|
2957
|
+
}
|
|
2958
|
+
);
|
|
2959
|
+
finalBuffer = Buffer.from(encryptedBytes);
|
|
2960
|
+
} catch {
|
|
2961
|
+
}
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
return finalBuffer;
|
|
2965
|
+
} catch {
|
|
2966
|
+
return pdfBuffer;
|
|
2967
|
+
}
|
|
2110
2968
|
}
|
|
2111
2969
|
} catch {
|
|
2112
2970
|
} finally {
|
|
@@ -2121,7 +2979,39 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2121
2979
|
return createFallbackPdfBuffer(doc.metadata.title || "MarkForge Document");
|
|
2122
2980
|
}
|
|
2123
2981
|
|
|
2982
|
+
// src/core/docx/docxBuilder.ts
|
|
2983
|
+
import {
|
|
2984
|
+
Document,
|
|
2985
|
+
Paragraph,
|
|
2986
|
+
TextRun,
|
|
2987
|
+
HeadingLevel,
|
|
2988
|
+
Table,
|
|
2989
|
+
TableRow,
|
|
2990
|
+
TableCell,
|
|
2991
|
+
WidthType,
|
|
2992
|
+
BorderStyle,
|
|
2993
|
+
AlignmentType,
|
|
2994
|
+
ImageRun,
|
|
2995
|
+
Header,
|
|
2996
|
+
Footer,
|
|
2997
|
+
PageNumber,
|
|
2998
|
+
Packer,
|
|
2999
|
+
PageOrientation,
|
|
3000
|
+
convertInchesToTwip,
|
|
3001
|
+
convertMillimetersToTwip,
|
|
3002
|
+
ShadingType,
|
|
3003
|
+
ExternalHyperlink,
|
|
3004
|
+
TabStopType,
|
|
3005
|
+
PageBreak,
|
|
3006
|
+
NumberFormat
|
|
3007
|
+
} from "docx";
|
|
3008
|
+
|
|
2124
3009
|
// src/core/mermaid/mermaidRenderer.ts
|
|
3010
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
3011
|
+
import * as fs4 from "fs";
|
|
3012
|
+
import * as os2 from "os";
|
|
3013
|
+
import * as path4 from "path";
|
|
3014
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2125
3015
|
async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
|
|
2126
3016
|
const chromePath = findChromeExecutable();
|
|
2127
3017
|
if (!chromePath) {
|
|
@@ -2129,8 +3019,8 @@ async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
|
|
|
2129
3019
|
}
|
|
2130
3020
|
const tmpId = Math.random().toString(36).substring(2, 9);
|
|
2131
3021
|
const tmpDir = os2.tmpdir();
|
|
2132
|
-
const tmpHtml =
|
|
2133
|
-
const tmpScreenshot =
|
|
3022
|
+
const tmpHtml = path4.join(tmpDir, `mermaid_${tmpId}.html`);
|
|
3023
|
+
const tmpScreenshot = path4.join(tmpDir, `mermaid_${tmpId}.png`);
|
|
2134
3024
|
const htmlContent = `<!DOCTYPE html>
|
|
2135
3025
|
<html>
|
|
2136
3026
|
<head>
|
|
@@ -2338,6 +3228,29 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
2338
3228
|
);
|
|
2339
3229
|
continue;
|
|
2340
3230
|
}
|
|
3231
|
+
if (span.type === "mathInline") {
|
|
3232
|
+
runs.push(
|
|
3233
|
+
new TextRun({
|
|
3234
|
+
text: span.content,
|
|
3235
|
+
font: "Cambria Math",
|
|
3236
|
+
italics: true,
|
|
3237
|
+
size: options.size,
|
|
3238
|
+
color: options.color || "0F172A"
|
|
3239
|
+
})
|
|
3240
|
+
);
|
|
3241
|
+
continue;
|
|
3242
|
+
}
|
|
3243
|
+
if (span.type === "footnoteRef") {
|
|
3244
|
+
runs.push(
|
|
3245
|
+
new TextRun({
|
|
3246
|
+
text: `[${span.content}]`,
|
|
3247
|
+
superScript: true,
|
|
3248
|
+
color: "009DA0",
|
|
3249
|
+
bold: true
|
|
3250
|
+
})
|
|
3251
|
+
);
|
|
3252
|
+
continue;
|
|
3253
|
+
}
|
|
2341
3254
|
runs.push(
|
|
2342
3255
|
new TextRun({
|
|
2343
3256
|
text: span.content,
|
|
@@ -2352,7 +3265,7 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
2352
3265
|
return runs;
|
|
2353
3266
|
}
|
|
2354
3267
|
async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
2355
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3268
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
2356
3269
|
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2357
3270
|
const docElements = [];
|
|
2358
3271
|
const themeProps = typeof resolved.theme === "object" ? resolved.theme : {};
|
|
@@ -2363,7 +3276,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2363
3276
|
const borderHex = (themeProps.borderColor || "#E2E8F0").replace("#", "");
|
|
2364
3277
|
const cardBgHex = (themeProps.cardBackground || "#F8FAFC").replace("#", "");
|
|
2365
3278
|
const defaultFont = themeProps.fontFamily ? themeProps.fontFamily.split(",")[0].replace(/['"]/g, "").trim() : "Segoe UI";
|
|
2366
|
-
if (resolved.title) {
|
|
3279
|
+
if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
|
|
2367
3280
|
docElements.push(
|
|
2368
3281
|
new Paragraph({
|
|
2369
3282
|
children: [
|
|
@@ -2424,6 +3337,9 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2424
3337
|
);
|
|
2425
3338
|
}
|
|
2426
3339
|
}
|
|
3340
|
+
if (((_b = resolved.numberHeadings) == null ? void 0 : _b.enabled) !== false && resolved.numberHeadings) {
|
|
3341
|
+
applyHeadingNumbering(doc.nodes, doc.tocEntries, resolved.numberHeadings);
|
|
3342
|
+
}
|
|
2427
3343
|
if (resolved.toc) {
|
|
2428
3344
|
const headingNodes = doc.nodes.filter(
|
|
2429
3345
|
(n) => n.type === "heading" && typeof n.level === "number" && n.level >= 1 && n.level <= 3
|
|
@@ -2493,7 +3409,11 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2493
3409
|
]
|
|
2494
3410
|
});
|
|
2495
3411
|
docElements.push(tocCard);
|
|
2496
|
-
docElements.push(
|
|
3412
|
+
docElements.push(
|
|
3413
|
+
new Paragraph({
|
|
3414
|
+
children: [new PageBreak()]
|
|
3415
|
+
})
|
|
3416
|
+
);
|
|
2497
3417
|
}
|
|
2498
3418
|
}
|
|
2499
3419
|
for (const node of doc.nodes) {
|
|
@@ -2503,7 +3423,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2503
3423
|
font: defaultFont,
|
|
2504
3424
|
size: 34,
|
|
2505
3425
|
// 17pt
|
|
2506
|
-
color:
|
|
3426
|
+
color: primaryDarkHex,
|
|
2507
3427
|
bold: true
|
|
2508
3428
|
});
|
|
2509
3429
|
docElements.push(
|
|
@@ -2549,7 +3469,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2549
3469
|
font: defaultFont,
|
|
2550
3470
|
size: 22,
|
|
2551
3471
|
// 11pt
|
|
2552
|
-
color:
|
|
3472
|
+
color: primaryDarkHex,
|
|
2553
3473
|
bold: true
|
|
2554
3474
|
});
|
|
2555
3475
|
docElements.push(
|
|
@@ -2779,7 +3699,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2779
3699
|
}
|
|
2780
3700
|
if (node.type === "table" && node.children) {
|
|
2781
3701
|
const tableRows = [];
|
|
2782
|
-
const numCols = ((
|
|
3702
|
+
const numCols = ((_d = (_c = node.children[0]) == null ? void 0 : _c.children) == null ? void 0 : _d.length) || 1;
|
|
2783
3703
|
const colWidth = Math.floor(9e3 / numCols);
|
|
2784
3704
|
for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
|
|
2785
3705
|
const rowNode = node.children[rowIdx];
|
|
@@ -2789,7 +3709,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2789
3709
|
if (rowNode.children) {
|
|
2790
3710
|
for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {
|
|
2791
3711
|
const cellNode = rowNode.children[colIdx];
|
|
2792
|
-
const align = (
|
|
3712
|
+
const align = (_e = node.align) == null ? void 0 : _e[colIdx];
|
|
2793
3713
|
let alignment = AlignmentType.LEFT;
|
|
2794
3714
|
if (align === "center") alignment = AlignmentType.CENTER;
|
|
2795
3715
|
if (align === "right") alignment = AlignmentType.RIGHT;
|
|
@@ -2928,6 +3848,113 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2928
3848
|
}
|
|
2929
3849
|
continue;
|
|
2930
3850
|
}
|
|
3851
|
+
if (node.type === "mathBlock") {
|
|
3852
|
+
docElements.push(
|
|
3853
|
+
new Paragraph({
|
|
3854
|
+
alignment: AlignmentType.CENTER,
|
|
3855
|
+
children: [
|
|
3856
|
+
new TextRun({
|
|
3857
|
+
text: node.text || "",
|
|
3858
|
+
font: "Cambria Math",
|
|
3859
|
+
italics: true,
|
|
3860
|
+
size: 24,
|
|
3861
|
+
// 12pt
|
|
3862
|
+
color: textHex
|
|
3863
|
+
})
|
|
3864
|
+
],
|
|
3865
|
+
spacing: { before: 180, after: 180 },
|
|
3866
|
+
shading: { fill: cardBgHex, type: ShadingType.CLEAR },
|
|
3867
|
+
border: {
|
|
3868
|
+
top: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3869
|
+
bottom: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3870
|
+
left: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3871
|
+
right: { style: BorderStyle.SINGLE, size: 4, color: borderHex }
|
|
3872
|
+
}
|
|
3873
|
+
})
|
|
3874
|
+
);
|
|
3875
|
+
continue;
|
|
3876
|
+
}
|
|
3877
|
+
if (node.type === "columns") {
|
|
3878
|
+
const cols = node.columnsCount || 2;
|
|
3879
|
+
const contentWidth = Math.max(
|
|
3880
|
+
1e3,
|
|
3881
|
+
resolved.paperDimensions.widthTwip - resolved.margins.leftTwip - resolved.margins.rightTwip
|
|
3882
|
+
);
|
|
3883
|
+
const cellWidthDxa = Math.floor(contentWidth / cols);
|
|
3884
|
+
const cells = [];
|
|
3885
|
+
for (const col of node.children || []) {
|
|
3886
|
+
const colParagraphs = [];
|
|
3887
|
+
for (const childNode of col.children || []) {
|
|
3888
|
+
if (childNode.type === "heading") {
|
|
3889
|
+
const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, bold: true, size: 24, color: primaryDarkHex });
|
|
3890
|
+
colParagraphs.push(new Paragraph({ children: runs, spacing: { before: 120, after: 60 } }));
|
|
3891
|
+
} else if (childNode.type === "paragraph") {
|
|
3892
|
+
const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
|
|
3893
|
+
colParagraphs.push(new Paragraph({ children: runs, spacing: { after: 100 } }));
|
|
3894
|
+
} else if (childNode.type === "list" && childNode.children) {
|
|
3895
|
+
for (const item of childNode.children) {
|
|
3896
|
+
const runs = await convertInlinesToTextRuns(item.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
|
|
3897
|
+
colParagraphs.push(new Paragraph({ children: [new TextRun({ text: "\u2022 ", font: defaultFont, color: primaryHex }), ...runs], spacing: { after: 40 } }));
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
}
|
|
3901
|
+
if (colParagraphs.length === 0) colParagraphs.push(new Paragraph({}));
|
|
3902
|
+
cells.push(
|
|
3903
|
+
new TableCell({
|
|
3904
|
+
width: { size: cellWidthDxa, type: WidthType.DXA },
|
|
3905
|
+
borders: {
|
|
3906
|
+
top: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3907
|
+
bottom: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3908
|
+
left: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3909
|
+
right: { style: BorderStyle.NONE, size: 0, color: "auto" }
|
|
3910
|
+
},
|
|
3911
|
+
margins: { top: 60, bottom: 60, left: 100, right: 100 },
|
|
3912
|
+
children: colParagraphs
|
|
3913
|
+
})
|
|
3914
|
+
);
|
|
3915
|
+
}
|
|
3916
|
+
docElements.push(
|
|
3917
|
+
new Table({
|
|
3918
|
+
width: { size: 100, type: WidthType.PERCENTAGE },
|
|
3919
|
+
rows: [new TableRow({ children: cells })]
|
|
3920
|
+
})
|
|
3921
|
+
);
|
|
3922
|
+
docElements.push(new Paragraph({ spacing: { after: 120 } }));
|
|
3923
|
+
continue;
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
3927
|
+
docElements.push(
|
|
3928
|
+
new Paragraph({
|
|
3929
|
+
border: {
|
|
3930
|
+
top: { style: BorderStyle.SINGLE, size: 4, color: borderHex, space: 8 }
|
|
3931
|
+
},
|
|
3932
|
+
spacing: { before: 360, after: 120 }
|
|
3933
|
+
})
|
|
3934
|
+
);
|
|
3935
|
+
for (const def of doc.footnoteDefs) {
|
|
3936
|
+
const defRuns = await convertInlinesToTextRuns(def.inlines, baseDir, {
|
|
3937
|
+
font: defaultFont,
|
|
3938
|
+
size: 18,
|
|
3939
|
+
// 9pt
|
|
3940
|
+
color: textMutedHex
|
|
3941
|
+
});
|
|
3942
|
+
docElements.push(
|
|
3943
|
+
new Paragraph({
|
|
3944
|
+
children: [
|
|
3945
|
+
new TextRun({
|
|
3946
|
+
text: `[${def.id}] `,
|
|
3947
|
+
bold: true,
|
|
3948
|
+
color: primaryDarkHex,
|
|
3949
|
+
font: defaultFont,
|
|
3950
|
+
size: 18
|
|
3951
|
+
}),
|
|
3952
|
+
...defRuns
|
|
3953
|
+
],
|
|
3954
|
+
spacing: { after: 60 }
|
|
3955
|
+
})
|
|
3956
|
+
);
|
|
3957
|
+
}
|
|
2931
3958
|
}
|
|
2932
3959
|
if (resolved.signatures && resolved.signatures.items.length > 0) {
|
|
2933
3960
|
const sig = resolved.signatures;
|
|
@@ -2989,7 +4016,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2989
4016
|
const centerPos = Math.round(contentWidthTwip / 2);
|
|
2990
4017
|
const rightPos = contentWidthTwip;
|
|
2991
4018
|
const headerRuns = [];
|
|
2992
|
-
if ((
|
|
4019
|
+
if ((_f = resolved.header) == null ? void 0 : _f.left) {
|
|
2993
4020
|
headerRuns.push(
|
|
2994
4021
|
new TextRun({
|
|
2995
4022
|
text: resolved.header.left.text,
|
|
@@ -3002,7 +4029,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3002
4029
|
);
|
|
3003
4030
|
}
|
|
3004
4031
|
headerRuns.push(new TextRun({ text: " " }));
|
|
3005
|
-
if ((
|
|
4032
|
+
if ((_g = resolved.header) == null ? void 0 : _g.center) {
|
|
3006
4033
|
headerRuns.push(
|
|
3007
4034
|
new TextRun({
|
|
3008
4035
|
text: resolved.header.center.text,
|
|
@@ -3015,7 +4042,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3015
4042
|
);
|
|
3016
4043
|
}
|
|
3017
4044
|
headerRuns.push(new TextRun({ text: " " }));
|
|
3018
|
-
if ((
|
|
4045
|
+
if ((_h = resolved.header) == null ? void 0 : _h.right) {
|
|
3019
4046
|
headerRuns.push(
|
|
3020
4047
|
new TextRun({
|
|
3021
4048
|
text: resolved.header.right.text,
|
|
@@ -3027,7 +4054,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3027
4054
|
})
|
|
3028
4055
|
);
|
|
3029
4056
|
}
|
|
3030
|
-
const docHeader = resolved.header ? new
|
|
4057
|
+
const docHeader = resolved.header ? new Header({
|
|
3031
4058
|
children: [
|
|
3032
4059
|
new Paragraph({
|
|
3033
4060
|
tabStops: [
|
|
@@ -3054,7 +4081,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3054
4081
|
]
|
|
3055
4082
|
}) : void 0;
|
|
3056
4083
|
const footerRuns = [];
|
|
3057
|
-
if ((
|
|
4084
|
+
if ((_i = resolved.footer) == null ? void 0 : _i.left) {
|
|
3058
4085
|
footerRuns.push(
|
|
3059
4086
|
new TextRun({
|
|
3060
4087
|
text: resolved.footer.left.text,
|
|
@@ -3067,7 +4094,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3067
4094
|
);
|
|
3068
4095
|
}
|
|
3069
4096
|
footerRuns.push(new TextRun({ text: " " }));
|
|
3070
|
-
if ((
|
|
4097
|
+
if ((_j = resolved.footer) == null ? void 0 : _j.center) {
|
|
3071
4098
|
footerRuns.push(
|
|
3072
4099
|
new TextRun({
|
|
3073
4100
|
text: resolved.footer.center.text,
|
|
@@ -3080,7 +4107,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3080
4107
|
);
|
|
3081
4108
|
}
|
|
3082
4109
|
footerRuns.push(new TextRun({ text: " " }));
|
|
3083
|
-
if ((
|
|
4110
|
+
if ((_k = resolved.footer) == null ? void 0 : _k.right) {
|
|
3084
4111
|
const rZone = resolved.footer.right;
|
|
3085
4112
|
const rColor = rZone.color.replace("#", "");
|
|
3086
4113
|
const rSize = (rZone.fontSize || 9) * 2;
|
|
@@ -3165,6 +4192,95 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3165
4192
|
]
|
|
3166
4193
|
}) : void 0;
|
|
3167
4194
|
const isLandscape = resolved.orientation === "landscape";
|
|
4195
|
+
const docSections = [];
|
|
4196
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
4197
|
+
const coverElements = await buildDocxCoverPageElements(
|
|
4198
|
+
resolved.coverPage,
|
|
4199
|
+
defaultFont,
|
|
4200
|
+
textHex,
|
|
4201
|
+
primaryHex,
|
|
4202
|
+
primaryDarkHex,
|
|
4203
|
+
textMutedHex,
|
|
4204
|
+
baseDir
|
|
4205
|
+
);
|
|
4206
|
+
docSections.push({
|
|
4207
|
+
properties: {
|
|
4208
|
+
page: {
|
|
4209
|
+
size: {
|
|
4210
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4211
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4212
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4213
|
+
},
|
|
4214
|
+
margin: {
|
|
4215
|
+
top: resolved.margins.topTwip,
|
|
4216
|
+
bottom: resolved.margins.bottomTwip,
|
|
4217
|
+
left: resolved.margins.leftTwip,
|
|
4218
|
+
right: resolved.margins.rightTwip
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
},
|
|
4222
|
+
headers: void 0,
|
|
4223
|
+
footers: void 0,
|
|
4224
|
+
children: coverElements
|
|
4225
|
+
});
|
|
4226
|
+
}
|
|
4227
|
+
docSections.push({
|
|
4228
|
+
properties: {
|
|
4229
|
+
page: {
|
|
4230
|
+
pageNumbers: {
|
|
4231
|
+
start: 1,
|
|
4232
|
+
formatType: NumberFormat.DECIMAL
|
|
4233
|
+
},
|
|
4234
|
+
size: {
|
|
4235
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4236
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4237
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4238
|
+
},
|
|
4239
|
+
margin: {
|
|
4240
|
+
top: resolved.margins.topTwip,
|
|
4241
|
+
bottom: resolved.margins.bottomTwip,
|
|
4242
|
+
left: resolved.margins.leftTwip,
|
|
4243
|
+
right: resolved.margins.rightTwip,
|
|
4244
|
+
header: 720,
|
|
4245
|
+
footer: 720
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
},
|
|
4249
|
+
headers: docHeader ? { default: docHeader } : void 0,
|
|
4250
|
+
footers: docFooter ? { default: docFooter } : void 0,
|
|
4251
|
+
children: docElements
|
|
4252
|
+
});
|
|
4253
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
4254
|
+
const backElements = await buildDocxBackCoverElements(
|
|
4255
|
+
resolved.backCover,
|
|
4256
|
+
defaultFont,
|
|
4257
|
+
textHex,
|
|
4258
|
+
primaryHex,
|
|
4259
|
+
primaryDarkHex,
|
|
4260
|
+
textMutedHex,
|
|
4261
|
+
baseDir
|
|
4262
|
+
);
|
|
4263
|
+
docSections.push({
|
|
4264
|
+
properties: {
|
|
4265
|
+
page: {
|
|
4266
|
+
size: {
|
|
4267
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4268
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4269
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4270
|
+
},
|
|
4271
|
+
margin: {
|
|
4272
|
+
top: resolved.margins.topTwip,
|
|
4273
|
+
bottom: resolved.margins.bottomTwip,
|
|
4274
|
+
left: resolved.margins.leftTwip,
|
|
4275
|
+
right: resolved.margins.rightTwip
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
},
|
|
4279
|
+
headers: void 0,
|
|
4280
|
+
footers: void 0,
|
|
4281
|
+
children: backElements
|
|
4282
|
+
});
|
|
4283
|
+
}
|
|
3168
4284
|
const document = new Document({
|
|
3169
4285
|
styles: {
|
|
3170
4286
|
default: {
|
|
@@ -3185,33 +4301,250 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3185
4301
|
}
|
|
3186
4302
|
}
|
|
3187
4303
|
},
|
|
3188
|
-
sections:
|
|
3189
|
-
{
|
|
3190
|
-
properties: {
|
|
3191
|
-
page: {
|
|
3192
|
-
size: {
|
|
3193
|
-
width: resolved.paperDimensions.widthTwip,
|
|
3194
|
-
height: resolved.paperDimensions.heightTwip,
|
|
3195
|
-
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
3196
|
-
},
|
|
3197
|
-
margin: {
|
|
3198
|
-
top: resolved.margins.topTwip,
|
|
3199
|
-
bottom: resolved.margins.bottomTwip,
|
|
3200
|
-
left: resolved.margins.leftTwip,
|
|
3201
|
-
right: resolved.margins.rightTwip,
|
|
3202
|
-
header: 720,
|
|
3203
|
-
footer: 720
|
|
3204
|
-
}
|
|
3205
|
-
}
|
|
3206
|
-
},
|
|
3207
|
-
headers: docHeader ? { default: docHeader } : void 0,
|
|
3208
|
-
footers: docFooter ? { default: docFooter } : void 0,
|
|
3209
|
-
children: docElements
|
|
3210
|
-
}
|
|
3211
|
-
]
|
|
4304
|
+
sections: docSections
|
|
3212
4305
|
});
|
|
3213
4306
|
return await Packer.toBuffer(document);
|
|
3214
4307
|
}
|
|
4308
|
+
async function buildDocxBackCoverElements(backCover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
|
|
4309
|
+
var _a;
|
|
4310
|
+
const elements = [];
|
|
4311
|
+
elements.push(new Paragraph({ spacing: { before: 1800 } }));
|
|
4312
|
+
if (backCover.logo) {
|
|
4313
|
+
const resolvedLogo = await resolveImage(backCover.logo, baseDir);
|
|
4314
|
+
if (resolvedLogo) {
|
|
4315
|
+
const logoW = typeof backCover.logoWidth === "number" ? backCover.logoWidth : 140;
|
|
4316
|
+
const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
|
|
4317
|
+
elements.push(
|
|
4318
|
+
new Paragraph({
|
|
4319
|
+
children: [
|
|
4320
|
+
new ImageRun({
|
|
4321
|
+
data: resolvedLogo.buffer,
|
|
4322
|
+
transformation: {
|
|
4323
|
+
width: logoW,
|
|
4324
|
+
height: Math.round(logoW * 0.75)
|
|
4325
|
+
},
|
|
4326
|
+
type: logoType
|
|
4327
|
+
})
|
|
4328
|
+
],
|
|
4329
|
+
spacing: { after: 240 }
|
|
4330
|
+
})
|
|
4331
|
+
);
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
if (backCover.badge) {
|
|
4335
|
+
elements.push(
|
|
4336
|
+
new Paragraph({
|
|
4337
|
+
children: [
|
|
4338
|
+
new TextRun({
|
|
4339
|
+
text: `[ ${backCover.badge.toUpperCase()} ]`,
|
|
4340
|
+
font: defaultFont,
|
|
4341
|
+
size: 20,
|
|
4342
|
+
bold: true,
|
|
4343
|
+
color: primaryDarkHex
|
|
4344
|
+
})
|
|
4345
|
+
],
|
|
4346
|
+
spacing: { after: 240 }
|
|
4347
|
+
})
|
|
4348
|
+
);
|
|
4349
|
+
}
|
|
4350
|
+
elements.push(
|
|
4351
|
+
new Paragraph({
|
|
4352
|
+
children: [
|
|
4353
|
+
new TextRun({
|
|
4354
|
+
text: backCover.title,
|
|
4355
|
+
font: defaultFont,
|
|
4356
|
+
size: 52,
|
|
4357
|
+
// 26pt
|
|
4358
|
+
bold: true,
|
|
4359
|
+
color: textHex
|
|
4360
|
+
})
|
|
4361
|
+
],
|
|
4362
|
+
spacing: { after: 140 }
|
|
4363
|
+
})
|
|
4364
|
+
);
|
|
4365
|
+
if (backCover.subtitle) {
|
|
4366
|
+
elements.push(
|
|
4367
|
+
new Paragraph({
|
|
4368
|
+
children: [
|
|
4369
|
+
new TextRun({
|
|
4370
|
+
text: backCover.subtitle,
|
|
4371
|
+
font: defaultFont,
|
|
4372
|
+
size: 24,
|
|
4373
|
+
// 12pt
|
|
4374
|
+
color: textMutedHex
|
|
4375
|
+
})
|
|
4376
|
+
],
|
|
4377
|
+
spacing: { after: 480 }
|
|
4378
|
+
})
|
|
4379
|
+
);
|
|
4380
|
+
}
|
|
4381
|
+
elements.push(
|
|
4382
|
+
new Paragraph({
|
|
4383
|
+
border: {
|
|
4384
|
+
bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
|
|
4385
|
+
},
|
|
4386
|
+
spacing: { after: 480 }
|
|
4387
|
+
})
|
|
4388
|
+
);
|
|
4389
|
+
const contactRuns = [];
|
|
4390
|
+
if (backCover.company) contactRuns.push(new TextRun({ text: `Organization: ${backCover.company}
|
|
4391
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4392
|
+
if (backCover.address) contactRuns.push(new TextRun({ text: `Address: ${backCover.address}
|
|
4393
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4394
|
+
if (backCover.email) contactRuns.push(new TextRun({ text: `Email: ${backCover.email}
|
|
4395
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4396
|
+
if (backCover.phone) contactRuns.push(new TextRun({ text: `Phone: ${backCover.phone}
|
|
4397
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4398
|
+
if (backCover.website) contactRuns.push(new TextRun({ text: `Website: ${backCover.website}
|
|
4399
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4400
|
+
if (backCover.social) {
|
|
4401
|
+
for (const [net, url] of Object.entries(backCover.social)) {
|
|
4402
|
+
if (url) {
|
|
4403
|
+
contactRuns.push(new TextRun({ text: `${net.toUpperCase()}: ${url}
|
|
4404
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
if (contactRuns.length > 0) {
|
|
4409
|
+
elements.push(
|
|
4410
|
+
new Paragraph({
|
|
4411
|
+
children: contactRuns,
|
|
4412
|
+
spacing: { before: 360, after: 360 }
|
|
4413
|
+
})
|
|
4414
|
+
);
|
|
4415
|
+
}
|
|
4416
|
+
if (backCover.copyright) {
|
|
4417
|
+
elements.push(
|
|
4418
|
+
new Paragraph({
|
|
4419
|
+
children: [
|
|
4420
|
+
new TextRun({
|
|
4421
|
+
text: backCover.copyright,
|
|
4422
|
+
font: defaultFont,
|
|
4423
|
+
size: 18,
|
|
4424
|
+
color: "94A3B8"
|
|
4425
|
+
})
|
|
4426
|
+
],
|
|
4427
|
+
spacing: { before: 720 }
|
|
4428
|
+
})
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
return elements;
|
|
4432
|
+
}
|
|
4433
|
+
async function buildDocxCoverPageElements(cover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
|
|
4434
|
+
var _a;
|
|
4435
|
+
const elements = [];
|
|
4436
|
+
elements.push(new Paragraph({ spacing: { before: 1800 } }));
|
|
4437
|
+
if (cover.logo) {
|
|
4438
|
+
const resolvedLogo = await resolveImage(cover.logo, baseDir);
|
|
4439
|
+
if (resolvedLogo) {
|
|
4440
|
+
const logoW = typeof cover.logoWidth === "number" ? cover.logoWidth : 140;
|
|
4441
|
+
const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
|
|
4442
|
+
elements.push(
|
|
4443
|
+
new Paragraph({
|
|
4444
|
+
children: [
|
|
4445
|
+
new ImageRun({
|
|
4446
|
+
data: resolvedLogo.buffer,
|
|
4447
|
+
transformation: {
|
|
4448
|
+
width: logoW,
|
|
4449
|
+
height: Math.round(logoW * 0.75)
|
|
4450
|
+
},
|
|
4451
|
+
type: logoType
|
|
4452
|
+
})
|
|
4453
|
+
],
|
|
4454
|
+
spacing: { after: 240 }
|
|
4455
|
+
})
|
|
4456
|
+
);
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
if (cover.badge) {
|
|
4460
|
+
elements.push(
|
|
4461
|
+
new Paragraph({
|
|
4462
|
+
children: [
|
|
4463
|
+
new TextRun({
|
|
4464
|
+
text: `[ ${cover.badge.toUpperCase()} ]`,
|
|
4465
|
+
font: defaultFont,
|
|
4466
|
+
size: 20,
|
|
4467
|
+
bold: true,
|
|
4468
|
+
color: primaryDarkHex
|
|
4469
|
+
})
|
|
4470
|
+
],
|
|
4471
|
+
spacing: { after: 240 }
|
|
4472
|
+
})
|
|
4473
|
+
);
|
|
4474
|
+
}
|
|
4475
|
+
elements.push(
|
|
4476
|
+
new Paragraph({
|
|
4477
|
+
children: [
|
|
4478
|
+
new TextRun({
|
|
4479
|
+
text: cover.title,
|
|
4480
|
+
font: defaultFont,
|
|
4481
|
+
size: 56,
|
|
4482
|
+
// 28pt
|
|
4483
|
+
bold: true,
|
|
4484
|
+
color: textHex
|
|
4485
|
+
})
|
|
4486
|
+
],
|
|
4487
|
+
spacing: { after: 140 }
|
|
4488
|
+
})
|
|
4489
|
+
);
|
|
4490
|
+
if (cover.subtitle) {
|
|
4491
|
+
elements.push(
|
|
4492
|
+
new Paragraph({
|
|
4493
|
+
children: [
|
|
4494
|
+
new TextRun({
|
|
4495
|
+
text: cover.subtitle,
|
|
4496
|
+
font: defaultFont,
|
|
4497
|
+
size: 26,
|
|
4498
|
+
// 13pt
|
|
4499
|
+
color: textMutedHex
|
|
4500
|
+
})
|
|
4501
|
+
],
|
|
4502
|
+
spacing: { after: 480 }
|
|
4503
|
+
})
|
|
4504
|
+
);
|
|
4505
|
+
}
|
|
4506
|
+
elements.push(
|
|
4507
|
+
new Paragraph({
|
|
4508
|
+
border: {
|
|
4509
|
+
bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
|
|
4510
|
+
},
|
|
4511
|
+
spacing: { after: 480 }
|
|
4512
|
+
})
|
|
4513
|
+
);
|
|
4514
|
+
if (cover.company || cover.author || cover.version || cover.date) {
|
|
4515
|
+
const metaRuns = [];
|
|
4516
|
+
if (cover.company) metaRuns.push(new TextRun({ text: `Organization: ${cover.company}
|
|
4517
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4518
|
+
if (cover.author) metaRuns.push(new TextRun({ text: `Author: ${cover.author}
|
|
4519
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4520
|
+
if (cover.version) metaRuns.push(new TextRun({ text: `Version: ${cover.version}
|
|
4521
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4522
|
+
if (cover.date) metaRuns.push(new TextRun({ text: `Date: ${cover.date}
|
|
4523
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4524
|
+
elements.push(
|
|
4525
|
+
new Paragraph({
|
|
4526
|
+
children: metaRuns,
|
|
4527
|
+
spacing: { before: 360, after: 360 }
|
|
4528
|
+
})
|
|
4529
|
+
);
|
|
4530
|
+
}
|
|
4531
|
+
if (cover.footerText) {
|
|
4532
|
+
elements.push(
|
|
4533
|
+
new Paragraph({
|
|
4534
|
+
children: [
|
|
4535
|
+
new TextRun({
|
|
4536
|
+
text: cover.footerText,
|
|
4537
|
+
font: defaultFont,
|
|
4538
|
+
size: 18,
|
|
4539
|
+
color: "94A3B8"
|
|
4540
|
+
})
|
|
4541
|
+
],
|
|
4542
|
+
spacing: { before: 720 }
|
|
4543
|
+
})
|
|
4544
|
+
);
|
|
4545
|
+
}
|
|
4546
|
+
return elements;
|
|
4547
|
+
}
|
|
3215
4548
|
async function buildDocxSignatureCell(item, sig, widthDxa, defaultFont, baseDir) {
|
|
3216
4549
|
const cellParagraphs = [];
|
|
3217
4550
|
if (item.title) {
|
|
@@ -3347,126 +4680,9 @@ function createEmptyDocxCell(widthDxa) {
|
|
|
3347
4680
|
});
|
|
3348
4681
|
}
|
|
3349
4682
|
|
|
3350
|
-
// src/core/engine.ts
|
|
3351
|
-
async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgress) {
|
|
3352
|
-
const startTime = Date.now();
|
|
3353
|
-
const config = { ...DEFAULT_CONFIG, ...userConfig };
|
|
3354
|
-
let rawMarkdown = "";
|
|
3355
|
-
let baseDir = process.cwd();
|
|
3356
|
-
let inputFileName = "document.md";
|
|
3357
|
-
let isFilePath = false;
|
|
3358
|
-
if (fs5.existsSync(inputFilePathOrContent)) {
|
|
3359
|
-
isFilePath = true;
|
|
3360
|
-
rawMarkdown = fs5.readFileSync(inputFilePathOrContent, "utf-8");
|
|
3361
|
-
baseDir = path7.dirname(path7.resolve(inputFilePathOrContent));
|
|
3362
|
-
inputFileName = path7.basename(inputFilePathOrContent);
|
|
3363
|
-
} else {
|
|
3364
|
-
rawMarkdown = inputFilePathOrContent;
|
|
3365
|
-
}
|
|
3366
|
-
onProgress == null ? void 0 : onProgress(`Parsing markdown AST: ${inputFileName}...`);
|
|
3367
|
-
const parsedDoc = parseMarkdownDocument(rawMarkdown);
|
|
3368
|
-
const baseName = inputFileName.replace(/\.(md|mdx|markdown)$/i, "");
|
|
3369
|
-
const outputDir = config.outputDir ? path7.isAbsolute(config.outputDir) ? config.outputDir : path7.resolve(process.cwd(), config.outputDir) : baseDir;
|
|
3370
|
-
if (!fs5.existsSync(outputDir)) {
|
|
3371
|
-
fs5.mkdirSync(outputDir, { recursive: true });
|
|
3372
|
-
}
|
|
3373
|
-
const formats = Array.isArray(config.to) ? config.to : [config.to || "docx", "pdf"];
|
|
3374
|
-
const generatedFiles = [];
|
|
3375
|
-
const errors = [];
|
|
3376
|
-
for (const fmt of formats) {
|
|
3377
|
-
try {
|
|
3378
|
-
if (fmt === "docx") {
|
|
3379
|
-
onProgress == null ? void 0 : onProgress(`Generating DOCX document: ${baseName}.docx...`);
|
|
3380
|
-
const docxBuffer = await buildDocxDocument(parsedDoc, config, baseDir);
|
|
3381
|
-
const docxPath = path7.join(outputDir, `${baseName}.docx`);
|
|
3382
|
-
fs5.writeFileSync(docxPath, docxBuffer);
|
|
3383
|
-
generatedFiles.push({
|
|
3384
|
-
format: "docx",
|
|
3385
|
-
filePath: docxPath,
|
|
3386
|
-
fileName: `${baseName}.docx`,
|
|
3387
|
-
sizeBytes: docxBuffer.length
|
|
3388
|
-
});
|
|
3389
|
-
} else if (fmt === "html") {
|
|
3390
|
-
onProgress == null ? void 0 : onProgress(`Generating HTML document: ${baseName}.html...`);
|
|
3391
|
-
const htmlString = await buildHtmlDocument(parsedDoc, config, baseDir);
|
|
3392
|
-
const htmlPath = path7.join(outputDir, `${baseName}.html`);
|
|
3393
|
-
fs5.writeFileSync(htmlPath, htmlString, "utf-8");
|
|
3394
|
-
generatedFiles.push({
|
|
3395
|
-
format: "html",
|
|
3396
|
-
filePath: htmlPath,
|
|
3397
|
-
fileName: `${baseName}.html`,
|
|
3398
|
-
sizeBytes: Buffer.byteLength(htmlString, "utf-8")
|
|
3399
|
-
});
|
|
3400
|
-
} else if (fmt === "pdf") {
|
|
3401
|
-
onProgress == null ? void 0 : onProgress(`Generating PDF document: ${baseName}.pdf...`);
|
|
3402
|
-
const pdfBuffer = await buildPdfDocument(parsedDoc, config, baseDir);
|
|
3403
|
-
const pdfPath = path7.join(outputDir, `${baseName}.pdf`);
|
|
3404
|
-
fs5.writeFileSync(pdfPath, pdfBuffer);
|
|
3405
|
-
generatedFiles.push({
|
|
3406
|
-
format: "pdf",
|
|
3407
|
-
filePath: pdfPath,
|
|
3408
|
-
fileName: `${baseName}.pdf`,
|
|
3409
|
-
sizeBytes: pdfBuffer.length
|
|
3410
|
-
});
|
|
3411
|
-
}
|
|
3412
|
-
} catch (err) {
|
|
3413
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3414
|
-
errors.push(`Failed to generate ${fmt}: ${errMsg}`);
|
|
3415
|
-
}
|
|
3416
|
-
}
|
|
3417
|
-
const durationMs = Date.now() - startTime;
|
|
3418
|
-
return {
|
|
3419
|
-
inputFile: isFilePath ? inputFilePathOrContent : "inline-string",
|
|
3420
|
-
durationMs,
|
|
3421
|
-
metadata: parsedDoc.metadata,
|
|
3422
|
-
files: generatedFiles,
|
|
3423
|
-
errors
|
|
3424
|
-
};
|
|
3425
|
-
}
|
|
3426
|
-
|
|
3427
|
-
// src/ui/App.tsx
|
|
3428
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3429
|
-
var App = ({ inputFile, config, onComplete }) => {
|
|
3430
|
-
const [status, setStatus] = useState("Initializing...");
|
|
3431
|
-
const [isCompiling, setIsCompiling] = useState(true);
|
|
3432
|
-
const [result, setResult] = useState(null);
|
|
3433
|
-
useEffect(() => {
|
|
3434
|
-
async function run() {
|
|
3435
|
-
try {
|
|
3436
|
-
const res = await compileMarkdown(inputFile, config, (msg) => setStatus(msg));
|
|
3437
|
-
setResult(res);
|
|
3438
|
-
setIsCompiling(false);
|
|
3439
|
-
onComplete == null ? void 0 : onComplete(res);
|
|
3440
|
-
} catch (err) {
|
|
3441
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3442
|
-
const errResult = {
|
|
3443
|
-
inputFile,
|
|
3444
|
-
durationMs: 0,
|
|
3445
|
-
metadata: {},
|
|
3446
|
-
files: [],
|
|
3447
|
-
errors: [errMsg]
|
|
3448
|
-
};
|
|
3449
|
-
setResult(errResult);
|
|
3450
|
-
setIsCompiling(false);
|
|
3451
|
-
onComplete == null ? void 0 : onComplete(errResult);
|
|
3452
|
-
}
|
|
3453
|
-
}
|
|
3454
|
-
run();
|
|
3455
|
-
}, [inputFile, config, onComplete]);
|
|
3456
|
-
const targetFormats = Array.isArray(config.to) ? config.to : config.to ? [String(config.to)] : ["docx", "pdf"];
|
|
3457
|
-
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
3458
|
-
/* @__PURE__ */ jsx4(
|
|
3459
|
-
Header,
|
|
3460
|
-
{
|
|
3461
|
-
inputFile,
|
|
3462
|
-
theme: config.theme,
|
|
3463
|
-
targetFormats
|
|
3464
|
-
}
|
|
3465
|
-
),
|
|
3466
|
-
/* @__PURE__ */ jsx4(LiveProgress, { status, isCompiling }),
|
|
3467
|
-
/* @__PURE__ */ jsx4(SummaryTable, { result })
|
|
3468
|
-
] });
|
|
3469
|
-
};
|
|
3470
4683
|
export {
|
|
3471
|
-
|
|
4684
|
+
parseMarkdownDocument,
|
|
4685
|
+
buildHtmlDocument,
|
|
4686
|
+
buildPdfDocument,
|
|
4687
|
+
buildDocxDocument
|
|
3472
4688
|
};
|