prev-cli 0.1.8 → 0.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": "prev-cli",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "description": "Transform MDX directories into beautiful documentation websites",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -3,13 +3,56 @@ import { Outlet, useLocation } from 'react-router-dom'
3
3
  import { Sidebar } from './Sidebar'
4
4
  import './styles.css'
5
5
 
6
+ // Simple hash function for cache keys
7
+ function hashCode(str: string): string {
8
+ let hash = 0
9
+ for (let i = 0; i < str.length; i++) {
10
+ const char = str.charCodeAt(i)
11
+ hash = ((hash << 5) - hash) + char
12
+ hash = hash & hash // Convert to 32bit integer
13
+ }
14
+ return hash.toString(36)
15
+ }
16
+
17
+ // In-memory cache for current session
18
+ const memoryCache = new Map<string, string>()
19
+
20
+ // Get cached SVG (memory first, then localStorage)
21
+ function getCachedSvg(type: string, code: string): string | null {
22
+ const key = `prev-diagram-${type}-${hashCode(code)}`
23
+
24
+ // Check memory cache first
25
+ if (memoryCache.has(key)) {
26
+ return memoryCache.get(key)!
27
+ }
28
+
29
+ // Check localStorage
30
+ try {
31
+ const cached = localStorage.getItem(key)
32
+ if (cached) {
33
+ memoryCache.set(key, cached) // Populate memory cache
34
+ return cached
35
+ }
36
+ } catch {}
37
+
38
+ return null
39
+ }
40
+
41
+ // Cache SVG (both memory and localStorage)
42
+ function cacheSvg(type: string, code: string, svg: string): void {
43
+ const key = `prev-diagram-${type}-${hashCode(code)}`
44
+ memoryCache.set(key, svg)
45
+ try {
46
+ localStorage.setItem(key, svg)
47
+ } catch {} // Ignore quota errors
48
+ }
49
+
6
50
  // Lazy-load and render mermaid diagrams
7
51
  async function renderMermaidDiagrams() {
8
52
  const codeBlocks = document.querySelectorAll('code.language-mermaid, code.hljs.language-mermaid')
9
53
  if (codeBlocks.length === 0) return
10
54
 
11
- const mermaid = await import('mermaid')
12
- mermaid.default.initialize({ startOnLoad: false, theme: 'neutral' })
55
+ let mermaidModule: any = null
13
56
 
14
57
  for (const block of codeBlocks) {
15
58
  const pre = block.parentElement as HTMLElement
@@ -20,10 +63,25 @@ async function renderMermaidDiagrams() {
20
63
  const container = document.createElement('div')
21
64
  container.className = 'mermaid-diagram'
22
65
 
66
+ // Check cache first
67
+ const cached = getCachedSvg('mermaid', code)
68
+ if (cached) {
69
+ container.innerHTML = cached
70
+ pre.style.display = 'none'
71
+ pre.insertAdjacentElement('afterend', container)
72
+ continue
73
+ }
74
+
75
+ // Load mermaid only if needed
76
+ if (!mermaidModule) {
77
+ mermaidModule = await import('mermaid')
78
+ mermaidModule.default.initialize({ startOnLoad: false, theme: 'neutral' })
79
+ }
80
+
23
81
  try {
24
- const { svg } = await mermaid.default.render(`mermaid-${Math.random().toString(36).slice(2)}`, code)
82
+ const { svg } = await mermaidModule.default.render(`mermaid-${Math.random().toString(36).slice(2)}`, code)
25
83
  container.innerHTML = svg
26
- // Hide original instead of replacing (avoids React DOM conflicts)
84
+ cacheSvg('mermaid', code, svg)
27
85
  pre.style.display = 'none'
28
86
  pre.insertAdjacentElement('afterend', container)
29
87
  } catch (e) {
@@ -37,33 +95,48 @@ async function renderD2Diagrams() {
37
95
  const codeBlocks = document.querySelectorAll('code.language-d2, code.hljs.language-d2')
38
96
  if (codeBlocks.length === 0) return
39
97
 
40
- try {
41
- const d2Module = await import('@terrastruct/d2')
42
- const { D2 } = d2Module
43
- const d2 = new D2()
98
+ let d2Instance: any = null
44
99
 
45
- for (const block of codeBlocks) {
46
- const pre = block.parentElement as HTMLElement
47
- if (!pre || pre.dataset.rendered) continue
48
- pre.dataset.rendered = 'true'
100
+ for (const block of codeBlocks) {
101
+ const pre = block.parentElement as HTMLElement
102
+ if (!pre || pre.dataset.rendered) continue
103
+ pre.dataset.rendered = 'true'
49
104
 
50
- const code = block.textContent || ''
51
- const container = document.createElement('div')
52
- container.className = 'd2-diagram'
105
+ const code = block.textContent || ''
106
+ const container = document.createElement('div')
107
+ container.className = 'd2-diagram'
53
108
 
109
+ // Check cache first
110
+ const cached = getCachedSvg('d2', code)
111
+ if (cached) {
112
+ container.innerHTML = cached
113
+ pre.style.display = 'none'
114
+ pre.insertAdjacentElement('afterend', container)
115
+ continue
116
+ }
117
+
118
+ // Load D2 only if needed
119
+ if (!d2Instance) {
54
120
  try {
55
- const result = await d2.compile(code)
56
- const svg = await d2.render(result.diagram, result.renderOptions)
57
- container.innerHTML = svg
58
- // Hide original instead of replacing (avoids React DOM conflicts)
59
- pre.style.display = 'none'
60
- pre.insertAdjacentElement('afterend', container)
121
+ const d2Module = await import('@terrastruct/d2')
122
+ const { D2 } = d2Module
123
+ d2Instance = new D2()
61
124
  } catch (e) {
62
- console.error('D2 render error:', e)
125
+ console.error('D2 library load error:', e)
126
+ return
63
127
  }
64
128
  }
65
- } catch (e) {
66
- console.error('D2 library load error:', e)
129
+
130
+ try {
131
+ const result = await d2Instance.compile(code)
132
+ const svg = await d2Instance.render(result.diagram, result.renderOptions)
133
+ container.innerHTML = svg
134
+ cacheSvg('d2', code, svg)
135
+ pre.style.display = 'none'
136
+ pre.insertAdjacentElement('afterend', container)
137
+ } catch (e) {
138
+ console.error('D2 render error:', e)
139
+ }
67
140
  }
68
141
  }
69
142