md2pdf2 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,15 +17,40 @@ A CLI tool that converts Markdown to PDF using customizable templates — think
17
17
 
18
18
  ```bash
19
19
  # Install globally (once published)
20
- npm install -g md2pdf
20
+ npm install -g md2pdf2
21
21
 
22
22
  # Or use npx
23
- npx md2pdf convert input.md -o output.pdf
23
+ npx md2pdf2 convert input.md -o output.pdf
24
24
 
25
25
  # With a custom template
26
- md2pdf convert input.md --template my-template.hbs -o output.pdf
26
+ md2pdf2 convert input.md --template my-template.hbs -o output.pdf
27
+
28
+ # Dev mode with live preview
29
+ md2pdf2 dev input.md
30
+ ```
31
+
32
+ ## Dev Mode
33
+
34
+ Start a live preview server to see your markdown rendered in different templates:
35
+
36
+ ```bash
37
+ md2pdf2 dev input.md --port 3456
27
38
  ```
28
39
 
40
+ Opens a browser with:
41
+ - **Left pane**: Template selector (switch between templates)
42
+ - **Right pane**: Live preview of your markdown
43
+
44
+ Changes to your `.md` file or templates auto-reload the preview.
45
+
46
+ ### Built-in Templates
47
+
48
+ - `default` - Clean, professional look
49
+ - `modern` - Bold colors, Inter-style typography
50
+ - `minimal` - Simple, classic serif
51
+ - `newsletter` - Email newsletter style
52
+ - `resume` - CV/resume formatting
53
+
29
54
  ## Project Structure
30
55
 
31
56
  ```
@@ -37,7 +62,7 @@ my-doc/
37
62
  │ ├── parts/
38
63
  │ │ └── header.hbs
39
64
  │ └── styles.css
40
- ├── md2pdf.config.js
65
+ ├── md2pdf2.config.js
41
66
  └── package.json
42
67
  ```
43
68
 
@@ -63,7 +88,7 @@ Templates use handlebars-like syntax for placeholders and partials:
63
88
 
64
89
  ## Configuration
65
90
 
66
- `md2pdf.config.js`:
91
+ `md2pdf2.config.js`:
67
92
 
