@masumdev/markforge 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/App-JOOTPDJN.mjs +847 -0
- package/dist/{chunk-R6DT335C.mjs → chunk-H3ZUUSHP.mjs} +77 -23
- package/dist/cli.mjs +2 -2
- package/dist/index.d.mts +44 -12
- package/dist/index.d.ts +44 -12
- package/dist/index.js +608 -67
- package/dist/index.mjs +595 -61
- package/dist/{previewServer-4EELOUAV.mjs → previewServer-U47WQ5FV.mjs} +1 -1
- package/package.json +1 -1
- package/dist/App-TPDCT2VL.mjs +0 -393
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
try {
|
|
3
|
+
if (typeof globalThis !== "undefined" && (!globalThis.localStorage || typeof globalThis.localStorage.getItem !== "function")) {
|
|
4
|
+
Object.defineProperty(globalThis, "localStorage", {
|
|
5
|
+
value: { getItem: () => null, setItem: () => {}, removeItem: () => {}, clear: () => {}, key: () => null, length: 0 },
|
|
6
|
+
configurable: true, writable: true,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
} catch {}
|
|
10
|
+
import {
|
|
11
|
+
MARKFORGE_VERSION
|
|
12
|
+
} from "./chunk-UNWAEVDU.mjs";
|
|
13
|
+
import {
|
|
14
|
+
applyHeadingNumbering,
|
|
15
|
+
buildDocxDocument,
|
|
16
|
+
buildHtmlDocument,
|
|
17
|
+
buildPdfDocument,
|
|
18
|
+
findChromeExecutable,
|
|
19
|
+
parseMarkdownDocument,
|
|
20
|
+
replaceDocumentTokens,
|
|
21
|
+
resolveDocumentConfig
|
|
22
|
+
} from "./chunk-H3ZUUSHP.mjs";
|
|
23
|
+
import {
|
|
24
|
+
DEFAULT_CONFIG
|
|
25
|
+
} from "./chunk-BPHDY6VB.mjs";
|
|
26
|
+
import "./chunk-YZHGBG4N.mjs";
|
|
27
|
+
|
|
28
|
+
// src/ui/App.tsx
|
|
29
|
+
import { useState, useEffect } from "react";
|
|
30
|
+
import { Box as Box4 } from "ink";
|
|
31
|
+
|
|
32
|
+
// src/ui/Header.tsx
|
|
33
|
+
import * as path from "path";
|
|
34
|
+
import { Box, Text } from "ink";
|
|
35
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
36
|
+
function formatDisplayPath(p) {
|
|
37
|
+
if (!p) return "";
|
|
38
|
+
try {
|
|
39
|
+
const rel = path.relative(process.cwd(), p);
|
|
40
|
+
return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p;
|
|
41
|
+
} catch {
|
|
42
|
+
return p;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var Header = ({
|
|
46
|
+
inputFile,
|
|
47
|
+
configPath,
|
|
48
|
+
config,
|
|
49
|
+
theme = "corporate",
|
|
50
|
+
targetFormats = ["docx", "pdf"]
|
|
51
|
+
}) => {
|
|
52
|
+
const resolvedTheme = (config == null ? void 0 : config.theme) || theme;
|
|
53
|
+
const themeLabel = typeof resolvedTheme === "object" ? "Custom (ThemeProps)" : String(resolvedTheme || "corporate");
|
|
54
|
+
const activeFeatures = [];
|
|
55
|
+
if (config == null ? void 0 : config.toc) activeFeatures.push("TOC");
|
|
56
|
+
if (config == null ? void 0 : config.numberHeadings) {
|
|
57
|
+
if (typeof config.numberHeadings === "object") {
|
|
58
|
+
const isNumEnabled = config.numberHeadings.enabled ?? true;
|
|
59
|
+
if (isNumEnabled) {
|
|
60
|
+
activeFeatures.push(`Numbering (depth ${config.numberHeadings.depth ?? 3})`);
|
|
61
|
+
}
|
|
62
|
+
} else if (config.numberHeadings === true) {
|
|
63
|
+
activeFeatures.push("Numbering (depth 3)");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (config == null ? void 0 : config.coverPage) {
|
|
67
|
+
if (typeof config.coverPage === "object" && config.coverPage.enabled !== false) {
|
|
68
|
+
activeFeatures.push(`Cover (${config.coverPage.preset || "corporate"})`);
|
|
69
|
+
} else if (config.coverPage === true) {
|
|
70
|
+
activeFeatures.push("Cover (corporate)");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (config == null ? void 0 : config.backCover) {
|
|
74
|
+
if (typeof config.backCover === "object" && config.backCover.enabled !== false) {
|
|
75
|
+
activeFeatures.push(`BackCover (${config.backCover.preset || "corporate"})`);
|
|
76
|
+
} else if (config.backCover === true) {
|
|
77
|
+
activeFeatures.push("BackCover (corporate)");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (config == null ? void 0 : config.watermark) {
|
|
81
|
+
const wmText = typeof config.watermark === "object" ? config.watermark.text : config.watermark;
|
|
82
|
+
if (wmText) {
|
|
83
|
+
activeFeatures.push(`Watermark ("${wmText}")`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if ((config == null ? void 0 : config.security) && (config.security.userPassword || config.security.ownerPassword)) {
|
|
87
|
+
activeFeatures.push("AES-256 Security");
|
|
88
|
+
}
|
|
89
|
+
if ((config == null ? void 0 : config.math) !== false) activeFeatures.push("KaTeX Math");
|
|
90
|
+
if (config == null ? void 0 : config.syntaxTheme) activeFeatures.push(`Syntax (${config.syntaxTheme})`);
|
|
91
|
+
const paperLabel = `${(config == null ? void 0 : config.paperSize) || "A4"} (${(config == null ? void 0 : config.orientation) || "portrait"})`;
|
|
92
|
+
const outputLabel = (config == null ? void 0 : config.outputDir) ? formatDisplayPath(config.outputDir) : "./ (default)";
|
|
93
|
+
const configLabel = configPath ? formatDisplayPath(configPath) : "(default auto-discovery)";
|
|
94
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs(
|
|
95
|
+
Box,
|
|
96
|
+
{
|
|
97
|
+
borderStyle: "round",
|
|
98
|
+
borderColor: "cyan",
|
|
99
|
+
paddingX: 2,
|
|
100
|
+
paddingY: 1,
|
|
101
|
+
flexDirection: "column",
|
|
102
|
+
children: [
|
|
103
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", alignItems: "center", children: [
|
|
104
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
105
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MARKFORGE" }),
|
|
106
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: " | Document Publishing Engine" })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "black", backgroundColor: "cyan", bold: true, children: [
|
|
109
|
+
" ",
|
|
110
|
+
"v",
|
|
111
|
+
MARKFORGE_VERSION,
|
|
112
|
+
" "
|
|
113
|
+
] }) })
|
|
114
|
+
] }),
|
|
115
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
116
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
117
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Source: " }),
|
|
119
|
+
/* @__PURE__ */ jsx(Text, { color: "white", bold: true, children: formatDisplayPath(inputFile) })
|
|
120
|
+
] }),
|
|
121
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
122
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Config: " }),
|
|
123
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: configLabel })
|
|
124
|
+
] })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginTop: 0, children: [
|
|
127
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
128
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Theme: " }),
|
|
129
|
+
/* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: themeLabel })
|
|
130
|
+
] }),
|
|
131
|
+
targetFormats && targetFormats.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
|
|
132
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Targets: " }),
|
|
133
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: targetFormats.map((f) => f.toUpperCase()).join(", ") })
|
|
134
|
+
] })
|
|
135
|
+
] }),
|
|
136
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginTop: 0, children: [
|
|
137
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
138
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Layout: " }),
|
|
139
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: paperLabel })
|
|
140
|
+
] }),
|
|
141
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
142
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Output: " }),
|
|
143
|
+
/* @__PURE__ */ jsx(Text, { color: "white", children: outputLabel })
|
|
144
|
+
] })
|
|
145
|
+
] }),
|
|
146
|
+
activeFeatures.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 0, children: [
|
|
147
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Modules: " }),
|
|
148
|
+
/* @__PURE__ */ jsx(Text, { color: "blue", children: activeFeatures.join(" | ") })
|
|
149
|
+
] })
|
|
150
|
+
] }),
|
|
151
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [
|
|
152
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
153
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "Author: " }),
|
|
154
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "Ma'sum" }),
|
|
155
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: " (@masumrpg)" })
|
|
156
|
+
] }),
|
|
157
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
158
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "GitHub: " }),
|
|
159
|
+
/* @__PURE__ */ jsx(Text, { color: "blue", underline: true, children: "https://github.com/masumrpg" })
|
|
160
|
+
] })
|
|
161
|
+
] })
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
) });
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// src/ui/LiveProgress.tsx
|
|
168
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
169
|
+
import Spinner from "ink-spinner";
|
|
170
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
171
|
+
var LiveProgress = ({ status, isCompiling }) => {
|
|
172
|
+
if (!isCompiling) return null;
|
|
173
|
+
return /* @__PURE__ */ jsxs2(Box2, { marginY: 1, alignItems: "center", children: [
|
|
174
|
+
/* @__PURE__ */ jsx2(Text2, { color: "cyan", children: /* @__PURE__ */ jsx2(Spinner, { type: "dots" }) }),
|
|
175
|
+
/* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, children: [
|
|
176
|
+
/* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "[COMPILING] " }),
|
|
177
|
+
/* @__PURE__ */ jsx2(Text2, { color: "white", children: status })
|
|
178
|
+
] })
|
|
179
|
+
] });
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// src/ui/SummaryTable.tsx
|
|
183
|
+
import * as path2 from "path";
|
|
184
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
185
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
186
|
+
function formatBytes(bytes) {
|
|
187
|
+
if (bytes === 0) return "0 B";
|
|
188
|
+
const k = 1024;
|
|
189
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
190
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
191
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
192
|
+
}
|
|
193
|
+
function formatDisplayPath2(p) {
|
|
194
|
+
if (!p) return "";
|
|
195
|
+
try {
|
|
196
|
+
const rel = path2.relative(process.cwd(), p);
|
|
197
|
+
return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p;
|
|
198
|
+
} catch {
|
|
199
|
+
return p;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
var SummaryTable = ({ result }) => {
|
|
203
|
+
if (!result) return null;
|
|
204
|
+
const hasErrors = result.errors.length > 0;
|
|
205
|
+
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs3(
|
|
206
|
+
Box3,
|
|
207
|
+
{
|
|
208
|
+
borderStyle: "round",
|
|
209
|
+
borderColor: hasErrors ? "red" : "green",
|
|
210
|
+
paddingX: 2,
|
|
211
|
+
paddingY: 1,
|
|
212
|
+
flexDirection: "column",
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", alignItems: "center", children: [
|
|
215
|
+
/* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: hasErrors ? "red" : "green", children: hasErrors ? "[COMPILATION FAILED]" : "[COMPILATION SUCCESSFUL]" }) }),
|
|
216
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
217
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Duration: " }),
|
|
218
|
+
/* @__PURE__ */ jsxs3(Text3, { color: "yellow", bold: true, children: [
|
|
219
|
+
result.durationMs,
|
|
220
|
+
"ms"
|
|
221
|
+
] })
|
|
222
|
+
] })
|
|
223
|
+
] }),
|
|
224
|
+
result.files.length > 0 && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
225
|
+
/* @__PURE__ */ jsxs3(Text3, { bold: true, color: "white", children: [
|
|
226
|
+
"Generated Documents (",
|
|
227
|
+
result.files.length,
|
|
228
|
+
"):"
|
|
229
|
+
] }),
|
|
230
|
+
result.files.map((f, i) => {
|
|
231
|
+
const formatColor = f.format === "docx" ? "blue" : f.format === "pdf" ? "red" : f.format === "html" ? "yellow" : f.format === "png" ? "magenta" : "green";
|
|
232
|
+
const paddedBadge = `[${f.format.toUpperCase()}]`.padEnd(7, " ");
|
|
233
|
+
return /* @__PURE__ */ jsxs3(Box3, { marginTop: 0, flexDirection: "column", marginLeft: 1, children: [
|
|
234
|
+
/* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", alignItems: "center", children: [
|
|
235
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
236
|
+
/* @__PURE__ */ jsx3(Text3, { color: formatColor, bold: true, children: paddedBadge }),
|
|
237
|
+
/* @__PURE__ */ jsx3(Text3, { color: "white", bold: true, children: f.fileName })
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: formatBytes(f.sizeBytes) })
|
|
240
|
+
] }),
|
|
241
|
+
/* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
242
|
+
"\u2514\u2500 ",
|
|
243
|
+
formatDisplayPath2(f.filePath)
|
|
244
|
+
] }) })
|
|
245
|
+
] }, i);
|
|
246
|
+
})
|
|
247
|
+
] }),
|
|
248
|
+
hasErrors && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
|
|
249
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: "red", children: "Errors:" }),
|
|
250
|
+
result.errors.map((err, i) => /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
|
|
251
|
+
"- ",
|
|
252
|
+
err
|
|
253
|
+
] }) }, i))
|
|
254
|
+
] }),
|
|
255
|
+
/* @__PURE__ */ jsxs3(Box3, { marginTop: 1, justifyContent: "space-between", alignItems: "center", children: [
|
|
256
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
257
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Author: " }),
|
|
258
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "Ma'sum" }),
|
|
259
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: " (@masumrpg)" })
|
|
260
|
+
] }),
|
|
261
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
262
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "GitHub: " }),
|
|
263
|
+
/* @__PURE__ */ jsx3(Text3, { color: "blue", underline: true, children: "https://github.com/masumrpg" })
|
|
264
|
+
] })
|
|
265
|
+
] })
|
|
266
|
+
]
|
|
267
|
+
}
|
|
268
|
+
) });
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// src/core/engine.ts
|
|
272
|
+
import * as fs2 from "fs";
|
|
273
|
+
import * as path4 from "path";
|
|
274
|
+
|
|
275
|
+
// src/core/text/textBuilder.ts
|
|
276
|
+
var LINE_WIDTH = 80;
|
|
277
|
+
var HR_DOUBLE = "=".repeat(LINE_WIDTH);
|
|
278
|
+
var HR_SINGLE = "-".repeat(LINE_WIDTH);
|
|
279
|
+
function centerText(text, width = LINE_WIDTH) {
|
|
280
|
+
if (text.length >= width) return text;
|
|
281
|
+
const leftPad = Math.floor((width - text.length) / 2);
|
|
282
|
+
return " ".repeat(leftPad) + text;
|
|
283
|
+
}
|
|
284
|
+
function renderInlinesToText(spans = [], meta = {}) {
|
|
285
|
+
let result = "";
|
|
286
|
+
for (const span of spans) {
|
|
287
|
+
switch (span.type) {
|
|
288
|
+
case "text": {
|
|
289
|
+
const content = replaceDocumentTokens(span.content, meta);
|
|
290
|
+
result += content;
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
case "bold": {
|
|
294
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
295
|
+
result += `**${inner}**`;
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
case "italic": {
|
|
299
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
300
|
+
result += `*${inner}*`;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
case "code": {
|
|
304
|
+
result += `\`${span.content}\``;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case "link": {
|
|
308
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
309
|
+
result += span.url && span.url !== inner ? `${inner} (${span.url})` : inner;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
case "image": {
|
|
313
|
+
result += `[Image: ${span.alt || "image"} (${span.url || ""})]`;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
case "strikethrough": {
|
|
317
|
+
const inner = span.children ? renderInlinesToText(span.children, meta) : replaceDocumentTokens(span.content, meta);
|
|
318
|
+
result += `~${inner}~`;
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case "mathInline": {
|
|
322
|
+
result += `$${span.content}$`;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
case "footnoteRef": {
|
|
326
|
+
const id = span.footnoteId || span.content;
|
|
327
|
+
result += `[${id}]`;
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case "htmlInline": {
|
|
331
|
+
result += span.content.replace(/<[^>]+>/g, "");
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
default: {
|
|
335
|
+
result += span.content || "";
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return result;
|
|
341
|
+
}
|
|
342
|
+
async function buildTextDocument(doc, config = {}, _baseDir = process.cwd()) {
|
|
343
|
+
const resolved = resolveDocumentConfig(doc.metadata, config);
|
|
344
|
+
const meta = {
|
|
345
|
+
...doc.metadata,
|
|
346
|
+
...config.metadata,
|
|
347
|
+
title: resolved.title,
|
|
348
|
+
subtitle: resolved.subtitle,
|
|
349
|
+
author: resolved.author,
|
|
350
|
+
company: resolved.company,
|
|
351
|
+
version: resolved.version,
|
|
352
|
+
date: resolved.date
|
|
353
|
+
};
|
|
354
|
+
const nodes = JSON.parse(JSON.stringify(doc.nodes));
|
|
355
|
+
const tocEntries = JSON.parse(JSON.stringify(doc.tocEntries));
|
|
356
|
+
if (resolved.numberHeadings && resolved.numberHeadings.enabled) {
|
|
357
|
+
applyHeadingNumbering(nodes, tocEntries, resolved.numberHeadings);
|
|
358
|
+
}
|
|
359
|
+
const lines = [];
|
|
360
|
+
if (resolved.coverPage && resolved.coverPage.enabled) {
|
|
361
|
+
const cover = resolved.coverPage;
|
|
362
|
+
const coverTitle = (cover.title || meta.title || "DOCUMENT").toUpperCase();
|
|
363
|
+
const coverSubtitle = cover.subtitle || meta.subtitle || "";
|
|
364
|
+
const coverAuthor = cover.author || meta.author || "";
|
|
365
|
+
const coverCompany = cover.company || meta.company || "";
|
|
366
|
+
const coverDate = cover.date || meta.date || "";
|
|
367
|
+
const coverVersion = cover.version || meta.version || "";
|
|
368
|
+
const coverBadge = cover.badge || "";
|
|
369
|
+
const coverFooter = cover.footerText || "";
|
|
370
|
+
lines.push(HR_DOUBLE);
|
|
371
|
+
lines.push(centerText(coverTitle));
|
|
372
|
+
if (coverSubtitle) {
|
|
373
|
+
lines.push(centerText(coverSubtitle));
|
|
374
|
+
}
|
|
375
|
+
lines.push(HR_DOUBLE);
|
|
376
|
+
if (coverBadge) {
|
|
377
|
+
lines.push(`[${coverBadge}]`);
|
|
378
|
+
lines.push("");
|
|
379
|
+
}
|
|
380
|
+
if (coverAuthor) lines.push(`Author: ${coverAuthor}`);
|
|
381
|
+
if (coverCompany) lines.push(`Company: ${coverCompany}`);
|
|
382
|
+
if (coverDate) lines.push(`Date: ${coverDate}`);
|
|
383
|
+
if (coverVersion) lines.push(`Version: ${coverVersion}`);
|
|
384
|
+
if (coverFooter) lines.push(`Notice: ${coverFooter}`);
|
|
385
|
+
lines.push(HR_DOUBLE);
|
|
386
|
+
lines.push("");
|
|
387
|
+
lines.push("");
|
|
388
|
+
}
|
|
389
|
+
if (resolved.toc) {
|
|
390
|
+
const headings = nodes.filter(
|
|
391
|
+
(n) => n.type === "heading" && (n.level || 1) <= 3
|
|
392
|
+
);
|
|
393
|
+
if (headings.length > 0) {
|
|
394
|
+
const tocTitle = "TABLE OF CONTENTS";
|
|
395
|
+
lines.push(HR_DOUBLE);
|
|
396
|
+
lines.push(centerText(tocTitle));
|
|
397
|
+
lines.push(HR_DOUBLE);
|
|
398
|
+
for (const h of headings) {
|
|
399
|
+
const level = h.level || 1;
|
|
400
|
+
const indent = " ".repeat(level - 1);
|
|
401
|
+
const headingText = renderInlinesToText(h.inlines, meta);
|
|
402
|
+
const prefix = level === 1 ? "* " : "- ";
|
|
403
|
+
lines.push(`${indent}${prefix}${headingText}`);
|
|
404
|
+
}
|
|
405
|
+
lines.push(HR_DOUBLE);
|
|
406
|
+
lines.push("");
|
|
407
|
+
lines.push("");
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function renderNode(node, listLevel = 0) {
|
|
411
|
+
var _a;
|
|
412
|
+
switch (node.type) {
|
|
413
|
+
case "heading": {
|
|
414
|
+
const level = node.level || 1;
|
|
415
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
416
|
+
lines.push("");
|
|
417
|
+
if (level === 1) {
|
|
418
|
+
lines.push(HR_DOUBLE);
|
|
419
|
+
lines.push(text.toUpperCase());
|
|
420
|
+
lines.push(HR_DOUBLE);
|
|
421
|
+
} else if (level === 2) {
|
|
422
|
+
lines.push(HR_SINGLE);
|
|
423
|
+
lines.push(text);
|
|
424
|
+
lines.push(HR_SINGLE);
|
|
425
|
+
} else {
|
|
426
|
+
const hashes = "#".repeat(level);
|
|
427
|
+
lines.push(`${hashes} ${text}`);
|
|
428
|
+
}
|
|
429
|
+
lines.push("");
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
case "paragraph": {
|
|
433
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
434
|
+
if (text.trim()) {
|
|
435
|
+
lines.push(text);
|
|
436
|
+
lines.push("");
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case "callout": {
|
|
441
|
+
const calloutType = (node.calloutType || "NOTE").toUpperCase();
|
|
442
|
+
lines.push(`| [${calloutType}]`);
|
|
443
|
+
if (node.inlines && node.inlines.length > 0) {
|
|
444
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
445
|
+
text.split("\n").forEach((l) => lines.push(`| ${l}`));
|
|
446
|
+
}
|
|
447
|
+
lines.push("");
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
case "blockquote": {
|
|
451
|
+
if (node.inlines && node.inlines.length > 0) {
|
|
452
|
+
const text = renderInlinesToText(node.inlines, meta);
|
|
453
|
+
text.split("\n").forEach((l) => lines.push(`> ${l}`));
|
|
454
|
+
lines.push("");
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case "codeBlock": {
|
|
459
|
+
const lang = node.language ? `[Language: ${node.language}]` : "[Code]";
|
|
460
|
+
lines.push(HR_SINGLE);
|
|
461
|
+
lines.push(lang);
|
|
462
|
+
lines.push(HR_SINGLE);
|
|
463
|
+
const codeText = node.text || "";
|
|
464
|
+
lines.push(codeText);
|
|
465
|
+
lines.push(HR_SINGLE);
|
|
466
|
+
lines.push("");
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
case "list": {
|
|
470
|
+
if (node.children) {
|
|
471
|
+
let itemIndex = 1;
|
|
472
|
+
for (const item of node.children) {
|
|
473
|
+
const indent = " ".repeat(listLevel);
|
|
474
|
+
let prefix = node.ordered ? `${itemIndex}. ` : "* ";
|
|
475
|
+
itemIndex++;
|
|
476
|
+
if (item.checked !== void 0) {
|
|
477
|
+
prefix = item.checked ? "[x] " : "[ ] ";
|
|
478
|
+
}
|
|
479
|
+
if (item.inlines && item.inlines.length > 0) {
|
|
480
|
+
const text = renderInlinesToText(item.inlines, meta);
|
|
481
|
+
lines.push(`${indent}${prefix}${text}`);
|
|
482
|
+
}
|
|
483
|
+
if (item.children && item.children.length > 0) {
|
|
484
|
+
for (const subChild of item.children) {
|
|
485
|
+
if (subChild.type === "list") {
|
|
486
|
+
renderNode(subChild, listLevel + 1);
|
|
487
|
+
} else if (subChild.type === "paragraph") {
|
|
488
|
+
const text = renderInlinesToText(subChild.inlines, meta);
|
|
489
|
+
lines.push(`${indent} ${text}`);
|
|
490
|
+
} else {
|
|
491
|
+
renderNode(subChild, listLevel + 1);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
lines.push("");
|
|
497
|
+
}
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
500
|
+
case "table": {
|
|
501
|
+
const rows = node.children || [];
|
|
502
|
+
if (rows.length === 0) break;
|
|
503
|
+
const rowCells = [];
|
|
504
|
+
let maxCols = 0;
|
|
505
|
+
for (const row of rows) {
|
|
506
|
+
const cells = row.children || [];
|
|
507
|
+
const texts = cells.map((c) => renderInlinesToText(c.inlines, meta));
|
|
508
|
+
const isHeader = cells.some((c) => c.isHeader);
|
|
509
|
+
maxCols = Math.max(maxCols, texts.length);
|
|
510
|
+
rowCells.push({ isHeader, texts });
|
|
511
|
+
}
|
|
512
|
+
if (maxCols === 0) break;
|
|
513
|
+
const colWidths = new Array(maxCols).fill(3);
|
|
514
|
+
for (const r of rowCells) {
|
|
515
|
+
for (let col = 0; col < maxCols; col++) {
|
|
516
|
+
const cellText = r.texts[col] || "";
|
|
517
|
+
colWidths[col] = Math.max(colWidths[col] ?? 3, cellText.length);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const separatorLine = "+" + colWidths.map((w) => "-".repeat(w + 2)).join("+") + "+";
|
|
521
|
+
const formatRow = (texts) => {
|
|
522
|
+
const paddedCells = colWidths.map((width, colIdx) => {
|
|
523
|
+
const text = texts[colIdx] || "";
|
|
524
|
+
return " " + text.padEnd(width, " ") + " ";
|
|
525
|
+
});
|
|
526
|
+
return "|" + paddedCells.join("|") + "|";
|
|
527
|
+
};
|
|
528
|
+
lines.push(separatorLine);
|
|
529
|
+
for (const r of rowCells) {
|
|
530
|
+
lines.push(formatRow(r.texts));
|
|
531
|
+
if (r.isHeader) {
|
|
532
|
+
lines.push(separatorLine);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (!((_a = rowCells[rowCells.length - 1]) == null ? void 0 : _a.isHeader)) {
|
|
536
|
+
lines.push(separatorLine);
|
|
537
|
+
}
|
|
538
|
+
lines.push("");
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
case "mathBlock": {
|
|
542
|
+
lines.push("[Equation]");
|
|
543
|
+
lines.push(` $$${node.text || ""} $$`);
|
|
544
|
+
lines.push("");
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
case "mermaid": {
|
|
548
|
+
lines.push("[Diagram: Mermaid]");
|
|
549
|
+
lines.push(node.text || "");
|
|
550
|
+
lines.push("");
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
case "thematicBreak": {
|
|
554
|
+
lines.push(HR_SINGLE);
|
|
555
|
+
lines.push("");
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
case "columns": {
|
|
559
|
+
if (node.children) {
|
|
560
|
+
for (const col of node.children) {
|
|
561
|
+
if (col.children) {
|
|
562
|
+
for (const child of col.children) {
|
|
563
|
+
renderNode(child, listLevel);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
break;
|
|
569
|
+
}
|
|
570
|
+
default: {
|
|
571
|
+
if (node.children && node.children.length > 0) {
|
|
572
|
+
for (const child of node.children) {
|
|
573
|
+
renderNode(child, listLevel);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
for (const node of nodes) {
|
|
581
|
+
renderNode(node);
|
|
582
|
+
}
|
|
583
|
+
if (doc.footnoteDefs && doc.footnoteDefs.length > 0) {
|
|
584
|
+
lines.push(HR_SINGLE);
|
|
585
|
+
lines.push("FOOTNOTES");
|
|
586
|
+
lines.push(HR_SINGLE);
|
|
587
|
+
for (const fn of doc.footnoteDefs) {
|
|
588
|
+
const text = renderInlinesToText(fn.inlines, meta);
|
|
589
|
+
lines.push(`[${fn.id}] ${text}`);
|
|
590
|
+
}
|
|
591
|
+
lines.push("");
|
|
592
|
+
}
|
|
593
|
+
if (resolved.signatures && resolved.signatures.items && resolved.signatures.items.length > 0) {
|
|
594
|
+
lines.push(HR_SINGLE);
|
|
595
|
+
lines.push("SIGNATURES & APPROVALS");
|
|
596
|
+
lines.push(HR_SINGLE);
|
|
597
|
+
lines.push("");
|
|
598
|
+
for (const item of resolved.signatures.items) {
|
|
599
|
+
const title = item.title || "Signatory";
|
|
600
|
+
const name = item.name ? replaceDocumentTokens(item.name, meta) : "";
|
|
601
|
+
const role = item.role ? replaceDocumentTokens(item.role, meta) : "";
|
|
602
|
+
const date = item.date ? replaceDocumentTokens(item.date, meta) : "";
|
|
603
|
+
lines.push(`[${title}]`);
|
|
604
|
+
lines.push("____________________________________");
|
|
605
|
+
if (name) lines.push(`Name: ${name}`);
|
|
606
|
+
if (role) lines.push(`Role: ${role}`);
|
|
607
|
+
if (date) lines.push(`Date: ${date}`);
|
|
608
|
+
lines.push("");
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (resolved.backCover && resolved.backCover.enabled) {
|
|
612
|
+
const back = resolved.backCover;
|
|
613
|
+
const backTitle = (back.title || "THANK YOU").toUpperCase();
|
|
614
|
+
const backSubtitle = back.subtitle || "";
|
|
615
|
+
const backCompany = back.company ? replaceDocumentTokens(back.company, meta) : "";
|
|
616
|
+
const backAddress = back.address ? replaceDocumentTokens(back.address, meta) : "";
|
|
617
|
+
const backEmail = back.email ? replaceDocumentTokens(back.email, meta) : "";
|
|
618
|
+
const backPhone = back.phone ? replaceDocumentTokens(back.phone, meta) : "";
|
|
619
|
+
const backWebsite = back.website ? replaceDocumentTokens(back.website, meta) : "";
|
|
620
|
+
const backCopyright = back.copyright ? replaceDocumentTokens(back.copyright, meta) : "";
|
|
621
|
+
lines.push(HR_DOUBLE);
|
|
622
|
+
lines.push(centerText(backTitle));
|
|
623
|
+
if (backSubtitle) {
|
|
624
|
+
lines.push(centerText(backSubtitle));
|
|
625
|
+
}
|
|
626
|
+
lines.push(HR_DOUBLE);
|
|
627
|
+
if (backCompany) lines.push(`Company: ${backCompany}`);
|
|
628
|
+
if (backAddress) lines.push(`Address: ${backAddress}`);
|
|
629
|
+
if (backEmail) lines.push(`Email: ${backEmail}`);
|
|
630
|
+
if (backPhone) lines.push(`Phone: ${backPhone}`);
|
|
631
|
+
if (backWebsite) lines.push(`Website: ${backWebsite}`);
|
|
632
|
+
if (back.social && back.social.github) {
|
|
633
|
+
lines.push(`GitHub: ${back.social.github}`);
|
|
634
|
+
}
|
|
635
|
+
if (backCopyright) {
|
|
636
|
+
lines.push("");
|
|
637
|
+
lines.push(backCopyright);
|
|
638
|
+
}
|
|
639
|
+
lines.push(HR_DOUBLE);
|
|
640
|
+
lines.push("");
|
|
641
|
+
}
|
|
642
|
+
return lines.join("\n").trim() + "\n";
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// src/core/png/pngBuilder.ts
|
|
646
|
+
import * as fs from "fs";
|
|
647
|
+
import * as path3 from "path";
|
|
648
|
+
import * as os from "os";
|
|
649
|
+
import { pathToFileURL } from "url";
|
|
650
|
+
import { spawnSync } from "child_process";
|
|
651
|
+
async function buildPngDocument(doc, config, baseDir) {
|
|
652
|
+
const htmlContent = await buildHtmlDocument(doc, config, baseDir);
|
|
653
|
+
const chromePath = findChromeExecutable();
|
|
654
|
+
if (!chromePath) {
|
|
655
|
+
throw new Error(
|
|
656
|
+
"Headless Chrome / Chromium / Edge executable not found for PNG document export. Please install Google Chrome, Chromium, or Microsoft Edge, or set CHROME_PATH environment variable."
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
const tmpHtml = path3.join(
|
|
660
|
+
os.tmpdir(),
|
|
661
|
+
`markforge-png-${Date.now()}-${Math.random().toString(36).slice(2)}.html`
|
|
662
|
+
);
|
|
663
|
+
const tmpPng = path3.join(
|
|
664
|
+
os.tmpdir(),
|
|
665
|
+
`markforge-png-${Date.now()}-${Math.random().toString(36).slice(2)}.png`
|
|
666
|
+
);
|
|
667
|
+
try {
|
|
668
|
+
fs.writeFileSync(tmpHtml, htmlContent, "utf-8");
|
|
669
|
+
const fileUrl = pathToFileURL(tmpHtml).href;
|
|
670
|
+
const spawnResult = spawnSync(
|
|
671
|
+
chromePath,
|
|
672
|
+
[
|
|
673
|
+
"--headless=new",
|
|
674
|
+
"--disable-gpu",
|
|
675
|
+
"--no-sandbox",
|
|
676
|
+
"--disable-setuid-sandbox",
|
|
677
|
+
"--hide-scrollbars",
|
|
678
|
+
"--force-device-scale-factor=2",
|
|
679
|
+
"--window-size=1200,1600",
|
|
680
|
+
`--screenshot=${tmpPng}`,
|
|
681
|
+
fileUrl
|
|
682
|
+
],
|
|
683
|
+
{ timeout: 3e4, windowsHide: true }
|
|
684
|
+
);
|
|
685
|
+
if (spawnResult.error) {
|
|
686
|
+
throw new Error(`Failed to execute Chromium for PNG export: ${spawnResult.error.message}`);
|
|
687
|
+
}
|
|
688
|
+
if (!fs.existsSync(tmpPng) || fs.statSync(tmpPng).size === 0) {
|
|
689
|
+
throw new Error("Chromium PNG export failed to generate output screenshot file.");
|
|
690
|
+
}
|
|
691
|
+
return fs.readFileSync(tmpPng);
|
|
692
|
+
} finally {
|
|
693
|
+
try {
|
|
694
|
+
if (fs.existsSync(tmpHtml)) fs.unlinkSync(tmpHtml);
|
|
695
|
+
if (fs.existsSync(tmpPng)) fs.unlinkSync(tmpPng);
|
|
696
|
+
} catch {
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// src/core/engine.ts
|
|
702
|
+
async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgress) {
|
|
703
|
+
const startTime = Date.now();
|
|
704
|
+
const config = { ...DEFAULT_CONFIG, ...userConfig };
|
|
705
|
+
let rawMarkdown = "";
|
|
706
|
+
let baseDir = process.cwd();
|
|
707
|
+
let inputFileName = "document.md";
|
|
708
|
+
let isFilePath = false;
|
|
709
|
+
if (fs2.existsSync(inputFilePathOrContent)) {
|
|
710
|
+
isFilePath = true;
|
|
711
|
+
rawMarkdown = fs2.readFileSync(inputFilePathOrContent, "utf-8");
|
|
712
|
+
baseDir = path4.dirname(path4.resolve(inputFilePathOrContent));
|
|
713
|
+
inputFileName = path4.basename(inputFilePathOrContent);
|
|
714
|
+
} else {
|
|
715
|
+
rawMarkdown = inputFilePathOrContent;
|
|
716
|
+
}
|
|
717
|
+
onProgress == null ? void 0 : onProgress(`Parsing markdown AST: ${inputFileName}...`);
|
|
718
|
+
const parsedDoc = parseMarkdownDocument(rawMarkdown);
|
|
719
|
+
const baseName = inputFileName.replace(/\.(md|mdx|markdown)$/i, "");
|
|
720
|
+
const outputDir = config.outputDir ? path4.isAbsolute(config.outputDir) ? config.outputDir : path4.resolve(process.cwd(), config.outputDir) : baseDir;
|
|
721
|
+
if (!fs2.existsSync(outputDir)) {
|
|
722
|
+
fs2.mkdirSync(outputDir, { recursive: true });
|
|
723
|
+
}
|
|
724
|
+
const formats = Array.isArray(config.to) ? config.to : [config.to || "docx", "pdf"];
|
|
725
|
+
const generatedFiles = [];
|
|
726
|
+
const errors = [];
|
|
727
|
+
for (const fmt of formats) {
|
|
728
|
+
try {
|
|
729
|
+
if (fmt === "docx") {
|
|
730
|
+
onProgress == null ? void 0 : onProgress(`Generating DOCX document: ${baseName}.docx...`);
|
|
731
|
+
const docxBuffer = await buildDocxDocument(parsedDoc, config, baseDir);
|
|
732
|
+
const docxPath = path4.join(outputDir, `${baseName}.docx`);
|
|
733
|
+
fs2.writeFileSync(docxPath, docxBuffer);
|
|
734
|
+
generatedFiles.push({
|
|
735
|
+
format: "docx",
|
|
736
|
+
filePath: docxPath,
|
|
737
|
+
fileName: `${baseName}.docx`,
|
|
738
|
+
sizeBytes: docxBuffer.length
|
|
739
|
+
});
|
|
740
|
+
} else if (fmt === "html") {
|
|
741
|
+
onProgress == null ? void 0 : onProgress(`Generating HTML document: ${baseName}.html...`);
|
|
742
|
+
const htmlString = await buildHtmlDocument(parsedDoc, config, baseDir);
|
|
743
|
+
const htmlPath = path4.join(outputDir, `${baseName}.html`);
|
|
744
|
+
fs2.writeFileSync(htmlPath, htmlString, "utf-8");
|
|
745
|
+
generatedFiles.push({
|
|
746
|
+
format: "html",
|
|
747
|
+
filePath: htmlPath,
|
|
748
|
+
fileName: `${baseName}.html`,
|
|
749
|
+
sizeBytes: Buffer.byteLength(htmlString, "utf-8")
|
|
750
|
+
});
|
|
751
|
+
} else if (fmt === "pdf") {
|
|
752
|
+
onProgress == null ? void 0 : onProgress(`Generating PDF document: ${baseName}.pdf...`);
|
|
753
|
+
const pdfBuffer = await buildPdfDocument(parsedDoc, config, baseDir);
|
|
754
|
+
const pdfPath = path4.join(outputDir, `${baseName}.pdf`);
|
|
755
|
+
fs2.writeFileSync(pdfPath, pdfBuffer);
|
|
756
|
+
generatedFiles.push({
|
|
757
|
+
format: "pdf",
|
|
758
|
+
filePath: pdfPath,
|
|
759
|
+
fileName: `${baseName}.pdf`,
|
|
760
|
+
sizeBytes: pdfBuffer.length
|
|
761
|
+
});
|
|
762
|
+
} else if (fmt === "txt") {
|
|
763
|
+
onProgress == null ? void 0 : onProgress(`Generating Plain Text document: ${baseName}.txt...`);
|
|
764
|
+
const textContent = await buildTextDocument(parsedDoc, config, baseDir);
|
|
765
|
+
const textPath = path4.join(outputDir, `${baseName}.txt`);
|
|
766
|
+
fs2.writeFileSync(textPath, textContent, "utf-8");
|
|
767
|
+
generatedFiles.push({
|
|
768
|
+
format: "txt",
|
|
769
|
+
filePath: textPath,
|
|
770
|
+
fileName: `${baseName}.txt`,
|
|
771
|
+
sizeBytes: Buffer.byteLength(textContent, "utf-8")
|
|
772
|
+
});
|
|
773
|
+
} else if (fmt === "png") {
|
|
774
|
+
onProgress == null ? void 0 : onProgress(`Generating PNG document: ${baseName}.png...`);
|
|
775
|
+
const pngBuffer = await buildPngDocument(parsedDoc, config, baseDir);
|
|
776
|
+
const pngPath = path4.join(outputDir, `${baseName}.png`);
|
|
777
|
+
fs2.writeFileSync(pngPath, pngBuffer);
|
|
778
|
+
generatedFiles.push({
|
|
779
|
+
format: "png",
|
|
780
|
+
filePath: pngPath,
|
|
781
|
+
fileName: `${baseName}.png`,
|
|
782
|
+
sizeBytes: pngBuffer.length
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
} catch (err) {
|
|
786
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
787
|
+
errors.push(`Failed to generate ${fmt}: ${errMsg}`);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
const durationMs = Date.now() - startTime;
|
|
791
|
+
return {
|
|
792
|
+
inputFile: isFilePath ? inputFilePathOrContent : "inline-string",
|
|
793
|
+
durationMs,
|
|
794
|
+
metadata: parsedDoc.metadata,
|
|
795
|
+
files: generatedFiles,
|
|
796
|
+
errors
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/ui/App.tsx
|
|
801
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
802
|
+
var App = ({ inputFile, config, configPath, onComplete }) => {
|
|
803
|
+
const [status, setStatus] = useState("Initializing...");
|
|
804
|
+
const [isCompiling, setIsCompiling] = useState(true);
|
|
805
|
+
const [result, setResult] = useState(null);
|
|
806
|
+
useEffect(() => {
|
|
807
|
+
async function run() {
|
|
808
|
+
try {
|
|
809
|
+
const res = await compileMarkdown(inputFile, config, (msg) => setStatus(msg));
|
|
810
|
+
setResult(res);
|
|
811
|
+
setIsCompiling(false);
|
|
812
|
+
onComplete == null ? void 0 : onComplete(res);
|
|
813
|
+
} catch (err) {
|
|
814
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
815
|
+
const errResult = {
|
|
816
|
+
inputFile,
|
|
817
|
+
durationMs: 0,
|
|
818
|
+
metadata: {},
|
|
819
|
+
files: [],
|
|
820
|
+
errors: [errMsg]
|
|
821
|
+
};
|
|
822
|
+
setResult(errResult);
|
|
823
|
+
setIsCompiling(false);
|
|
824
|
+
onComplete == null ? void 0 : onComplete(errResult);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
run();
|
|
828
|
+
}, [inputFile, config, onComplete]);
|
|
829
|
+
const targetFormats = Array.isArray(config.to) ? config.to : config.to ? [String(config.to)] : ["docx", "pdf"];
|
|
830
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
831
|
+
/* @__PURE__ */ jsx4(
|
|
832
|
+
Header,
|
|
833
|
+
{
|
|
834
|
+
inputFile,
|
|
835
|
+
configPath,
|
|
836
|
+
config,
|
|
837
|
+
theme: config.theme,
|
|
838
|
+
targetFormats
|
|
839
|
+
}
|
|
840
|
+
),
|
|
841
|
+
/* @__PURE__ */ jsx4(LiveProgress, { status, isCompiling }),
|
|
842
|
+
/* @__PURE__ */ jsx4(SummaryTable, { result })
|
|
843
|
+
] });
|
|
844
|
+
};
|
|
845
|
+
export {
|
|
846
|
+
App
|
|
847
|
+
};
|