astro-mermaid 1.1.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/astro-mermaid-integration.js +64 -6
- package/package.json +18 -3
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { resolve } from 'import-meta-resolve';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to HTML-escape text content
|
|
5
|
+
* This ensures HTML tags in mermaid diagrams are preserved as text
|
|
6
|
+
*/
|
|
7
|
+
function escapeHtml(text) {
|
|
8
|
+
const htmlEntities = {
|
|
9
|
+
'&': '&',
|
|
10
|
+
'<': '<',
|
|
11
|
+
'>': '>',
|
|
12
|
+
'"': '"',
|
|
13
|
+
"'": '''
|
|
14
|
+
};
|
|
15
|
+
return text.replace(/[&<>"']/g, char => htmlEntities[char]);
|
|
16
|
+
}
|
|
17
|
+
|
|
3
18
|
/**
|
|
4
19
|
* Remark plugin to transform mermaid code blocks at the markdown level
|
|
5
20
|
*/
|
|
@@ -13,10 +28,10 @@ function remarkMermaidPlugin(options = {}) {
|
|
|
13
28
|
if (node.lang === 'mermaid') {
|
|
14
29
|
mermaidCount++;
|
|
15
30
|
|
|
16
|
-
// Transform to html node with pre.mermaid
|
|
31
|
+
// Transform to html node with pre.mermaid, escaping HTML content
|
|
17
32
|
const htmlNode = {
|
|
18
33
|
type: 'html',
|
|
19
|
-
value: `<pre class="mermaid">${node.value}</pre>`
|
|
34
|
+
value: `<pre class="mermaid">${escapeHtml(node.value)}</pre>`
|
|
20
35
|
};
|
|
21
36
|
|
|
22
37
|
// Replace the code node with html node
|
|
@@ -36,6 +51,49 @@ function remarkMermaidPlugin(options = {}) {
|
|
|
36
51
|
};
|
|
37
52
|
}
|
|
38
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Helper function to serialize HAST nodes back to HTML text
|
|
56
|
+
* This preserves HTML tags within the mermaid content
|
|
57
|
+
*/
|
|
58
|
+
function serializeHastChildren(children) {
|
|
59
|
+
let result = '';
|
|
60
|
+
|
|
61
|
+
for (const child of children) {
|
|
62
|
+
if (child.type === 'text') {
|
|
63
|
+
result += child.value;
|
|
64
|
+
} else if (child.type === 'element') {
|
|
65
|
+
// Reconstruct the HTML tag
|
|
66
|
+
const tagName = child.tagName;
|
|
67
|
+
const selfClosing = ['br', 'hr', 'img', 'input', 'meta', 'link'].includes(tagName);
|
|
68
|
+
|
|
69
|
+
result += `<${tagName}`;
|
|
70
|
+
|
|
71
|
+
// Add attributes if any
|
|
72
|
+
if (child.properties) {
|
|
73
|
+
for (const [key, value] of Object.entries(child.properties)) {
|
|
74
|
+
if (key !== 'className') {
|
|
75
|
+
result += ` ${key}="${value}"`;
|
|
76
|
+
} else if (Array.isArray(value)) {
|
|
77
|
+
result += ` class="${value.join(' ')}"`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (selfClosing) {
|
|
83
|
+
result += '/>';
|
|
84
|
+
} else {
|
|
85
|
+
result += '>';
|
|
86
|
+
if (child.children && child.children.length > 0) {
|
|
87
|
+
result += serializeHastChildren(child.children);
|
|
88
|
+
}
|
|
89
|
+
result += `</${tagName}>`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
39
97
|
/**
|
|
40
98
|
* Rehype plugin to transform mermaid code blocks
|
|
41
99
|
* Converts ```mermaid code blocks to <pre class="mermaid">
|
|
@@ -43,7 +101,6 @@ function remarkMermaidPlugin(options = {}) {
|
|
|
43
101
|
function rehypeMermaidPlugin(options = {}) {
|
|
44
102
|
return async function transformer(tree, file) {
|
|
45
103
|
const { visit } = await import('unist-util-visit');
|
|
46
|
-
const { toString } = await import('mdast-util-to-string');
|
|
47
104
|
|
|
48
105
|
let mermaidCount = 0;
|
|
49
106
|
|
|
@@ -59,8 +116,8 @@ function rehypeMermaidPlugin(options = {}) {
|
|
|
59
116
|
|
|
60
117
|
if (Array.isArray(className) && className.includes('language-mermaid')) {
|
|
61
118
|
mermaidCount++;
|
|
62
|
-
// Get the mermaid diagram content
|
|
63
|
-
const diagramContent =
|
|
119
|
+
// Get the mermaid diagram content, preserving HTML tags
|
|
120
|
+
const diagramContent = serializeHastChildren(codeNode.children || []);
|
|
64
121
|
|
|
65
122
|
// Transform to <pre class="mermaid">
|
|
66
123
|
node.properties = {
|
|
@@ -68,9 +125,10 @@ function rehypeMermaidPlugin(options = {}) {
|
|
|
68
125
|
className: ['mermaid']
|
|
69
126
|
};
|
|
70
127
|
|
|
128
|
+
// Escape HTML to preserve it as text content
|
|
71
129
|
node.children = [{
|
|
72
130
|
type: 'text',
|
|
73
|
-
value: diagramContent
|
|
131
|
+
value: escapeHtml(diagramContent)
|
|
74
132
|
}];
|
|
75
133
|
|
|
76
134
|
if (options.logger) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-mermaid",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "An Astro integration for rendering Mermaid diagrams with automatic theme switching and client-side rendering",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./astro-mermaid-integration.js",
|
|
@@ -39,15 +39,30 @@
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"@anthropic-ai/claude-code": "^1.0.128",
|
|
42
43
|
"import-meta-resolve": "^4.2.0",
|
|
43
44
|
"mdast-util-to-string": "^4.0.0",
|
|
44
45
|
"unist-util-visit": "^5.0.0"
|
|
45
46
|
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"claude": "claude",
|
|
49
|
+
"test": "vitest",
|
|
50
|
+
"test:ui": "vitest --ui",
|
|
51
|
+
"test:coverage": "vitest --coverage"
|
|
52
|
+
},
|
|
46
53
|
"devDependencies": {
|
|
47
54
|
"@types/hast": "^3.0.4",
|
|
55
|
+
"@vitest/ui": "^3.2.4",
|
|
48
56
|
"astro": "^5.0.0",
|
|
57
|
+
"hast-util-from-html": "^2.0.3",
|
|
49
58
|
"mermaid": "^11.0.0",
|
|
50
|
-
"
|
|
59
|
+
"rehype-parse": "^9.0.1",
|
|
60
|
+
"rehype-stringify": "^10.0.1",
|
|
61
|
+
"remark-mermaid": "^0.2.0",
|
|
62
|
+
"remark-parse": "^11.0.0",
|
|
63
|
+
"typescript": "^5.0.0",
|
|
64
|
+
"unified": "^11.0.5",
|
|
65
|
+
"vitest": "^3.2.4"
|
|
51
66
|
},
|
|
52
67
|
"repository": {
|
|
53
68
|
"type": "git",
|
|
@@ -57,4 +72,4 @@
|
|
|
57
72
|
"bugs": {
|
|
58
73
|
"url": "https://github.com/joesaby/astro-mermaid/issues"
|
|
59
74
|
}
|
|
60
|
-
}
|
|
75
|
+
}
|