68
93
  ```js
69
94
  export default {
package/dist/cli.js CHANGED
@@ -5,9 +5,10 @@ import { Converter } from './converter.js';
5
5
  import { TemplateEngine } from './template-engine.js';
6
6
  import { PDFGenerator } from './pdf-generator.js';
7
7
  import { DEFAULT_CONFIG } from './types.js';
8
+ import { startDevServer } from './dev-server.js';
8
9
  const program = new Command();
9
10
  program
10
- .name('md2pdf')
11
+ .name('md2pdf2')
11
12
  .description('Convert Markdown to PDF using customizable templates')
12
13
  .version('0.1.0');
13
14
  program
@@ -17,8 +18,7 @@ program
17
18
  .option('-o, --output <file>', 'Output PDF file')
18
19
  .option('-t, --template <file>', 'Custom template file (Handlebars)')
19
20
  .option('-s, --style <file>', 'Custom CSS file')
20
- .option('-c, --config <file>', 'Configuration file (md2pdf.config.js)')
21
- .option('--no-pdf', 'Only generate HTML, do not create PDF')
21
+ .option('-c, --config <file>', 'Configuration file (md2pdf2.config.js)')
22
22
  .action(async (input, options) => {
23
23
  try {
24
24
  // Load configuration
@@ -59,12 +59,10 @@ program
59
59
  // Save HTML for debugging
60
60
  await writeFileAsync(htmlPath, renderedHtml);
61
61
  console.log(`✓ HTML generated: ${htmlPath}`);
62
- // Generate PDF unless disabled
63
- if (!options.pdf) {
64
- const generator = new PDFGenerator();
65
- await generator.generate(renderedHtml, outputPath, config.pdfOptions);
66
- console.log(`✓ PDF generated: ${outputPath}`);
67
- }
62
+ // Generate PDF
63
+ const generator = new PDFGenerator();
64
+ await generator.generate(renderedHtml, outputPath, config.pdfOptions);
65
+ console.log(`✓ PDF generated: ${outputPath}`);
68
66
  }
69
67
  catch (error) {
70
68
  console.error('Error:', error instanceof Error ? error.message : error);
@@ -84,5 +82,28 @@ function getOutputPath(inputPath) {
84
82
  const baseName = getFileName(inputPath);
85
83
  return `${baseName}.pdf`;
86
84
  }
85
+ program
86
+ .command('dev')
87
+ .description('Start dev server with live preview')
88
+ .argument('<input>', 'Input Markdown file')
89
+ .option('-p, --port <port>', 'Dev server port', '3456')
90
+ .option('-c, --config <file>', 'Configuration file')
91
+ .action(async (input, options) => {
92
+ try {
93
+ if (!(await fileExists(input))) {
94
+ console.error(`Error: Input file not found: ${input}`);
95
+ process.exit(1);
96
+ }
97
+ await startDevServer({
98
+ input,
99
+ port: parseInt(options.port, 10),
100
+ config: options.config
101
+ });
102
+ }
103
+ catch (error) {
104
+ console.error('Error:', error instanceof Error ? error.message : error);
105
+ process.exit(1);
106
+ }
107
+ });
87
108
  program.parse();
88
109
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface DevServerOptions {
2
+ input: string;
3
+ port?: number;
4
+ config?: string;
5
+ }
6
+ export declare function startDevServer(options: DevServerOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=dev-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAYA,UAAU,gBAAgB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,iBA2I7D"}
@@ -0,0 +1,406 @@
1
+ import express from 'express';
2
+ import { WebSocketServer, WebSocket } from 'ws';
3
+ import { createServer } from 'http';
4
+ import { watch } from 'chokidar';
5
+ import { readdirSync, statSync } from 'fs';
6
+ import { readFileAsync, fileExists, getFileName } from './utils.js';
7
+ import { Converter } from './converter.js';
8
+ import { TemplateEngine } from './template-engine.js';
9
+ import { PDFGenerator } from './pdf-generator.js';
10
+ import path from 'path';
11
+ import { DEFAULT_CONFIG } from './types.js';
12
+ export async function startDevServer(options) {
13
+ const port = options.port || 3456;
14
+ const app = express();
15
+ const server = createServer(app);
16
+ const wss = new WebSocketServer({ server });
17
+ let config = { ...DEFAULT_CONFIG };
18
+ let clients = [];
19
+ let templates = [];
20
+ const inputFile = path.resolve(options.input);
21
+ const inputDir = path.dirname(inputFile);
22
+ const inputBaseName = getFileName(inputFile);
23
+ if (options.config && await fileExists(options.config)) {
24
+ const configModule = await import(path.resolve(process.cwd(), options.config));
25
+ const userConfig = configModule.default || configModule;
26
+ Object.assign(config, userConfig);
27
+ }
28
+ const templatesDir = config.template ? path.dirname(config.template) : './templates';
29
+ templates = await discoverTemplates(templatesDir);
30
+ async function discoverTemplates(dir) {
31
+ try {
32
+ const results = [];
33
+ const scanDir = (d) => {
34
+ const entries = readdirSync(d);
35
+ for (const entry of entries) {
36
+ const fullPath = path.join(d, entry);
37
+ if (statSync(fullPath).isDirectory()) {
38
+ if (entry !== 'parts')
39
+ scanDir(fullPath);
40
+ }
41
+ else if (entry.endsWith('.hbs')) {
42
+ results.push(fullPath);
43
+ }
44
+ }
45
+ };
46
+ scanDir(dir);
47
+ return results;
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ }
53
+ async function renderMarkdown(templatePath) {
54
+ if (!(await fileExists(options.input))) {
55
+ return '<p style="color: red;">Input file not found</p>';
56
+ }
57
+ const markdown = await readFileAsync(options.input);
58
+ const converter = new Converter();
59
+ const { html, frontMatter } = converter.convert(markdown);
60
+ let styles = '';
61
+ if (config.style && await fileExists(config.style)) {
62
+ styles = await readFileAsync(config.style);
63
+ }
64
+ const engine = new TemplateEngine(config);
65
+ if (templatePath && await fileExists(templatePath)) {
66
+ await engine.loadTemplate(templatePath);
67
+ }
68
+ else {
69
+ engine.loadDefaultTemplate();
70
+ }
71
+ return engine.render(html, frontMatter, styles);
72
+ }
73
+ function getTemplateList() {
74
+ return templates.map(t => ({
75
+ name: path.basename(t, '.hbs'),
76
+ path: t
77
+ }));
78
+ }
79
+ app.get('/', (_req, res) => {
80
+ res.send(getDevHTML(port));
81
+ });
82
+ app.get('/api/templates', (_req, res) => {
83
+ res.json(getTemplateList());
84
+ });
85
+ app.get('/api/render', async (req, res) => {
86
+ const template = req.query.template;
87
+ const html = await renderMarkdown(template);
88
+ res.send(html);
89
+ });
90
+ app.get('/api/generate-pdf', async (req, res) => {
91
+ try {
92
+ const template = req.query.template;
93
+ const html = await renderMarkdown(template);
94
+ const templateInfo = templates.find(t => t === template);
95
+ const templateName = templateInfo ? path.basename(templateInfo, '.hbs') : 'output';
96
+ const outputPath = path.join(inputDir, `${inputBaseName}-${templateName}.pdf`);
97
+ const generator = new PDFGenerator();
98
+ await generator.generate(html, outputPath, config.pdfOptions);
99
+ res.download(outputPath);
100
+ }
101
+ catch (error) {
102
+ res.status(500).json({ error: error instanceof Error ? error.message : 'Failed to generate PDF' });
103
+ }
104
+ });
105
+ wss.on('connection', (ws) => {
106
+ clients.push(ws);
107
+ ws.on('close', () => {
108
+ clients = clients.filter(c => c !== ws);
109
+ });
110
+ });
111
+ function broadcast(type, data) {
112
+ const message = JSON.stringify({ type, data });
113
+ clients.forEach(client => {
114
+ if (client.readyState === WebSocket.OPEN) {
115
+ client.send(message);
116
+ }
117
+ });
118
+ }
119
+ const watcher = watch([options.input, templatesDir], {
120
+ ignoreInitial: true,
121
+ awaitWriteFinish: { stabilityThreshold: 100 }
122
+ });
123
+ watcher.on('change', async (filepath) => {
124
+ if (filepath.endsWith('.hbs')) {
125
+ templates = await discoverTemplates(templatesDir);
126
+ broadcast('templates-updated', getTemplateList());
127
+ }
128
+ broadcast('reload');
129
+ });
130
+ server.listen(port, () => {
131
+ console.log(`\n Dev server running at http://localhost:${port}`);
132
+ console.log(` Watching: ${options.input}, ${templatesDir}/\n`);
133
+ });
134
+ }
135
+ function getDevHTML(port) {
136
+ return `<!DOCTYPE html>
137
+ <html lang="en">
138
+ <head>
139
+ <meta charset="UTF-8">
140
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
141
+ <title>md2pdf2 - Dev Preview</title>
142
+ <style>
143
+ * { box-sizing: border-box; margin: 0; padding: 0; }
144
+ body {
145
+ font-family: system-ui, -apple-system, sans-serif;
146
+ height: 100vh;
147
+ display: flex;
148
+ overflow: hidden;
149
+ background: #0f172a;
150
+ color: #e2e8f0;
151
+ }
152
+ .sidebar {
153
+ width: 280px;
154
+ background: #1e293b;
155
+ border-right: 1px solid #334155;
156
+ display: flex;
157
+ flex-direction: column;
158
+ }
159
+ .sidebar-header {
160
+ padding: 20px;
161
+ border-bottom: 1px solid #334155;
162
+ }
163
+ .sidebar-header h1 {
164
+ font-size: 18px;
165
+ font-weight: 600;
166
+ color: #f8fafc;
167
+ }
168
+ .sidebar-header p {
169
+ font-size: 12px;
170
+ color: #94a3b8;
171
+ margin-top: 4px;
172
+ }
173
+ .template-list {
174
+ flex: 1;
175
+ overflow-y: auto;
176
+ padding: 12px;
177
+ }
178
+ .template-item {
179
+ padding: 12px 16px;
180
+ border-radius: 8px;
181
+ cursor: pointer;
182
+ margin-bottom: 4px;
183
+ font-size: 14px;
184
+ transition: all 0.15s;
185
+ border: 1px solid transparent;
186
+ }
187
+ .template-item:hover {
188
+ background: #334155;
189
+ }
190
+ .template-item.active {
191
+ background: #3b82f6;
192
+ color: white;
193
+ border-color: #60a5fa;
194
+ }
195
+ .preview-container {
196
+ flex: 1;
197
+ display: flex;
198
+ flex-direction: column;
199
+ }
200
+ .preview-header {
201
+ padding: 12px 20px;
202
+ background: #1e293b;
203
+ border-bottom: 1px solid #334155;
204
+ display: flex;
205
+ justify-content: space-between;
206
+ align-items: center;
207
+ }
208
+ .preview-header span {
209
+ font-size: 13px;
210
+ color: #94a3b8;
211
+ }
212
+ .status-dot {
213
+ width: 8px;
214
+ height: 8px;
215
+ background: #22c55e;
216
+ border-radius: 50%;
217
+ display: inline-block;
218
+ margin-right: 6px;
219
+ }
220
+ .export-btn {
221
+ background: #3b82f6;
222
+ color: white;
223
+ border: none;
224
+ padding: 8px 16px;
225
+ border-radius: 6px;
226
+ font-size: 13px;
227
+ cursor: pointer;
228
+ display: flex;
229
+ align-items: center;
230
+ gap: 6px;
231
+ transition: background 0.15s;
232
+ }
233
+ .export-btn:hover {
234
+ background: #2563eb;
235
+ }
236
+ .export-btn:disabled {
237
+ background: #475569;
238
+ cursor: not-allowed;
239
+ }
240
+ .export-btn svg {
241
+ width: 16px;
242
+ height: 16px;
243
+ }
244
+ .preview-frame {
245
+ flex: 1;
246
+ background: white;
247
+ border: none;
248
+ }
249
+ .loading {
250
+ position: absolute;
251
+ top: 50%;
252
+ left: 50%;
253
+ transform: translate(-50%, -50%);
254
+ color: #94a3b8;
255
+ font-size: 14px;
256
+ }
257
+ .toast {
258
+ position: fixed;
259
+ bottom: 20px;
260
+ right: 20px;
261
+ background: #1e293b;
262
+ color: #e2e8f0;
263
+ padding: 12px 20px;
264
+ border-radius: 8px;
265
+ font-size: 13px;
266
+ opacity: 0;
267
+ transform: translateY(10px);
268
+ transition: all 0.3s ease;
269
+ pointer-events: none;
270
+ border: 1px solid #334155;
271
+ }
272
+ .toast.show {
273
+ opacity: 1;
274
+ transform: translateY(0);
275
+ }
276
+ .toast .toast-dot {
277
+ width: 6px;
278
+ height: 6px;
279
+ background: #22c55e;
280
+ border-radius: 50%;
281
+ display: inline-block;
282
+ margin-right: 8px;
283
+ animation: pulse 1s ease infinite;
284
+ }
285
+ @keyframes pulse {
286
+ 0%, 100% { opacity: 1; }
287
+ 50% { opacity: 0.5; }
288
+ }
289
+ </style>
290
+ </head>
291
+ <body>
292
+ <div class="toast" id="toast"><span class="toast-dot"></span><span id="toastMsg">Reloading...</span></div>
293
+ <div class="sidebar">
294
+ <div class="sidebar-header">
295
+ <h1>md2pdf2</h1>
296
+ <p id="currentTemplate"><span style="color: #22c55e;">●</span> Watching for changes</p>
297
+ </div>
298
+ <div class="template-list" id="templateList"></div>
299
+ </div>
300
+ <div class="preview-container">
301
+ <div class="preview-header">
302
+ <span><span class="status-dot"></span>Live Preview</span>
303
+ <button class="export-btn" id="exportBtn" onclick="exportPDF()">
304
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
305
+ <span id="btnText">Export PDF</span>
306
+ </button>
307
+ </div>
308
+ <iframe class="preview-frame" id="previewFrame"></iframe>
309
+ </div>
310
+ <script>
311
+ const templateList = document.getElementById('templateList');
312
+ const previewFrame = document.getElementById('previewFrame');
313
+ const currentTemplateEl = document.getElementById('currentTemplate');
314
+ let templates = [];
315
+ let activeTemplate = null;
316
+
317
+ async function loadTemplates() {
318
+ const res = await fetch('/api/templates');
319
+ templates = await res.json();
320
+ renderTemplateList();
321
+ if (templates.length > 0 && !activeTemplate) {
322
+ selectTemplate(templates[0].path);
323
+ }
324
+ }
325
+
326
+ function renderTemplateList() {
327
+ templateList.innerHTML = templates.map(t => \`
328
+ <div class="template-item \${activeTemplate === t.path ? 'active' : ''}" data-path="\${t.path}">
329
+ \${t.name}
330
+ </div>
331
+ \`).join('');
332
+
333
+ templateList.querySelectorAll('.template-item').forEach(el => {
334
+ el.addEventListener('click', () => selectTemplate(el.dataset.path));
335
+ });
336
+ }
337
+
338
+ async function selectTemplate(path) {
339
+ activeTemplate = path;
340
+ const template = templates.find(t => t.path === path);
341
+ if (template) currentTemplateEl.innerHTML = '<span style="color: #22c55e;">●</span> ' + template.name;
342
+ renderTemplateList();
343
+ await renderPreview();
344
+ }
345
+
346
+ async function renderPreview() {
347
+ const res = await fetch('/api/render?template=' + encodeURIComponent(activeTemplate));
348
+ const html = await res.text();
349
+ previewFrame.srcdoc = html;
350
+ }
351
+
352
+ async function exportPDF() {
353
+ const btn = document.getElementById('exportBtn');
354
+ const btnText = document.getElementById('btnText');
355
+ btn.disabled = true;
356
+ btnText.textContent = 'Generating...';
357
+
358
+ try {
359
+ const res = await fetch('/api/generate-pdf?template=' + encodeURIComponent(activeTemplate));
360
+ if (!res.ok) throw new Error('Failed to generate PDF');
361
+
362
+ const blob = await res.blob();
363
+ const url = URL.createObjectURL(blob);
364
+ const a = document.createElement('a');
365
+ a.href = url;
366
+ a.download = 'output.pdf';
367
+ document.body.appendChild(a);
368
+ a.click();
369
+ document.body.removeChild(a);
370
+ URL.revokeObjectURL(url);
371
+ } catch (err) {
372
+ alert('Failed to generate PDF: ' + err.message);
373
+ } finally {
374
+ btn.disabled = false;
375
+ btnText.textContent = 'Export PDF';
376
+ }
377
+ }
378
+
379
+ function showToast(msg) {
380
+ const toast = document.getElementById('toast');
381
+ const toastMsg = document.getElementById('toastMsg');
382
+ toastMsg.textContent = msg;
383
+ toast.classList.add('show');
384
+ setTimeout(() => toast.classList.remove('show'), 2000);
385
+ }
386
+
387
+ const ws = new WebSocket('ws://localhost:${port}');
388
+ ws.onmessage = async (event) => {
389
+ const msg = JSON.parse(event.data);
390
+ if (msg.type === 'reload') {
391
+ showToast('File changed, reloading...');
392
+ await renderPreview();
393
+ }
394
+ if (msg.type === 'templates-updated') {
395
+ templates = msg.data;
396
+ renderTemplateList();
397
+ showToast('Templates updated');
398
+ }
399
+ };
400
+
401
+ loadTemplates();
402
+ </script>
403
+ </body>
404
+ </html>`;
405
+ }
406
+ //# sourceMappingURL=dev-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server.js","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../src/template-engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,QAAQ,CAAkD;gBAEtD,MAAM,EAAE,YAAY;IAUhC,OAAO,CAAC,eAAe;YAMT,sBAAsB;IAW9B,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,mBAAmB,IAAI,IAAI;IAiD3B,OAAO,CAAC,eAAe;IAIvB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;CAQlF"}
1
+ {"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../src/template-engine.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,QAAQ,CAAkD;gBAEtD,MAAM,EAAE,YAAY;IAUhC,OAAO,CAAC,eAAe;YAaT,sBAAsB;IAW9B,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvD,mBAAmB,IAAI,IAAI;IAiD3B,OAAO,CAAC,eAAe;IAIvB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;CASlF"}
@@ -15,6 +15,14 @@ export class TemplateEngine {
15
15
  Handlebars.registerHelper('hasPartial', (name) => {
16
16
  return !!this.partials[name];
17
17
  });
18
+ Handlebars.registerHelper('currentDate', () => {
19
+ return new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
20
+ });
21
+ Handlebars.registerHelper('slice', (str, start, end) => {
22
+ if (typeof str !== 'string')
23
+ return '';
24
+ return str.slice(start, end);
25
+ });
18
26
  }
