@masumdev/markforge 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,393 @@
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
+ buildDocxDocument,
15
+ buildHtmlDocument,
16
+ buildPdfDocument,
17
+ parseMarkdownDocument
18
+ } from "./chunk-R6DT335C.mjs";
19
+ import {
20
+ DEFAULT_CONFIG
21
+ } from "./chunk-BPHDY6VB.mjs";
22
+ import "./chunk-YZHGBG4N.mjs";
23
+
24
+ // src/ui/App.tsx
25
+ import { useState, useEffect } from "react";
26
+ import { Box as Box4 } from "ink";
27
+
28
+ // src/ui/Header.tsx
29
+ import * as path from "path";
30
+ import { Box, Text } from "ink";
31
+ import { jsx, jsxs } from "react/jsx-runtime";
32
+ function formatDisplayPath(p) {
33
+ if (!p) return "";
34
+ try {
35
+ const rel = path.relative(process.cwd(), p);
36
+ return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p;
37
+ } catch {
38
+ return p;
39
+ }
40
+ }
41
+ var Header = ({
42
+ inputFile,
43
+ configPath,
44
+ config,
45
+ theme = "corporate",
46
+ targetFormats = ["docx", "pdf"]
47
+ }) => {
48
+ const resolvedTheme = (config == null ? void 0 : config.theme) || theme;
49
+ const themeLabel = typeof resolvedTheme === "object" ? "Custom (ThemeProps)" : String(resolvedTheme || "corporate");
50
+ const activeFeatures = [];
51
+ if (config == null ? void 0 : config.toc) activeFeatures.push("TOC");
52
+ if (config == null ? void 0 : config.numberHeadings) {
53
+ if (typeof config.numberHeadings === "object") {
54
+ const isNumEnabled = config.numberHeadings.enabled ?? true;
55
+ if (isNumEnabled) {
56
+ activeFeatures.push(`Numbering (depth ${config.numberHeadings.depth ?? 3})`);
57
+ }
58
+ } else if (config.numberHeadings === true) {
59
+ activeFeatures.push("Numbering (depth 3)");
60
+ }
61
+ }
62
+ if (config == null ? void 0 : config.coverPage) {
63
+ if (typeof config.coverPage === "object" && config.coverPage.enabled !== false) {
64
+ activeFeatures.push(`Cover (${config.coverPage.preset || "corporate"})`);
65
+ } else if (config.coverPage === true) {
66
+ activeFeatures.push("Cover (corporate)");
67
+ }
68
+ }
69
+ if (config == null ? void 0 : config.backCover) {
70
+ if (typeof config.backCover === "object" && config.backCover.enabled !== false) {
71
+ activeFeatures.push(`BackCover (${config.backCover.preset || "corporate"})`);
72
+ } else if (config.backCover === true) {
73
+ activeFeatures.push("BackCover (corporate)");
74
+ }
75
+ }
76
+ if (config == null ? void 0 : config.watermark) {
77
+ const wmText = typeof config.watermark === "object" ? config.watermark.text : config.watermark;
78
+ if (wmText) {
79
+ activeFeatures.push(`Watermark ("${wmText}")`);
80
+ }
81
+ }
82
+ if ((config == null ? void 0 : config.security) && (config.security.userPassword || config.security.ownerPassword)) {
83
+ activeFeatures.push("AES-256 Security");
84
+ }
85
+ if ((config == null ? void 0 : config.math) !== false) activeFeatures.push("KaTeX Math");
86
+ if (config == null ? void 0 : config.syntaxTheme) activeFeatures.push(`Syntax (${config.syntaxTheme})`);
87
+ const paperLabel = `${(config == null ? void 0 : config.paperSize) || "A4"} (${(config == null ? void 0 : config.orientation) || "portrait"})`;
88
+ const outputLabel = (config == null ? void 0 : config.outputDir) ? formatDisplayPath(config.outputDir) : "./ (default)";
89
+ const configLabel = configPath ? formatDisplayPath(configPath) : "(default auto-discovery)";
90
+ return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs(
91
+ Box,
92
+ {
93
+ borderStyle: "round",
94
+ borderColor: "cyan",
95
+ paddingX: 2,
96
+ paddingY: 1,
97
+ flexDirection: "column",
98
+ children: [
99
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", alignItems: "center", children: [
100
+ /* @__PURE__ */ jsxs(Box, { children: [
101
+ /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "MARKFORGE" }),
102
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: " | Document Publishing Engine" })
103
+ ] }),
104
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: "black", backgroundColor: "cyan", bold: true, children: [
105
+ " ",
106
+ "v",
107
+ MARKFORGE_VERSION,
108
+ " "
109
+ ] }) })
110
+ ] }),
111
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
112
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
113
+ /* @__PURE__ */ jsxs(Box, { children: [
114
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Source: " }),
115
+ /* @__PURE__ */ jsx(Text, { color: "white", bold: true, children: formatDisplayPath(inputFile) })
116
+ ] }),
117
+ /* @__PURE__ */ jsxs(Box, { children: [
118
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Config: " }),
119
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: configLabel })
120
+ ] })
121
+ ] }),
122
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginTop: 0, children: [
123
+ /* @__PURE__ */ jsxs(Box, { children: [
124
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Theme: " }),
125
+ /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: themeLabel })
126
+ ] }),
127
+ targetFormats && targetFormats.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
128
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Targets: " }),
129
+ /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: targetFormats.map((f) => f.toUpperCase()).join(", ") })
130
+ ] })
131
+ ] }),
132
+ /* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginTop: 0, children: [
133
+ /* @__PURE__ */ jsxs(Box, { children: [
134
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Layout: " }),
135
+ /* @__PURE__ */ jsx(Text, { color: "green", children: paperLabel })
136
+ ] }),
137
+ /* @__PURE__ */ jsxs(Box, { children: [
138
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Output: " }),
139
+ /* @__PURE__ */ jsx(Text, { color: "white", children: outputLabel })
140
+ ] })
141
+ ] }),
142
+ activeFeatures.length > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 0, children: [
143
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Modules: " }),
144
+ /* @__PURE__ */ jsx(Text, { color: "blue", children: activeFeatures.join(" | ") })
145
+ ] })
146
+ ] }),
147
+ /* @__PURE__ */ jsxs(Box, { marginTop: 1, justifyContent: "space-between", children: [
148
+ /* @__PURE__ */ jsxs(Box, { children: [
149
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Author: " }),
150
+ /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "Ma'sum" }),
151
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: " (@masumrpg)" })
152
+ ] }),
153
+ /* @__PURE__ */ jsxs(Box, { children: [
154
+ /* @__PURE__ */ jsx(Text, { color: "gray", children: "GitHub: " }),
155
+ /* @__PURE__ */ jsx(Text, { color: "blue", underline: true, children: "https://github.com/masumrpg" })
156
+ ] })
157
+ ] })
158
+ ]
159
+ }
160
+ ) });
161
+ };
162
+
163
+ // src/ui/LiveProgress.tsx
164
+ import { Box as Box2, Text as Text2 } from "ink";
165
+ import Spinner from "ink-spinner";
166
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
167
+ var LiveProgress = ({ status, isCompiling }) => {
168
+ if (!isCompiling) return null;
169
+ return /* @__PURE__ */ jsxs2(Box2, { marginY: 1, alignItems: "center", children: [
170
+ /* @__PURE__ */ jsx2(Text2, { color: "cyan", children: /* @__PURE__ */ jsx2(Spinner, { type: "dots" }) }),
171
+ /* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, children: [
172
+ /* @__PURE__ */ jsx2(Text2, { color: "yellow", children: "[COMPILING] " }),
173
+ /* @__PURE__ */ jsx2(Text2, { color: "white", children: status })
174
+ ] })
175
+ ] });
176
+ };
177
+
178
+ // src/ui/SummaryTable.tsx
179
+ import * as path2 from "path";
180
+ import { Box as Box3, Text as Text3 } from "ink";
181
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
182
+ function formatBytes(bytes) {
183
+ if (bytes === 0) return "0 B";
184
+ const k = 1024;
185
+ const sizes = ["B", "KB", "MB", "GB"];
186
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
187
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
188
+ }
189
+ function formatDisplayPath2(p) {
190
+ if (!p) return "";
191
+ try {
192
+ const rel = path2.relative(process.cwd(), p);
193
+ return rel && !rel.startsWith("..") && rel.length < p.length ? `./${rel}` : p;
194
+ } catch {
195
+ return p;
196
+ }
197
+ }
198
+ var SummaryTable = ({ result }) => {
199
+ if (!result) return null;
200
+ const hasErrors = result.errors.length > 0;
201
+ return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", marginY: 1, children: /* @__PURE__ */ jsxs3(
202
+ Box3,
203
+ {
204
+ borderStyle: "round",
205
+ borderColor: hasErrors ? "red" : "green",
206
+ paddingX: 2,
207
+ paddingY: 1,
208
+ flexDirection: "column",
209
+ children: [
210
+ /* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", alignItems: "center", children: [
211
+ /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text3, { bold: true, color: hasErrors ? "red" : "green", children: hasErrors ? "[COMPILATION FAILED]" : "[COMPILATION SUCCESSFUL]" }) }),
212
+ /* @__PURE__ */ jsxs3(Box3, { children: [
213
+ /* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Duration: " }),
214
+ /* @__PURE__ */ jsxs3(Text3, { color: "yellow", bold: true, children: [
215
+ result.durationMs,
216
+ "ms"
217
+ ] })
218
+ ] })
219
+ ] }),
220
+ result.files.length > 0 && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
221
+ /* @__PURE__ */ jsxs3(Text3, { bold: true, color: "white", children: [
222
+ "Generated Documents (",
223
+ result.files.length,
224
+ "):"
225
+ ] }),
226
+ result.files.map((f, i) => {
227
+ const formatColor = f.format === "docx" ? "blue" : f.format === "pdf" ? "red" : "yellow";
228
+ const paddedBadge = `[${f.format.toUpperCase()}]`.padEnd(7, " ");
229
+ return /* @__PURE__ */ jsxs3(Box3, { marginTop: 0, flexDirection: "column", marginLeft: 1, children: [
230
+ /* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", alignItems: "center", children: [
231
+ /* @__PURE__ */ jsxs3(Box3, { children: [
232
+ /* @__PURE__ */ jsx3(Text3, { color: formatColor, bold: true, children: paddedBadge }),
233
+ /* @__PURE__ */ jsx3(Text3, { color: "white", bold: true, children: f.fileName })
234
+ ] }),
235
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: formatBytes(f.sizeBytes) })
236
+ ] }),
237
+ /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
238
+ "\u2514\u2500 ",
239
+ formatDisplayPath2(f.filePath)
240
+ ] }) })
241
+ ] }, i);
242
+ })
243
+ ] }),
244
+ hasErrors && /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
245
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: "red", children: "Errors:" }),
246
+ result.errors.map((err, i) => /* @__PURE__ */ jsx3(Box3, { marginLeft: 2, children: /* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
247
+ "- ",
248
+ err
249
+ ] }) }, i))
250
+ ] }),
251
+ /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, justifyContent: "space-between", alignItems: "center", children: [
252
+ /* @__PURE__ */ jsxs3(Box3, { children: [
253
+ /* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Author: " }),
254
+ /* @__PURE__ */ jsx3(Text3, { color: "cyan", bold: true, children: "Ma'sum" }),
255
+ /* @__PURE__ */ jsx3(Text3, { color: "gray", children: " (@masumrpg)" })
256
+ ] }),
257
+ /* @__PURE__ */ jsxs3(Box3, { children: [
258
+ /* @__PURE__ */ jsx3(Text3, { color: "gray", children: "GitHub: " }),
259
+ /* @__PURE__ */ jsx3(Text3, { color: "blue", underline: true, children: "https://github.com/masumrpg" })
260
+ ] })
261
+ ] })
262
+ ]
263
+ }
264
+ ) });
265
+ };
266
+
267
+ // src/core/engine.ts
268
+ import * as fs from "fs";
269
+ import * as path3 from "path";
270
+ async function compileMarkdown(inputFilePathOrContent, userConfig = {}, onProgress) {
271
+ const startTime = Date.now();
272
+ const config = { ...DEFAULT_CONFIG, ...userConfig };
273
+ let rawMarkdown = "";
274
+ let baseDir = process.cwd();
275
+ let inputFileName = "document.md";
276
+ let isFilePath = false;
277
+ if (fs.existsSync(inputFilePathOrContent)) {
278
+ isFilePath = true;
279
+ rawMarkdown = fs.readFileSync(inputFilePathOrContent, "utf-8");
280
+ baseDir = path3.dirname(path3.resolve(inputFilePathOrContent));
281
+ inputFileName = path3.basename(inputFilePathOrContent);
282
+ } else {
283
+ rawMarkdown = inputFilePathOrContent;
284
+ }
285
+ onProgress == null ? void 0 : onProgress(`Parsing markdown AST: ${inputFileName}...`);
286
+ const parsedDoc = parseMarkdownDocument(rawMarkdown);
287
+ const baseName = inputFileName.replace(/\.(md|mdx|markdown)$/i, "");
288
+ const outputDir = config.outputDir ? path3.isAbsolute(config.outputDir) ? config.outputDir : path3.resolve(process.cwd(), config.outputDir) : baseDir;
289
+ if (!fs.existsSync(outputDir)) {
290
+ fs.mkdirSync(outputDir, { recursive: true });
291
+ }
292
+ const formats = Array.isArray(config.to) ? config.to : [config.to || "docx", "pdf"];
293
+ const generatedFiles = [];
294
+ const errors = [];
295
+ for (const fmt of formats) {
296
+ try {
297
+ if (fmt === "docx") {
298
+ onProgress == null ? void 0 : onProgress(`Generating DOCX document: ${baseName}.docx...`);
299
+ const docxBuffer = await buildDocxDocument(parsedDoc, config, baseDir);
300
+ const docxPath = path3.join(outputDir, `${baseName}.docx`);
301
+ fs.writeFileSync(docxPath, docxBuffer);
302
+ generatedFiles.push({
303
+ format: "docx",
304
+ filePath: docxPath,
305
+ fileName: `${baseName}.docx`,
306
+ sizeBytes: docxBuffer.length
307
+ });
308
+ } else if (fmt === "html") {
309
+ onProgress == null ? void 0 : onProgress(`Generating HTML document: ${baseName}.html...`);
310
+ const htmlString = await buildHtmlDocument(parsedDoc, config, baseDir);
311
+ const htmlPath = path3.join(outputDir, `${baseName}.html`);
312
+ fs.writeFileSync(htmlPath, htmlString, "utf-8");
313
+ generatedFiles.push({
314
+ format: "html",
315
+ filePath: htmlPath,
316
+ fileName: `${baseName}.html`,
317
+ sizeBytes: Buffer.byteLength(htmlString, "utf-8")
318
+ });
319
+ } else if (fmt === "pdf") {
320
+ onProgress == null ? void 0 : onProgress(`Generating PDF document: ${baseName}.pdf...`);
321
+ const pdfBuffer = await buildPdfDocument(parsedDoc, config, baseDir);
322
+ const pdfPath = path3.join(outputDir, `${baseName}.pdf`);
323
+ fs.writeFileSync(pdfPath, pdfBuffer);
324
+ generatedFiles.push({
325
+ format: "pdf",
326
+ filePath: pdfPath,
327
+ fileName: `${baseName}.pdf`,
328
+ sizeBytes: pdfBuffer.length
329
+ });
330
+ }
331
+ } catch (err) {
332
+ const errMsg = err instanceof Error ? err.message : String(err);
333
+ errors.push(`Failed to generate ${fmt}: ${errMsg}`);
334
+ }
335
+ }
336
+ const durationMs = Date.now() - startTime;
337
+ return {
338
+ inputFile: isFilePath ? inputFilePathOrContent : "inline-string",
339
+ durationMs,
340
+ metadata: parsedDoc.metadata,
341
+ files: generatedFiles,
342
+ errors
343
+ };
344
+ }
345
+
346
+ // src/ui/App.tsx
347
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
348
+ var App = ({ inputFile, config, configPath, onComplete }) => {
349
+ const [status, setStatus] = useState("Initializing...");
350
+ const [isCompiling, setIsCompiling] = useState(true);
351
+ const [result, setResult] = useState(null);
352
+ useEffect(() => {
353
+ async function run() {
354
+ try {
355
+ const res = await compileMarkdown(inputFile, config, (msg) => setStatus(msg));
356
+ setResult(res);
357
+ setIsCompiling(false);
358
+ onComplete == null ? void 0 : onComplete(res);
359
+ } catch (err) {
360
+ const errMsg = err instanceof Error ? err.message : String(err);
361
+ const errResult = {
362
+ inputFile,
363
+ durationMs: 0,
364
+ metadata: {},
365
+ files: [],
366
+ errors: [errMsg]
367
+ };
368
+ setResult(errResult);
369
+ setIsCompiling(false);
370
+ onComplete == null ? void 0 : onComplete(errResult);
371
+ }
372
+ }
373
+ run();
374
+ }, [inputFile, config, onComplete]);
375
+ const targetFormats = Array.isArray(config.to) ? config.to : config.to ? [String(config.to)] : ["docx", "pdf"];
376
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
377
+ /* @__PURE__ */ jsx4(
378
+ Header,
379
+ {
380
+ inputFile,
381
+ configPath,
382
+ config,
383
+ theme: config.theme,
384
+ targetFormats
385
+ }
386
+ ),
387
+ /* @__PURE__ */ jsx4(LiveProgress, { status, isCompiling }),
388
+ /* @__PURE__ */ jsx4(SummaryTable, { result })
389
+ ] });
390
+ };
391
+ export {
392
+ App
393
+ };
@@ -48,6 +48,12 @@ var DEFAULT_CONFIG = {
48
48
  },
49
49
  toc: false,
50
50
  watermark: void 0,
51
+ signatures: void 0,
52
+ coverPage: void 0,
53
+ backCover: void 0,
54
+ numberHeadings: void 0,
55
+ security: void 0,
56
+ math: true,
51
57
  embedImages: true,
52
58
  metadata: void 0,
53
59
  watch: false,