@masumdev/markforge 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +168 -141
- package/dist/App-3QDKBKHG.mjs +328 -0
- package/dist/{chunk-IYGPJIK5.mjs → chunk-BPHDY6VB.mjs} +6 -0
- package/dist/{App-AM2CWXHJ.mjs → chunk-CRV7R2BG.mjs} +1722 -657
- package/dist/{chunk-HKB4CSPZ.mjs → chunk-TNWZ4MFS.mjs} +1 -1
- package/dist/cli.mjs +29 -7
- package/dist/index.d.mts +506 -123
- package/dist/index.d.ts +506 -123
- package/dist/index.js +2481 -208
- package/dist/index.mjs +2470 -208
- package/dist/{loadConfig-PD6ENMAM.mjs → loadConfig-PGJKPE6G.mjs} +1 -1
- package/dist/previewServer-XAUOBNBZ.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",
|
|
@@ -356,6 +188,35 @@ function parseInlineSpans(text) {
|
|
|
356
188
|
function slugify(text) {
|
|
357
189
|
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
358
190
|
}
|
|
191
|
+
function applyHeadingNumbering(nodes, tocEntries, options) {
|
|
192
|
+
const depth = options.depth ?? 3;
|
|
193
|
+
const skipH1 = options.skipH1 ?? false;
|
|
194
|
+
const prefix = options.prefix ?? "";
|
|
195
|
+
const counters = [0, 0, 0, 0, 0, 0];
|
|
196
|
+
for (const node of nodes) {
|
|
197
|
+
if (node.type === "heading" && node.level) {
|
|
198
|
+
const lvl = node.level;
|
|
199
|
+
if (lvl > depth) continue;
|
|
200
|
+
if (lvl === 1 && skipH1) continue;
|
|
201
|
+
const idx = lvl - 1;
|
|
202
|
+
counters[idx]++;
|
|
203
|
+
for (let c = idx + 1; c < counters.length; c++) {
|
|
204
|
+
counters[c] = 0;
|
|
205
|
+
}
|
|
206
|
+
const startIdx = skipH1 ? 1 : 0;
|
|
207
|
+
const parts = counters.slice(startIdx, idx + 1).filter((n) => n > 0);
|
|
208
|
+
const numberStr = parts.join(".") + ".";
|
|
209
|
+
const fullPrefix = prefix ? `${prefix} ${numberStr} ` : `${numberStr} `;
|
|
210
|
+
const originalText = node.text || "";
|
|
211
|
+
node.text = fullPrefix + originalText;
|
|
212
|
+
node.inlines = parseInlineSpans(node.text);
|
|
213
|
+
const toc = tocEntries.find((t) => t.id === node.id);
|
|
214
|
+
if (toc) {
|
|
215
|
+
toc.text = node.text;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
359
220
|
function parseMarkdownDocument(rawMarkdown) {
|
|
360
221
|
const { data: frontmatter, content } = matter(rawMarkdown);
|
|
361
222
|
const metadata = frontmatter || {};
|
|
@@ -367,6 +228,7 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
367
228
|
const lines = cleanContent.split(/\r?\n/);
|
|
368
229
|
const nodes = [];
|
|
369
230
|
const tocEntries = [];
|
|
231
|
+
const footnoteDefs = [];
|
|
370
232
|
let i = 0;
|
|
371
233
|
while (i < lines.length) {
|
|
372
234
|
const line = lines[i];
|
|
@@ -395,6 +257,29 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
395
257
|
i++;
|
|
396
258
|
continue;
|
|
397
259
|
}
|
|
260
|
+
if (line.trim().startsWith("$$")) {
|
|
261
|
+
const mathLines = [];
|
|
262
|
+
const singleLine = line.trim().match(/^\$\$(.+)\$\$$/);
|
|
263
|
+
if (singleLine) {
|
|
264
|
+
nodes.push({
|
|
265
|
+
type: "mathBlock",
|
|
266
|
+
text: singleLine[1].trim()
|
|
267
|
+
});
|
|
268
|
+
i++;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
i++;
|
|
272
|
+
while (i < lines.length && !lines[i].trim().startsWith("$$")) {
|
|
273
|
+
mathLines.push(lines[i]);
|
|
274
|
+
i++;
|
|
275
|
+
}
|
|
276
|
+
if (i < lines.length) i++;
|
|
277
|
+
nodes.push({
|
|
278
|
+
type: "mathBlock",
|
|
279
|
+
text: mathLines.join("\n").trim()
|
|
280
|
+
});
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
398
283
|
const codeBlockMatch = line.match(/^```(\w+)?/);
|
|
399
284
|
if (codeBlockMatch) {
|
|
400
285
|
const language = (codeBlockMatch[1] || "text").trim().toLowerCase();
|
|
@@ -421,6 +306,100 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
421
306
|
}
|
|
422
307
|
continue;
|
|
423
308
|
}
|
|
309
|
+
const colsMatch = line.trim().match(/^:::columns(?:\s+\[?([\w\s=.-]+)\]?)?$/i);
|
|
310
|
+
if (colsMatch) {
|
|
311
|
+
const attrStr = colsMatch[1] || "";
|
|
312
|
+
let colsCount = 2;
|
|
313
|
+
let colGap = "1.5rem";
|
|
314
|
+
if (attrStr) {
|
|
315
|
+
const numMatch = attrStr.trim().match(/^(\d+)$/);
|
|
316
|
+
const cMatch = attrStr.match(/cols=(\d+)/i) || attrStr.match(/columns=(\d+)/i);
|
|
317
|
+
const gMatch = attrStr.match(/gap=([^\s]+)/i);
|
|
318
|
+
if (numMatch) colsCount = parseInt(numMatch[1], 10);
|
|
319
|
+
else if (cMatch) colsCount = parseInt(cMatch[1], 10);
|
|
320
|
+
if (gMatch) colGap = gMatch[1];
|
|
321
|
+
}
|
|
322
|
+
const columnNodes = [];
|
|
323
|
+
let currentColumnLines = [];
|
|
324
|
+
let inColBlock = false;
|
|
325
|
+
i++;
|
|
326
|
+
while (i < lines.length) {
|
|
327
|
+
const curLine = lines[i];
|
|
328
|
+
const trimmed = curLine.trim();
|
|
329
|
+
if (/^:::col(?:umn)?$/i.test(trimmed)) {
|
|
330
|
+
if (currentColumnLines.length > 0) {
|
|
331
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
332
|
+
columnNodes.push({
|
|
333
|
+
type: "column",
|
|
334
|
+
children: subDoc.nodes
|
|
335
|
+
});
|
|
336
|
+
currentColumnLines = [];
|
|
337
|
+
}
|
|
338
|
+
inColBlock = true;
|
|
339
|
+
i++;
|
|
340
|
+
} else if (trimmed === ":::") {
|
|
341
|
+
if (inColBlock) {
|
|
342
|
+
if (currentColumnLines.length > 0) {
|
|
343
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
344
|
+
columnNodes.push({
|
|
345
|
+
type: "column",
|
|
346
|
+
children: subDoc.nodes
|
|
347
|
+
});
|
|
348
|
+
currentColumnLines = [];
|
|
349
|
+
}
|
|
350
|
+
inColBlock = false;
|
|
351
|
+
i++;
|
|
352
|
+
} else {
|
|
353
|
+
if (currentColumnLines.length > 0) {
|
|
354
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
355
|
+
columnNodes.push({
|
|
356
|
+
type: "column",
|
|
357
|
+
children: subDoc.nodes
|
|
358
|
+
});
|
|
359
|
+
currentColumnLines = [];
|
|
360
|
+
}
|
|
361
|
+
i++;
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
} else {
|
|
365
|
+
currentColumnLines.push(curLine);
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (currentColumnLines.length > 0) {
|
|
370
|
+
const subDoc = parseMarkdownDocument(currentColumnLines.join("\n"));
|
|
371
|
+
columnNodes.push({
|
|
372
|
+
type: "column",
|
|
373
|
+
children: subDoc.nodes
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
nodes.push({
|
|
377
|
+
type: "columns",
|
|
378
|
+
columnsCount: columnNodes.length > 0 ? columnNodes.length : colsCount,
|
|
379
|
+
columnGap: colGap,
|
|
380
|
+
children: columnNodes
|
|
381
|
+
});
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const fnDefMatch = line.match(/^\[\^([\w-]+)\]:\s+(.+)$/);
|
|
385
|
+
if (fnDefMatch) {
|
|
386
|
+
const fnId = fnDefMatch[1];
|
|
387
|
+
const fnText = fnDefMatch[2].trim();
|
|
388
|
+
const inlines = parseInlineSpans(fnText);
|
|
389
|
+
footnoteDefs.push({
|
|
390
|
+
id: fnId,
|
|
391
|
+
text: fnText,
|
|
392
|
+
inlines
|
|
393
|
+
});
|
|
394
|
+
nodes.push({
|
|
395
|
+
type: "footnoteDef",
|
|
396
|
+
footnoteId: fnId,
|
|
397
|
+
text: fnText,
|
|
398
|
+
inlines
|
|
399
|
+
});
|
|
400
|
+
i++;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
424
403
|
const calloutMatch = line.match(/^>\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*$/i);
|
|
425
404
|
if (calloutMatch) {
|
|
426
405
|
const calloutType = calloutMatch[1].toUpperCase();
|
|
@@ -544,7 +523,7 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
544
523
|
continue;
|
|
545
524
|
}
|
|
546
525
|
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+/)) {
|
|
526
|
+
while (i < lines.length && lines[i].trim() && !lines[i].match(/^#{1,6}\s+/) && !lines[i].startsWith("```") && !lines[i].startsWith("$$") && !lines[i].startsWith(">") && !lines[i].trim().startsWith("|") && !lines[i].match(/^:::columns/) && !lines[i].match(/^\[\^[\w-]+\]:\s+/) && !lines[i].match(/^(\s*)([-*+]|\d+\.)\s+/)) {
|
|
548
527
|
paraLines.push(lines[i]);
|
|
549
528
|
i++;
|
|
550
529
|
}
|
|
@@ -555,43 +534,29 @@ function parseMarkdownDocument(rawMarkdown) {
|
|
|
555
534
|
inlines: parseInlineSpans(paraText)
|
|
556
535
|
});
|
|
557
536
|
}
|
|
537
|
+
if (metadata.numberHeadings) {
|
|
538
|
+
const opts = typeof metadata.numberHeadings === "boolean" ? { enabled: metadata.numberHeadings } : metadata.numberHeadings;
|
|
539
|
+
if (opts.enabled !== false) {
|
|
540
|
+
applyHeadingNumbering(nodes, tocEntries, opts);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
558
543
|
return {
|
|
559
544
|
metadata,
|
|
560
545
|
content: cleanContent,
|
|
561
546
|
nodes,
|
|
562
547
|
tocEntries,
|
|
563
|
-
inlinedStyles
|
|
548
|
+
inlinedStyles,
|
|
549
|
+
footnoteDefs
|
|
564
550
|
};
|
|
565
551
|
}
|
|
566
552
|
|
|
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";
|
|
553
|
+
// src/core/html/htmlBuilder.ts
|
|
554
|
+
import * as fs2 from "fs";
|
|
555
|
+
import * as path2 from "path";
|
|
591
556
|
|
|
592
557
|
// src/core/imageResolver.ts
|
|
593
558
|
import * as fs from "fs";
|
|
594
|
-
import * as
|
|
559
|
+
import * as path from "path";
|
|
595
560
|
var memoryImageCache = /* @__PURE__ */ new Map();
|
|
596
561
|
function getMimeType(filePathOrUrl) {
|
|
597
562
|
const clean = filePathOrUrl.split("?")[0].toLowerCase();
|
|
@@ -648,9 +613,14 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
648
613
|
memoryImageCache.set(cacheKey, resolved2);
|
|
649
614
|
return resolved2;
|
|
650
615
|
}
|
|
651
|
-
|
|
616
|
+
let localPath = path.isAbsolute(src) ? src : path.resolve(baseDir, src);
|
|
652
617
|
if (!fs.existsSync(localPath)) {
|
|
653
|
-
|
|
618
|
+
const cwdPath = path.resolve(process.cwd(), src);
|
|
619
|
+
if (fs.existsSync(cwdPath)) {
|
|
620
|
+
localPath = cwdPath;
|
|
621
|
+
} else {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
654
624
|
}
|
|
655
625
|
const buffer = fs.readFileSync(localPath);
|
|
656
626
|
const mimeType = getMimeType(localPath);
|
|
@@ -670,6 +640,164 @@ async function resolveImage(src, baseDir = process.cwd()) {
|
|
|
670
640
|
}
|
|
671
641
|
}
|
|
672
642
|
|
|
643
|
+
// src/core/html/htmlThemes.ts
|
|
644
|
+
var THEME_COMPONENTS = `
|
|
645
|
+
/* Fallback CSS variables \u2014 overridden by each named theme's :root block */
|
|
646
|
+
:root {
|
|
647
|
+
--mf-bg: #ffffff;
|
|
648
|
+
--mf-text: #0f172a;
|
|
649
|
+
--mf-text-muted: #64748b;
|
|
650
|
+
--mf-primary: #33CDCF;
|
|
651
|
+
--mf-primary-dark: #009DA0;
|
|
652
|
+
--mf-primary-light: #ECFDFD;
|
|
653
|
+
--mf-border: #e2e8f0;
|
|
654
|
+
--mf-card-bg: #f8fafc;
|
|
655
|
+
--mf-code-bg: #0f172a;
|
|
656
|
+
--mf-code-text: #f8fafc;
|
|
657
|
+
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
658
|
+
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/* Document header */
|
|
662
|
+
.document-header { margin-bottom: 2.5rem; padding-bottom: 1.5rem; border-bottom: 2px solid var(--mf-border); }
|
|
663
|
+
.document-title { font-size: 2.5rem; font-weight: 800; margin: 0 0 0.5rem 0; }
|
|
664
|
+
.document-subtitle { font-size: 1.25rem; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
665
|
+
.document-meta { font-size: 0.9rem; color: var(--mf-text-muted); display: flex; gap: 1.5rem; flex-wrap: wrap; }
|
|
666
|
+
|
|
667
|
+
/* Table of Contents */
|
|
668
|
+
.table-of-contents { background: var(--mf-card-bg); border: 1px solid var(--mf-border); border-radius: 8px; padding: 1.5rem 2rem; margin: 2rem 0; }
|
|
669
|
+
.table-of-contents h2 { font-size: 1rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--mf-text-muted); margin: 0 0 1rem 0; }
|
|
670
|
+
.table-of-contents ul { list-style: none; padding: 0; margin: 0; }
|
|
671
|
+
.table-of-contents li { padding: 0.25rem 0; }
|
|
672
|
+
.table-of-contents a { color: var(--mf-primary-dark); text-decoration: none; }
|
|
673
|
+
.table-of-contents a:hover { text-decoration: underline; }
|
|
674
|
+
|
|
675
|
+
/* Links */
|
|
676
|
+
a { color: var(--mf-primary-dark); font-weight: 600; text-decoration: none; }
|
|
677
|
+
a:hover { text-decoration: underline; }
|
|
678
|
+
|
|
679
|
+
/* Blockquote */
|
|
680
|
+
blockquote { border-left: 4px solid var(--mf-primary); background-color: var(--mf-card-bg); margin: 1.2rem 0; padding: 0.8rem 1.2rem; border-radius: 0 8px 8px 0; color: #334155; font-style: italic; }
|
|
681
|
+
|
|
682
|
+
/* Callout / Alert Boxes */
|
|
683
|
+
.callout { border-left: 4px solid var(--mf-primary); background: var(--mf-card-bg); border-radius: 6px; padding: 1rem 1.2rem; margin: 1.2rem 0; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
684
|
+
.callout-title { font-weight: 700; font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
|
|
685
|
+
.callout-NOTE { border-color: #33CDCF; background: #ECFDFD; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
686
|
+
.callout-NOTE .callout-title { color: #009DA0; }
|
|
687
|
+
.callout-TIP { border-color: #10b981; background: #ecfdf5; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
688
|
+
.callout-TIP .callout-title { color: #10b981; }
|
|
689
|
+
.callout-WARNING { border-color: #f59e0b; background: #fffbeb; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
690
|
+
.callout-WARNING .callout-title { color: #f59e0b; }
|
|
691
|
+
.callout-CAUTION { border-color: #ef4444; background: #fef2f2; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
692
|
+
.callout-CAUTION .callout-title { color: #ef4444; }
|
|
693
|
+
.callout-IMPORTANT { border-color: #8b5cf6; background: #f5f3ff; -webkit-print-color-adjust: exact; print-color-adjust: exact; }
|
|
694
|
+
.callout-IMPORTANT .callout-title { color: #8b5cf6; }
|
|
695
|
+
|
|
696
|
+
/* Inline Code */
|
|
697
|
+
code { font-family: var(--mf-font-mono); font-size: 0.88em; background-color: #f1f5f9; padding: 0.2em 0.4em; border-radius: 4px; color: #0f172a; }
|
|
698
|
+
|
|
699
|
+
/* Code Blocks */
|
|
700
|
+
pre { background-color: var(--mf-code-bg); color: var(--mf-code-text); padding: 1.2rem; border-radius: 8px; overflow-x: auto; font-family: var(--mf-font-mono); font-size: 0.9rem; line-height: 1.5; margin: 1.2rem 0; }
|
|
701
|
+
pre code { background-color: transparent; color: inherit; padding: 0; }
|
|
702
|
+
|
|
703
|
+
/* Tables */
|
|
704
|
+
table { width: 100%; border-collapse: collapse; margin: 1.5rem 0; font-size: 0.95rem; }
|
|
705
|
+
th, td { border: 1px solid var(--mf-border); padding: 0.75rem 1rem; text-align: left; }
|
|
706
|
+
th { background-color: var(--mf-card-bg); font-weight: 600; color: #0f172a; }
|
|
707
|
+
tr:nth-child(even) { background-color: var(--mf-card-bg); }
|
|
708
|
+
|
|
709
|
+
/* Images */
|
|
710
|
+
img { max-width: 100%; height: auto; border-radius: 6px; margin: 1rem 0; }
|
|
711
|
+
|
|
712
|
+
/* Dividers */
|
|
713
|
+
hr { border: none; border-top: 1px solid var(--mf-border); margin: 2rem 0; }
|
|
714
|
+
|
|
715
|
+
/* Print / PDF */
|
|
716
|
+
@media print {
|
|
717
|
+
body { padding: 0; }
|
|
718
|
+
.document-container { max-width: 100%; }
|
|
719
|
+
pre, table, blockquote, .callout { break-inside: avoid; }
|
|
720
|
+
/* Remove scrollbars \u2014 PDF has no scrolling */
|
|
721
|
+
pre { overflow: visible; white-space: pre-wrap; word-break: break-all; }
|
|
722
|
+
}
|
|
723
|
+
`;
|
|
724
|
+
var THEME_CORPORATE = `
|
|
725
|
+
:root {
|
|
726
|
+
--mf-bg: #ffffff;
|
|
727
|
+
--mf-text: #0f172a;
|
|
728
|
+
--mf-text-muted: #64748b;
|
|
729
|
+
--mf-primary: #33CDCF;
|
|
730
|
+
--mf-primary-dark: #009DA0;
|
|
731
|
+
--mf-primary-light: #ECFDFD;
|
|
732
|
+
--mf-border: #e2e8f0;
|
|
733
|
+
--mf-card-bg: #f8fafc;
|
|
734
|
+
--mf-code-bg: #0f172a;
|
|
735
|
+
--mf-code-text: #f8fafc;
|
|
736
|
+
--mf-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
737
|
+
--mf-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
738
|
+
}
|
|
739
|
+
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
740
|
+
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
741
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
742
|
+
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
743
|
+
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid #CCFBF1; padding-bottom: 0.4rem; }
|
|
744
|
+
h3 { font-size: 1.3rem; }
|
|
745
|
+
h4 { font-size: 1.1rem; }
|
|
746
|
+
p { margin: 0.8rem 0; }
|
|
747
|
+
`;
|
|
748
|
+
var THEMES = {
|
|
749
|
+
corporate: THEME_CORPORATE,
|
|
750
|
+
default: THEME_CORPORATE
|
|
751
|
+
};
|
|
752
|
+
function generateThemeCss(theme) {
|
|
753
|
+
if (!theme || theme === "corporate" || theme === "default" || theme === "corporate" /* CORPORATE */) {
|
|
754
|
+
return THEME_CORPORATE;
|
|
755
|
+
}
|
|
756
|
+
if (typeof theme === "object") {
|
|
757
|
+
const bg = theme.backgroundColor || "#ffffff";
|
|
758
|
+
const text = theme.textColor || "#0f172a";
|
|
759
|
+
const textMuted = theme.textMuted || "#64748b";
|
|
760
|
+
const primary = theme.primaryColor || "#33CDCF";
|
|
761
|
+
const primaryDark = theme.primaryDark || primary;
|
|
762
|
+
const primaryLight = theme.primaryLight || "#ECFDFD";
|
|
763
|
+
const border = theme.borderColor || "#e2e8f0";
|
|
764
|
+
const cardBg = theme.cardBackground || "#f8fafc";
|
|
765
|
+
const codeBg = theme.codeBackground || "#0f172a";
|
|
766
|
+
const codeText = theme.codeText || "#f8fafc";
|
|
767
|
+
const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
768
|
+
const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
|
|
769
|
+
return `
|
|
770
|
+
:root {
|
|
771
|
+
--mf-bg: ${bg};
|
|
772
|
+
--mf-text: ${text};
|
|
773
|
+
--mf-text-muted: ${textMuted};
|
|
774
|
+
--mf-primary: ${primary};
|
|
775
|
+
--mf-primary-dark: ${primaryDark};
|
|
776
|
+
--mf-primary-light: ${primaryLight};
|
|
777
|
+
--mf-border: ${border};
|
|
778
|
+
--mf-card-bg: ${cardBg};
|
|
779
|
+
--mf-code-bg: ${codeBg};
|
|
780
|
+
--mf-code-text: ${codeText};
|
|
781
|
+
--mf-font-family: ${font};
|
|
782
|
+
--mf-font-mono: ${fontMono};
|
|
783
|
+
}
|
|
784
|
+
body { background-color: var(--mf-bg); color: var(--mf-text); font-family: var(--mf-font-family); font-size: 15px; line-height: 1.65; margin: 0; padding: 2.5rem; }
|
|
785
|
+
.document-container { max-width: 860px; margin: 0 auto; position: relative; z-index: 1; }
|
|
786
|
+
h1, h2, h3, h4, h5, h6 { color: var(--mf-text); font-weight: 700; margin-top: 1.8rem; margin-bottom: 0.8rem; line-height: 1.25; }
|
|
787
|
+
h1 { font-size: 2.2rem; border-bottom: 2px solid var(--mf-primary); padding-bottom: 0.5rem; }
|
|
788
|
+
h2 { font-size: 1.6rem; color: var(--mf-primary-dark); border-bottom: 1px solid var(--mf-border); padding-bottom: 0.4rem; }
|
|
789
|
+
h3 { font-size: 1.3rem; }
|
|
790
|
+
h4 { font-size: 1.1rem; }
|
|
791
|
+
p { margin: 0.8rem 0; }
|
|
792
|
+
${theme.customCss || ""}
|
|
793
|
+
`;
|
|
794
|
+
}
|
|
795
|
+
if (typeof theme === "string" && THEMES[theme]) {
|
|
796
|
+
return THEMES[theme];
|
|
797
|
+
}
|
|
798
|
+
return THEME_CORPORATE;
|
|
799
|
+
}
|
|
800
|
+
|
|
673
801
|
// src/core/syntax/syntaxHighlighter.ts
|
|
674
802
|
var SYNTAX_COLORS = {
|
|
675
803
|
keyword: "FF7B72",
|
|
@@ -1025,182 +1153,6 @@ function highlightCodeToHtml(code, lang = "", theme = "github-dark") {
|
|
|
1025
1153
|
return htmlLines.join("\n");
|
|
1026
1154
|
}
|
|
1027
1155
|
|
|
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;
|
|
1158
|
-
}
|
|
1159
|
-
if (typeof theme === "object") {
|
|
1160
|
-
const bg = theme.backgroundColor || "#ffffff";
|
|
1161
|
-
const text = theme.textColor || "#0f172a";
|
|
1162
|
-
const textMuted = theme.textMuted || "#64748b";
|
|
1163
|
-
const primary = theme.primaryColor || "#33CDCF";
|
|
1164
|
-
const primaryDark = theme.primaryDark || primary;
|
|
1165
|
-
const primaryLight = theme.primaryLight || "#ECFDFD";
|
|
1166
|
-
const border = theme.borderColor || "#e2e8f0";
|
|
1167
|
-
const cardBg = theme.cardBackground || "#f8fafc";
|
|
1168
|
-
const codeBg = theme.codeBackground || "#0f172a";
|
|
1169
|
-
const codeText = theme.codeText || "#f8fafc";
|
|
1170
|
-
const font = theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
1171
|
-
const fontMono = theme.fontMono || "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
|
|
1172
|
-
return `
|
|
1173
|
-
:root {
|
|
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
|
-
`;
|
|
1197
|
-
}
|
|
1198
|
-
if (typeof theme === "string" && THEMES[theme]) {
|
|
1199
|
-
return THEMES[theme];
|
|
1200
|
-
}
|
|
1201
|
-
return THEME_CORPORATE;
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
1156
|
// src/config/resolveConfig.ts
|
|
1205
1157
|
var PAPER_DIMENSIONS_TWIP = {
|
|
1206
1158
|
A4: { width: 11906, height: 16838 },
|
|
@@ -1246,7 +1198,8 @@ function formatMarginCss(margin, defaultCss = "2.5cm") {
|
|
|
1246
1198
|
return str;
|
|
1247
1199
|
}
|
|
1248
1200
|
function replaceDocumentTokens(template = "", meta) {
|
|
1249
|
-
|
|
1201
|
+
const currentYear = meta.year || (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1202
|
+
return template.replace(/\{title\}/gi, meta.title || "").replace(/\{subtitle\}/gi, meta.subtitle || "").replace(/\{author\}/gi, meta.author || "").replace(/\{version\}/gi, meta.version || "").replace(/\{date\}/gi, meta.date || "").replace(/\{year\}/gi, currentYear).replace(/\{company\}/gi, meta.company || "");
|
|
1250
1203
|
}
|
|
1251
1204
|
function normalizeWatermark(rawWatermark) {
|
|
1252
1205
|
if (!rawWatermark) {
|
|
@@ -1383,6 +1336,129 @@ function normalizeSignatures(raw, meta = {}) {
|
|
|
1383
1336
|
spacingBeforeTwip
|
|
1384
1337
|
};
|
|
1385
1338
|
}
|
|
1339
|
+
function normalizeCoverPage(rawCover, tokenCtx = {}) {
|
|
1340
|
+
if (!rawCover) return void 0;
|
|
1341
|
+
const cfg = typeof rawCover === "object" ? rawCover : {};
|
|
1342
|
+
if (cfg.enabled === false) return void 0;
|
|
1343
|
+
const preset = cfg.preset || "modern";
|
|
1344
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : tokenCtx.title || "Document Title";
|
|
1345
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : tokenCtx.subtitle;
|
|
1346
|
+
const author = Array.isArray(cfg.author) ? cfg.author.join(", ") : cfg.author ? replaceDocumentTokens(String(cfg.author), tokenCtx) : tokenCtx.author;
|
|
1347
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
|
|
1348
|
+
const version = cfg.version ? replaceDocumentTokens(String(cfg.version), tokenCtx) : tokenCtx.version;
|
|
1349
|
+
let dateStr;
|
|
1350
|
+
if (typeof cfg.date === "string") {
|
|
1351
|
+
dateStr = replaceDocumentTokens(cfg.date, tokenCtx);
|
|
1352
|
+
} else if (cfg.date === true) {
|
|
1353
|
+
dateStr = tokenCtx.date || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1354
|
+
} else {
|
|
1355
|
+
dateStr = tokenCtx.date;
|
|
1356
|
+
}
|
|
1357
|
+
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1358
|
+
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1359
|
+
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1360
|
+
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1361
|
+
const logoWidth = cfg.logoWidth;
|
|
1362
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
|
|
1363
|
+
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1364
|
+
const footerText = cfg.footerText ? replaceDocumentTokens(String(cfg.footerText), tokenCtx) : void 0;
|
|
1365
|
+
return {
|
|
1366
|
+
enabled: true,
|
|
1367
|
+
preset,
|
|
1368
|
+
title,
|
|
1369
|
+
subtitle,
|
|
1370
|
+
author,
|
|
1371
|
+
company,
|
|
1372
|
+
version,
|
|
1373
|
+
date: dateStr,
|
|
1374
|
+
badge,
|
|
1375
|
+
badgeColor,
|
|
1376
|
+
badgeTextColor,
|
|
1377
|
+
logo,
|
|
1378
|
+
logoWidth,
|
|
1379
|
+
bgGradient,
|
|
1380
|
+
textColor,
|
|
1381
|
+
footerText
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
function normalizeBackCover(rawBack, tokenCtx = {}) {
|
|
1385
|
+
if (!rawBack) return void 0;
|
|
1386
|
+
const cfg = typeof rawBack === "object" ? rawBack : {};
|
|
1387
|
+
if (cfg.enabled === false) return void 0;
|
|
1388
|
+
const preset = cfg.preset || "modern";
|
|
1389
|
+
const title = cfg.title ? replaceDocumentTokens(String(cfg.title), tokenCtx) : "Thank You";
|
|
1390
|
+
const subtitle = cfg.subtitle ? replaceDocumentTokens(String(cfg.subtitle), tokenCtx) : void 0;
|
|
1391
|
+
const company = cfg.company ? replaceDocumentTokens(String(cfg.company), tokenCtx) : tokenCtx.company;
|
|
1392
|
+
const address = cfg.address ? replaceDocumentTokens(String(cfg.address), tokenCtx) : void 0;
|
|
1393
|
+
const email = cfg.email ? replaceDocumentTokens(String(cfg.email), tokenCtx) : void 0;
|
|
1394
|
+
const phone = cfg.phone ? replaceDocumentTokens(String(cfg.phone), tokenCtx) : void 0;
|
|
1395
|
+
const website = cfg.website ? replaceDocumentTokens(String(cfg.website), tokenCtx) : void 0;
|
|
1396
|
+
let socialMap;
|
|
1397
|
+
if (cfg.social && typeof cfg.social === "object") {
|
|
1398
|
+
socialMap = {};
|
|
1399
|
+
for (const [k, v] of Object.entries(cfg.social)) {
|
|
1400
|
+
if (typeof v === "string") {
|
|
1401
|
+
socialMap[k] = replaceDocumentTokens(v, tokenCtx);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
|
|
1406
|
+
const copyright = cfg.copyright ? replaceDocumentTokens(String(cfg.copyright), { ...tokenCtx, year: currentYear }) : company ? `Copyright (c) ${currentYear} ${company}. All Rights Reserved.` : void 0;
|
|
1407
|
+
const badge = cfg.badge ? replaceDocumentTokens(String(cfg.badge), tokenCtx) : void 0;
|
|
1408
|
+
const badgeColor = typeof cfg.badgeColor === "string" ? cfg.badgeColor : void 0;
|
|
1409
|
+
const badgeTextColor = typeof cfg.badgeTextColor === "string" ? cfg.badgeTextColor : void 0;
|
|
1410
|
+
const logo = typeof cfg.logo === "string" ? cfg.logo : void 0;
|
|
1411
|
+
const logoWidth = cfg.logoWidth;
|
|
1412
|
+
const bgGradient = typeof cfg.bgGradient === "string" ? cfg.bgGradient : void 0;
|
|
1413
|
+
const textColor = typeof cfg.textColor === "string" ? cfg.textColor : void 0;
|
|
1414
|
+
return {
|
|
1415
|
+
enabled: true,
|
|
1416
|
+
preset,
|
|
1417
|
+
title,
|
|
1418
|
+
subtitle,
|
|
1419
|
+
company,
|
|
1420
|
+
address,
|
|
1421
|
+
email,
|
|
1422
|
+
phone,
|
|
1423
|
+
website,
|
|
1424
|
+
social: socialMap,
|
|
1425
|
+
copyright,
|
|
1426
|
+
badge,
|
|
1427
|
+
badgeColor,
|
|
1428
|
+
badgeTextColor,
|
|
1429
|
+
logo,
|
|
1430
|
+
logoWidth,
|
|
1431
|
+
bgGradient,
|
|
1432
|
+
textColor
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
function normalizeNumberHeadings(raw) {
|
|
1436
|
+
if (raw === void 0 || raw === false) return void 0;
|
|
1437
|
+
if (raw === true) {
|
|
1438
|
+
return { enabled: true, depth: 3, skipH1: false, prefix: "" };
|
|
1439
|
+
}
|
|
1440
|
+
if (typeof raw === "object") {
|
|
1441
|
+
const obj = raw;
|
|
1442
|
+
if (obj.enabled === false) return void 0;
|
|
1443
|
+
return {
|
|
1444
|
+
enabled: true,
|
|
1445
|
+
depth: obj.depth ?? 3,
|
|
1446
|
+
skipH1: obj.skipH1 ?? false,
|
|
1447
|
+
prefix: obj.prefix ?? ""
|
|
1448
|
+
};
|
|
1449
|
+
}
|
|
1450
|
+
return void 0;
|
|
1451
|
+
}
|
|
1452
|
+
function normalizeSecurity(raw) {
|
|
1453
|
+
if (!raw) return void 0;
|
|
1454
|
+
const sec = raw;
|
|
1455
|
+
if (!sec.userPassword && !sec.ownerPassword && !sec.permissions) return void 0;
|
|
1456
|
+
return {
|
|
1457
|
+
userPassword: sec.userPassword,
|
|
1458
|
+
ownerPassword: sec.ownerPassword,
|
|
1459
|
+
permissions: sec.permissions
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1386
1462
|
function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
1387
1463
|
const configMeta = userConfig.metadata || {};
|
|
1388
1464
|
const mergedMeta = { ...configMeta, ...frontmatter };
|
|
@@ -1425,6 +1501,15 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1425
1501
|
const watermark = normalizeWatermark(rawWatermark);
|
|
1426
1502
|
const rawSignatures = mergedMeta.signatures || userConfig.signatures;
|
|
1427
1503
|
const signatures = normalizeSignatures(rawSignatures, tokenContext);
|
|
1504
|
+
const rawCover = mergedMeta.coverPage !== void 0 ? mergedMeta.coverPage : userConfig.coverPage;
|
|
1505
|
+
const coverPage = normalizeCoverPage(rawCover, tokenContext);
|
|
1506
|
+
const rawBack = mergedMeta.backCover !== void 0 ? mergedMeta.backCover : userConfig.backCover;
|
|
1507
|
+
const backCover = normalizeBackCover(rawBack, tokenContext);
|
|
1508
|
+
const rawNumberHeadings = mergedMeta.numberHeadings !== void 0 ? mergedMeta.numberHeadings : userConfig.numberHeadings;
|
|
1509
|
+
const numberHeadings = normalizeNumberHeadings(rawNumberHeadings);
|
|
1510
|
+
const rawSecurity = mergedMeta.security || userConfig.security;
|
|
1511
|
+
const security = normalizeSecurity(rawSecurity);
|
|
1512
|
+
const math = mergedMeta.math !== false && userConfig.math !== false;
|
|
1428
1513
|
const cssList = [];
|
|
1429
1514
|
const addCss = (item) => {
|
|
1430
1515
|
if (!item) return;
|
|
@@ -1454,6 +1539,11 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1454
1539
|
toc,
|
|
1455
1540
|
signatures,
|
|
1456
1541
|
watermark,
|
|
1542
|
+
coverPage,
|
|
1543
|
+
backCover,
|
|
1544
|
+
numberHeadings,
|
|
1545
|
+
security,
|
|
1546
|
+
math,
|
|
1457
1547
|
css: cssList,
|
|
1458
1548
|
embedImages,
|
|
1459
1549
|
bundleHtml,
|
|
@@ -1461,6 +1551,45 @@ function resolveDocumentConfig(frontmatter = {}, userConfig = {}) {
|
|
|
1461
1551
|
};
|
|
1462
1552
|
}
|
|
1463
1553
|
|
|
1554
|
+
// src/core/math/mathRenderer.ts
|
|
1555
|
+
import katex from "katex";
|
|
1556
|
+
function renderMathToHtml(latex, displayMode = false) {
|
|
1557
|
+
try {
|
|
1558
|
+
return katex.renderToString(latex.trim(), {
|
|
1559
|
+
displayMode,
|
|
1560
|
+
throwOnError: false,
|
|
1561
|
+
output: "htmlAndMathml",
|
|
1562
|
+
strict: false
|
|
1563
|
+
});
|
|
1564
|
+
} catch {
|
|
1565
|
+
return `<span class="katex-fallback">${latex}</span>`;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
var KATEX_INLINE_CSS = `
|
|
1569
|
+
.katex { font: normal 1.21em KaTeX_Main, Times New Roman, serif; line-height: 1.2; text-indent: 0; text-rendering: auto; border-color: currentColor; }
|
|
1570
|
+
.katex * { -ms-high-contrast-adjust: none !important; }
|
|
1571
|
+
.katex .katex-html { display: inline-block; }
|
|
1572
|
+
.katex .katex-mathml { clip: rect(1px, 1px, 1px, 1px); border: 0; height: 1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
|
|
1573
|
+
.katex-display { display: block; margin: 1em 0; text-align: center; }
|
|
1574
|
+
.katex-display > .katex { display: inline-block; text-align: initial; }
|
|
1575
|
+
.katex .base { position: relative; white-space: nowrap; width: min-content; }
|
|
1576
|
+
.katex .strut { display: inline-block; }
|
|
1577
|
+
.katex .mord { display: inline-block; }
|
|
1578
|
+
.katex .mbin { display: inline-block; }
|
|
1579
|
+
.katex .mrel { display: inline-block; }
|
|
1580
|
+
.katex .mopen { display: inline-block; }
|
|
1581
|
+
.katex .mclose { display: inline-block; }
|
|
1582
|
+
.katex .mpunct { display: inline-block; }
|
|
1583
|
+
.katex .minner { display: inline-block; }
|
|
1584
|
+
.katex .mop { display: inline-block; }
|
|
1585
|
+
.katex .frac-line { width: 100%; border-bottom-style: solid; }
|
|
1586
|
+
.katex .vlist-t { display: inline-table; table-layout: fixed; }
|
|
1587
|
+
.katex .vlist-r { display: table-row; }
|
|
1588
|
+
.katex .vlist { display: table-cell; vertical-align: bottom; position: relative; }
|
|
1589
|
+
.katex .msupsub { text-align: left; }
|
|
1590
|
+
.katex .sqrt > .root { margin-left: 0.27777778em; margin-right: -0.55555556em; }
|
|
1591
|
+
`;
|
|
1592
|
+
|
|
1464
1593
|
// src/core/html/htmlBuilder.ts
|
|
1465
1594
|
function escapeHtml(str) {
|
|
1466
1595
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -1499,78 +1628,30 @@ async function renderInlinesToHtml(spans = [], baseDir = process.cwd()) {
|
|
|
1499
1628
|
result += `<del>${inner}</del>`;
|
|
1500
1629
|
continue;
|
|
1501
1630
|
}
|
|
1502
|
-
if (span.type === "code") {
|
|
1503
|
-
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
|
-
`;
|
|
1631
|
+
if (span.type === "code") {
|
|
1632
|
+
result += `<code>${escapeHtml(span.content)}</code>`;
|
|
1633
|
+
continue;
|
|
1554
1634
|
}
|
|
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
|
-
`;
|
|
1635
|
+
if (span.type === "mathInline") {
|
|
1636
|
+
result += renderMathToHtml(span.content, false);
|
|
1637
|
+
continue;
|
|
1568
1638
|
}
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1639
|
+
if (span.type === "footnoteRef") {
|
|
1640
|
+
const id = escapeHtml(span.footnoteId || span.content);
|
|
1641
|
+
result += `<sup><a href="#fn-${id}" id="fnref-${id}" class="markforge-fnref">[${escapeHtml(span.content)}]</a></sup>`;
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
if (span.type === "htmlInline") {
|
|
1645
|
+
result += span.content;
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
result += escapeHtml(span.content);
|
|
1572
1649
|
}
|
|
1573
|
-
|
|
1650
|
+
return result;
|
|
1651
|
+
}
|
|
1652
|
+
async function renderNodesToHtml(nodes, resolved, baseDir = process.cwd()) {
|
|
1653
|
+
let bodyHtml = "";
|
|
1654
|
+
for (const node of nodes) {
|
|
1574
1655
|
if (node.type === "heading") {
|
|
1575
1656
|
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1576
1657
|
bodyHtml += ` <h${node.level} id="${node.id}">${inner}</h${node.level}>
|
|
@@ -1580,6 +1661,26 @@ async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
|
1580
1661
|
if (node.type === "paragraph") {
|
|
1581
1662
|
const inner = await renderInlinesToHtml(node.inlines, baseDir);
|
|
1582
1663
|
bodyHtml += ` <p>${inner}</p>
|
|
1664
|
+
`;
|
|
1665
|
+
continue;
|
|
1666
|
+
}
|
|
1667
|
+
if (node.type === "mathBlock") {
|
|
1668
|
+
bodyHtml += ` <div class="math-block">${renderMathToHtml(node.text || "", true)}</div>
|
|
1669
|
+
`;
|
|
1670
|
+
continue;
|
|
1671
|
+
}
|
|
1672
|
+
if (node.type === "columns") {
|
|
1673
|
+
const cols = node.columnsCount || 2;
|
|
1674
|
+
const gap = node.columnGap || "1.5rem";
|
|
1675
|
+
let colChildrenHtml = "";
|
|
1676
|
+
for (const col of node.children || []) {
|
|
1677
|
+
const colInner = await renderNodesToHtml(col.children || [], resolved, baseDir);
|
|
1678
|
+
colChildrenHtml += ` <div class="markforge-col">
|
|
1679
|
+
${colInner} </div>
|
|
1680
|
+
`;
|
|
1681
|
+
}
|
|
1682
|
+
bodyHtml += ` <div class="markforge-columns" style="--cols: ${cols}; --col-gap: ${gap};">
|
|
1683
|
+
${colChildrenHtml} </div>
|
|
1583
1684
|
`;
|
|
1584
1685
|
continue;
|
|
1585
1686
|
}
|
|
@@ -1668,6 +1769,429 @@ ${escapeHtml(node.text || "")}
|
|
|
1668
1769
|
continue;
|
|
1669
1770
|
}
|
|
1670
1771
|
}
|
|
1772
|
+
return bodyHtml;
|
|
1773
|
+
}
|
|
1774
|
+
async function renderCoverPageHtml(cover, baseDir = process.cwd()) {
|
|
1775
|
+
let logoHtml = "";
|
|
1776
|
+
if (cover.logo) {
|
|
1777
|
+
const resolvedLogo = await resolveImage(cover.logo, baseDir);
|
|
1778
|
+
const src = resolvedLogo ? resolvedLogo.dataUri : cover.logo;
|
|
1779
|
+
const widthStyle = cover.logoWidth ? `max-width: ${typeof cover.logoWidth === "number" ? cover.logoWidth + "px" : cover.logoWidth}; max-height: 80px; width: auto; height: auto;` : "max-height: 60px; max-width: 180px; width: auto; height: auto;";
|
|
1780
|
+
logoHtml = `<div class="cover-logo"><img src="${src}" alt="Logo" style="${widthStyle} object-fit: contain;" /></div>`;
|
|
1781
|
+
}
|
|
1782
|
+
const badgeHtml = cover.badge ? `<div class="cover-badge" style="${cover.badgeColor ? `background-color: ${cover.badgeColor};` : ""}${cover.badgeTextColor ? `color: ${cover.badgeTextColor};` : ""}">${escapeHtml(cover.badge)}</div>` : "";
|
|
1783
|
+
const titleHtml = `<h1 class="cover-title">${escapeHtml(cover.title)}</h1>`;
|
|
1784
|
+
const subtitleHtml = cover.subtitle ? `<div class="cover-subtitle">${escapeHtml(cover.subtitle)}</div>` : "";
|
|
1785
|
+
const metaItems = [];
|
|
1786
|
+
if (cover.company) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Organization:</span> <span class="cover-meta-value">${escapeHtml(cover.company)}</span></div>`);
|
|
1787
|
+
if (cover.author) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Author:</span> <span class="cover-meta-value">${escapeHtml(cover.author)}</span></div>`);
|
|
1788
|
+
if (cover.version) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Version:</span> <span class="cover-meta-value">${escapeHtml(cover.version)}</span></div>`);
|
|
1789
|
+
if (cover.date) metaItems.push(`<div class="cover-meta-item"><span class="cover-meta-label">Date:</span> <span class="cover-meta-value">${escapeHtml(cover.date)}</span></div>`);
|
|
1790
|
+
const metaHtml = metaItems.length > 0 ? `<div class="cover-meta">${metaItems.join("\n")}</div>` : "";
|
|
1791
|
+
const footerHtml = cover.footerText ? `<div class="cover-footer-text">${escapeHtml(cover.footerText)}</div>` : "";
|
|
1792
|
+
const css = `
|
|
1793
|
+
.markforge-cover {
|
|
1794
|
+
min-height: 100vh;
|
|
1795
|
+
box-sizing: border-box;
|
|
1796
|
+
display: flex;
|
|
1797
|
+
flex-direction: column;
|
|
1798
|
+
justify-content: space-between;
|
|
1799
|
+
padding: 4rem 3.5rem;
|
|
1800
|
+
page-break-after: always;
|
|
1801
|
+
break-after: page;
|
|
1802
|
+
position: relative;
|
|
1803
|
+
z-index: 2;
|
|
1804
|
+
background: ${cover.bgGradient || "#FFFFFF"};
|
|
1805
|
+
-webkit-print-color-adjust: exact;
|
|
1806
|
+
print-color-adjust: exact;
|
|
1807
|
+
color: ${cover.textColor || "#0F172A"};
|
|
1808
|
+
}
|
|
1809
|
+
.markforge-cover.cover-modern {
|
|
1810
|
+
border-top: 8px solid #0D998D;
|
|
1811
|
+
}
|
|
1812
|
+
.markforge-cover.cover-corporate-split {
|
|
1813
|
+
border-left: 12px solid #0D998D;
|
|
1814
|
+
}
|
|
1815
|
+
.markforge-cover.cover-card {
|
|
1816
|
+
background: #F8FAFC;
|
|
1817
|
+
}
|
|
1818
|
+
.cover-top {
|
|
1819
|
+
display: flex;
|
|
1820
|
+
justify-content: space-between;
|
|
1821
|
+
align-items: flex-start;
|
|
1822
|
+
width: 100%;
|
|
1823
|
+
}
|
|
1824
|
+
.cover-badge {
|
|
1825
|
+
display: inline-block;
|
|
1826
|
+
padding: 0.35rem 0.85rem;
|
|
1827
|
+
font-size: 0.78rem;
|
|
1828
|
+
font-weight: 700;
|
|
1829
|
+
letter-spacing: 0.08em;
|
|
1830
|
+
text-transform: uppercase;
|
|
1831
|
+
background-color: #ECFDFD;
|
|
1832
|
+
color: #0D998D;
|
|
1833
|
+
border-radius: 4px;
|
|
1834
|
+
border: 1px solid #33CDCF;
|
|
1835
|
+
}
|
|
1836
|
+
.cover-body {
|
|
1837
|
+
margin: auto 0;
|
|
1838
|
+
}
|
|
1839
|
+
.cover-title {
|
|
1840
|
+
font-size: 2.8rem;
|
|
1841
|
+
font-weight: 800;
|
|
1842
|
+
line-height: 1.15;
|
|
1843
|
+
margin: 0 0 1rem 0;
|
|
1844
|
+
color: inherit;
|
|
1845
|
+
}
|
|
1846
|
+
.cover-subtitle {
|
|
1847
|
+
font-size: 1.35rem;
|
|
1848
|
+
font-weight: 400;
|
|
1849
|
+
color: #64748B;
|
|
1850
|
+
margin: 0 0 2rem 0;
|
|
1851
|
+
line-height: 1.4;
|
|
1852
|
+
}
|
|
1853
|
+
.cover-meta {
|
|
1854
|
+
display: flex;
|
|
1855
|
+
flex-direction: column;
|
|
1856
|
+
gap: 0.5rem;
|
|
1857
|
+
border-top: 1.5px solid #E2E8F0;
|
|
1858
|
+
padding-top: 1.5rem;
|
|
1859
|
+
max-width: 480px;
|
|
1860
|
+
}
|
|
1861
|
+
.cover-meta-item {
|
|
1862
|
+
font-size: 0.92rem;
|
|
1863
|
+
display: flex;
|
|
1864
|
+
gap: 0.75rem;
|
|
1865
|
+
}
|
|
1866
|
+
.cover-meta-label {
|
|
1867
|
+
font-weight: 600;
|
|
1868
|
+
color: #64748B;
|
|
1869
|
+
min-width: 110px;
|
|
1870
|
+
}
|
|
1871
|
+
.cover-meta-value {
|
|
1872
|
+
font-weight: 500;
|
|
1873
|
+
color: #0F172A;
|
|
1874
|
+
}
|
|
1875
|
+
.cover-bottom {
|
|
1876
|
+
display: flex;
|
|
1877
|
+
justify-content: space-between;
|
|
1878
|
+
align-items: flex-end;
|
|
1879
|
+
font-size: 0.82rem;
|
|
1880
|
+
color: #94A3B8;
|
|
1881
|
+
}
|
|
1882
|
+
@media print {
|
|
1883
|
+
.markforge-cover {
|
|
1884
|
+
page-break-after: always;
|
|
1885
|
+
break-after: page;
|
|
1886
|
+
height: 100vh;
|
|
1887
|
+
min-height: 100vh;
|
|
1888
|
+
max-height: 100vh;
|
|
1889
|
+
box-sizing: border-box;
|
|
1890
|
+
overflow: hidden;
|
|
1891
|
+
margin: 0;
|
|
1892
|
+
-webkit-print-color-adjust: exact;
|
|
1893
|
+
print-color-adjust: exact;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
`;
|
|
1897
|
+
const html = ` <section class="markforge-cover cover-${cover.preset}">
|
|
1898
|
+
<div class="cover-top">
|
|
1899
|
+
${logoHtml}
|
|
1900
|
+
${badgeHtml}
|
|
1901
|
+
</div>
|
|
1902
|
+
<div class="cover-body">
|
|
1903
|
+
${titleHtml}
|
|
1904
|
+
${subtitleHtml}
|
|
1905
|
+
${metaHtml}
|
|
1906
|
+
</div>
|
|
1907
|
+
<div class="cover-bottom">
|
|
1908
|
+
${footerHtml}
|
|
1909
|
+
</div>
|
|
1910
|
+
</section>
|
|
1911
|
+
`;
|
|
1912
|
+
return { html, css };
|
|
1913
|
+
}
|
|
1914
|
+
async function renderBackCoverHtml(backCover, baseDir = process.cwd()) {
|
|
1915
|
+
let logoHtml = "";
|
|
1916
|
+
if (backCover.logo) {
|
|
1917
|
+
const resolved = await resolveImage(backCover.logo, baseDir);
|
|
1918
|
+
const src = resolved ? resolved.dataUri : backCover.logo;
|
|
1919
|
+
const widthStyle = backCover.logoWidth ? `style="width: ${typeof backCover.logoWidth === "number" ? `${backCover.logoWidth}px` : backCover.logoWidth}; max-width: 100%;"` : `style="max-width: 160px; height: auto;"`;
|
|
1920
|
+
logoHtml = `<div class="back-logo"><img src="${src}" alt="Brand Logo" ${widthStyle} /></div>`;
|
|
1921
|
+
}
|
|
1922
|
+
const badgeHtml = backCover.badge ? `<div class="back-badge" style="${backCover.badgeColor ? `background-color: ${backCover.badgeColor};` : ""}${backCover.badgeTextColor ? `color: ${backCover.badgeTextColor};` : ""}">${escapeHtml(backCover.badge)}</div>` : "";
|
|
1923
|
+
const titleHtml = `<h1 class="back-title">${escapeHtml(backCover.title)}</h1>`;
|
|
1924
|
+
const subtitleHtml = backCover.subtitle ? `<div class="back-subtitle">${escapeHtml(backCover.subtitle)}</div>` : "";
|
|
1925
|
+
const contactItems = [];
|
|
1926
|
+
if (backCover.company) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Organization:</span> <span class="back-contact-value">${escapeHtml(backCover.company)}</span></div>`);
|
|
1927
|
+
if (backCover.address) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Address:</span> <span class="back-contact-value">${escapeHtml(backCover.address)}</span></div>`);
|
|
1928
|
+
if (backCover.email) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Email:</span> <a href="mailto:${escapeHtml(backCover.email)}" class="back-contact-link">${escapeHtml(backCover.email)}</a></div>`);
|
|
1929
|
+
if (backCover.phone) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Phone:</span> <span class="back-contact-value">${escapeHtml(backCover.phone)}</span></div>`);
|
|
1930
|
+
if (backCover.website) contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">Website:</span> <a href="${escapeHtml(backCover.website)}" target="_blank" class="back-contact-link">${escapeHtml(backCover.website)}</a></div>`);
|
|
1931
|
+
if (backCover.social) {
|
|
1932
|
+
for (const [network, url] of Object.entries(backCover.social)) {
|
|
1933
|
+
if (url) {
|
|
1934
|
+
contactItems.push(`<div class="back-contact-item"><span class="back-contact-label">${escapeHtml(network.toUpperCase())}:</span> <a href="${escapeHtml(url)}" target="_blank" class="back-contact-link">${escapeHtml(url)}</a></div>`);
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
const contactHtml = contactItems.length > 0 ? `<div class="back-contact-grid">${contactItems.join("\n")}</div>` : "";
|
|
1939
|
+
const copyrightHtml = backCover.copyright ? `<div class="back-copyright">${escapeHtml(backCover.copyright)}</div>` : "";
|
|
1940
|
+
const isDark = backCover.preset === "corporate";
|
|
1941
|
+
const css = `
|
|
1942
|
+
.markforge-back-cover {
|
|
1943
|
+
min-height: 100vh;
|
|
1944
|
+
box-sizing: border-box;
|
|
1945
|
+
display: flex;
|
|
1946
|
+
flex-direction: column;
|
|
1947
|
+
justify-content: space-between;
|
|
1948
|
+
padding: 4rem 3.5rem;
|
|
1949
|
+
page-break-before: always;
|
|
1950
|
+
break-before: page;
|
|
1951
|
+
position: relative;
|
|
1952
|
+
z-index: 2;
|
|
1953
|
+
background: ${backCover.bgGradient || (isDark ? "#0F172A" : "#FFFFFF")};
|
|
1954
|
+
color: ${backCover.textColor || (isDark ? "#F8FAFC" : "#0F172A")};
|
|
1955
|
+
}
|
|
1956
|
+
.markforge-back-cover.back-modern {
|
|
1957
|
+
border-bottom: 8px solid #0D998D;
|
|
1958
|
+
}
|
|
1959
|
+
.markforge-back-cover.back-corporate {
|
|
1960
|
+
border-left: 12px solid #33CDCF;
|
|
1961
|
+
}
|
|
1962
|
+
.markforge-back-cover.back-card {
|
|
1963
|
+
background: #F8FAFC;
|
|
1964
|
+
}
|
|
1965
|
+
.back-top {
|
|
1966
|
+
display: flex;
|
|
1967
|
+
justify-content: space-between;
|
|
1968
|
+
align-items: flex-start;
|
|
1969
|
+
width: 100%;
|
|
1970
|
+
}
|
|
1971
|
+
.back-badge {
|
|
1972
|
+
display: inline-block;
|
|
1973
|
+
padding: 0.35rem 0.85rem;
|
|
1974
|
+
font-size: 0.78rem;
|
|
1975
|
+
font-weight: 700;
|
|
1976
|
+
letter-spacing: 0.08em;
|
|
1977
|
+
text-transform: uppercase;
|
|
1978
|
+
background-color: #ECFDFD;
|
|
1979
|
+
color: #0D998D;
|
|
1980
|
+
border-radius: 4px;
|
|
1981
|
+
border: 1px solid #33CDCF;
|
|
1982
|
+
}
|
|
1983
|
+
.back-body {
|
|
1984
|
+
margin: auto 0;
|
|
1985
|
+
}
|
|
1986
|
+
.back-title {
|
|
1987
|
+
font-size: 2.6rem;
|
|
1988
|
+
font-weight: 800;
|
|
1989
|
+
line-height: 1.15;
|
|
1990
|
+
margin: 0 0 0.75rem 0;
|
|
1991
|
+
color: inherit;
|
|
1992
|
+
}
|
|
1993
|
+
.back-subtitle {
|
|
1994
|
+
font-size: 1.25rem;
|
|
1995
|
+
font-weight: 400;
|
|
1996
|
+
color: ${isDark ? "#94A3B8" : "#64748B"};
|
|
1997
|
+
margin: 0 0 2rem 0;
|
|
1998
|
+
line-height: 1.4;
|
|
1999
|
+
}
|
|
2000
|
+
.back-contact-grid {
|
|
2001
|
+
display: flex;
|
|
2002
|
+
flex-direction: column;
|
|
2003
|
+
gap: 0.6rem;
|
|
2004
|
+
border-top: 1.5px solid ${isDark ? "#334155" : "#E2E8F0"};
|
|
2005
|
+
padding-top: 1.5rem;
|
|
2006
|
+
max-width: 540px;
|
|
2007
|
+
}
|
|
2008
|
+
.back-contact-item {
|
|
2009
|
+
font-size: 0.92rem;
|
|
2010
|
+
display: flex;
|
|
2011
|
+
gap: 0.75rem;
|
|
2012
|
+
}
|
|
2013
|
+
.back-contact-label {
|
|
2014
|
+
font-weight: 600;
|
|
2015
|
+
color: ${isDark ? "#94A3B8" : "#64748B"};
|
|
2016
|
+
min-width: 110px;
|
|
2017
|
+
}
|
|
2018
|
+
.back-contact-link {
|
|
2019
|
+
color: #0D998D;
|
|
2020
|
+
text-decoration: none;
|
|
2021
|
+
font-weight: 600;
|
|
2022
|
+
}
|
|
2023
|
+
.back-contact-link:hover {
|
|
2024
|
+
text-decoration: underline;
|
|
2025
|
+
}
|
|
2026
|
+
.back-copyright {
|
|
2027
|
+
font-size: 0.82rem;
|
|
2028
|
+
color: ${isDark ? "#64748B" : "#94A3B8"};
|
|
2029
|
+
border-top: 1px solid ${isDark ? "#1E293B" : "#F1F5F9"};
|
|
2030
|
+
padding-top: 1rem;
|
|
2031
|
+
margin-top: 2rem;
|
|
2032
|
+
}
|
|
2033
|
+
@media print {
|
|
2034
|
+
.markforge-back-cover {
|
|
2035
|
+
page: back-cover-page;
|
|
2036
|
+
page-break-before: always;
|
|
2037
|
+
break-before: page;
|
|
2038
|
+
page-break-after: avoid;
|
|
2039
|
+
break-after: avoid;
|
|
2040
|
+
min-height: 100vh;
|
|
2041
|
+
height: 100vh;
|
|
2042
|
+
max-height: 100vh;
|
|
2043
|
+
margin: 0;
|
|
2044
|
+
box-sizing: border-box;
|
|
2045
|
+
overflow: hidden;
|
|
2046
|
+
-webkit-print-color-adjust: exact;
|
|
2047
|
+
print-color-adjust: exact;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
`;
|
|
2051
|
+
const html = ` <section class="markforge-back-cover back-${backCover.preset}">
|
|
2052
|
+
<div class="back-top">
|
|
2053
|
+
${logoHtml}
|
|
2054
|
+
${badgeHtml}
|
|
2055
|
+
</div>
|
|
2056
|
+
<div class="back-body">
|
|
2057
|
+
${titleHtml}
|
|
2058
|
+
${subtitleHtml}
|
|
2059
|
+
${contactHtml}
|
|
2060
|
+
</div>
|
|
2061
|
+
${copyrightHtml}
|
|
2062
|
+
</section>
|
|
2063
|
+
`;
|
|
2064
|
+
return { html, css };
|
|
2065
|
+
}
|
|
2066
|
+
async function buildHtmlDocument(doc, config, baseDir = process.cwd()) {
|
|
2067
|
+
var _a;
|
|
2068
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2069
|
+
const baseThemeCss = generateThemeCss(resolved.theme);
|
|
2070
|
+
let customCss = "";
|
|
2071
|
+
for (const cssPath of resolved.css) {
|
|
2072
|
+
const fullCssPath = path2.isAbsolute(cssPath) ? cssPath : path2.resolve(baseDir, cssPath);
|
|
2073
|
+
if (fs2.existsSync(fullCssPath)) {
|
|
2074
|
+
customCss += `
|
|
2075
|
+
/* Custom CSS: ${cssPath} */
|
|
2076
|
+
` + fs2.readFileSync(fullCssPath, "utf-8");
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
const inlinedCss = doc.inlinedStyles.join("\n");
|
|
2080
|
+
const extraCss = `
|
|
2081
|
+
.markforge-columns {
|
|
2082
|
+
display: grid;
|
|
2083
|
+
grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
|
|
2084
|
+
gap: var(--col-gap, 1.5rem);
|
|
2085
|
+
margin: 1.5rem 0;
|
|
2086
|
+
}
|
|
2087
|
+
.markforge-col {
|
|
2088
|
+
min-width: 0;
|
|
2089
|
+
}
|
|
2090
|
+
.markforge-fnref {
|
|
2091
|
+
text-decoration: none;
|
|
2092
|
+
font-size: 0.8em;
|
|
2093
|
+
vertical-align: super;
|
|
2094
|
+
color: #0D998D;
|
|
2095
|
+
font-weight: 700;
|
|
2096
|
+
}
|
|
2097
|
+
.markforge-footnotes {
|
|
2098
|
+
margin-top: 3rem;
|
|
2099
|
+
padding-top: 1rem;
|
|
2100
|
+
font-size: 0.88rem;
|
|
2101
|
+
color: #64748B;
|
|
2102
|
+
}
|
|
2103
|
+
.markforge-footnotes hr {
|
|
2104
|
+
border: 0;
|
|
2105
|
+
border-top: 1px solid #E2E8F0;
|
|
2106
|
+
margin-bottom: 1rem;
|
|
2107
|
+
}
|
|
2108
|
+
.markforge-fn-return {
|
|
2109
|
+
text-decoration: none;
|
|
2110
|
+
color: #0D998D;
|
|
2111
|
+
}
|
|
2112
|
+
.math-block {
|
|
2113
|
+
margin: 1.5rem 0;
|
|
2114
|
+
text-align: center;
|
|
2115
|
+
overflow-x: auto;
|
|
2116
|
+
}
|
|
2117
|
+
`;
|
|
2118
|
+
let coverHtml = "";
|
|
2119
|
+
let coverCss = "";
|
|
2120
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
2121
|
+
const coverRes = await renderCoverPageHtml(resolved.coverPage, baseDir);
|
|
2122
|
+
coverHtml = coverRes.html;
|
|
2123
|
+
coverCss = coverRes.css;
|
|
2124
|
+
}
|
|
2125
|
+
let backHtml = "";
|
|
2126
|
+
let backCss = "";
|
|
2127
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
2128
|
+
const backRes = await renderBackCoverHtml(resolved.backCover, baseDir);
|
|
2129
|
+
backHtml = backRes.html;
|
|
2130
|
+
backCss = backRes.css;
|
|
2131
|
+
}
|
|
2132
|
+
let bodyHtml = "";
|
|
2133
|
+
if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
|
|
2134
|
+
bodyHtml += ` <header class="document-header">
|
|
2135
|
+
`;
|
|
2136
|
+
bodyHtml += ` <h1 class="document-title">${escapeHtml(resolved.title)}</h1>
|
|
2137
|
+
`;
|
|
2138
|
+
if (resolved.subtitle) {
|
|
2139
|
+
bodyHtml += ` <div class="document-subtitle">${escapeHtml(resolved.subtitle)}</div>
|
|
2140
|
+
`;
|
|
2141
|
+
}
|
|
2142
|
+
if (resolved.author || resolved.date || resolved.version) {
|
|
2143
|
+
bodyHtml += ` <div class="document-meta">
|
|
2144
|
+
`;
|
|
2145
|
+
if (resolved.author) {
|
|
2146
|
+
bodyHtml += ` <span>Author: ${escapeHtml(resolved.author)}</span>
|
|
2147
|
+
`;
|
|
2148
|
+
}
|
|
2149
|
+
if (resolved.version) {
|
|
2150
|
+
bodyHtml += ` <span>Version: ${escapeHtml(resolved.version)}</span>
|
|
2151
|
+
`;
|
|
2152
|
+
}
|
|
2153
|
+
if (resolved.date) {
|
|
2154
|
+
bodyHtml += ` <span>Date: ${escapeHtml(resolved.date)}</span>
|
|
2155
|
+
`;
|
|
2156
|
+
}
|
|
2157
|
+
bodyHtml += ` </div>
|
|
2158
|
+
`;
|
|
2159
|
+
}
|
|
2160
|
+
bodyHtml += ` </header>
|
|
2161
|
+
`;
|
|
2162
|
+
}
|
|
2163
|
+
if (resolved.toc && doc.tocEntries.length > 0) {
|
|
2164
|
+
bodyHtml += ` <nav class="table-of-contents">
|
|
2165
|
+
`;
|
|
2166
|
+
bodyHtml += ` <h2>Table of Contents</h2>
|
|
2167
|
+
<ul>
|
|
2168
|
+
`;
|
|
2169
|
+
for (const entry of doc.tocEntries) {
|
|
2170
|
+
const indent = " ".repeat(entry.level);
|
|
2171
|
+
bodyHtml += ` ${indent}<li><a href="#${entry.id}">${escapeHtml(entry.text)}</a></li>
|
|
2172
|
+
`;
|
|
2173
|
+
}
|
|
2174
|
+
bodyHtml += ` </ul>
|
|
2175
|
+
</nav>
|
|
2176
|
+
`;
|
|
2177
|
+
}
|
|
2178
|
+
bodyHtml += await renderNodesToHtml(doc.nodes, resolved, baseDir);
|
|
2179
|
+
let footnotesHtml = "";
|
|
2180
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
2181
|
+
let fnListHtml = "";
|
|
2182
|
+
for (const def of doc.footnoteDefs) {
|
|
2183
|
+
const defInner = await renderInlinesToHtml(def.inlines, baseDir);
|
|
2184
|
+
fnListHtml += ` <li id="fn-${escapeHtml(def.id)}">${defInner} <a href="#fnref-${escapeHtml(def.id)}" class="markforge-fn-return">↩</a></li>
|
|
2185
|
+
`;
|
|
2186
|
+
}
|
|
2187
|
+
footnotesHtml = `
|
|
2188
|
+
<footer class="markforge-footnotes">
|
|
2189
|
+
<hr />
|
|
2190
|
+
<ol>
|
|
2191
|
+
${fnListHtml} </ol>
|
|
2192
|
+
</footer>
|
|
2193
|
+
`;
|
|
2194
|
+
}
|
|
1671
2195
|
let watermarkCss = "";
|
|
1672
2196
|
let watermarkHtml = "";
|
|
1673
2197
|
if (resolved.watermark) {
|
|
@@ -1677,12 +2201,16 @@ ${escapeHtml(node.text || "")}
|
|
|
1677
2201
|
position: fixed;
|
|
1678
2202
|
top: 0;
|
|
1679
2203
|
left: 0;
|
|
1680
|
-
|
|
1681
|
-
|
|
2204
|
+
right: 0;
|
|
2205
|
+
bottom: 0;
|
|
2206
|
+
width: 100%;
|
|
2207
|
+
height: 100%;
|
|
1682
2208
|
pointer-events: none;
|
|
1683
2209
|
z-index: 0;
|
|
1684
2210
|
user-select: none;
|
|
1685
2211
|
-webkit-user-select: none;
|
|
2212
|
+
-webkit-print-color-adjust: exact;
|
|
2213
|
+
print-color-adjust: exact;
|
|
1686
2214
|
}
|
|
1687
2215
|
.document-container {
|
|
1688
2216
|
position: relative;
|
|
@@ -1693,8 +2221,12 @@ ${escapeHtml(node.text || "")}
|
|
|
1693
2221
|
position: fixed;
|
|
1694
2222
|
top: 0;
|
|
1695
2223
|
left: 0;
|
|
2224
|
+
right: 0;
|
|
2225
|
+
bottom: 0;
|
|
1696
2226
|
width: 100vw;
|
|
1697
2227
|
height: 100vh;
|
|
2228
|
+
pointer-events: none;
|
|
2229
|
+
z-index: 0;
|
|
1698
2230
|
-webkit-print-color-adjust: exact;
|
|
1699
2231
|
print-color-adjust: exact;
|
|
1700
2232
|
}
|
|
@@ -1705,16 +2237,16 @@ ${escapeHtml(node.text || "")}
|
|
|
1705
2237
|
(function() {
|
|
1706
2238
|
try {
|
|
1707
2239
|
var canvas = document.createElement('canvas');
|
|
1708
|
-
var dpr =
|
|
1709
|
-
var width =
|
|
1710
|
-
var height =
|
|
1711
|
-
canvas.width =
|
|
1712
|
-
canvas.height =
|
|
2240
|
+
var dpr = 2;
|
|
2241
|
+
var width = 1200;
|
|
2242
|
+
var height = 1600;
|
|
2243
|
+
canvas.width = width * dpr;
|
|
2244
|
+
canvas.height = height * dpr;
|
|
1713
2245
|
var ctx = canvas.getContext('2d');
|
|
1714
2246
|
if (ctx) {
|
|
1715
2247
|
ctx.scale(dpr, dpr);
|
|
1716
2248
|
ctx.translate(width / 2, height / 2);
|
|
1717
|
-
ctx.rotate((${wm.rotate} * Math.PI) / 180);
|
|
2249
|
+
ctx.rotate((-Math.abs(${wm.rotate || 45}) * Math.PI) / 180);
|
|
1718
2250
|
ctx.textAlign = 'center';
|
|
1719
2251
|
ctx.textBaseline = 'middle';
|
|
1720
2252
|
ctx.font = '900 ${wm.fontSize * 1.5}px system-ui, -apple-system, sans-serif';
|
|
@@ -1741,10 +2273,6 @@ ${escapeHtml(node.text || "")}
|
|
|
1741
2273
|
if (resolved.signatures && resolved.signatures.items.length > 0) {
|
|
1742
2274
|
const sig = resolved.signatures;
|
|
1743
2275
|
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
2276
|
signaturesCss = `
|
|
1749
2277
|
.markforge-signatures {
|
|
1750
2278
|
margin-top: ${sig.spacingBefore};
|
|
@@ -1856,6 +2384,10 @@ ${itemCards}
|
|
|
1856
2384
|
<style>
|
|
1857
2385
|
${THEME_COMPONENTS}
|
|
1858
2386
|
${baseThemeCss}
|
|
2387
|
+
${KATEX_INLINE_CSS}
|
|
2388
|
+
${extraCss}
|
|
2389
|
+
${coverCss}
|
|
2390
|
+
${backCss}
|
|
1859
2391
|
${customCss}
|
|
1860
2392
|
${inlinedCss}
|
|
1861
2393
|
${watermarkCss}
|
|
@@ -1863,14 +2395,102 @@ ${signaturesCss}
|
|
|
1863
2395
|
</style>
|
|
1864
2396
|
</head>
|
|
1865
2397
|
<body>
|
|
1866
|
-
${watermarkHtml} <div class="document-container">
|
|
1867
|
-
${bodyHtml}${signaturesHtml} </div>
|
|
2398
|
+
${watermarkHtml}${coverHtml} <div class="document-container">
|
|
2399
|
+
${bodyHtml}${footnotesHtml}${signaturesHtml} </div>
|
|
1868
2400
|
${mermaidScript}
|
|
1869
|
-
</body>
|
|
2401
|
+
${backHtml}</body>
|
|
1870
2402
|
</html>`;
|
|
1871
2403
|
}
|
|
1872
2404
|
|
|
1873
2405
|
// src/core/pdf/pdfBuilder.ts
|
|
2406
|
+
import * as fs3 from "fs";
|
|
2407
|
+
import * as path3 from "path";
|
|
2408
|
+
import * as os from "os";
|
|
2409
|
+
import { pathToFileURL } from "url";
|
|
2410
|
+
import { spawnSync } from "child_process";
|
|
2411
|
+
import { PDFDocument } from "pdf-lib";
|
|
2412
|
+
import { encryptPDF } from "@pdfsmaller/pdf-encrypt";
|
|
2413
|
+
function escapeXml(str) {
|
|
2414
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2415
|
+
}
|
|
2416
|
+
function generateWatermarkPngBuffer(chromePath, wm) {
|
|
2417
|
+
const tmpHtml = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.html`);
|
|
2418
|
+
const tmpPng = path3.join(os.tmpdir(), `markforge-wm-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
|
|
2419
|
+
try {
|
|
2420
|
+
const text = escapeXml(wm.text.toUpperCase());
|
|
2421
|
+
const fontSize = (wm.fontSize || 52) * 1.5;
|
|
2422
|
+
const color = wm.color || "#E11D48";
|
|
2423
|
+
const opacity = wm.opacity !== void 0 ? wm.opacity : 0.12;
|
|
2424
|
+
const rotate = wm.rotate !== void 0 ? wm.rotate : -45;
|
|
2425
|
+
const html = `<!DOCTYPE html>
|
|
2426
|
+
<html>
|
|
2427
|
+
<head>
|
|
2428
|
+
<meta charset="utf-8">
|
|
2429
|
+
<style>
|
|
2430
|
+
html, body {
|
|
2431
|
+
margin: 0;
|
|
2432
|
+
padding: 0;
|
|
2433
|
+
width: 1200px;
|
|
2434
|
+
height: 1600px;
|
|
2435
|
+
background: transparent;
|
|
2436
|
+
overflow: hidden;
|
|
2437
|
+
}
|
|
2438
|
+
.wm-box {
|
|
2439
|
+
width: 1200px;
|
|
2440
|
+
height: 1600px;
|
|
2441
|
+
display: flex;
|
|
2442
|
+
align-items: center;
|
|
2443
|
+
justify-content: center;
|
|
2444
|
+
transform: rotate(${rotate}deg);
|
|
2445
|
+
}
|
|
2446
|
+
.wm-text {
|
|
2447
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
2448
|
+
font-weight: 900;
|
|
2449
|
+
font-size: ${fontSize}px;
|
|
2450
|
+
color: ${color};
|
|
2451
|
+
opacity: ${opacity};
|
|
2452
|
+
letter-spacing: 0.15em;
|
|
2453
|
+
text-transform: uppercase;
|
|
2454
|
+
white-space: nowrap;
|
|
2455
|
+
}
|
|
2456
|
+
</style>
|
|
2457
|
+
</head>
|
|
2458
|
+
<body>
|
|
2459
|
+
<div class="wm-box"><span class="wm-text">${text}</span></div>
|
|
2460
|
+
</body>
|
|
2461
|
+
</html>`;
|
|
2462
|
+
fs3.writeFileSync(tmpHtml, html, "utf8");
|
|
2463
|
+
const fileUrl = pathToFileURL(tmpHtml).href;
|
|
2464
|
+
const isWin = process.platform === "win32";
|
|
2465
|
+
spawnSync(
|
|
2466
|
+
chromePath,
|
|
2467
|
+
[
|
|
2468
|
+
"--headless=new",
|
|
2469
|
+
"--disable-gpu",
|
|
2470
|
+
"--disable-sync",
|
|
2471
|
+
"--disable-extensions",
|
|
2472
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
2473
|
+
`--screenshot=${tmpPng}`,
|
|
2474
|
+
"--window-size=1200,1600",
|
|
2475
|
+
"--default-background-color=00000000",
|
|
2476
|
+
fileUrl
|
|
2477
|
+
],
|
|
2478
|
+
{ timeout: 15e3, windowsHide: true }
|
|
2479
|
+
);
|
|
2480
|
+
if (fs3.existsSync(tmpPng) && fs3.statSync(tmpPng).size > 0) {
|
|
2481
|
+
return fs3.readFileSync(tmpPng);
|
|
2482
|
+
}
|
|
2483
|
+
return null;
|
|
2484
|
+
} catch {
|
|
2485
|
+
return null;
|
|
2486
|
+
} finally {
|
|
2487
|
+
try {
|
|
2488
|
+
if (fs3.existsSync(tmpHtml)) fs3.unlinkSync(tmpHtml);
|
|
2489
|
+
if (fs3.existsSync(tmpPng)) fs3.unlinkSync(tmpPng);
|
|
2490
|
+
} catch {
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
1874
2494
|
function findChromeExecutable() {
|
|
1875
2495
|
if (process.env.CHROME_PATH && fs3.existsSync(process.env.CHROME_PATH)) {
|
|
1876
2496
|
return process.env.CHROME_PATH;
|
|
@@ -1935,7 +2555,7 @@ function findChromeExecutable() {
|
|
|
1935
2555
|
return null;
|
|
1936
2556
|
}
|
|
1937
2557
|
function injectPagedMediaStyles(html, config, metadata) {
|
|
1938
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2558
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1939
2559
|
const resolved = resolveDocumentConfig(metadata || {}, config);
|
|
1940
2560
|
const size = resolved.paperSize;
|
|
1941
2561
|
const orientation = resolved.orientation;
|
|
@@ -1979,6 +2599,38 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
1979
2599
|
${fontStyle}
|
|
1980
2600
|
}`;
|
|
1981
2601
|
};
|
|
2602
|
+
const coverPageCss = ((_a = resolved.coverPage) == null ? void 0 : _a.enabled) ? `
|
|
2603
|
+
@page :first {
|
|
2604
|
+
margin-top: 0;
|
|
2605
|
+
margin-bottom: 0;
|
|
2606
|
+
margin-left: 0;
|
|
2607
|
+
margin-right: 0;
|
|
2608
|
+
background-image: none !important;
|
|
2609
|
+
@top-left { content: none; }
|
|
2610
|
+
@top-center { content: none; }
|
|
2611
|
+
@top-right { content: none; }
|
|
2612
|
+
@bottom-left { content: none; }
|
|
2613
|
+
@bottom-center { content: none; }
|
|
2614
|
+
@bottom-right { content: none; }
|
|
2615
|
+
}` : "";
|
|
2616
|
+
const backCoverCss = ((_b = resolved.backCover) == null ? void 0 : _b.enabled) ? `
|
|
2617
|
+
@page back-cover-page {
|
|
2618
|
+
size: ${size} ${orientation};
|
|
2619
|
+
margin: 0;
|
|
2620
|
+
background-image: none !important;
|
|
2621
|
+
@top-left { content: none; }
|
|
2622
|
+
@top-center { content: none; }
|
|
2623
|
+
@top-right { content: none; }
|
|
2624
|
+
@bottom-left { content: none; }
|
|
2625
|
+
@bottom-center { content: none; }
|
|
2626
|
+
@bottom-right { content: none; }
|
|
2627
|
+
}
|
|
2628
|
+
.markforge-back-cover {
|
|
2629
|
+
page: back-cover-page;
|
|
2630
|
+
min-height: 100vh;
|
|
2631
|
+
height: 100vh;
|
|
2632
|
+
box-sizing: border-box;
|
|
2633
|
+
}` : "";
|
|
1982
2634
|
const pagedCss = `
|
|
1983
2635
|
@page {
|
|
1984
2636
|
size: ${size} ${orientation};
|
|
@@ -1986,15 +2638,18 @@ function injectPagedMediaStyles(html, config, metadata) {
|
|
|
1986
2638
|
margin-bottom: ${bottom};
|
|
1987
2639
|
margin-left: ${left};
|
|
1988
2640
|
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", (
|
|
2641
|
+
${buildZoneCss("top-left", (_c = resolved.header) == null ? void 0 : _c.left)}
|
|
2642
|
+
${buildZoneCss("top-center", (_d = resolved.header) == null ? void 0 : _d.center)}
|
|
2643
|
+
${buildZoneCss("top-right", (_e = resolved.header) == null ? void 0 : _e.right)}
|
|
2644
|
+
${buildZoneCss("bottom-left", (_f = resolved.footer) == null ? void 0 : _f.left)}
|
|
2645
|
+
${buildZoneCss("bottom-center", (_g = resolved.footer) == null ? void 0 : _g.center)}
|
|
2646
|
+
${buildZoneCss("bottom-right", (_h = resolved.footer) == null ? void 0 : _h.right, true)}
|
|
1995
2647
|
}
|
|
2648
|
+
${coverPageCss}
|
|
2649
|
+
${backCoverCss}
|
|
1996
2650
|
@media print {
|
|
1997
2651
|
body { padding: 0; }
|
|
2652
|
+
.document-watermark { display: none !important; }
|
|
1998
2653
|
h1, h2, h3, pre, table, blockquote, .callout {
|
|
1999
2654
|
break-inside: avoid;
|
|
2000
2655
|
}
|
|
@@ -2042,15 +2697,17 @@ startxref
|
|
|
2042
2697
|
return Buffer.from(pdfBody, "utf-8");
|
|
2043
2698
|
}
|
|
2044
2699
|
async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
2700
|
+
var _a, _b, _c;
|
|
2045
2701
|
const baseHtml = await buildHtmlDocument(doc, config, baseDir);
|
|
2046
2702
|
const pagedHtml = injectPagedMediaStyles(baseHtml, config, doc.metadata);
|
|
2047
2703
|
const chromePath = findChromeExecutable();
|
|
2048
2704
|
if (chromePath) {
|
|
2049
2705
|
const tmpId = Math.random().toString(36).substring(2, 9);
|
|
2050
2706
|
const tmpDir = os.tmpdir();
|
|
2051
|
-
const tmpHtml =
|
|
2052
|
-
const tmpPdf =
|
|
2053
|
-
const tmpProfile =
|
|
2707
|
+
const tmpHtml = path3.join(tmpDir, `markforge_${tmpId}.html`);
|
|
2708
|
+
const tmpPdf = path3.join(tmpDir, `markforge_${tmpId}.pdf`);
|
|
2709
|
+
const tmpProfile = path3.join(tmpDir, `markforge_prof_${tmpId}`);
|
|
2710
|
+
const isWin = process.platform === "win32";
|
|
2054
2711
|
const isolatedFlags = [
|
|
2055
2712
|
`--user-data-dir=${tmpProfile}`,
|
|
2056
2713
|
"--no-first-run",
|
|
@@ -2061,7 +2718,6 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2061
2718
|
"--disable-default-apps",
|
|
2062
2719
|
"--disable-extensions",
|
|
2063
2720
|
"--disable-domain-reliability",
|
|
2064
|
-
"--disable-client-side-phishing-detection",
|
|
2065
2721
|
"--disable-breakpad",
|
|
2066
2722
|
"--disable-component-extensions-with-background-pages",
|
|
2067
2723
|
"--disable-features=Translate,OptimizationHints,MediaRouter,DialMediaRouteProvider,CalculatedNewTabPage,ChromeWhatsNewUI,PrivacySandboxSettings4",
|
|
@@ -2070,12 +2726,10 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2070
2726
|
"--mute-audio",
|
|
2071
2727
|
"--no-service-autorun",
|
|
2072
2728
|
"--disable-gpu",
|
|
2073
|
-
"--no-sandbox",
|
|
2074
|
-
"--disable-setuid-sandbox",
|
|
2075
|
-
"--allow-file-access-from-files",
|
|
2076
|
-
"--disable-web-security",
|
|
2729
|
+
...isWin ? [] : ["--no-sandbox", "--disable-setuid-sandbox"],
|
|
2077
2730
|
"--force-color-profile=srgb",
|
|
2078
|
-
"--no-pdf-header-footer"
|
|
2731
|
+
"--no-pdf-header-footer",
|
|
2732
|
+
"--window-size=1200,1600"
|
|
2079
2733
|
];
|
|
2080
2734
|
try {
|
|
2081
2735
|
fs3.writeFileSync(tmpHtml, pagedHtml, "utf-8");
|
|
@@ -2090,7 +2744,7 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2090
2744
|
`--print-to-pdf=${tmpPdf}`,
|
|
2091
2745
|
fileUrl
|
|
2092
2746
|
],
|
|
2093
|
-
{ timeout: 3e4 }
|
|
2747
|
+
{ timeout: 3e4, windowsHide: true }
|
|
2094
2748
|
);
|
|
2095
2749
|
if ((res.status !== 0 || !fs3.existsSync(tmpPdf)) && chromePath) {
|
|
2096
2750
|
res = spawnSync(
|
|
@@ -2101,12 +2755,78 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2101
2755
|
`--print-to-pdf=${tmpPdf}`,
|
|
2102
2756
|
fileUrl
|
|
2103
2757
|
],
|
|
2104
|
-
{ timeout: 3e4 }
|
|
2758
|
+
{ timeout: 3e4, windowsHide: true }
|
|
2105
2759
|
);
|
|
2106
2760
|
}
|
|
2107
2761
|
if (fs3.existsSync(tmpPdf) && fs3.statSync(tmpPdf).size > 0) {
|
|
2108
2762
|
const pdfBuffer = fs3.readFileSync(tmpPdf);
|
|
2109
|
-
|
|
2763
|
+
try {
|
|
2764
|
+
const pdfDoc = await PDFDocument.load(pdfBuffer);
|
|
2765
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2766
|
+
if (resolved.title) pdfDoc.setTitle(resolved.title);
|
|
2767
|
+
if (resolved.author) pdfDoc.setAuthor(resolved.author);
|
|
2768
|
+
if (resolved.subtitle) pdfDoc.setSubject(resolved.subtitle);
|
|
2769
|
+
pdfDoc.setCreator("MarkForge Enterprise Document Generator");
|
|
2770
|
+
pdfDoc.setProducer("MarkForge (by Ma'sum)");
|
|
2771
|
+
pdfDoc.setModificationDate(/* @__PURE__ */ new Date());
|
|
2772
|
+
if (((_a = resolved.backCover) == null ? void 0 : _a.enabled) && pdfDoc.getPageCount() > 2) {
|
|
2773
|
+
pdfDoc.removePage(pdfDoc.getPageCount() - 1);
|
|
2774
|
+
}
|
|
2775
|
+
if (resolved.watermark) {
|
|
2776
|
+
const wmPng = generateWatermarkPngBuffer(chromePath, resolved.watermark);
|
|
2777
|
+
if (wmPng) {
|
|
2778
|
+
const embeddedPng = await pdfDoc.embedPng(wmPng);
|
|
2779
|
+
const pages = pdfDoc.getPages();
|
|
2780
|
+
const startPageIndex = ((_b = resolved.coverPage) == null ? void 0 : _b.enabled) ? 1 : 0;
|
|
2781
|
+
const endPageIndex = ((_c = resolved.backCover) == null ? void 0 : _c.enabled) ? pages.length - 1 : pages.length;
|
|
2782
|
+
for (let i = startPageIndex; i < endPageIndex; i++) {
|
|
2783
|
+
const page = pages[i];
|
|
2784
|
+
const { width, height } = page.getSize();
|
|
2785
|
+
page.drawImage(embeddedPng, {
|
|
2786
|
+
x: 0,
|
|
2787
|
+
y: 0,
|
|
2788
|
+
width,
|
|
2789
|
+
height
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
const savedBytes = await pdfDoc.save();
|
|
2795
|
+
let finalBuffer = Buffer.from(savedBytes);
|
|
2796
|
+
if (resolved.security) {
|
|
2797
|
+
const sec = resolved.security;
|
|
2798
|
+
const hasUserPassword = typeof sec.userPassword === "string" && sec.userPassword.length > 0;
|
|
2799
|
+
const hasOwnerPassword = typeof sec.ownerPassword === "string" && sec.ownerPassword.length > 0;
|
|
2800
|
+
if (hasUserPassword || hasOwnerPassword) {
|
|
2801
|
+
try {
|
|
2802
|
+
const userPass = sec.userPassword ?? "";
|
|
2803
|
+
const ownerPass = sec.ownerPassword ?? userPass;
|
|
2804
|
+
const perms = sec.permissions;
|
|
2805
|
+
const encryptedBytes = await encryptPDF(
|
|
2806
|
+
new Uint8Array(finalBuffer),
|
|
2807
|
+
userPass,
|
|
2808
|
+
{
|
|
2809
|
+
ownerPassword: ownerPass,
|
|
2810
|
+
algorithm: "AES-256",
|
|
2811
|
+
allowPrinting: (perms == null ? void 0 : perms.printing) !== "none",
|
|
2812
|
+
allowHighQualityPrint: (perms == null ? void 0 : perms.printing) === "highResolution",
|
|
2813
|
+
allowModifying: (perms == null ? void 0 : perms.modifying) ?? true,
|
|
2814
|
+
allowCopying: (perms == null ? void 0 : perms.copying) ?? true,
|
|
2815
|
+
allowAnnotating: (perms == null ? void 0 : perms.annotating) ?? true,
|
|
2816
|
+
allowFillingForms: (perms == null ? void 0 : perms.fillingForms) ?? true,
|
|
2817
|
+
allowExtraction: (perms == null ? void 0 : perms.contentAccessibility) ?? true,
|
|
2818
|
+
allowAssembly: (perms == null ? void 0 : perms.documentAssembly) ?? true
|
|
2819
|
+
}
|
|
2820
|
+
);
|
|
2821
|
+
finalBuffer = Buffer.from(encryptedBytes);
|
|
2822
|
+
} catch {
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2825
|
+
}
|
|
2826
|
+
return finalBuffer;
|
|
2827
|
+
} catch {
|
|
2828
|
+
return pdfBuffer;
|
|
2829
|
+
}
|
|
2110
2830
|
}
|
|
2111
2831
|
} catch {
|
|
2112
2832
|
} finally {
|
|
@@ -2121,7 +2841,37 @@ async function buildPdfDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2121
2841
|
return createFallbackPdfBuffer(doc.metadata.title || "MarkForge Document");
|
|
2122
2842
|
}
|
|
2123
2843
|
|
|
2844
|
+
// src/core/docx/docxBuilder.ts
|
|
2845
|
+
import {
|
|
2846
|
+
Document,
|
|
2847
|
+
Paragraph,
|
|
2848
|
+
TextRun,
|
|
2849
|
+
HeadingLevel,
|
|
2850
|
+
Table,
|
|
2851
|
+
TableRow,
|
|
2852
|
+
TableCell,
|
|
2853
|
+
WidthType,
|
|
2854
|
+
BorderStyle,
|
|
2855
|
+
AlignmentType,
|
|
2856
|
+
ImageRun,
|
|
2857
|
+
Header,
|
|
2858
|
+
Footer,
|
|
2859
|
+
PageNumber,
|
|
2860
|
+
Packer,
|
|
2861
|
+
PageOrientation,
|
|
2862
|
+
convertInchesToTwip,
|
|
2863
|
+
convertMillimetersToTwip,
|
|
2864
|
+
ShadingType,
|
|
2865
|
+
ExternalHyperlink,
|
|
2866
|
+
TabStopType
|
|
2867
|
+
} from "docx";
|
|
2868
|
+
|
|
2124
2869
|
// src/core/mermaid/mermaidRenderer.ts
|
|
2870
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
2871
|
+
import * as fs4 from "fs";
|
|
2872
|
+
import * as os2 from "os";
|
|
2873
|
+
import * as path4 from "path";
|
|
2874
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2125
2875
|
async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
|
|
2126
2876
|
const chromePath = findChromeExecutable();
|
|
2127
2877
|
if (!chromePath) {
|
|
@@ -2129,8 +2879,8 @@ async function renderMermaidToPng(mermaidCode, _baseDir = process.cwd()) {
|
|
|
2129
2879
|
}
|
|
2130
2880
|
const tmpId = Math.random().toString(36).substring(2, 9);
|
|
2131
2881
|
const tmpDir = os2.tmpdir();
|
|
2132
|
-
const tmpHtml =
|
|
2133
|
-
const tmpScreenshot =
|
|
2882
|
+
const tmpHtml = path4.join(tmpDir, `mermaid_${tmpId}.html`);
|
|
2883
|
+
const tmpScreenshot = path4.join(tmpDir, `mermaid_${tmpId}.png`);
|
|
2134
2884
|
const htmlContent = `<!DOCTYPE html>
|
|
2135
2885
|
<html>
|
|
2136
2886
|
<head>
|
|
@@ -2338,6 +3088,29 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
2338
3088
|
);
|
|
2339
3089
|
continue;
|
|
2340
3090
|
}
|
|
3091
|
+
if (span.type === "mathInline") {
|
|
3092
|
+
runs.push(
|
|
3093
|
+
new TextRun({
|
|
3094
|
+
text: span.content,
|
|
3095
|
+
font: "Cambria Math",
|
|
3096
|
+
italics: true,
|
|
3097
|
+
size: options.size,
|
|
3098
|
+
color: options.color || "0F172A"
|
|
3099
|
+
})
|
|
3100
|
+
);
|
|
3101
|
+
continue;
|
|
3102
|
+
}
|
|
3103
|
+
if (span.type === "footnoteRef") {
|
|
3104
|
+
runs.push(
|
|
3105
|
+
new TextRun({
|
|
3106
|
+
text: `[${span.content}]`,
|
|
3107
|
+
superScript: true,
|
|
3108
|
+
color: "009DA0",
|
|
3109
|
+
bold: true
|
|
3110
|
+
})
|
|
3111
|
+
);
|
|
3112
|
+
continue;
|
|
3113
|
+
}
|
|
2341
3114
|
runs.push(
|
|
2342
3115
|
new TextRun({
|
|
2343
3116
|
text: span.content,
|
|
@@ -2352,7 +3125,7 @@ async function convertInlinesToTextRuns(spans = [], baseDir = process.cwd(), opt
|
|
|
2352
3125
|
return runs;
|
|
2353
3126
|
}
|
|
2354
3127
|
async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
2355
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3128
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2356
3129
|
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
2357
3130
|
const docElements = [];
|
|
2358
3131
|
const themeProps = typeof resolved.theme === "object" ? resolved.theme : {};
|
|
@@ -2363,7 +3136,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2363
3136
|
const borderHex = (themeProps.borderColor || "#E2E8F0").replace("#", "");
|
|
2364
3137
|
const cardBgHex = (themeProps.cardBackground || "#F8FAFC").replace("#", "");
|
|
2365
3138
|
const defaultFont = themeProps.fontFamily ? themeProps.fontFamily.split(",")[0].replace(/['"]/g, "").trim() : "Segoe UI";
|
|
2366
|
-
if (resolved.title) {
|
|
3139
|
+
if (resolved.title && !((_a = resolved.coverPage) == null ? void 0 : _a.enabled)) {
|
|
2367
3140
|
docElements.push(
|
|
2368
3141
|
new Paragraph({
|
|
2369
3142
|
children: [
|
|
@@ -2779,7 +3552,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2779
3552
|
}
|
|
2780
3553
|
if (node.type === "table" && node.children) {
|
|
2781
3554
|
const tableRows = [];
|
|
2782
|
-
const numCols = ((
|
|
3555
|
+
const numCols = ((_c = (_b = node.children[0]) == null ? void 0 : _b.children) == null ? void 0 : _c.length) || 1;
|
|
2783
3556
|
const colWidth = Math.floor(9e3 / numCols);
|
|
2784
3557
|
for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
|
|
2785
3558
|
const rowNode = node.children[rowIdx];
|
|
@@ -2789,7 +3562,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2789
3562
|
if (rowNode.children) {
|
|
2790
3563
|
for (let colIdx = 0; colIdx < rowNode.children.length; colIdx++) {
|
|
2791
3564
|
const cellNode = rowNode.children[colIdx];
|
|
2792
|
-
const align = (
|
|
3565
|
+
const align = (_d = node.align) == null ? void 0 : _d[colIdx];
|
|
2793
3566
|
let alignment = AlignmentType.LEFT;
|
|
2794
3567
|
if (align === "center") alignment = AlignmentType.CENTER;
|
|
2795
3568
|
if (align === "right") alignment = AlignmentType.RIGHT;
|
|
@@ -2928,6 +3701,113 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2928
3701
|
}
|
|
2929
3702
|
continue;
|
|
2930
3703
|
}
|
|
3704
|
+
if (node.type === "mathBlock") {
|
|
3705
|
+
docElements.push(
|
|
3706
|
+
new Paragraph({
|
|
3707
|
+
alignment: AlignmentType.CENTER,
|
|
3708
|
+
children: [
|
|
3709
|
+
new TextRun({
|
|
3710
|
+
text: node.text || "",
|
|
3711
|
+
font: "Cambria Math",
|
|
3712
|
+
italics: true,
|
|
3713
|
+
size: 24,
|
|
3714
|
+
// 12pt
|
|
3715
|
+
color: textHex
|
|
3716
|
+
})
|
|
3717
|
+
],
|
|
3718
|
+
spacing: { before: 180, after: 180 },
|
|
3719
|
+
shading: { fill: cardBgHex, type: ShadingType.CLEAR },
|
|
3720
|
+
border: {
|
|
3721
|
+
top: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3722
|
+
bottom: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3723
|
+
left: { style: BorderStyle.SINGLE, size: 4, color: borderHex },
|
|
3724
|
+
right: { style: BorderStyle.SINGLE, size: 4, color: borderHex }
|
|
3725
|
+
}
|
|
3726
|
+
})
|
|
3727
|
+
);
|
|
3728
|
+
continue;
|
|
3729
|
+
}
|
|
3730
|
+
if (node.type === "columns") {
|
|
3731
|
+
const cols = node.columnsCount || 2;
|
|
3732
|
+
const contentWidth = Math.max(
|
|
3733
|
+
1e3,
|
|
3734
|
+
resolved.paperDimensions.widthTwip - resolved.margins.leftTwip - resolved.margins.rightTwip
|
|
3735
|
+
);
|
|
3736
|
+
const cellWidthDxa = Math.floor(contentWidth / cols);
|
|
3737
|
+
const cells = [];
|
|
3738
|
+
for (const col of node.children || []) {
|
|
3739
|
+
const colParagraphs = [];
|
|
3740
|
+
for (const childNode of col.children || []) {
|
|
3741
|
+
if (childNode.type === "heading") {
|
|
3742
|
+
const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, bold: true, size: 24, color: primaryDarkHex });
|
|
3743
|
+
colParagraphs.push(new Paragraph({ children: runs, spacing: { before: 120, after: 60 } }));
|
|
3744
|
+
} else if (childNode.type === "paragraph") {
|
|
3745
|
+
const runs = await convertInlinesToTextRuns(childNode.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
|
|
3746
|
+
colParagraphs.push(new Paragraph({ children: runs, spacing: { after: 100 } }));
|
|
3747
|
+
} else if (childNode.type === "list" && childNode.children) {
|
|
3748
|
+
for (const item of childNode.children) {
|
|
3749
|
+
const runs = await convertInlinesToTextRuns(item.inlines, baseDir, { font: defaultFont, size: 21, color: textHex });
|
|
3750
|
+
colParagraphs.push(new Paragraph({ children: [new TextRun({ text: "\u2022 ", font: defaultFont, color: primaryHex }), ...runs], spacing: { after: 40 } }));
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
if (colParagraphs.length === 0) colParagraphs.push(new Paragraph({}));
|
|
3755
|
+
cells.push(
|
|
3756
|
+
new TableCell({
|
|
3757
|
+
width: { size: cellWidthDxa, type: WidthType.DXA },
|
|
3758
|
+
borders: {
|
|
3759
|
+
top: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3760
|
+
bottom: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3761
|
+
left: { style: BorderStyle.NONE, size: 0, color: "auto" },
|
|
3762
|
+
right: { style: BorderStyle.NONE, size: 0, color: "auto" }
|
|
3763
|
+
},
|
|
3764
|
+
margins: { top: 60, bottom: 60, left: 100, right: 100 },
|
|
3765
|
+
children: colParagraphs
|
|
3766
|
+
})
|
|
3767
|
+
);
|
|
3768
|
+
}
|
|
3769
|
+
docElements.push(
|
|
3770
|
+
new Table({
|
|
3771
|
+
width: { size: 100, type: WidthType.PERCENTAGE },
|
|
3772
|
+
rows: [new TableRow({ children: cells })]
|
|
3773
|
+
})
|
|
3774
|
+
);
|
|
3775
|
+
docElements.push(new Paragraph({ spacing: { after: 120 } }));
|
|
3776
|
+
continue;
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
3780
|
+
docElements.push(
|
|
3781
|
+
new Paragraph({
|
|
3782
|
+
border: {
|
|
3783
|
+
top: { style: BorderStyle.SINGLE, size: 4, color: borderHex, space: 8 }
|
|
3784
|
+
},
|
|
3785
|
+
spacing: { before: 360, after: 120 }
|
|
3786
|
+
})
|
|
3787
|
+
);
|
|
3788
|
+
for (const def of doc.footnoteDefs) {
|
|
3789
|
+
const defRuns = await convertInlinesToTextRuns(def.inlines, baseDir, {
|
|
3790
|
+
font: defaultFont,
|
|
3791
|
+
size: 18,
|
|
3792
|
+
// 9pt
|
|
3793
|
+
color: textMutedHex
|
|
3794
|
+
});
|
|
3795
|
+
docElements.push(
|
|
3796
|
+
new Paragraph({
|
|
3797
|
+
children: [
|
|
3798
|
+
new TextRun({
|
|
3799
|
+
text: `[${def.id}] `,
|
|
3800
|
+
bold: true,
|
|
3801
|
+
color: primaryDarkHex,
|
|
3802
|
+
font: defaultFont,
|
|
3803
|
+
size: 18
|
|
3804
|
+
}),
|
|
3805
|
+
...defRuns
|
|
3806
|
+
],
|
|
3807
|
+
spacing: { after: 60 }
|
|
3808
|
+
})
|
|
3809
|
+
);
|
|
3810
|
+
}
|
|
2931
3811
|
}
|
|
2932
3812
|
if (resolved.signatures && resolved.signatures.items.length > 0) {
|
|
2933
3813
|
const sig = resolved.signatures;
|
|
@@ -2989,7 +3869,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
2989
3869
|
const centerPos = Math.round(contentWidthTwip / 2);
|
|
2990
3870
|
const rightPos = contentWidthTwip;
|
|
2991
3871
|
const headerRuns = [];
|
|
2992
|
-
if ((
|
|
3872
|
+
if ((_e = resolved.header) == null ? void 0 : _e.left) {
|
|
2993
3873
|
headerRuns.push(
|
|
2994
3874
|
new TextRun({
|
|
2995
3875
|
text: resolved.header.left.text,
|
|
@@ -3002,7 +3882,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3002
3882
|
);
|
|
3003
3883
|
}
|
|
3004
3884
|
headerRuns.push(new TextRun({ text: " " }));
|
|
3005
|
-
if ((
|
|
3885
|
+
if ((_f = resolved.header) == null ? void 0 : _f.center) {
|
|
3006
3886
|
headerRuns.push(
|
|
3007
3887
|
new TextRun({
|
|
3008
3888
|
text: resolved.header.center.text,
|
|
@@ -3015,7 +3895,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3015
3895
|
);
|
|
3016
3896
|
}
|
|
3017
3897
|
headerRuns.push(new TextRun({ text: " " }));
|
|
3018
|
-
if ((
|
|
3898
|
+
if ((_g = resolved.header) == null ? void 0 : _g.right) {
|
|
3019
3899
|
headerRuns.push(
|
|
3020
3900
|
new TextRun({
|
|
3021
3901
|
text: resolved.header.right.text,
|
|
@@ -3027,7 +3907,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3027
3907
|
})
|
|
3028
3908
|
);
|
|
3029
3909
|
}
|
|
3030
|
-
const docHeader = resolved.header ? new
|
|
3910
|
+
const docHeader = resolved.header ? new Header({
|
|
3031
3911
|
children: [
|
|
3032
3912
|
new Paragraph({
|
|
3033
3913
|
tabStops: [
|
|
@@ -3054,7 +3934,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3054
3934
|
]
|
|
3055
3935
|
}) : void 0;
|
|
3056
3936
|
const footerRuns = [];
|
|
3057
|
-
if ((
|
|
3937
|
+
if ((_h = resolved.footer) == null ? void 0 : _h.left) {
|
|
3058
3938
|
footerRuns.push(
|
|
3059
3939
|
new TextRun({
|
|
3060
3940
|
text: resolved.footer.left.text,
|
|
@@ -3067,7 +3947,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3067
3947
|
);
|
|
3068
3948
|
}
|
|
3069
3949
|
footerRuns.push(new TextRun({ text: " " }));
|
|
3070
|
-
if ((
|
|
3950
|
+
if ((_i = resolved.footer) == null ? void 0 : _i.center) {
|
|
3071
3951
|
footerRuns.push(
|
|
3072
3952
|
new TextRun({
|
|
3073
3953
|
text: resolved.footer.center.text,
|
|
@@ -3080,7 +3960,7 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3080
3960
|
);
|
|
3081
3961
|
}
|
|
3082
3962
|
footerRuns.push(new TextRun({ text: " " }));
|
|
3083
|
-
if ((
|
|
3963
|
+
if ((_j = resolved.footer) == null ? void 0 : _j.right) {
|
|
3084
3964
|
const rZone = resolved.footer.right;
|
|
3085
3965
|
const rColor = rZone.color.replace("#", "");
|
|
3086
3966
|
const rSize = (rZone.fontSize || 9) * 2;
|
|
@@ -3165,6 +4045,91 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3165
4045
|
]
|
|
3166
4046
|
}) : void 0;
|
|
3167
4047
|
const isLandscape = resolved.orientation === "landscape";
|
|
4048
|
+
const docSections = [];
|
|
4049
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
4050
|
+
const coverElements = await buildDocxCoverPageElements(
|
|
4051
|
+
resolved.coverPage,
|
|
4052
|
+
defaultFont,
|
|
4053
|
+
textHex,
|
|
4054
|
+
primaryHex,
|
|
4055
|
+
primaryDarkHex,
|
|
4056
|
+
textMutedHex,
|
|
4057
|
+
baseDir
|
|
4058
|
+
);
|
|
4059
|
+
docSections.push({
|
|
4060
|
+
properties: {
|
|
4061
|
+
page: {
|
|
4062
|
+
size: {
|
|
4063
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4064
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4065
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4066
|
+
},
|
|
4067
|
+
margin: {
|
|
4068
|
+
top: resolved.margins.topTwip,
|
|
4069
|
+
bottom: resolved.margins.bottomTwip,
|
|
4070
|
+
left: resolved.margins.leftTwip,
|
|
4071
|
+
right: resolved.margins.rightTwip
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
},
|
|
4075
|
+
headers: void 0,
|
|
4076
|
+
footers: void 0,
|
|
4077
|
+
children: coverElements
|
|
4078
|
+
});
|
|
4079
|
+
}
|
|
4080
|
+
docSections.push({
|
|
4081
|
+
properties: {
|
|
4082
|
+
page: {
|
|
4083
|
+
size: {
|
|
4084
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4085
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4086
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4087
|
+
},
|
|
4088
|
+
margin: {
|
|
4089
|
+
top: resolved.margins.topTwip,
|
|
4090
|
+
bottom: resolved.margins.bottomTwip,
|
|
4091
|
+
left: resolved.margins.leftTwip,
|
|
4092
|
+
right: resolved.margins.rightTwip,
|
|
4093
|
+
header: 720,
|
|
4094
|
+
footer: 720
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
},
|
|
4098
|
+
headers: docHeader ? { default: docHeader } : void 0,
|
|
4099
|
+
footers: docFooter ? { default: docFooter } : void 0,
|
|
4100
|
+
children: docElements
|
|
4101
|
+
});
|
|
4102
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
4103
|
+
const backElements = await buildDocxBackCoverElements(
|
|
4104
|
+
resolved.backCover,
|
|
4105
|
+
defaultFont,
|
|
4106
|
+
textHex,
|
|
4107
|
+
primaryHex,
|
|
4108
|
+
primaryDarkHex,
|
|
4109
|
+
textMutedHex,
|
|
4110
|
+
baseDir
|
|
4111
|
+
);
|
|
4112
|
+
docSections.push({
|
|
4113
|
+
properties: {
|
|
4114
|
+
page: {
|
|
4115
|
+
size: {
|
|
4116
|
+
width: resolved.paperDimensions.widthTwip,
|
|
4117
|
+
height: resolved.paperDimensions.heightTwip,
|
|
4118
|
+
orientation: isLandscape ? PageOrientation.LANDSCAPE : PageOrientation.PORTRAIT
|
|
4119
|
+
},
|
|
4120
|
+
margin: {
|
|
4121
|
+
top: resolved.margins.topTwip,
|
|
4122
|
+
bottom: resolved.margins.bottomTwip,
|
|
4123
|
+
left: resolved.margins.leftTwip,
|
|
4124
|
+
right: resolved.margins.rightTwip
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
},
|
|
4128
|
+
headers: void 0,
|
|
4129
|
+
footers: void 0,
|
|
4130
|
+
children: backElements
|
|
4131
|
+
});
|
|
4132
|
+
}
|
|
3168
4133
|
const document = new Document({
|
|
3169
4134
|
styles: {
|
|
3170
4135
|
default: {
|
|
@@ -3185,33 +4150,250 @@ async function buildDocxDocument(doc, config, baseDir = process.cwd()) {
|
|
|
3185
4150
|
}
|
|
3186
4151
|
}
|
|
3187
4152
|
},
|
|
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
|
-
]
|
|
4153
|
+
sections: docSections
|
|
3212
4154
|
});
|
|
3213
4155
|
return await Packer.toBuffer(document);
|
|
3214
4156
|
}
|
|
4157
|
+
async function buildDocxBackCoverElements(backCover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
|
|
4158
|
+
var _a;
|
|
4159
|
+
const elements = [];
|
|
4160
|
+
elements.push(new Paragraph({ spacing: { before: 1800 } }));
|
|
4161
|
+
if (backCover.logo) {
|
|
4162
|
+
const resolvedLogo = await resolveImage(backCover.logo, baseDir);
|
|
4163
|
+
if (resolvedLogo) {
|
|
4164
|
+
const logoW = typeof backCover.logoWidth === "number" ? backCover.logoWidth : 140;
|
|
4165
|
+
const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
|
|
4166
|
+
elements.push(
|
|
4167
|
+
new Paragraph({
|
|
4168
|
+
children: [
|
|
4169
|
+
new ImageRun({
|
|
4170
|
+
data: resolvedLogo.buffer,
|
|
4171
|
+
transformation: {
|
|
4172
|
+
width: logoW,
|
|
4173
|
+
height: Math.round(logoW * 0.75)
|
|
4174
|
+
},
|
|
4175
|
+
type: logoType
|
|
4176
|
+
})
|
|
4177
|
+
],
|
|
4178
|
+
spacing: { after: 240 }
|
|
4179
|
+
})
|
|
4180
|
+
);
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
if (backCover.badge) {
|
|
4184
|
+
elements.push(
|
|
4185
|
+
new Paragraph({
|
|
4186
|
+
children: [
|
|
4187
|
+
new TextRun({
|
|
4188
|
+
text: `[ ${backCover.badge.toUpperCase()} ]`,
|
|
4189
|
+
font: defaultFont,
|
|
4190
|
+
size: 20,
|
|
4191
|
+
bold: true,
|
|
4192
|
+
color: primaryDarkHex
|
|
4193
|
+
})
|
|
4194
|
+
],
|
|
4195
|
+
spacing: { after: 240 }
|
|
4196
|
+
})
|
|
4197
|
+
);
|
|
4198
|
+
}
|
|
4199
|
+
elements.push(
|
|
4200
|
+
new Paragraph({
|
|
4201
|
+
children: [
|
|
4202
|
+
new TextRun({
|
|
4203
|
+
text: backCover.title,
|
|
4204
|
+
font: defaultFont,
|
|
4205
|
+
size: 52,
|
|
4206
|
+
// 26pt
|
|
4207
|
+
bold: true,
|
|
4208
|
+
color: textHex
|
|
4209
|
+
})
|
|
4210
|
+
],
|
|
4211
|
+
spacing: { after: 140 }
|
|
4212
|
+
})
|
|
4213
|
+
);
|
|
4214
|
+
if (backCover.subtitle) {
|
|
4215
|
+
elements.push(
|
|
4216
|
+
new Paragraph({
|
|
4217
|
+
children: [
|
|
4218
|
+
new TextRun({
|
|
4219
|
+
text: backCover.subtitle,
|
|
4220
|
+
font: defaultFont,
|
|
4221
|
+
size: 24,
|
|
4222
|
+
// 12pt
|
|
4223
|
+
color: textMutedHex
|
|
4224
|
+
})
|
|
4225
|
+
],
|
|
4226
|
+
spacing: { after: 480 }
|
|
4227
|
+
})
|
|
4228
|
+
);
|
|
4229
|
+
}
|
|
4230
|
+
elements.push(
|
|
4231
|
+
new Paragraph({
|
|
4232
|
+
border: {
|
|
4233
|
+
bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
|
|
4234
|
+
},
|
|
4235
|
+
spacing: { after: 480 }
|
|
4236
|
+
})
|
|
4237
|
+
);
|
|
4238
|
+
const contactRuns = [];
|
|
4239
|
+
if (backCover.company) contactRuns.push(new TextRun({ text: `Organization: ${backCover.company}
|
|
4240
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4241
|
+
if (backCover.address) contactRuns.push(new TextRun({ text: `Address: ${backCover.address}
|
|
4242
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4243
|
+
if (backCover.email) contactRuns.push(new TextRun({ text: `Email: ${backCover.email}
|
|
4244
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4245
|
+
if (backCover.phone) contactRuns.push(new TextRun({ text: `Phone: ${backCover.phone}
|
|
4246
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4247
|
+
if (backCover.website) contactRuns.push(new TextRun({ text: `Website: ${backCover.website}
|
|
4248
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4249
|
+
if (backCover.social) {
|
|
4250
|
+
for (const [net, url] of Object.entries(backCover.social)) {
|
|
4251
|
+
if (url) {
|
|
4252
|
+
contactRuns.push(new TextRun({ text: `${net.toUpperCase()}: ${url}
|
|
4253
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
if (contactRuns.length > 0) {
|
|
4258
|
+
elements.push(
|
|
4259
|
+
new Paragraph({
|
|
4260
|
+
children: contactRuns,
|
|
4261
|
+
spacing: { before: 360, after: 360 }
|
|
4262
|
+
})
|
|
4263
|
+
);
|
|
4264
|
+
}
|
|
4265
|
+
if (backCover.copyright) {
|
|
4266
|
+
elements.push(
|
|
4267
|
+
new Paragraph({
|
|
4268
|
+
children: [
|
|
4269
|
+
new TextRun({
|
|
4270
|
+
text: backCover.copyright,
|
|
4271
|
+
font: defaultFont,
|
|
4272
|
+
size: 18,
|
|
4273
|
+
color: "94A3B8"
|
|
4274
|
+
})
|
|
4275
|
+
],
|
|
4276
|
+
spacing: { before: 720 }
|
|
4277
|
+
})
|
|
4278
|
+
);
|
|
4279
|
+
}
|
|
4280
|
+
return elements;
|
|
4281
|
+
}
|
|
4282
|
+
async function buildDocxCoverPageElements(cover, defaultFont, textHex, primaryHex, primaryDarkHex, textMutedHex, baseDir) {
|
|
4283
|
+
var _a;
|
|
4284
|
+
const elements = [];
|
|
4285
|
+
elements.push(new Paragraph({ spacing: { before: 1800 } }));
|
|
4286
|
+
if (cover.logo) {
|
|
4287
|
+
const resolvedLogo = await resolveImage(cover.logo, baseDir);
|
|
4288
|
+
if (resolvedLogo) {
|
|
4289
|
+
const logoW = typeof cover.logoWidth === "number" ? cover.logoWidth : 140;
|
|
4290
|
+
const logoType = ((_a = resolvedLogo.mimeType) == null ? void 0 : _a.includes("png")) ? "png" : "jpg";
|
|
4291
|
+
elements.push(
|
|
4292
|
+
new Paragraph({
|
|
4293
|
+
children: [
|
|
4294
|
+
new ImageRun({
|
|
4295
|
+
data: resolvedLogo.buffer,
|
|
4296
|
+
transformation: {
|
|
4297
|
+
width: logoW,
|
|
4298
|
+
height: Math.round(logoW * 0.75)
|
|
4299
|
+
},
|
|
4300
|
+
type: logoType
|
|
4301
|
+
})
|
|
4302
|
+
],
|
|
4303
|
+
spacing: { after: 240 }
|
|
4304
|
+
})
|
|
4305
|
+
);
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
if (cover.badge) {
|
|
4309
|
+
elements.push(
|
|
4310
|
+
new Paragraph({
|
|
4311
|
+
children: [
|
|
4312
|
+
new TextRun({
|
|
4313
|
+
text: `[ ${cover.badge.toUpperCase()} ]`,
|
|
4314
|
+
font: defaultFont,
|
|
4315
|
+
size: 20,
|
|
4316
|
+
bold: true,
|
|
4317
|
+
color: primaryDarkHex
|
|
4318
|
+
})
|
|
4319
|
+
],
|
|
4320
|
+
spacing: { after: 240 }
|
|
4321
|
+
})
|
|
4322
|
+
);
|
|
4323
|
+
}
|
|
4324
|
+
elements.push(
|
|
4325
|
+
new Paragraph({
|
|
4326
|
+
children: [
|
|
4327
|
+
new TextRun({
|
|
4328
|
+
text: cover.title,
|
|
4329
|
+
font: defaultFont,
|
|
4330
|
+
size: 56,
|
|
4331
|
+
// 28pt
|
|
4332
|
+
bold: true,
|
|
4333
|
+
color: textHex
|
|
4334
|
+
})
|
|
4335
|
+
],
|
|
4336
|
+
spacing: { after: 140 }
|
|
4337
|
+
})
|
|
4338
|
+
);
|
|
4339
|
+
if (cover.subtitle) {
|
|
4340
|
+
elements.push(
|
|
4341
|
+
new Paragraph({
|
|
4342
|
+
children: [
|
|
4343
|
+
new TextRun({
|
|
4344
|
+
text: cover.subtitle,
|
|
4345
|
+
font: defaultFont,
|
|
4346
|
+
size: 26,
|
|
4347
|
+
// 13pt
|
|
4348
|
+
color: textMutedHex
|
|
4349
|
+
})
|
|
4350
|
+
],
|
|
4351
|
+
spacing: { after: 480 }
|
|
4352
|
+
})
|
|
4353
|
+
);
|
|
4354
|
+
}
|
|
4355
|
+
elements.push(
|
|
4356
|
+
new Paragraph({
|
|
4357
|
+
border: {
|
|
4358
|
+
bottom: { style: BorderStyle.SINGLE, size: 16, color: primaryHex, space: 8 }
|
|
4359
|
+
},
|
|
4360
|
+
spacing: { after: 480 }
|
|
4361
|
+
})
|
|
4362
|
+
);
|
|
4363
|
+
if (cover.company || cover.author || cover.version || cover.date) {
|
|
4364
|
+
const metaRuns = [];
|
|
4365
|
+
if (cover.company) metaRuns.push(new TextRun({ text: `Organization: ${cover.company}
|
|
4366
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4367
|
+
if (cover.author) metaRuns.push(new TextRun({ text: `Author: ${cover.author}
|
|
4368
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4369
|
+
if (cover.version) metaRuns.push(new TextRun({ text: `Version: ${cover.version}
|
|
4370
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4371
|
+
if (cover.date) metaRuns.push(new TextRun({ text: `Date: ${cover.date}
|
|
4372
|
+
`, font: defaultFont, size: 21, color: textHex }));
|
|
4373
|
+
elements.push(
|
|
4374
|
+
new Paragraph({
|
|
4375
|
+
children: metaRuns,
|
|
4376
|
+
spacing: { before: 360, after: 360 }
|
|
4377
|
+
})
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
if (cover.footerText) {
|
|
4381
|
+
elements.push(
|
|
4382
|
+
new Paragraph({
|
|
4383
|
+
children: [
|
|
4384
|
+
new TextRun({
|
|
4385
|
+
text: cover.footerText,
|
|
4386
|
+
font: defaultFont,
|
|
4387
|
+
size: 18,
|
|
4388
|
+
color: "94A3B8"
|
|
4389
|
+
})
|
|
4390
|
+
],
|
|
4391
|
+
spacing: { before: 720 }
|
|
4392
|
+
})
|
|
4393
|
+
);
|
|
4394
|
+
}
|
|
4395
|
+
return elements;
|
|
4396
|
+
}
|
|
3215
4397
|
async function buildDocxSignatureCell(item, sig, widthDxa, defaultFont, baseDir) {
|
|
3216
4398
|
const cellParagraphs = [];
|
|
3217
4399
|
if (item.title) {
|
|
@@ -3347,126 +4529,9 @@ function createEmptyDocxCell(widthDxa) {
|
|
|
3347
4529
|
});
|
|
3348
4530
|
}
|
|
3349
4531
|
|
|
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
4532
|
export {
|
|
3471
|
-
|
|
4533
|
+
parseMarkdownDocument,
|
|
4534
|
+
buildHtmlDocument,
|
|
4535
|
+
buildPdfDocument,
|
|
4536
|
+
buildDocxDocument
|
|
3472
4537
|
};
|