19
27
  async loadPartialsFromConfig(partialsConfig) {
20
28
  for (const [name, path] of Object.entries(partialsConfig)) {
@@ -90,7 +98,8 @@ export class TemplateEngine {
90
98
  content,
91
99
  frontMatter,
92
100
  styles,
93
- partials: this.partials
101
+ partials: this.partials,
102
+ ...frontMatter
94
103
  });
95
104
  }
96
105
  }
@@ -1 +1 @@
1
- {"version":3,"file":"template-engine.js","sourceRoot":"","sources":["../src/template-engine.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,OAAO,cAAc;IACjB,QAAQ,CAA8B;IACtC,QAAQ,GAA+C,EAAE,CAAC;IAElE,YAAY,MAAoB;QAC9B,4BAA4B;QAC5B,IAAI,CAAC,eAAe,EAAE,CAAC;QAEvB,wCAAwC;QACxC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEO,eAAe;QACrB,UAAU,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE;YACvD,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,cAAsC;QACzE,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,oCAAoC,IAAI,UAAU,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,MAAM,eAAe,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;QAC1D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;IACxD,CAAC;IAED,mBAAmB;QACjB,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4CpB,CAAC;QACL,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;IACxD,CAAC;IAEO,eAAe,CAAC,OAAe;QACrC,OAAO,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,eAAe,CAAC,IAAY,EAAE,OAAe;QAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,OAAe,EAAE,WAAgC,EAAE,MAAc;QACtE,OAAO,IAAI,CAAC,QAAQ,CAAC;YACnB,OAAO;YACP,WAAW;YACX,MAAM;YACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;IACL,CAAC;CACF"}
1
+ {"version":3,"file":"template-engine.js","sourceRoot":"","sources":["../src/template-engine.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,OAAO,cAAc;IACjB,QAAQ,CAA8B;IACtC,QAAQ,GAA+C,EAAE,CAAC;IAElE,YAAY,MAAoB;QAC9B,4BAA4B;QAC5B,IAAI,CAAC,eAAe,EAAE,CAAC;QAEvB,wCAAwC;QACxC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpB,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEO,eAAe;QACrB,UAAU,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC,IAAY,EAAE,EAAE;YACvD,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,UAAU,CAAC,cAAc,CAAC,aAAa,EAAE,GAAG,EAAE;YAC5C,OAAO,IAAI,IAAI,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;QACpG,CAAC,CAAC,CAAC;QACH,UAAU,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,GAAW,EAAE,KAAa,EAAE,GAAY,EAAE,EAAE;YAC9E,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAC;YACvC,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,cAAsC;QACzE,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACpD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,oCAAoC,IAAI,UAAU,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,YAAoB;QACrC,MAAM,eAAe,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC,CAAC;QAC1D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;IACxD,CAAC;IAED,mBAAmB;QACjB,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4CpB,CAAC;QACL,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;IACxD,CAAC;IAEO,eAAe,CAAC,OAAe;QACrC,OAAO,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,eAAe,CAAC,IAAY,EAAE,OAAe;QAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,CAAC,OAAe,EAAE,WAAgC,EAAE,MAAc;QACtE,OAAO,IAAI,CAAC,QAAQ,CAAC;YACnB,OAAO;YACP,WAAW;YACX,MAAM;YACN,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,WAAW;SACf,CAAC,CAAC;IACL,CAAC;CACF"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "md2pdf2",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Convert Markdown to PDF using customizable templates",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
7
7
  "bin": {
8
- "md2pdf": "dist/cli.js"
8
+ "md2pdf2": "dist/cli.js"
9
9
  },
10
10
  "scripts": {
11
11
  "build": "tsc",
@@ -29,14 +29,19 @@
29
29
  "url": "git+https://github.com/areai51/md2pdf.git"
30
30
  },
31
31
  "dependencies": {
32
+ "chokidar": "^5.0.0",
32
33
  "commander": "^12.1.0",
34
+ "express": "^5.2.1",
33
35
  "front-matter": "^4.0.2",
34
36
  "handlebars": "^4.7.8",
35
37
  "marked": "^11.1.1",
36
- "puppeteer": "^23.0.0"
38
+ "puppeteer": "^23.0.0",
39
+ "ws": "^8.19.0"
37
40
  },
38
41
  "devDependencies": {
42
+ "@types/express": "^5.0.6",
39
43
  "@types/node": "^20.11.0",
44
+ "@types/ws": "^8.18.1",
40
45
  "@typescript-eslint/eslint-plugin": "^6.19.0",
41
46
  "@typescript-eslint/parser": "^6.19.0",
42
47
  "eslint": "^8.56.0",