mrmd-js 2.0.1 → 2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mrmd-js",
3
- "version": "2.0.1",
3
+ "version": "2.2.0",
4
4
  "description": "MRP-compliant browser JavaScript runtime for mrmd notebooks",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -21,12 +21,14 @@ export {
21
21
  scopeStyles,
22
22
  generateScopeClass,
23
23
  } from './css.js';
24
+ export { MermaidExecutor, createMermaidExecutor } from './mermaid.js';
24
25
 
25
26
  // Import for factory function
26
27
  import { ExecutorRegistry } from './registry.js';
27
28
  import { JavaScriptExecutor } from './javascript.js';
28
29
  import { HtmlExecutor } from './html.js';
29
30
  import { CssExecutor } from './css.js';
31
+ import { MermaidExecutor } from './mermaid.js';
30
32
 
31
33
  /**
32
34
  * Create a registry with default executors registered
@@ -37,5 +39,6 @@ export function createDefaultExecutorRegistry() {
37
39
  registry.register(new JavaScriptExecutor());
38
40
  registry.register(new HtmlExecutor());
39
41
  registry.register(new CssExecutor());
42
+ registry.register(new MermaidExecutor());
40
43
  return registry;
41
44
  }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Mermaid Executor
3
+ *
4
+ * Executes Mermaid diagram cells by rendering them to SVG.
5
+ * Loads mermaid from CDN on first use and returns HTML displayData.
6
+ *
7
+ * @module execute/mermaid
8
+ */
9
+
10
+ import { BaseExecutor } from './interface.js';
11
+
12
+ /**
13
+ * @typedef {import('../session/context/interface.js').ExecutionContext} ExecutionContext
14
+ * @typedef {import('../types/execution.js').ExecuteOptions} ExecuteOptions
15
+ * @typedef {import('../types/execution.js').ExecutionResult} ExecutionResult
16
+ * @typedef {import('../types/execution.js').DisplayData} DisplayData
17
+ */
18
+
19
+ /** CDN URL for mermaid */
20
+ const MERMAID_CDN = 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js';
21
+
22
+ /** Counter for unique diagram IDs */
23
+ let diagramCounter = 0;
24
+
25
+ /**
26
+ * Load mermaid from CDN if not already loaded
27
+ * @returns {Promise<void>}
28
+ */
29
+ async function ensureMermaidLoaded() {
30
+ // Check if already loaded
31
+ if (typeof window !== 'undefined' && window.mermaid) {
32
+ return;
33
+ }
34
+
35
+ // Load from CDN
36
+ return new Promise((resolve, reject) => {
37
+ const script = document.createElement('script');
38
+ script.src = MERMAID_CDN;
39
+ script.onload = () => {
40
+ // Initialize mermaid with safe defaults
41
+ window.mermaid.initialize({
42
+ startOnLoad: false,
43
+ theme: 'default',
44
+ securityLevel: 'loose', // Allow clicks/links in diagrams
45
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
46
+ });
47
+ resolve();
48
+ };
49
+ script.onerror = () => reject(new Error('Failed to load mermaid from CDN'));
50
+ document.head.appendChild(script);
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Mermaid executor - renders Mermaid diagrams to SVG
56
+ */
57
+ export class MermaidExecutor extends BaseExecutor {
58
+ /** @type {readonly string[]} */
59
+ languages = ['mermaid'];
60
+
61
+ /**
62
+ * Execute Mermaid diagram cell
63
+ * @param {string} code - Mermaid diagram definition
64
+ * @param {ExecutionContext} context - Execution context
65
+ * @param {ExecuteOptions} [options] - Execution options
66
+ * @returns {Promise<ExecutionResult>}
67
+ */
68
+ async execute(code, context, options = {}) {
69
+ const startTime = performance.now();
70
+
71
+ try {
72
+ // Ensure mermaid is loaded
73
+ await ensureMermaidLoaded();
74
+
75
+ // Generate unique ID for this diagram
76
+ const diagramId = `mermaid-diagram-${++diagramCounter}`;
77
+
78
+ // Render the diagram
79
+ const { svg } = await window.mermaid.render(diagramId, code.trim());
80
+
81
+ const duration = performance.now() - startTime;
82
+
83
+ // Build display data with the rendered SVG
84
+ /** @type {DisplayData[]} */
85
+ const displayData = [
86
+ {
87
+ data: {
88
+ 'text/html': svg,
89
+ 'text/plain': `[Mermaid diagram rendered]`,
90
+ },
91
+ metadata: {
92
+ mermaid: true,
93
+ diagramId,
94
+ },
95
+ },
96
+ ];
97
+
98
+ return {
99
+ success: true,
100
+ stdout: '',
101
+ stderr: '',
102
+ result: undefined,
103
+ displayData,
104
+ assets: [],
105
+ executionCount: 0,
106
+ duration,
107
+ };
108
+ } catch (error) {
109
+ const duration = performance.now() - startTime;
110
+ const errorMessage = error instanceof Error ? error.message : String(error);
111
+
112
+ // Return error as stderr with helpful message
113
+ return {
114
+ success: false,
115
+ stdout: '',
116
+ stderr: `Mermaid rendering error: ${errorMessage}`,
117
+ result: undefined,
118
+ error: {
119
+ type: 'MermaidError',
120
+ message: errorMessage,
121
+ },
122
+ displayData: [],
123
+ assets: [],
124
+ executionCount: 0,
125
+ duration,
126
+ };
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Create a Mermaid executor
133
+ * @returns {MermaidExecutor}
134
+ */
135
+ export function createMermaidExecutor() {
136
+ return new MermaidExecutor();
137
+ }
package/src/index.js CHANGED
@@ -66,6 +66,9 @@ export {
66
66
  createCssExecutor,
67
67
  scopeStyles,
68
68
  generateScopeClass,
69
+ // Mermaid
70
+ MermaidExecutor,
71
+ createMermaidExecutor,
69
72
  } from './execute/index.js';
70
73
 
71
74
  // LSP Features (Phase 4)