@stonedeck/cli 0.7.1 ā 0.7.3
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/dist/index.js +86 -31
- package/dist/index.js.map +1 -1
- package/package.json +4 -5
- package/src/index.ts +93 -32
- package/tsconfig.json +0 -3
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { processStoneDeck } from '@stonedeck/core';
|
|
3
|
-
import { PdfPlugin } from '@stonedeck/pdf-plugin';
|
|
4
3
|
import { HtmlPlugin } from '@stonedeck/html-plugin';
|
|
5
4
|
import * as fs from 'fs';
|
|
6
5
|
import * as path from 'path';
|
|
6
|
+
import * as http from 'http';
|
|
7
|
+
import { createRequire } from 'module';
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const pkg = require('../package.json');
|
|
7
10
|
async function main() {
|
|
8
11
|
const args = process.argv.slice(2);
|
|
9
12
|
if (args.length < 1 || args.includes('--help') || args.includes('-h')) {
|
|
@@ -24,28 +27,26 @@ async function main() {
|
|
|
24
27
|
}
|
|
25
28
|
function printUsage() {
|
|
26
29
|
console.log(`
|
|
27
|
-
StoneDeck CLI
|
|
30
|
+
StoneDeck CLI v${pkg.version}
|
|
28
31
|
|
|
29
32
|
Usage:
|
|
30
|
-
stonedeck export <input.md>
|
|
33
|
+
stonedeck export <input.md> [options]
|
|
31
34
|
stonedeck preview <input.md> [options]
|
|
32
|
-
stonedeck <input.md> [output.
|
|
35
|
+
stonedeck <input.md> [output.html] (Legacy)
|
|
33
36
|
|
|
34
37
|
Commands:
|
|
35
|
-
export <input.md>
|
|
36
|
-
preview <input.md>
|
|
38
|
+
export <input.md> Export a presentation to HTML
|
|
39
|
+
preview <input.md> Quick HTML preview (defaults to internal browser or static)
|
|
37
40
|
|
|
38
41
|
Options:
|
|
39
|
-
--output, -o <path>
|
|
40
|
-
--theme, -t <path>
|
|
41
|
-
--watch, -w
|
|
42
|
-
--no-offline
|
|
43
|
-
--debug
|
|
44
|
-
--help, -h
|
|
42
|
+
--output, -o <path> Output file path
|
|
43
|
+
--theme, -t <path> Theme file override
|
|
44
|
+
--watch, -w Watch for changes and re-generate
|
|
45
|
+
--no-offline Disable automatic Base64 conversion for HTML
|
|
46
|
+
--debug Save IR to .ir.json for debugging
|
|
47
|
+
--help, -h Show this help message
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
pdf Generate a PDF presentation
|
|
48
|
-
html Generate an offline-capable HTML presentation
|
|
49
|
+
Note: To get a PDF, export to HTML and use your browser's "Print to PDF" feature.
|
|
49
50
|
`);
|
|
50
51
|
}
|
|
51
52
|
async function handleExport(args, legacy = false) {
|
|
@@ -60,19 +61,18 @@ async function handleExport(args, legacy = false) {
|
|
|
60
61
|
if (legacy) {
|
|
61
62
|
inputPath = path.resolve(args[0]);
|
|
62
63
|
outputPath = args[1] && !args[1].startsWith('--') ? path.resolve(args[1]) : undefined;
|
|
63
|
-
format = outputPath?.toLowerCase().endsWith('.html') ? 'html' : 'pdf';
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
66
|
inputPath = path.resolve(args[0]);
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
process.exit(1);
|
|
67
|
+
// If second argument is 'html' or 'pdf', ignore it (for backward compatibility)
|
|
68
|
+
if (args[1] === 'html' || args[1] === 'pdf') {
|
|
69
|
+
args.splice(1, 1);
|
|
71
70
|
}
|
|
72
71
|
const outIdx = args.indexOf('--output') !== -1 ? args.indexOf('--output') : args.indexOf('-o');
|
|
73
72
|
if (outIdx !== -1)
|
|
74
73
|
outputPath = path.resolve(args[outIdx + 1]);
|
|
75
74
|
}
|
|
75
|
+
format = 'html';
|
|
76
76
|
// Default output path if not specified
|
|
77
77
|
if (!outputPath) {
|
|
78
78
|
outputPath = inputPath.replace(/\.md$/, `.${format}`);
|
|
@@ -101,16 +101,11 @@ async function handleExport(args, legacy = false) {
|
|
|
101
101
|
console.log(`š Debug: IR saved to ${path.basename(irPath)}`);
|
|
102
102
|
}
|
|
103
103
|
const htmlPlugin = new HtmlPlugin();
|
|
104
|
-
const pdfPlugin = new PdfPlugin();
|
|
105
104
|
const offline = !args.includes('--no-offline');
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
console.log(`šØ Generating PDF: ${path.basename(outputPath)}...`);
|
|
112
|
-
await pdfPlugin.generate(ir, outputPath);
|
|
113
|
-
}
|
|
105
|
+
const portIdx = args.indexOf('--live-reload-port');
|
|
106
|
+
const liveReloadPort = portIdx !== -1 ? parseInt(args[portIdx + 1]) : undefined;
|
|
107
|
+
console.log(`š Generating HTML: ${path.basename(outputPath)}...`);
|
|
108
|
+
await htmlPlugin.generate(ir, outputPath, { offline, liveReloadPort });
|
|
114
109
|
console.log('ā
Done!');
|
|
115
110
|
}
|
|
116
111
|
catch (e) {
|
|
@@ -128,15 +123,75 @@ async function handlePreview(args) {
|
|
|
128
123
|
const isWatch = args.includes('--watch') || args.includes('-w');
|
|
129
124
|
// Default preview is always HTML
|
|
130
125
|
const outputPath = inputPath.replace(/\.md$/, '.preview.html');
|
|
126
|
+
// Live Reload Server State
|
|
127
|
+
let sseClients = [];
|
|
128
|
+
let lrPort = 3000;
|
|
129
|
+
const startLiveReloadServer = async () => {
|
|
130
|
+
return new Promise((resolve) => {
|
|
131
|
+
const server = http.createServer((req, res) => {
|
|
132
|
+
const url = new URL(req.url || '/', `http://localhost:${lrPort}`);
|
|
133
|
+
if (url.pathname === '/live-reload') {
|
|
134
|
+
res.writeHead(200, {
|
|
135
|
+
'Content-Type': 'text/event-stream',
|
|
136
|
+
'Cache-Control': 'no-cache',
|
|
137
|
+
'Connection': 'keep-alive',
|
|
138
|
+
'Access-Control-Allow-Origin': '*'
|
|
139
|
+
});
|
|
140
|
+
res.write('data: connected\n\n');
|
|
141
|
+
sseClients.push(res);
|
|
142
|
+
req.on('close', () => {
|
|
143
|
+
sseClients = sseClients.filter(c => c !== res);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else if (url.pathname === '/' || url.pathname === '/index.html') {
|
|
147
|
+
if (fs.existsSync(outputPath)) {
|
|
148
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
149
|
+
res.end(fs.readFileSync(outputPath));
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
res.writeHead(404);
|
|
153
|
+
res.end('Preview not generated yet. Please wait...');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
res.writeHead(404);
|
|
158
|
+
res.end();
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
server.on('error', (e) => {
|
|
162
|
+
if (e.code === 'EADDRINUSE') {
|
|
163
|
+
lrPort++;
|
|
164
|
+
server.listen(lrPort);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
server.listen(lrPort, () => {
|
|
168
|
+
resolve(lrPort);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
if (isWatch) {
|
|
173
|
+
lrPort = await startLiveReloadServer();
|
|
174
|
+
console.log(`š” Live Reload server started on port ${lrPort}`);
|
|
175
|
+
}
|
|
131
176
|
const run = async () => {
|
|
132
177
|
try {
|
|
133
178
|
console.log(`\nš ${isWatch ? 'Updating' : 'Generating'} preview...`);
|
|
134
179
|
// Preview defaults to no-offline for speed
|
|
135
|
-
const exportArgs = [args[0], '
|
|
180
|
+
const exportArgs = [args[0], '--output', outputPath, ...args.filter(a => a !== args[0] && a !== '--watch' && a !== '-w')];
|
|
136
181
|
if (!exportArgs.includes('--no-offline'))
|
|
137
182
|
exportArgs.push('--no-offline');
|
|
183
|
+
if (isWatch) {
|
|
184
|
+
exportArgs.push('--live-reload-port', lrPort.toString());
|
|
185
|
+
}
|
|
138
186
|
await handleExport(exportArgs, false);
|
|
139
|
-
|
|
187
|
+
// Notify clients
|
|
188
|
+
sseClients.forEach(client => client.write('data: reload\n\n'));
|
|
189
|
+
if (isWatch) {
|
|
190
|
+
console.log(`š Preview available at: http://localhost:${lrPort}`);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
console.log(`š Preview available at: file://${outputPath}`);
|
|
194
|
+
}
|
|
140
195
|
}
|
|
141
196
|
catch (e) {
|
|
142
197
|
const message = e instanceof Error ? e.message : String(e);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonedeck/cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"stonedeck": "./dist/index.js"
|
|
@@ -19,13 +19,12 @@
|
|
|
19
19
|
"start": "node dist/index.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@stonedeck/core": "^0.7.
|
|
23
|
-
"@stonedeck/html-plugin": "^0.7.
|
|
24
|
-
"@stonedeck/pdf-plugin": "^0.7.0"
|
|
22
|
+
"@stonedeck/core": "^0.7.2",
|
|
23
|
+
"@stonedeck/html-plugin": "^0.7.2"
|
|
25
24
|
},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"typescript": "^5.0.0",
|
|
28
27
|
"@types/node": "^20.0.0",
|
|
29
28
|
"tsx": "^4.7.0"
|
|
30
29
|
}
|
|
31
|
-
}
|
|
30
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { processStoneDeck } from '@stonedeck/core';
|
|
3
|
-
import { PdfPlugin } from '@stonedeck/pdf-plugin';
|
|
4
3
|
import { HtmlPlugin } from '@stonedeck/html-plugin';
|
|
5
4
|
import * as fs from 'fs';
|
|
6
5
|
import * as path from 'path';
|
|
6
|
+
import * as http from 'http';
|
|
7
|
+
import { createRequire } from 'module';
|
|
8
|
+
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const pkg = require('../package.json');
|
|
7
11
|
|
|
8
12
|
async function main() {
|
|
9
13
|
const args = process.argv.slice(2);
|
|
@@ -27,28 +31,26 @@ async function main() {
|
|
|
27
31
|
|
|
28
32
|
function printUsage() {
|
|
29
33
|
console.log(`
|
|
30
|
-
StoneDeck CLI
|
|
34
|
+
StoneDeck CLI v${pkg.version}
|
|
31
35
|
|
|
32
36
|
Usage:
|
|
33
|
-
stonedeck export <input.md>
|
|
37
|
+
stonedeck export <input.md> [options]
|
|
34
38
|
stonedeck preview <input.md> [options]
|
|
35
|
-
stonedeck <input.md> [output.
|
|
39
|
+
stonedeck <input.md> [output.html] (Legacy)
|
|
36
40
|
|
|
37
41
|
Commands:
|
|
38
|
-
export <input.md>
|
|
39
|
-
preview <input.md>
|
|
42
|
+
export <input.md> Export a presentation to HTML
|
|
43
|
+
preview <input.md> Quick HTML preview (defaults to internal browser or static)
|
|
40
44
|
|
|
41
45
|
Options:
|
|
42
|
-
--output, -o <path>
|
|
43
|
-
--theme, -t <path>
|
|
44
|
-
--watch, -w
|
|
45
|
-
--no-offline
|
|
46
|
-
--debug
|
|
47
|
-
--help, -h
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
pdf Generate a PDF presentation
|
|
51
|
-
html Generate an offline-capable HTML presentation
|
|
46
|
+
--output, -o <path> Output file path
|
|
47
|
+
--theme, -t <path> Theme file override
|
|
48
|
+
--watch, -w Watch for changes and re-generate
|
|
49
|
+
--no-offline Disable automatic Base64 conversion for HTML
|
|
50
|
+
--debug Save IR to .ir.json for debugging
|
|
51
|
+
--help, -h Show this help message
|
|
52
|
+
|
|
53
|
+
Note: To get a PDF, export to HTML and use your browser's "Print to PDF" feature.
|
|
52
54
|
`);
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -66,20 +68,20 @@ async function handleExport(args: string[], legacy = false) {
|
|
|
66
68
|
if (legacy) {
|
|
67
69
|
inputPath = path.resolve(args[0]!);
|
|
68
70
|
outputPath = args[1] && !args[1].startsWith('--') ? path.resolve(args[1]) : undefined;
|
|
69
|
-
format = outputPath?.toLowerCase().endsWith('.html') ? 'html' : 'pdf';
|
|
70
71
|
} else {
|
|
71
72
|
inputPath = path.resolve(args[0]!);
|
|
72
|
-
format = args[1]?.toLowerCase();
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
// If second argument is 'html' or 'pdf', ignore it (for backward compatibility)
|
|
75
|
+
if (args[1] === 'html' || args[1] === 'pdf') {
|
|
76
|
+
args.splice(1, 1);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
const outIdx = args.indexOf('--output') !== -1 ? args.indexOf('--output') : args.indexOf('-o');
|
|
80
80
|
if (outIdx !== -1) outputPath = path.resolve(args[outIdx + 1]!);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
format = 'html';
|
|
84
|
+
|
|
83
85
|
// Default output path if not specified
|
|
84
86
|
if (!outputPath) {
|
|
85
87
|
outputPath = inputPath.replace(/\.md$/, `.${format}`);
|
|
@@ -112,17 +114,13 @@ async function handleExport(args: string[], legacy = false) {
|
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
const htmlPlugin = new HtmlPlugin();
|
|
115
|
-
const pdfPlugin = new PdfPlugin();
|
|
116
|
-
|
|
117
117
|
const offline = !args.includes('--no-offline');
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await pdfPlugin.generate(ir, outputPath);
|
|
125
|
-
}
|
|
119
|
+
const portIdx = args.indexOf('--live-reload-port');
|
|
120
|
+
const liveReloadPort = portIdx !== -1 ? parseInt(args[portIdx + 1]!) : undefined;
|
|
121
|
+
|
|
122
|
+
console.log(`š Generating HTML: ${path.basename(outputPath)}...`);
|
|
123
|
+
await htmlPlugin.generate(ir, outputPath, { offline, liveReloadPort });
|
|
126
124
|
|
|
127
125
|
console.log('ā
Done!');
|
|
128
126
|
} catch (e: unknown) {
|
|
@@ -144,15 +142,78 @@ async function handlePreview(args: string[]) {
|
|
|
144
142
|
// Default preview is always HTML
|
|
145
143
|
const outputPath = inputPath.replace(/\.md$/, '.preview.html');
|
|
146
144
|
|
|
145
|
+
// Live Reload Server State
|
|
146
|
+
let sseClients: http.ServerResponse[] = [];
|
|
147
|
+
let lrPort = 3000;
|
|
148
|
+
|
|
149
|
+
const startLiveReloadServer = async () => {
|
|
150
|
+
return new Promise<number>((resolve) => {
|
|
151
|
+
const server = http.createServer((req, res) => {
|
|
152
|
+
const url = new URL(req.url || '/', `http://localhost:${lrPort}`);
|
|
153
|
+
if (url.pathname === '/live-reload') {
|
|
154
|
+
res.writeHead(200, {
|
|
155
|
+
'Content-Type': 'text/event-stream',
|
|
156
|
+
'Cache-Control': 'no-cache',
|
|
157
|
+
'Connection': 'keep-alive',
|
|
158
|
+
'Access-Control-Allow-Origin': '*'
|
|
159
|
+
});
|
|
160
|
+
res.write('data: connected\n\n');
|
|
161
|
+
sseClients.push(res);
|
|
162
|
+
req.on('close', () => {
|
|
163
|
+
sseClients = sseClients.filter(c => c !== res);
|
|
164
|
+
});
|
|
165
|
+
} else if (url.pathname === '/' || url.pathname === '/index.html') {
|
|
166
|
+
if (fs.existsSync(outputPath)) {
|
|
167
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
168
|
+
res.end(fs.readFileSync(outputPath));
|
|
169
|
+
} else {
|
|
170
|
+
res.writeHead(404);
|
|
171
|
+
res.end('Preview not generated yet. Please wait...');
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
res.writeHead(404);
|
|
175
|
+
res.end();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
server.on('error', (e: any) => {
|
|
180
|
+
if (e.code === 'EADDRINUSE') {
|
|
181
|
+
lrPort++;
|
|
182
|
+
server.listen(lrPort);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
server.listen(lrPort, () => {
|
|
187
|
+
resolve(lrPort);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
if (isWatch) {
|
|
193
|
+
lrPort = await startLiveReloadServer();
|
|
194
|
+
console.log(`š” Live Reload server started on port ${lrPort}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
147
197
|
const run = async () => {
|
|
148
198
|
try {
|
|
149
199
|
console.log(`\nš ${isWatch ? 'Updating' : 'Generating'} preview...`);
|
|
150
200
|
// Preview defaults to no-offline for speed
|
|
151
|
-
const exportArgs = [args[0]!, '
|
|
201
|
+
const exportArgs = [args[0]!, '--output', outputPath, ...args.filter(a => a !== args[0] && a !== '--watch' && a !== '-w')];
|
|
152
202
|
if (!exportArgs.includes('--no-offline')) exportArgs.push('--no-offline');
|
|
203
|
+
if (isWatch) {
|
|
204
|
+
exportArgs.push('--live-reload-port', lrPort.toString());
|
|
205
|
+
}
|
|
153
206
|
|
|
154
207
|
await handleExport(exportArgs, false);
|
|
155
|
-
|
|
208
|
+
|
|
209
|
+
// Notify clients
|
|
210
|
+
sseClients.forEach(client => client.write('data: reload\n\n'));
|
|
211
|
+
|
|
212
|
+
if (isWatch) {
|
|
213
|
+
console.log(`š Preview available at: http://localhost:${lrPort}`);
|
|
214
|
+
} else {
|
|
215
|
+
console.log(`š Preview available at: file://${outputPath}`);
|
|
216
|
+
}
|
|
156
217
|
} catch (e: unknown) {
|
|
157
218
|
const message = e instanceof Error ? e.message : String(e);
|
|
158
219
|
console.error(`ā Preview update failed: ${message}`);
|