sdocs 0.0.35 → 0.0.36
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/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.0.36] - 2026-07-03
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Usage code is syntax-highlighted in static builds.** The usage snippet
|
|
15
|
+
regenerates in the browser as controls change and used to be highlighted
|
|
16
|
+
through a dev-server endpoint — deployed builds fell back to plain text.
|
|
17
|
+
Highlighting now runs client-side (lazy-loaded Shiki with the JavaScript
|
|
18
|
+
regex engine), identical on the dev server and any static host; the
|
|
19
|
+
dev-server endpoint is gone.
|
|
20
|
+
|
|
10
21
|
## [0.0.35] - 2026-07-03
|
|
11
22
|
|
|
12
23
|
### Fixed
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Client-side Shiki for code that's generated in the browser (the usage
|
|
2
|
+
// snippet re-renders as controls change). Everything loads lazily on first
|
|
3
|
+
// use so the Explorer bundle stays lean, and the JavaScript regex engine
|
|
4
|
+
// avoids shipping wasm — highlighting works the same on the dev server and
|
|
5
|
+
// in static builds.
|
|
6
|
+
let highlighterPromise;
|
|
7
|
+
async function getHighlighter() {
|
|
8
|
+
highlighterPromise ??= (async () => {
|
|
9
|
+
const [{ createHighlighterCore }, { createJavaScriptRegexEngine }, { bundledLanguages }, { bundledThemes }] = await Promise.all([
|
|
10
|
+
import('shiki/core'),
|
|
11
|
+
import('shiki/engine/javascript'),
|
|
12
|
+
import('shiki/langs'),
|
|
13
|
+
import('shiki/themes'),
|
|
14
|
+
]);
|
|
15
|
+
return createHighlighterCore({
|
|
16
|
+
langs: [bundledLanguages.svelte],
|
|
17
|
+
themes: [bundledThemes['github-light'], bundledThemes['github-dark']],
|
|
18
|
+
engine: createJavaScriptRegexEngine({ forgiving: true }),
|
|
19
|
+
});
|
|
20
|
+
})();
|
|
21
|
+
return highlighterPromise;
|
|
22
|
+
}
|
|
23
|
+
/** Highlight Svelte code, matching the build-time highlighter's output shape */
|
|
24
|
+
export async function highlightSvelte(code) {
|
|
25
|
+
const highlighter = await getHighlighter();
|
|
26
|
+
return highlighter.codeToHtml(code, {
|
|
27
|
+
lang: 'svelte',
|
|
28
|
+
themes: {
|
|
29
|
+
light: 'github-light',
|
|
30
|
+
dark: 'github-dark',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { DocEntry } from '../../types.js';
|
|
3
3
|
import { Icon } from '../../ui/Icon/index.js';
|
|
4
|
+
import { highlightSvelte } from '../highlighter.js';
|
|
4
5
|
import CollapsiblePanel from './CollapsiblePanel.svelte';
|
|
5
6
|
import PreviewFrame from './PreviewFrame.svelte';
|
|
6
7
|
import ControlsPanel from './ControlsPanel.svelte';
|
|
@@ -169,36 +170,20 @@
|
|
|
169
170
|
return generateFallbackCode(componentName, propValues, cssValues);
|
|
170
171
|
});
|
|
171
172
|
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
173
|
+
// Usage code is generated in the browser, so it's highlighted client-side
|
|
174
|
+
// (lazy Shiki — see ../highlighter.ts). Debounced while controls change;
|
|
175
|
+
// stale results are dropped.
|
|
175
176
|
let highlightedUsageHtml = $state('');
|
|
176
177
|
let highlightTimer: ReturnType<typeof setTimeout> | undefined;
|
|
177
|
-
let highlightAvailable = true;
|
|
178
178
|
|
|
179
179
|
$effect(() => {
|
|
180
180
|
const code = usageCode;
|
|
181
181
|
clearTimeout(highlightTimer);
|
|
182
|
-
if (!highlightAvailable) {
|
|
183
|
-
highlightedUsageHtml = '';
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
182
|
highlightTimer = setTimeout(async () => {
|
|
187
183
|
try {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
headers: { 'Content-Type': 'application/json' },
|
|
191
|
-
body: JSON.stringify({ code, lang: 'svelte' }),
|
|
192
|
-
});
|
|
193
|
-
if (res.ok) {
|
|
194
|
-
const { html } = await res.json();
|
|
195
|
-
highlightedUsageHtml = html;
|
|
196
|
-
} else {
|
|
197
|
-
highlightAvailable = false;
|
|
198
|
-
highlightedUsageHtml = '';
|
|
199
|
-
}
|
|
184
|
+
const html = await highlightSvelte(code);
|
|
185
|
+
if (code === usageCode) highlightedUsageHtml = html;
|
|
200
186
|
} catch {
|
|
201
|
-
highlightAvailable = false;
|
|
202
187
|
highlightedUsageHtml = '';
|
|
203
188
|
}
|
|
204
189
|
}, 150);
|
package/dist/vite.js
CHANGED
|
@@ -72,25 +72,6 @@ export function sdocsPlugin(userConfig) {
|
|
|
72
72
|
res.end('Internal error');
|
|
73
73
|
});
|
|
74
74
|
});
|
|
75
|
-
// API: highlight code on demand
|
|
76
|
-
server.middlewares.use((req, res, next) => {
|
|
77
|
-
if (req.url !== '/__sdocs/highlight' || req.method !== 'POST')
|
|
78
|
-
return next();
|
|
79
|
-
let body = '';
|
|
80
|
-
req.on('data', (chunk) => { body += chunk; });
|
|
81
|
-
req.on('end', async () => {
|
|
82
|
-
try {
|
|
83
|
-
const { code, lang } = JSON.parse(body);
|
|
84
|
-
const html = await highlight(code, lang);
|
|
85
|
-
res.setHeader('Content-Type', 'application/json');
|
|
86
|
-
res.end(JSON.stringify({ html }));
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
res.statusCode = 400;
|
|
90
|
-
res.end('Invalid request');
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
75
|
// Watch for .sdoc file add/unlink/change
|
|
95
76
|
server.watcher.on('add', async (filePath) => {
|
|
96
77
|
if (isDocFile(filePath)) {
|