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 CHANGED
@@ -453,7 +453,7 @@ async function main() {
453
453
  }
454
454
 
455
455
  if (values.version) {
456
- console.log('mdv v0.3.3');
456
+ console.log('mdv v0.5.0');
457
457
  process.exit(0);
458
458
  }
459
459
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdv-live",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "Markdown Viewer - File tree + Live preview + Marp support + Hot reload",
5
5
  "main": "src/server.js",
6
6
  "bin": {
package/src/api/file.js CHANGED
@@ -160,7 +160,8 @@ export function setupFileRoutes(app) {
160
160
  });
161
161
  }
162
162
 
163
- const rendered = await renderFile(fullPath);
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') {
@@ -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.3.3';
20
+ const VERSION = '0.5.0';
21
21
 
22
22
  /**
23
23
  * Setup API routes for the Express app