mdv-live 0.4.4 → 0.5.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/bin/mdv.js +1 -1
- package/package.json +1 -1
- package/src/api/file.js +2 -1
- package/src/rendering/index.js +26 -5
- package/src/rendering/markdown.js +0 -12
- package/src/server.js +1 -1
package/bin/mdv.js
CHANGED
package/package.json
CHANGED
package/src/api/file.js
CHANGED
|
@@ -160,7 +160,8 @@ export function setupFileRoutes(app) {
|
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
const
|
|
163
|
+
const relativeDir = path.dirname(relativePath);
|
|
164
|
+
const rendered = await renderFile(fullPath, relativeDir === '.' ? '' : relativeDir);
|
|
164
165
|
res.json({ name, ...rendered });
|
|
165
166
|
} catch (err) {
|
|
166
167
|
if (err.code === 'ENOENT') {
|
package/src/rendering/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import fs from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
6
7
|
import { getFileType } from '../utils/fileTypes.js';
|
|
7
8
|
import { renderMarkdown, isMarp } from './markdown.js';
|
|
8
9
|
import { renderMarp } from './marp.js';
|
|
@@ -43,17 +44,36 @@ function renderText(content) {
|
|
|
43
44
|
return `<pre class="plain-text">${escaped}</pre>`;
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Rewrite relative image/video/audio src paths to /raw/ URLs
|
|
49
|
+
* @param {string} html - Rendered HTML
|
|
50
|
+
* @param {string} relativeDir - Directory of the source file relative to rootDir
|
|
51
|
+
* @returns {string} HTML with rewritten paths
|
|
52
|
+
*/
|
|
53
|
+
function rewriteMediaPaths(html, relativeDir) {
|
|
54
|
+
// Match src="..." that are not absolute URLs or data URIs
|
|
55
|
+
return html.replace(
|
|
56
|
+
/(<(?:img|video|audio|source)\s[^>]*?\bsrc=")([^"]+)(")/gi,
|
|
57
|
+
(match, before, src, after) => {
|
|
58
|
+
if (/^(https?:\/\/|data:|\/raw\/|\/)/.test(src)) return match;
|
|
59
|
+
const resolved = relativeDir ? `${relativeDir}/${src}` : src;
|
|
60
|
+
return `${before}/raw/${resolved}${after}`;
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
/**
|
|
47
66
|
* Render a file and return content for the frontend
|
|
48
67
|
* @param {string} filePath - Full path to the file
|
|
68
|
+
* @param {string} [relativeDir] - Directory of the file relative to rootDir (for resolving relative paths)
|
|
49
69
|
* @returns {Promise<Object>} Rendered content and metadata
|
|
50
70
|
*/
|
|
51
|
-
export async function renderFile(filePath) {
|
|
71
|
+
export async function renderFile(filePath, relativeDir) {
|
|
52
72
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
53
73
|
const fileType = getFileType(filePath);
|
|
54
74
|
|
|
55
75
|
if (fileType.type === 'markdown') {
|
|
56
|
-
return renderMarkdownFile(content);
|
|
76
|
+
return renderMarkdownFile(content, relativeDir);
|
|
57
77
|
}
|
|
58
78
|
|
|
59
79
|
if (fileType.type === 'code') {
|
|
@@ -74,13 +94,14 @@ export async function renderFile(filePath) {
|
|
|
74
94
|
/**
|
|
75
95
|
* Render markdown content, detecting Marp presentations
|
|
76
96
|
* @param {string} content - Raw markdown content
|
|
97
|
+
* @param {string} [relativeDir] - Directory relative to rootDir for resolving image paths
|
|
77
98
|
* @returns {Object} Rendered content and metadata
|
|
78
99
|
*/
|
|
79
|
-
function renderMarkdownFile(content) {
|
|
100
|
+
function renderMarkdownFile(content, relativeDir) {
|
|
80
101
|
if (isMarp(content)) {
|
|
81
102
|
const { html, css } = renderMarp(content);
|
|
82
103
|
return {
|
|
83
|
-
content: html,
|
|
104
|
+
content: rewriteMediaPaths(html, relativeDir),
|
|
84
105
|
css,
|
|
85
106
|
raw: content,
|
|
86
107
|
fileType: 'markdown',
|
|
@@ -89,7 +110,7 @@ function renderMarkdownFile(content) {
|
|
|
89
110
|
}
|
|
90
111
|
|
|
91
112
|
return {
|
|
92
|
-
content: renderMarkdown(content),
|
|
113
|
+
content: rewriteMediaPaths(renderMarkdown(content), relativeDir),
|
|
93
114
|
raw: content,
|
|
94
115
|
fileType: 'markdown',
|
|
95
116
|
isMarp: false
|
|
@@ -26,9 +26,6 @@ const MARP_PATTERN = /^---\s*\n[\s\S]*?marp:\s*true[\s\S]*?\n---/;
|
|
|
26
26
|
// Pattern to detect YAML frontmatter at start of file
|
|
27
27
|
const FRONTMATTER_PATTERN = /^---\s*\n([\s\S]*?)\n---\s*(\n|$)/;
|
|
28
28
|
|
|
29
|
-
// Pattern to detect metadata block after h1 heading (Claude Agent format)
|
|
30
|
-
const HEADING_METADATA_PATTERN = /^(#[^\n]+\n+)(---\s*\n)([\s\S]*?)(\n---\s*)(\n|$)/;
|
|
31
|
-
|
|
32
29
|
// Pattern for Mermaid code blocks
|
|
33
30
|
const MERMAID_PATTERN = /```mermaid\s*\n([\s\S]*?)\n```/g;
|
|
34
31
|
|
|
@@ -55,15 +52,6 @@ function convertFrontmatter(content) {
|
|
|
55
52
|
return `\`\`\`yaml\n${frontmatter}\n\`\`\`\n${rest}`;
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
// Check for metadata block after h1 heading (Claude Agent format)
|
|
59
|
-
const headingMatch = content.match(HEADING_METADATA_PATTERN);
|
|
60
|
-
if (headingMatch) {
|
|
61
|
-
const heading = headingMatch[1];
|
|
62
|
-
const metadata = headingMatch[3];
|
|
63
|
-
const rest = content.slice(headingMatch[0].length);
|
|
64
|
-
return `${heading}\`\`\`yaml\n${metadata}\n\`\`\`\n${rest}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
55
|
return content;
|
|
68
56
|
}
|
|
69
57
|
|
package/src/server.js
CHANGED
|
@@ -17,7 +17,7 @@ import { setupWebSocket } from './websocket.js';
|
|
|
17
17
|
|
|
18
18
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
19
|
const STATIC_DIR = path.join(__dirname, 'static');
|
|
20
|
-
const VERSION = '0.
|
|
20
|
+
const VERSION = '0.5.0';
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Setup API routes for the Express app
|