mduck 1.0.6 → 2.0.2
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/bin/mduck +49 -2
- package/package.json +17 -11
- package/bin/mduck.cmd +0 -9
- package/bin/mduck.js +0 -317
- package/src/template.html +0 -28
package/bin/mduck
CHANGED
|
@@ -1,2 +1,49 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
|
|
1
|
+
#!/bin/sh -
|
|
2
|
+
':'; /*-
|
|
3
|
+
test1=$(bun --version 2>&1) && exec bun "$0" "$@"
|
|
4
|
+
test2=$(node --version 2>&1) && exec node "$0" "$@"
|
|
5
|
+
exec printf '%s\n' "$test1" "$test2" 1>&2
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { execFileSync } from "child_process";
|
|
9
|
+
import { arch, platform } from "os";
|
|
10
|
+
import { resolve, dirname } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
12
|
+
import { existsSync } from "fs";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const plat = platform();
|
|
16
|
+
const a = arch();
|
|
17
|
+
const ext = plat === "win32" ? ".exe" : "";
|
|
18
|
+
const pkgName = `mduck-${plat}-${a}`;
|
|
19
|
+
|
|
20
|
+
const candidates = [
|
|
21
|
+
// Typical node_modules layout (npx, npm install -g, etc.)
|
|
22
|
+
resolve(__dirname, "..", "node_modules", "@simplyhexagonal", pkgName, "bin", `mduck${ext}`),
|
|
23
|
+
// pnpm / hoisted layout
|
|
24
|
+
resolve(__dirname, "..", "..", "@simplyhexagonal", pkgName, "bin", `mduck${ext}`),
|
|
25
|
+
// Global install with lib/node_modules
|
|
26
|
+
resolve(__dirname, "..", "lib", "node_modules", "@simplyhexagonal", pkgName, "bin", `mduck${ext}`),
|
|
27
|
+
// Bun global layout
|
|
28
|
+
resolve(__dirname, "..", "..", "..", "@simplyhexagonal", pkgName, "bin", `mduck${ext}`),
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const binary = candidates.find((c) => existsSync(c));
|
|
32
|
+
|
|
33
|
+
if (!binary) {
|
|
34
|
+
const supported = ["darwin-arm64", "darwin-x64", "linux-arm64", "linux-x64", "win32-x64"];
|
|
35
|
+
console.error(`\n mduck: no binary found for ${plat}-${a}\n`);
|
|
36
|
+
console.error(` Supported platforms: ${supported.join(", ")}`);
|
|
37
|
+
console.error(` Searched:`);
|
|
38
|
+
for (const c of candidates) {
|
|
39
|
+
console.error(` - ${c}`);
|
|
40
|
+
}
|
|
41
|
+
console.error(`\n Try reinstalling: npm install -g mduck\n`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
execFileSync(binary, process.argv.slice(2), { stdio: "inherit" });
|
|
47
|
+
} catch (e) {
|
|
48
|
+
process.exit(e.status ?? 1);
|
|
49
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mduck",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "A CLI tool to convert Markdown files into HTML and PDF documents using Tailwind CSS v4 for styling.",
|
|
5
5
|
"files": [
|
|
6
6
|
"bin/",
|
|
7
|
-
"src/template.html",
|
|
8
7
|
"README.md"
|
|
9
8
|
],
|
|
10
9
|
"keywords": [
|
|
@@ -19,26 +18,33 @@
|
|
|
19
18
|
],
|
|
20
19
|
"author": "Jean M. Lescure",
|
|
21
20
|
"license": "Apache-2.0",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/simplyhexagonal/mduck.git"
|
|
24
|
+
},
|
|
22
25
|
"bin": {
|
|
23
26
|
"mduck": "./bin/mduck"
|
|
24
27
|
},
|
|
25
28
|
"scripts": {
|
|
26
|
-
"build": "
|
|
29
|
+
"build": "bun run build.ts",
|
|
30
|
+
"publish-all": "bun run publish.ts",
|
|
31
|
+
"publish-all:dry": "bun run publish.ts --dry-run",
|
|
32
|
+
"prepack": "bun run build",
|
|
27
33
|
"dev": "bun --watch run ./src/index.ts convert test/input/test.md test/output/"
|
|
28
34
|
},
|
|
29
35
|
"type": "module",
|
|
30
|
-
"
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
36
|
+
"optionalDependencies": {
|
|
37
|
+
"@simplyhexagonal/mduck-darwin-arm64": "2.0.0",
|
|
38
|
+
"@simplyhexagonal/mduck-darwin-x64": "2.0.0",
|
|
39
|
+
"@simplyhexagonal/mduck-linux-arm64": "2.0.0",
|
|
40
|
+
"@simplyhexagonal/mduck-linux-x64": "2.0.0",
|
|
41
|
+
"@simplyhexagonal/mduck-win32-x64": "2.0.0"
|
|
33
42
|
},
|
|
34
|
-
"
|
|
35
|
-
"typescript": "^5"
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
43
|
+
"devDependencies": {
|
|
38
44
|
"@tailwindcss/typography": "^0.5.19",
|
|
39
45
|
"citty": "^0.2.1",
|
|
40
46
|
"marked": "^17.0.4",
|
|
41
|
-
"puppeteer": "^24.38.0",
|
|
47
|
+
"puppeteer-core": "^24.38.0",
|
|
42
48
|
"tailwindcss": "^4.2.1"
|
|
43
49
|
}
|
|
44
50
|
}
|
package/bin/mduck.cmd
DELETED
package/bin/mduck.js
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { mkdir, readFile, stat, writeFile } from "fs/promises";
|
|
3
|
-
import { basename, dirname, extname, isAbsolute, join, resolve, sep } from "path";
|
|
4
|
-
import { createRequire } from "module";
|
|
5
|
-
import { pathToFileURL } from "url";
|
|
6
|
-
import { defineCommand, runMain } from "citty";
|
|
7
|
-
import { marked } from "marked";
|
|
8
|
-
import puppeteer from "puppeteer";
|
|
9
|
-
import { compile } from "tailwindcss";
|
|
10
|
-
|
|
11
|
-
// src/template.html
|
|
12
|
-
var template_default = '<!DOCTYPE html>\n<html lang="en">\n<head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n <title>Document</title>\n</head>\n<body>\n <article class="prose lg:prose-xl print:prose-sm mx-auto my-8 print:m-0 px-4">\n [BODY]\n </article>\n <style>\n @media print {\n @page {\n margin: 2cm !important; /* Sets a 2cm margin on all sides of every printed page */\n }\n }\n table {\n border: 1px solid black;\n border-collapse: collapse;\n }\n th, td {\n border: 1px solid black;\n padding: 0.5em;\n }\n </style>\n</body>\n</html>\n';
|
|
13
|
-
|
|
14
|
-
// package.json
|
|
15
|
-
var package_default = {
|
|
16
|
-
name: "mduck",
|
|
17
|
-
version: "1.0.5",
|
|
18
|
-
description: "A CLI tool to convert Markdown files into HTML and PDF documents using Tailwind CSS v4 for styling.",
|
|
19
|
-
files: [
|
|
20
|
-
"bin/",
|
|
21
|
-
"src/template.html",
|
|
22
|
-
"README.md"
|
|
23
|
-
],
|
|
24
|
-
keywords: [
|
|
25
|
-
"markdown",
|
|
26
|
-
"md",
|
|
27
|
-
"html",
|
|
28
|
-
"pdf",
|
|
29
|
-
"converter",
|
|
30
|
-
"cli",
|
|
31
|
-
"tailwind",
|
|
32
|
-
"puppeteer"
|
|
33
|
-
],
|
|
34
|
-
author: "Jean M. Lescure",
|
|
35
|
-
license: "Apache-2.0",
|
|
36
|
-
bin: {
|
|
37
|
-
mduck: "./bin/mduck.js"
|
|
38
|
-
},
|
|
39
|
-
scripts: {
|
|
40
|
-
build: "tsup --config tsup.config.ts",
|
|
41
|
-
dev: "bun --watch run ./src/index.ts convert test/input/test.md test/output/"
|
|
42
|
-
},
|
|
43
|
-
type: "module",
|
|
44
|
-
devDependencies: {
|
|
45
|
-
"@types/bun": "latest",
|
|
46
|
-
tsup: "^8.5.1"
|
|
47
|
-
},
|
|
48
|
-
peerDependencies: {
|
|
49
|
-
typescript: "^5"
|
|
50
|
-
},
|
|
51
|
-
dependencies: {
|
|
52
|
-
"@tailwindcss/typography": "^0.5.19",
|
|
53
|
-
citty: "^0.2.1",
|
|
54
|
-
marked: "^17.0.4",
|
|
55
|
-
puppeteer: "^24.38.0",
|
|
56
|
-
tailwindcss: "^4.2.1"
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// src/index.ts
|
|
61
|
-
var BODY_PLACEHOLDER = "[BODY]";
|
|
62
|
-
var DEFAULT_TEMPLATE_HTML = template_default;
|
|
63
|
-
var DEFAULT_EJECTED_TEMPLATE_FILENAME = "mduck.template.html";
|
|
64
|
-
var RUNTIME_ENTRY_DIR = dirname(resolve(process.argv[1] ?? process.cwd()));
|
|
65
|
-
var require2 = createRequire(resolve(RUNTIME_ENTRY_DIR, "__mduck_require__.cjs"));
|
|
66
|
-
var TAILWIND_INPUT_CSS = `@import "tailwindcss";
|
|
67
|
-
@plugin "@tailwindcss/typography";`;
|
|
68
|
-
var pageBreak = {
|
|
69
|
-
name: "pageBreak",
|
|
70
|
-
level: "inline",
|
|
71
|
-
start: (src) => src.indexOf("[PAGE-BREAK]"),
|
|
72
|
-
tokenizer: (src) => {
|
|
73
|
-
if (src.startsWith("[PAGE-BREAK]")) {
|
|
74
|
-
return { type: "pageBreak", raw: "[PAGE-BREAK]" };
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
renderer: () => '<div class="break-after-page"></div>'
|
|
78
|
-
};
|
|
79
|
-
var toAbsolutePath = (filePath) => {
|
|
80
|
-
return isAbsolute(filePath) ? filePath : resolve(process.cwd(), filePath);
|
|
81
|
-
};
|
|
82
|
-
var inferOutputPath = (inputPath) => {
|
|
83
|
-
const inputExt = extname(inputPath).toLowerCase();
|
|
84
|
-
if (inputExt === ".md") {
|
|
85
|
-
return inputPath.slice(0, -3) + ".html";
|
|
86
|
-
}
|
|
87
|
-
return `${inputPath}.html`;
|
|
88
|
-
};
|
|
89
|
-
var inferHtmlBasename = (inputPath) => {
|
|
90
|
-
return basename(inferOutputPath(inputPath));
|
|
91
|
-
};
|
|
92
|
-
var inferPdfPath = (htmlOutputPath) => {
|
|
93
|
-
const outputExt = extname(htmlOutputPath).toLowerCase();
|
|
94
|
-
if (!outputExt) {
|
|
95
|
-
return `${htmlOutputPath}.pdf`;
|
|
96
|
-
}
|
|
97
|
-
return `${htmlOutputPath.slice(0, -outputExt.length)}.pdf`;
|
|
98
|
-
};
|
|
99
|
-
var renderDocument = (template, markdownHtml) => {
|
|
100
|
-
const body = markdownHtml;
|
|
101
|
-
if (template.includes(BODY_PLACEHOLDER)) {
|
|
102
|
-
return template.replace(BODY_PLACEHOLDER, body);
|
|
103
|
-
}
|
|
104
|
-
const bodyCloseTag = "</body>";
|
|
105
|
-
if (template.includes(bodyCloseTag)) {
|
|
106
|
-
return template.replace(bodyCloseTag, `${body}
|
|
107
|
-
${bodyCloseTag}`);
|
|
108
|
-
}
|
|
109
|
-
return `${template}
|
|
110
|
-
${body}`;
|
|
111
|
-
};
|
|
112
|
-
var collectTailwindCandidates = (html) => {
|
|
113
|
-
const candidates = /* @__PURE__ */ new Set(["prose", "lg:prose-xl", "mx-auto", "my-8", "px-4"]);
|
|
114
|
-
const classRegex = /class\s*=\s*"([^"]+)"/g;
|
|
115
|
-
for (const match of html.matchAll(classRegex)) {
|
|
116
|
-
const classValue = match[1];
|
|
117
|
-
for (const className of classValue?.split(/\s+/) ?? []) {
|
|
118
|
-
const trimmed = className.trim();
|
|
119
|
-
if (trimmed) {
|
|
120
|
-
candidates.add(trimmed);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return Array.from(candidates);
|
|
125
|
-
};
|
|
126
|
-
var resolveCssImportPath = (id, base) => {
|
|
127
|
-
if (id === "tailwindcss") {
|
|
128
|
-
return require2.resolve("tailwindcss/index.css", { paths: [base, process.cwd()] });
|
|
129
|
-
}
|
|
130
|
-
if (id.startsWith("tailwindcss/")) {
|
|
131
|
-
const resolvedId = id.endsWith(".css") ? id : `${id}.css`;
|
|
132
|
-
return require2.resolve(resolvedId, { paths: [base, process.cwd()] });
|
|
133
|
-
}
|
|
134
|
-
try {
|
|
135
|
-
return require2.resolve(id, { paths: [base] });
|
|
136
|
-
} catch {
|
|
137
|
-
return require2.resolve(id, { paths: [process.cwd()] });
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
var compileTailwindCss = async (html) => {
|
|
141
|
-
const compiler = await compile(TAILWIND_INPUT_CSS, {
|
|
142
|
-
base: process.cwd(),
|
|
143
|
-
from: "mduck.inline.css",
|
|
144
|
-
loadModule: async (id, base) => {
|
|
145
|
-
const resolvedPath = resolveCssImportPath(id, base);
|
|
146
|
-
const imported = await import(pathToFileURL(resolvedPath).href);
|
|
147
|
-
const module = imported.default ?? imported;
|
|
148
|
-
return { path: resolvedPath, base: dirname(resolvedPath), module };
|
|
149
|
-
},
|
|
150
|
-
loadStylesheet: async (id, base) => {
|
|
151
|
-
const resolvedPath = resolveCssImportPath(id, base);
|
|
152
|
-
const content = await readFile(resolvedPath, "utf8");
|
|
153
|
-
return { path: resolvedPath, base: dirname(resolvedPath), content };
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
return compiler.build(collectTailwindCandidates(html));
|
|
157
|
-
};
|
|
158
|
-
var inlineCssInHead = (html, css) => {
|
|
159
|
-
const styleTag = `<style>${css}</style>`;
|
|
160
|
-
const headCloseTag = "</head>";
|
|
161
|
-
if (html.includes(headCloseTag)) {
|
|
162
|
-
return html.replace(headCloseTag, ` ${styleTag}
|
|
163
|
-
${headCloseTag}`);
|
|
164
|
-
}
|
|
165
|
-
return `${styleTag}
|
|
166
|
-
${html}`;
|
|
167
|
-
};
|
|
168
|
-
var renderPdf = async (html, outputPath) => {
|
|
169
|
-
const browser = await puppeteer.launch();
|
|
170
|
-
try {
|
|
171
|
-
const page = await browser.newPage();
|
|
172
|
-
await page.setContent(html, { waitUntil: "networkidle0" });
|
|
173
|
-
await page.pdf({
|
|
174
|
-
path: outputPath,
|
|
175
|
-
format: "Letter",
|
|
176
|
-
printBackground: true,
|
|
177
|
-
preferCSSPageSize: true
|
|
178
|
-
});
|
|
179
|
-
} finally {
|
|
180
|
-
await browser.close();
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
var resolveEjectedTemplatePath = async (outputArg) => {
|
|
184
|
-
if (!outputArg) {
|
|
185
|
-
return resolve(process.cwd(), DEFAULT_EJECTED_TEMPLATE_FILENAME);
|
|
186
|
-
}
|
|
187
|
-
const resolvedTargetPath = toAbsolutePath(outputArg);
|
|
188
|
-
const targetStats = await stat(resolvedTargetPath).catch(() => null);
|
|
189
|
-
const looksLikeDirectory = outputArg.endsWith(sep) || outputArg.endsWith("/");
|
|
190
|
-
const isDirectoryTarget = Boolean(targetStats?.isDirectory() || looksLikeDirectory);
|
|
191
|
-
if (isDirectoryTarget) {
|
|
192
|
-
return join(resolvedTargetPath, DEFAULT_EJECTED_TEMPLATE_FILENAME);
|
|
193
|
-
}
|
|
194
|
-
return resolvedTargetPath;
|
|
195
|
-
};
|
|
196
|
-
var runEjectTemplate = async (outputArg) => {
|
|
197
|
-
const templateOutputPath = await resolveEjectedTemplatePath(outputArg);
|
|
198
|
-
await mkdir(dirname(templateOutputPath), { recursive: true });
|
|
199
|
-
await writeFile(templateOutputPath, DEFAULT_TEMPLATE_HTML, "utf8");
|
|
200
|
-
console.log(`Wrote template to: ${templateOutputPath}`);
|
|
201
|
-
};
|
|
202
|
-
var runVersion = async () => {
|
|
203
|
-
const version = typeof package_default.version === "string" ? package_default.version : "unknown";
|
|
204
|
-
console.log(version);
|
|
205
|
-
};
|
|
206
|
-
var runConvert = async (inputArg, outputArg, templateArg) => {
|
|
207
|
-
marked.use({ extensions: [pageBreak] });
|
|
208
|
-
const inputPath = toAbsolutePath(inputArg);
|
|
209
|
-
let outputPath = toAbsolutePath(outputArg ?? inferOutputPath(inputPath));
|
|
210
|
-
let activeTemplateHtml = DEFAULT_TEMPLATE_HTML;
|
|
211
|
-
const inputStats = await stat(inputPath).catch(() => null);
|
|
212
|
-
if (!inputStats) {
|
|
213
|
-
throw new Error(`Input file does not exist: ${inputPath}`);
|
|
214
|
-
}
|
|
215
|
-
if (!inputStats.isFile()) {
|
|
216
|
-
throw new Error(`Input path is not a file: ${inputPath}`);
|
|
217
|
-
}
|
|
218
|
-
if (outputArg) {
|
|
219
|
-
const outputStats = await stat(outputPath).catch(() => null);
|
|
220
|
-
if (outputStats?.isDirectory()) {
|
|
221
|
-
outputPath = join(outputPath, inferHtmlBasename(inputPath));
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
if (templateArg) {
|
|
225
|
-
const templatePath = toAbsolutePath(templateArg);
|
|
226
|
-
const templateStats = await stat(templatePath).catch(() => null);
|
|
227
|
-
if (!templateStats) {
|
|
228
|
-
throw new Error(`Template file does not exist: ${templatePath}`);
|
|
229
|
-
}
|
|
230
|
-
if (!templateStats.isFile()) {
|
|
231
|
-
throw new Error(`Template path is not a file: ${templatePath}`);
|
|
232
|
-
}
|
|
233
|
-
activeTemplateHtml = await readFile(templatePath, "utf8");
|
|
234
|
-
}
|
|
235
|
-
const markdown = await readFile(inputPath, "utf8");
|
|
236
|
-
const markdownHtml = await marked.parse(markdown);
|
|
237
|
-
const documentHtml = renderDocument(activeTemplateHtml, markdownHtml);
|
|
238
|
-
const tailwindCss = await compileTailwindCss(documentHtml);
|
|
239
|
-
const html = inlineCssInHead(documentHtml, tailwindCss);
|
|
240
|
-
const pdfOutputPath = inferPdfPath(outputPath);
|
|
241
|
-
console.log("Rendering HTML...");
|
|
242
|
-
await mkdir(dirname(outputPath), { recursive: true });
|
|
243
|
-
await writeFile(outputPath, html, "utf8");
|
|
244
|
-
console.log(`Wrote HTML to: ${outputPath}`);
|
|
245
|
-
console.log("Rendering PDF...");
|
|
246
|
-
await mkdir(dirname(pdfOutputPath), { recursive: true });
|
|
247
|
-
await renderPdf(html, pdfOutputPath);
|
|
248
|
-
console.log(`Wrote PDF to: ${pdfOutputPath}`);
|
|
249
|
-
};
|
|
250
|
-
var convertCommand = defineCommand({
|
|
251
|
-
meta: {
|
|
252
|
-
name: "convert",
|
|
253
|
-
description: "Convert Markdown files to HTML and PDF."
|
|
254
|
-
},
|
|
255
|
-
args: {
|
|
256
|
-
inputFile: {
|
|
257
|
-
type: "positional",
|
|
258
|
-
description: "Input markdown file path",
|
|
259
|
-
required: true
|
|
260
|
-
},
|
|
261
|
-
outputFile: {
|
|
262
|
-
type: "positional",
|
|
263
|
-
description: "Optional output HTML file path (or existing directory)",
|
|
264
|
-
required: false
|
|
265
|
-
},
|
|
266
|
-
template: {
|
|
267
|
-
type: "string",
|
|
268
|
-
description: "Optional HTML template path (absolute or relative)",
|
|
269
|
-
required: false,
|
|
270
|
-
alias: "t"
|
|
271
|
-
}
|
|
272
|
-
},
|
|
273
|
-
run: async ({ args }) => {
|
|
274
|
-
const inputArg = String(args.inputFile);
|
|
275
|
-
const outputArg = typeof args.outputFile === "string" ? args.outputFile : void 0;
|
|
276
|
-
const templateArg = typeof args.template === "string" ? args.template : void 0;
|
|
277
|
-
await runConvert(inputArg, outputArg, templateArg);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
var ejectTemplateCommand = defineCommand({
|
|
281
|
-
meta: {
|
|
282
|
-
name: "eject-template",
|
|
283
|
-
description: "Write the default HTML template to disk."
|
|
284
|
-
},
|
|
285
|
-
args: {
|
|
286
|
-
outputTemplatePath: {
|
|
287
|
-
type: "positional",
|
|
288
|
-
description: "Optional output file path or target directory",
|
|
289
|
-
required: false
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
run: async ({ args }) => {
|
|
293
|
-
const outputArg = typeof args.outputTemplatePath === "string" ? args.outputTemplatePath : void 0;
|
|
294
|
-
await runEjectTemplate(outputArg);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
var versionCommand = defineCommand({
|
|
298
|
-
meta: {
|
|
299
|
-
name: "version",
|
|
300
|
-
description: "Print current CLI version."
|
|
301
|
-
},
|
|
302
|
-
run: async () => {
|
|
303
|
-
await runVersion();
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
var main = defineCommand({
|
|
307
|
-
meta: {
|
|
308
|
-
name: "mduck",
|
|
309
|
-
description: "Convert Markdown files to HTML/PDF and manage templates."
|
|
310
|
-
},
|
|
311
|
-
subCommands: {
|
|
312
|
-
convert: convertCommand,
|
|
313
|
-
"eject-template": ejectTemplateCommand,
|
|
314
|
-
version: versionCommand
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
await runMain(main);
|
package/src/template.html
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Document</title>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
<article class="prose lg:prose-xl print:prose-sm mx-auto my-8 print:m-0 px-4">
|
|
10
|
-
[BODY]
|
|
11
|
-
</article>
|
|
12
|
-
<style>
|
|
13
|
-
@media print {
|
|
14
|
-
@page {
|
|
15
|
-
margin: 2cm !important; /* Sets a 2cm margin on all sides of every printed page */
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
table {
|
|
19
|
-
border: 1px solid black;
|
|
20
|
-
border-collapse: collapse;
|
|
21
|
-
}
|
|
22
|
-
th, td {
|
|
23
|
-
border: 1px solid black;
|
|
24
|
-
padding: 0.5em;
|
|
25
|
-
}
|
|
26
|
-
</style>
|
|
27
|
-
</body>
|
|
28
|
-
</html>
|