@udx/md2html 1.0.0 ā 1.2.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 +23 -0
- package/index.js +100 -9
- package/package.json +4 -2
- package/static/view.hbs +25 -0
package/README.md
CHANGED
|
@@ -101,6 +101,29 @@ Add captions to images with this syntax:
|
|
|
101
101
|
*This is the image caption*
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
### Mermaid Diagrams
|
|
105
|
+
|
|
106
|
+
Create professional diagrams using Mermaid syntax:
|
|
107
|
+
|
|
108
|
+
````markdown
|
|
109
|
+
```mermaid
|
|
110
|
+
flowchart LR
|
|
111
|
+
A[Client] --> B[Load Balancer]
|
|
112
|
+
B --> C[Server1]
|
|
113
|
+
B --> D[Server2]
|
|
114
|
+
```
|
|
115
|
+
````
|
|
116
|
+
|
|
117
|
+
Supported Mermaid diagram types:
|
|
118
|
+
- **Flowcharts**: Process flows and workflows
|
|
119
|
+
- **Sequence Diagrams**: System interactions over time
|
|
120
|
+
- **Gantt Charts**: Project timelines and schedules
|
|
121
|
+
- **Entity Relationship Diagrams**: Database schemas
|
|
122
|
+
- **User Journey**: User experience flows
|
|
123
|
+
- **Git Graphs**: Version control workflows
|
|
124
|
+
|
|
125
|
+
The diagrams are automatically rendered when the HTML document loads, with professional styling that matches the document theme.
|
|
126
|
+
|
|
104
127
|
## Customization
|
|
105
128
|
|
|
106
129
|
This tool is designed to be easily customizable:
|
package/index.js
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* - Applies syntax highlighting to code blocks
|
|
40
40
|
* - Supports watch mode for automatic rebuilding
|
|
41
41
|
*
|
|
42
|
-
* @version 1.
|
|
42
|
+
* @version 1.1.0
|
|
43
43
|
* @author UDX Team
|
|
44
44
|
* @copyright 2025
|
|
45
45
|
*/
|
|
@@ -50,6 +50,9 @@ import { marked } from 'marked';
|
|
|
50
50
|
import { program } from 'commander';
|
|
51
51
|
import chokidar from 'chokidar';
|
|
52
52
|
import Handlebars from 'handlebars';
|
|
53
|
+
import express from 'express';
|
|
54
|
+
import { createServer } from 'http';
|
|
55
|
+
import open from 'open';
|
|
53
56
|
|
|
54
57
|
// Custom renderer for handling math blocks
|
|
55
58
|
const renderer = new marked.Renderer();
|
|
@@ -86,24 +89,41 @@ const CHAPTER_NAV_STYLES_PATH = path.join(path.dirname(new URL(import.meta.url).
|
|
|
86
89
|
const SCRIPTS_PATH = path.join(path.dirname(new URL(import.meta.url).pathname), 'static/scripts.js');
|
|
87
90
|
|
|
88
91
|
program
|
|
89
|
-
.version('1.
|
|
92
|
+
.version('1.2.0')
|
|
90
93
|
.description('Convert markdown files to a single HTML document with Google Docs styling')
|
|
91
|
-
.option('-s, --src <
|
|
92
|
-
.option('-o, --out <file>', 'Output HTML file path')
|
|
94
|
+
.option('-s, --src <file>', 'Source markdown file or directory')
|
|
95
|
+
.option('-o, --out <file>', 'Output HTML file path (optional - defaults to ./output.html)')
|
|
93
96
|
.option('-w, --watch', 'Watch for changes and rebuild automatically', false)
|
|
94
97
|
.option('-d, --debug', 'Enable debug logging', false)
|
|
98
|
+
.option('-p, --preview', 'Open generated HTML in browser with live preview server', false)
|
|
99
|
+
.option('--port <number>', 'Port for preview server (default: random)', parseInt)
|
|
100
|
+
.addHelpText('after', `
|
|
101
|
+
Examples:
|
|
102
|
+
Basic conversion:
|
|
103
|
+
md2html -s content/docs
|
|
104
|
+
md2html --src=content/docs --out=output.html
|
|
105
|
+
|
|
106
|
+
Watch mode:
|
|
107
|
+
md2html -s content/docs --watch
|
|
108
|
+
|
|
109
|
+
Browser preview:
|
|
110
|
+
md2html -s content/docs --preview
|
|
111
|
+
md2html -s content/docs --preview --port 3000
|
|
112
|
+
|
|
113
|
+
Single file:
|
|
114
|
+
md2html -s document.md --preview`)
|
|
95
115
|
.parse(process.argv);
|
|
96
116
|
|
|
97
117
|
const options = program.opts();
|
|
98
118
|
|
|
99
|
-
if (!options.src
|
|
100
|
-
console.error('Error: Source
|
|
119
|
+
if (!options.src) {
|
|
120
|
+
console.error('Error: Source markdown file or directory is required');
|
|
101
121
|
program.help();
|
|
102
122
|
process.exit(1);
|
|
103
123
|
}
|
|
104
124
|
|
|
105
125
|
const srcPath = path.resolve(options.src);
|
|
106
|
-
const outputFile = path.resolve(options.out);
|
|
126
|
+
const outputFile = options.out ? path.resolve(options.out) : path.resolve('./output.html');
|
|
107
127
|
|
|
108
128
|
const debug = (message) => {
|
|
109
129
|
if (options.debug) {
|
|
@@ -647,6 +667,57 @@ async function buildHtml(srcDir, outputFile) {
|
|
|
647
667
|
}
|
|
648
668
|
}
|
|
649
669
|
|
|
670
|
+
/**
|
|
671
|
+
* Gets a random port between 3000-9999
|
|
672
|
+
*/
|
|
673
|
+
function getRandomPort() {
|
|
674
|
+
return Math.floor(Math.random() * (9999 - 3000 + 1)) + 3000;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Starts a preview server for the generated HTML
|
|
679
|
+
* @param {string} outputFile - Path to the HTML file to serve
|
|
680
|
+
* @param {number|null} port - Port to use (null for random)
|
|
681
|
+
* @returns {Promise<number>} The port the server is running on
|
|
682
|
+
*/
|
|
683
|
+
function startPreviewServer(outputFile, port = null) {
|
|
684
|
+
return new Promise((resolve, reject) => {
|
|
685
|
+
const app = express();
|
|
686
|
+
const targetPort = port || getRandomPort();
|
|
687
|
+
|
|
688
|
+
// Serve the generated HTML file at root
|
|
689
|
+
app.get('/', (req, res) => {
|
|
690
|
+
if (!fs.existsSync(outputFile)) {
|
|
691
|
+
res.status(404).send('<h1>HTML file not found</h1><p>Try rebuilding first</p>');
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
res.sendFile(path.resolve(outputFile));
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
// Serve any static assets if they exist
|
|
698
|
+
const staticDir = path.join(path.dirname(outputFile), 'assets');
|
|
699
|
+
if (fs.existsSync(staticDir)) {
|
|
700
|
+
app.use('/assets', express.static(staticDir));
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const server = createServer(app);
|
|
704
|
+
|
|
705
|
+
server.listen(targetPort, () => {
|
|
706
|
+
console.log(`š Preview server running at http://localhost:${targetPort}`);
|
|
707
|
+
resolve(targetPort);
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
server.on('error', (err) => {
|
|
711
|
+
if (err.code === 'EADDRINUSE' && !port) {
|
|
712
|
+
// If random port is in use, try another random port
|
|
713
|
+
startPreviewServer(outputFile, null).then(resolve).catch(reject);
|
|
714
|
+
} else {
|
|
715
|
+
reject(err);
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
|
|
650
721
|
/**
|
|
651
722
|
* Watches for changes in markdown files and rebuilds HTML
|
|
652
723
|
* @param {string} srcDir - Source directory containing markdown files
|
|
@@ -730,8 +801,28 @@ function watchMarkdown(srcDir, outputFile) {
|
|
|
730
801
|
});
|
|
731
802
|
}
|
|
732
803
|
|
|
733
|
-
//
|
|
734
|
-
if (options.
|
|
804
|
+
// Handle different execution modes
|
|
805
|
+
if (options.preview) {
|
|
806
|
+
// Preview mode: build HTML, start server, and optionally watch
|
|
807
|
+
buildHtml(srcPath, outputFile).then((success) => {
|
|
808
|
+
if (success) {
|
|
809
|
+
startPreviewServer(outputFile, options.port).then((port) => {
|
|
810
|
+
// Open browser
|
|
811
|
+
open(`http://localhost:${port}`);
|
|
812
|
+
|
|
813
|
+
if (options.watch) {
|
|
814
|
+
console.log('\nš Watching for file changes...');
|
|
815
|
+
watchMarkdown(srcPath, outputFile);
|
|
816
|
+
} else {
|
|
817
|
+
console.log('\nš” Use --watch flag to auto-rebuild on file changes');
|
|
818
|
+
console.log('Press Ctrl+C to stop the server');
|
|
819
|
+
}
|
|
820
|
+
}).catch((err) => {
|
|
821
|
+
console.error('Failed to start preview server:', err);
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
} else if (options.watch) {
|
|
735
826
|
watchMarkdown(srcPath, outputFile);
|
|
736
827
|
} else {
|
|
737
828
|
buildHtml(srcPath, outputFile);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@udx/md2html",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Magazine-quality Markdown to HTML converter with professional styling",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -34,8 +34,10 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"chokidar": "^3.5.3",
|
|
36
36
|
"commander": "^11.0.0",
|
|
37
|
+
"express": "^4.18.2",
|
|
37
38
|
"handlebars": "^4.7.8",
|
|
38
|
-
"marked": "^9.1.0"
|
|
39
|
+
"marked": "^9.1.0",
|
|
40
|
+
"open": "^9.1.0"
|
|
39
41
|
},
|
|
40
42
|
"engines": {
|
|
41
43
|
"node": ">=14.16"
|
package/static/view.hbs
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
|
|
49
49
|
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
|
50
50
|
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
|
51
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
|
|
51
52
|
<script>
|
|
52
53
|
tailwind.config = {
|
|
53
54
|
theme: {
|
|
@@ -301,6 +302,30 @@
|
|
|
301
302
|
});
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
// Initialize Mermaid diagrams
|
|
306
|
+
if (window.mermaid) {
|
|
307
|
+
mermaid.initialize({
|
|
308
|
+
startOnLoad: true,
|
|
309
|
+
theme: 'default',
|
|
310
|
+
securityLevel: 'loose',
|
|
311
|
+
fontFamily: 'inherit'
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Convert mermaid code blocks to diagrams
|
|
315
|
+
document.querySelectorAll('pre[data-file-type="mermaid"]').forEach((pre) => {
|
|
316
|
+
const code = pre.querySelector('code');
|
|
317
|
+
if (code) {
|
|
318
|
+
const mermaidDiv = document.createElement('div');
|
|
319
|
+
mermaidDiv.className = 'mermaid';
|
|
320
|
+
mermaidDiv.textContent = code.textContent;
|
|
321
|
+
pre.parentNode.replaceChild(mermaidDiv, pre);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Re-render after conversion
|
|
326
|
+
mermaid.init();
|
|
327
|
+
}
|
|
328
|
+
|
|
304
329
|
// Initialize the annotation system if available
|
|
305
330
|
if (window.ScienceUsability && typeof ScienceUsability.init === 'function') {
|
|
306
331
|
console.log('Initializing ScienceUsability annotation system...');
|