void-plugin-hono-jsx 0.1.0-rc.1 → 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.
Files changed (40) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +29 -23
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/dist/plugins/hono-islands.d.ts.map +1 -1
  5. package/dist/plugins/hono-islands.js +11 -3
  6. package/dist/plugins/hono-islands.js.map +1 -1
  7. package/dist/plugins/hono-markdown.d.ts +3 -1
  8. package/dist/plugins/hono-markdown.d.ts.map +1 -1
  9. package/dist/plugins/hono-markdown.js +13 -6
  10. package/dist/plugins/hono-markdown.js.map +1 -1
  11. package/dist/plugins/markdown-compiler.d.ts +65 -2
  12. package/dist/plugins/markdown-compiler.d.ts.map +1 -1
  13. package/dist/plugins/markdown-compiler.js +54 -40
  14. package/dist/plugins/markdown-compiler.js.map +1 -1
  15. package/dist/plugins/markdown-copy.d.ts +3 -0
  16. package/dist/plugins/markdown-copy.d.ts.map +1 -0
  17. package/dist/plugins/markdown-copy.js +31 -0
  18. package/dist/plugins/markdown-copy.js.map +1 -0
  19. package/dist/plugins/markdown-features.d.ts +12 -0
  20. package/dist/plugins/markdown-features.d.ts.map +1 -0
  21. package/dist/plugins/markdown-features.js +56 -0
  22. package/dist/plugins/markdown-features.js.map +1 -0
  23. package/dist/theme/code.css +202 -0
  24. package/dist/theme/containers.css +125 -0
  25. package/dist/theme/content.css +4 -0
  26. package/dist/theme/index.css +7 -0
  27. package/dist/theme/prose.css +294 -0
  28. package/dist/theme/reset.css +100 -0
  29. package/package.json +20 -2
  30. package/src/plugins/hono-islands.ts +11 -3
  31. package/src/plugins/hono-markdown.ts +15 -8
  32. package/src/plugins/markdown-compiler.ts +46 -30
  33. package/src/plugins/markdown-copy.ts +30 -0
  34. package/src/plugins/markdown-features.ts +57 -0
  35. package/src/theme/code.css +202 -0
  36. package/src/theme/containers.css +125 -0
  37. package/src/theme/content.css +4 -0
  38. package/src/theme/index.css +7 -0
  39. package/src/theme/prose.css +294 -0
  40. package/src/theme/reset.css +100 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0...v0.2.0) (2026-10-18)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * Markdown projects must add markdown-it-container, shiki and @shikijs/transformers peers. Fenced code now includes copy controls and a page-local module by default, matching the official framework plugins. See docs/markdown.md for migration.
9
+
10
+ ### Features
11
+
12
+ * align Hono Markdown code and themes with official plugins ([#114](https://github.com/ts-76/void-plugin-hono-jsx/issues/114)) ([757ec0c](https://github.com/ts-76/void-plugin-hono-jsx/commit/757ec0cf66192ad6e464585ed9428a2b7309218c))
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * align published release docs and dry-run validation ([#112](https://github.com/ts-76/void-plugin-hono-jsx/issues/112)) ([96d242c](https://github.com/ts-76/void-plugin-hono-jsx/commit/96d242c771c76c3eddbd73c040327a18acb36930))
18
+
19
+ ## [0.1.0](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-rc.1...v0.1.0) (2026-10-18)
20
+
21
+
22
+ ### Documentation
23
+
24
+ * prepare grouped 0.1.0 normal release ([3d1c3b8](https://github.com/ts-76/void-plugin-hono-jsx/commit/3d1c3b8a323103bcd78ed2716f4d4ecaa5dcf6dd))
25
+ * record RC.1 Workers verification and cleanup ([#109](https://github.com/ts-76/void-plugin-hono-jsx/issues/109)) ([54c0441](https://github.com/ts-76/void-plugin-hono-jsx/commit/54c0441a1d70fee55cad36a41f30f3308048e1f2))
26
+
3
27
  ## [0.1.0-rc.1](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-rc.0...v0.1.0-rc.1) (2026-10-17)
4
28
 
5
29
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Experimental Hono Pages adapter for Void
1
+ # Hono JSX adapter for Void Pages
2
2
 
3
- This package integrates Hono JSX with Void Pages. This source documents the upcoming 0.1.0 RC/normal release; published alpha.4 has a different compatibility contract. Prereleases use `next`; normal releases move to `latest` after public verification. Before registry approval, use a local tarball. The package is [MIT licensed](LICENSE) and is not an official Void adapter.
3
+ This package integrates Hono JSX with Void Pages. The normal 0.1.x series is published under the [MIT license](LICENSE). Install the default package below; `latest` selects the publicly verified normal release. `next` may select a prerelease during later release cycles. Normal releases are promoted after public artifact/consumer verification. Historical alpha releases have a different compatibility contract. This is not an official Void adapter.
4
4
 
5
5
  ## Supported versions
6
6
 
@@ -13,18 +13,18 @@ This package integrates Hono JSX with Void Pages. This source documents the upco
13
13
  | Vite Plus | Host Vite must satisfy the Vite range | 1.3.0 |
14
14
  | TypeScript | Project tooling | 7.0.2 |
15
15
 
16
- The upcoming RC targets Void 1.1 and Node 24 only. Published alpha.4 retains its earlier Void 0.x contract; it does not provide this support change or multipart transport. Old Void/launcher manifests remain historical comparison records, not release-selectable configurations. The two supported Hono-only consumers use Void 1.1.11 with plain Vite 8.3.4 or aligned Vite Plus 1.3.0 (host Vite 8.3.4). Ranges admit stable updates, but only locked fixtures are observed test results. New upstream releases require refreshed fixtures, full checks and audit review; prereleases and other Void minors are excluded.
16
+ The normal 0.1.x series targets Void 1.1 and Node 24 only. Published alpha.4 retains its earlier Void 0.x contract; it does not provide this support change or multipart transport. Old Void/launcher manifests remain historical comparison records, not release-selectable configurations. The two supported Hono-only consumers use Void 1.1.11 with plain Vite 8.3.4 or aligned Vite Plus 1.3.0 (host Vite 8.3.4). Ranges admit stable updates, but only locked fixtures are observed test results. New upstream releases require refreshed fixtures, full checks and audit review; prereleases and other Void minors are excluded.
17
17
 
18
- Alpha.4 introduced the expanded Link/Form APIs, island forms and graphs, deferred contracts, page options and optional Markdown. This source adds the Void 1.1 contract and multipart transport for the RC; use the local tarball until the RC is approved. Do not combine the RC setup instructions with alpha.4.
18
+ The normal 0.1.x series includes the expanded Link/Form APIs, multipart transport, island forms and graphs, deferred contracts with deferredResult/use/Suspense, navigation fallback, page options and optional Markdown. These instructions describe that normal series; historical alpha releases do not provide the same Void 1.1 contract.
19
19
 
20
20
  ## Install
21
21
 
22
- Use Node 24.21.0 or newer within Node 24:
22
+ Use Node 24.21.0 or newer within Node 24. The unqualified package selects the normal release on `latest`. To reproduce the first normal release, install `void-plugin-hono-jsx@0.1.0`; use `@next` only when deliberately testing the currently approved candidate.
23
23
 
24
- The commands below target the RC line. Check registry availability after owner approval. Published alpha.4 does not accept Void 1.1; use a local tarball until the RC has been approved. Use Node >=24.21.0 <25.0.0.
24
+ The commands below use the supported Void 1.1 baseline. Local tarballs remain available for source verification.
25
25
 
26
26
  ```sh
27
- npm install void-plugin-hono-jsx@0.1.0-rc.0 hono@4.13.13
27
+ npm install void-plugin-hono-jsx hono@4.13.13
28
28
  npm install --save-dev void@1.1.11 vite@8.3.4 typescript@7.0.2
29
29
  ```
30
30
 
@@ -37,7 +37,7 @@ npm install --save-dev void@1.1.11 vite@8.3.4 typescript@7.0.2
37
37
 
38
38
  ## Configure
39
39
 
40
- `voidHonoJsx()` and `HonoJsxOptions` replace the earlier `voidHonoPages()` and `HonoPagesOptions` names. This is a breaking alpha API change; the old names are not exported. Alpha.3 uses the earlier names. Use a local tarball or a release containing this rename for the configuration below.
40
+ `voidHonoJsx()` and `HonoJsxOptions` replace the earlier `voidHonoPages()` and `HonoPagesOptions` names. This is a breaking alpha API change; the old names are not exported. Alpha.3 uses the earlier names; the normal 0.1.x series exports the new names shown below.
41
41
 
42
42
  ```ts
43
43
  // vite.config.ts
@@ -56,7 +56,7 @@ Use `jsx: "react-jsx"` and `jsxImportSource: "hono/jsx"` in TypeScript. The plug
56
56
 
57
57
  The config hook reads `this.meta.viteVersion` from the Vite instance executing the hook. Resolving `vite/package.json` from the adapter or project is not evidence of the running host. The adapter also checks the actual Vite helper module it imports. Errors include the host version, helper version, and absolute adapter/project package.json paths; different pnpm peer copies therefore remain visible.
58
58
 
59
- Bundled launchers such as `vp dev` can execute another Vite even when a direct npm `vite` is installed. The supported Vite Plus 1.3.0 configuration aliases `vite` to `npm:@voidzero-dev/vite-plus-core@1.3.0` and uses `overrides: { vite: "$vite" }` to keep helper and host peers aligned. The real config-hook host is Vite 8.3.4. Plain Vite 8.3.4 is independently exercised. Installing npm Vite alone does not change a bundled host; diagnostics identify launcher and helper peer paths separately. Historical 0.x scaffold settings are outside RC support. The alias aligns the launcher; it is not a vulnerability override.
59
+ Bundled launchers such as `vp dev` can execute another Vite even when a direct npm `vite` is installed. The supported Vite Plus 1.3.0 configuration aliases `vite` to `npm:@voidzero-dev/vite-plus-core@1.3.0` and uses `overrides: { vite: "$vite" }` to keep helper and host peers aligned. The real config-hook host is Vite 8.3.4. Plain Vite 8.3.4 is independently exercised. Installing npm Vite alone does not change a bundled host; diagnostics identify launcher and helper peer paths separately. Historical 0.x scaffold settings are outside the normal 0.1.x support policy. The alias aligns the launcher; it is not a vulnerability override.
60
60
 
61
61
  If the project version is already correct, inspect the paths in the diagnostic and refresh stale adapter peer resolutions/lockfiles. Do not infer the host identity from the project dependency alone. Missing hook version information fails closed. [Vite plugin context metadata](https://vite.dev/guide/api-plugin.html#plugin-context-meta)
62
62
 
@@ -110,7 +110,7 @@ The adapter snapshots FormData at submission and leaves `Content-Type` unset so
110
110
 
111
111
  Full Pages multipart uses a dedicated same-origin mutation request followed by **one explicit GET** through Void's public router on success. Void's public engine cannot consume a raw multipart body or an externally fetched page shell. The GET commits through normal Hono rendering, history, layout/head, navigation state and cancellation checks while preserving component state. It also reruns loaders and may re-evaluate deferred data; the resolved-deferred retention contract for JSON mutations does not apply to multipart. The destination must support a GET. Island multipart retains its existing success behavior: reload or redirect the document.
112
112
 
113
- This API is part of the release preparation branch and is not in published alpha.4. It does not add a multipart-capable public transport hook to Void or change the one-shot `action()` helper's body contract.
113
+ This API is included in RC.1 and is not in published alpha.4. It does not add a multipart-capable public transport hook to Void or change the one-shot `action()` helper's body contract.
114
114
 
115
115
  ## Static output and prerendering
116
116
 
@@ -165,16 +165,16 @@ export default function Page() {
165
165
 
166
166
  Place the counter outside the pages directory. It can use Hono hooks and event handlers normally. The adapter renders its initial HTML inside Void's `data-island`, `data-hydrate` and `data-props` markers, then uses `initIslands` to load and mount only interactive components. Props must be JSON-serializable values. Hono escapes the JSON attribute; parsed browser props match the server values. Mounting redraws the island contents. It does not reuse the server DOM.
167
167
 
168
- A static-only island page emits no client script or module preload tags. Static page modules stay outside the normal Pages browser manifest. A project containing only static island pages builds empty client entry modules with no framework code. Void's own automatic prerender policy still applies to eligible island pages. Full static output and explicit prerender configuration follow the static output contract below.
168
+ A static-only island page without authored client scripts or Markdown code-copy controls emits no client script or module preload tags. Static page modules stay outside the normal Pages browser manifest. A project containing only static island pages builds empty client entry modules with no framework code. Void's own automatic prerender policy still applies to eligible island pages. Full static output and explicit prerender configuration follow the static output contract below.
169
169
 
170
170
  The `load`, `visible`, `idle` and `media:(query)` policies use Void's shared scheduler. Use a single default relative TSX/JSX import, with attributes directly in the island page. Unknown policies and obvious malformed media queries fail discovery; the browser checks the media query through CSSOM before scheduling. Each island mounts once when its condition is met. Island layouts and attributed imports in their static TSX/JSX component graph are supported, including named layouts and repeated components with independent JSON props. The graph handles cycles and invalidates island entries when a known static component changes. Static chains without interactive imports emit no client script. Interactive components form a boundary: use ordinary imports inside them; another attributed island inside an already interactive component is rejected to avoid overlapping mounts. Full Pages cannot inherit an island layout (Void diagnoses the mixed mode). `useIslandForm(defaults)` provides the same data/dirty/error/submit/reset/clear state without a Pages provider. Submit to an explicit same-origin URL, or use `<Form form={form} url="/blog?save">`. Island success reloads or redirects the document, so state is rebuilt from SSR props. Duplicate submissions are suppressed; cancellation aborts the owned fetch but does not roll back a server write. Fields are sent as JSON by default; explicit FormData/multipart is described above. Ordinary `useForm` and the one-shot Pages `action` still require full Pages; use named imports of `useIslandForm`/`Form` in islands. Pages-only form imports (`useForm`, `action`) and ambiguous namespace/default form imports fail with a diagnostic in an island page or component. `useForm` also requires a full Pages provider at runtime. Use ordinary document links in static island pages. Pages navigation falls back to a document request for island routes. Static layouts remain server content and do not retain interactive state.
171
171
 
172
172
  ## Optional Markdown
173
173
 
174
- For this source and its Void 1.1 baseline, use the RC after approval or the local tarball steps above. Published alpha.4 has the Markdown exports but retains its earlier Void 0.x contract; alpha.3 predates this API. Add parser peers explicitly only when using Markdown:
174
+ Optional Markdown is included in the normal 0.1.x series on the Void 1.1 baseline. Add parser peers explicitly only when using Markdown:
175
175
 
176
176
  ```sh
177
- npm install markdown-exit@1.3.0 yaml@2.9.1
177
+ npm install markdown-exit@1.3.0 yaml@2.9.1 markdown-it-container@4.0.0 shiki@4.5.0 @shikijs/transformers@4.5.0
178
178
  ```
179
179
 
180
180
  ```ts
@@ -190,9 +190,15 @@ export default defineConfig({
190
190
 
191
191
  Create `.md` files in the Pages directory. Standard Markdown, tables, authored HTML, fenced code, heading anchors, YAML frontmatter, companion server loaders and TSX/JSX layouts are supported. Import `useFrontmatter()`, `useMarkdownHeadings()` and `useMarkdownProps()` from `void-plugin-hono-jsx/markdown` in layouts or islands. A leading `<script>` block before frontmatter may contain page-specific browser code and default relative TSX/JSX island imports. Islands use literal props and the load/visible/idle/media policies, including canonical identities for symlinked components. Frontmatter must be a JSON-serializable mapping; duplicate keys, invalid YAML and cycles fail compilation.
192
192
 
193
- Markdown routes use document navigation, and static-only pages emit no executable script. Interactive/script pages reload on development edits; zero-script pages need a normal refresh. Raw HTML is preserved for repository-authored content, without sanitization for untrusted input. Markdown layout files, JSX-expression/tag-child island props, Shiki themes, footnotes, custom containers and a page-catalog virtual module are unsupported. Do not also configure `@void/md/plugin`. Ordinary Pages users do not need these parser peers. See the repository's [Markdown guide](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/markdown.md) for page examples, metadata scoping and the complete contract.
193
+ Markdown routes use document navigation. Pages without fences, islands or authored scripts emit no executable script. Interactive island pages reload on development edits; copy-only, script-only and zero-script pages need a normal refresh. Raw HTML is preserved for repository-authored content, without sanitization for untrusted input. Markdown layout files, JSX-expression/tag-child island props, footnotes, emoji, arbitrary attrs, GitHub alerts, inline TOC and a page-catalog virtual module are unsupported. Do not also configure `@void/md/plugin`.
194
194
 
195
- ## Experimental limitations
195
+ Fenced code uses build-time Shiki highlighting and copy buttons by default, matching the official framework plugins. `voidHonoMarkdown({ shiki: { themes: { light: 'github-light', dark: 'github-dark' } } })` customizes the default dual theme; language grammars load on demand. Unknown languages fall back to escaped text. Diff/highlight/focus/warning/error annotations and line numbers are supported. Copy-only pages load a small page-specific module, not the island scheduler; copying requires a supported secure context and permission. Pages without fences, islands or authored scripts remain zero-script.
196
+
197
+ Containers use the official `::: tip`, `info`, `warning`, `danger`, `details` syntax with optional Markdown titles and nested content. Import `void-plugin-hono-jsx/theme-content.css` and wrap content in `.void-md` to use the official scoped theme and `--vmd-*` variables. `void-plugin-hono-jsx/theme.css` additionally opts into the global reset/baseline; neither is injected automatically. Color mode follows system preference or `data-theme="light"` / `"dark"` on `<html>`.
198
+
199
+ Existing Markdown projects add the new container/Shiki/transformer peers shown above; existing calls to `voidHonoMarkdown()` keep working. Ordinary Pages users do not need these parser/highlighter peers. See the repository's [Markdown guide](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/markdown.md) for page examples, metadata scoping and the complete contract.
200
+
201
+ ## Compatibility and rendering limits
196
202
 
197
203
  The virtual renderer/client entries follow version-specific conventions observed in Void's official adapter rather than a documented third-party registration API. Browser mounting redraws the SSR page; DOM reuse is not guaranteed. Local ISR uses Void's native direct-worker KV/Cache API runtime; managed edge behavior remains unverified. Unsupported modes fail clearly. Package publication and repository visibility are separate maintainer decisions.
198
204
 
@@ -206,7 +212,7 @@ The advisory concerns esbuild's own development server. The adapter uses Vite/Ox
206
212
 
207
213
  The package adds no overrides and does not force changes to Void's internal dependencies. Consumers install the framework peers and their dependencies even though this archive contains no dependency implementation. Follow compatible upstream fixes; a peer upgrade requires renewed validation. New unreviewed advisories continue to block release preparation policy.
208
214
 
209
- The historical scaffold Vite Plus 0.1.24 brings unapproved tinypool Critical findings. It is outside the RC support range; use the tested Vite Plus 1.3.0/core alias or plain Vite 8.3.4. Old functional CI success does not accept those findings. See the repository `docs/scaffold-compatibility.md` for historical evidence.
215
+ The historical scaffold Vite Plus 0.1.24 brings unapproved tinypool Critical findings. It is outside the normal 0.1.x support policy; use the tested Vite Plus 1.3.0/core alias or plain Vite 8.3.4. Old functional CI success does not accept those findings. See the repository `docs/scaffold-compatibility.md` for historical evidence.
210
216
 
211
217
  ## Verification
212
218
 
@@ -230,14 +236,14 @@ The fixture binds local `ISR_CACHE` storage for Void production preview. Real de
230
236
 
231
237
  ## Known local development limitation
232
238
 
233
- On the tested macOS Void/Miniflare development runtime, a POST to an undefined named action can reset the next request on a reused connection. Declared-action browser behavior is verified; this transport edge case remains unresolved upstream. Managed runtime behavior for the edge case is unverified. This historical local limitation must be rechecked on the selected RC baseline; it is not evidence about managed production behavior.
239
+ On the tested macOS Void/Miniflare development runtime, a POST to an undefined named action can reset the next request on a reused connection. Declared-action browser behavior is verified; this transport edge case remains unresolved upstream. Managed runtime behavior for the edge case is unverified. On the RC.1 D1 fixture, an oversized-body rejection followed by another pooled request also failed locally; consuming the response body did not prevent it. Local negative checks isolate connections as a test workaround, not a repair. On 2026-10-18, direct Cloudflare HTTPS with RC.1 passed rejection/undefined-action requests followed by healthy GETs through the normal pool, without retries or Connection: close. That does not prove every environment or a forced single TCP socket. The [dated Workers record](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/cloudflare-rc1-verification.md) and [limitations ledger](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/known-limitations.md) separate observed behavior from remaining upstream diagnosis.
234
240
 
235
- ## RC and normal-release policy
241
+ ## Normal-release policy
236
242
 
237
- The planned first candidate is 0.1.0-rc.0 on next, followed by 0.1.0 after public-consumer and real Workers verification. It is not yet a published-release claim. Production ISR remains outside the initial guarantee. Patches in 0.1.x preserve documented APIs; breaking changes move to 0.2.0 or later. Read the [release contract](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/release-contract.md) and [security policy](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/SECURITY.md). Report vulnerabilities [privately](https://github.com/ts-76/void-plugin-hono-jsx/security/advisories/new).
243
+ The first normal release, 0.1.0, passed public bytes/signatures/provenance verification and both registry-installed consumers; latest and next were aligned to it on 2026-10-18. The [dated publication record](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/releasing.md#010-publication-and-tag-verification) identifies the exact archive and checks. Each subsequent candidate needs fresh CI/audits, stage, owner approval and public verification before normal-release tag promotion. The actual Workers/D1 migration, redeployment and cleanup exercise used RC.1; production ISR remains outside the initial guarantee. Patches in 0.1.x preserve documented APIs; breaking changes move to 0.2.0 or later. Read the [release contract](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/release-contract.md) and [security policy](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/SECURITY.md). Report vulnerabilities [privately](https://github.com/ts-76/void-plugin-hono-jsx/security/advisories/new).
238
244
 
239
245
 
240
- ### Common navigation fallback (after RC.0)
246
+ ### Common navigation fallback (included in RC.1)
241
247
 
242
248
  Register a default-exported local TSX/JSX module by path. The plugin imports the
243
249
  component into its client entry; it does not serialize a function in Vite config.
@@ -265,10 +271,10 @@ JSON/multipart submission UI remains under
265
271
  `useNavigation()`/form pending state. SSR stays idle and emits no fallback.
266
272
  Without this option, existing behavior is unchanged. The normal page reset and
267
273
  preserveState/preserveScroll rules still apply when the destination commits.
268
- This addition is not included in the already published RC.0.
274
+ This addition shipped in RC.1; RC.0 does not include it.
269
275
 
270
276
 
271
- ### Hono use() / Suspense for deferred props (after RC.0)
277
+ ### Hono use() / Suspense for deferred props (included in RC.1)
272
278
 
273
279
  `deferredResult(state)` gives Hono a stable, render-only Promise. Void still runs
274
280
  the resolver, delivers HTML callbacks/NDJSON and manages prefetch/navigation.
@@ -313,4 +319,4 @@ the later result to the browser. The adapter does not send Hono replacement HTML
313
319
  or wait for deferred data in its server renderer. Only full Pages are supported;
314
320
  deferred islands/static remain unsupported. Upstream failed-prefetch null values
315
321
  remain null (the success value type includes null); this helper does not repair
316
- that upstream limitation. This API is not in published RC.0.
322
+ that upstream limitation. This API shipped in RC.1; RC.0 does not include it.
@@ -4,7 +4,7 @@ The renderer/client entry conventions and provider integration were adapted from
4
4
 
5
5
  ## Void, @void/react and @void/md
6
6
 
7
- Source distributions: `void@0.26.0` and `@void/react@0.26.0`, published npm packages. Link, prefetch lifecycle and form API behavior also reference the published `@void/react@0.27.0` adapter. Hono's render/navigation integration uses the public `void@0.26.1` / `void@0.27.0` navigation engine and router facade, with lifecycle behavior adapted from Void's router. Markdown script extraction, component-tag splitting and entry conventions reference the published `@void/md@0.27.0` implementation; its MIT attribution is preserved here. Markdown parsing uses the public `markdown-exit` and `yaml` APIs as optional peers. No private `@void/md` module is imported. The adapter imports framework APIs rather than bundling the framework.
7
+ Source distributions: `void@0.26.0` and `@void/react@0.26.0`, published npm packages. Link, prefetch lifecycle and form API behavior also reference the published `@void/react@0.27.0` adapter. Hono's render/navigation integration uses the public `void@0.26.1` / `void@0.27.0` navigation engine and router facade, with lifecycle behavior adapted from Void's router. Markdown script extraction, component-tag splitting and entry conventions reference the published `@void/md@0.27.0` implementation; its MIT attribution is preserved here. Code highlighting/copy, container conventions and the six theme CSS files also reference the published `@void/md@1.1.11`; theme CSS is included under this notice, with keyboard/touch copy-button additions in code.css. Production static-layout CSS collection follows the official `@void/react@1.1.11` adapter using Void's public CSS import utilities. Markdown parsing/highlighting uses the public `markdown-exit`, `yaml`, `markdown-it-container`, `shiki` and `@shikijs/transformers` APIs as optional peers. No private `@void/md` module is imported. The adapter imports framework APIs rather than bundling the framework.
8
8
 
9
9
  MIT License
10
10
 
@@ -1 +1 @@
1
- {"version":3,"file":"hono-islands.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-islands.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAQ7D,4DAA4D;AAC5D,wBAAgB,WAAW,IAAI,MAAM,CA+NpC"}
1
+ {"version":3,"file":"hono-islands.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-islands.ts"],"names":[],"mappings":"AAEA,OAAO,EAA4B,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAQ7D,4DAA4D;AAC5D,wBAAgB,WAAW,IAAI,MAAM,CAuOpC"}
@@ -2,7 +2,7 @@ import { readFileSync, realpathSync } from 'node:fs';
2
2
  import { join, relative, resolve, dirname, basename } from 'node:path';
3
3
  import { normalizePath, parseSync } from 'vite';
4
4
  import { scanPages, resolveEffectiveLayoutChain, resolvePagesDir } from 'void/pages';
5
- import { findIslandImports, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';
5
+ import { findIslandImports, findStaticCssImports, rewriteCssImportForVirtualModule, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';
6
6
  import { resolveComponent } from './resolve-component.js';
7
7
  import { markdownApi, markdownDiagnostic } from './markdown-api.js';
8
8
  /** Hono mounting through Void's shared island scheduler. */
@@ -12,6 +12,7 @@ export function honoIslands() {
12
12
  const islands = new Map();
13
13
  const pageFiles = new Set();
14
14
  let dependencyFiles = new Set();
15
+ let cssImports = [];
15
16
  const graph = new Map();
16
17
  const directlyInteractive = new Set();
17
18
  const interactivePages = new Set();
@@ -163,6 +164,10 @@ export function honoIslands() {
163
164
  for (const file of [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)])
164
165
  validateInteractive(join(pagesDir, file));
165
166
  }
167
+ // Match the official adapters: retain static-layout CSS in the client build
168
+ // even when the document itself needs no client-side JavaScript. Reuse the
169
+ // analysis snapshot rather than rereading modules during entry generation.
170
+ cssImports = [...new Set([...pageFiles].flatMap(file => findStaticCssImports(analyses.get(file).code, file).map(item => rewriteCssImportForVirtualModule(item.statement, item.specifier, file))))];
166
171
  dependencyFiles = watched;
167
172
  const needsJS = new Set(directlyInteractive);
168
173
  let changed = true;
@@ -265,10 +270,13 @@ export function renderIslandPage(page, assets) {
265
270
  }`;
266
271
  }
267
272
  if (id === `\0${ISLANDS_CLIENT_ENTRY_ID}`) {
273
+ // Void owns dev first-paint CSS. Production needs the static imports
274
+ // so its shared manifest asset collector can emit stylesheet links.
275
+ const styles = this.environment?.mode === 'dev' ? '' : cssImports.join('\n');
268
276
  if (!islands.size || !interactivePages.size)
269
- return 'export {};';
277
+ return styles || 'export {};';
270
278
  const loaders = [...islands].map(([name, path]) => `${JSON.stringify(name)}: () => import(${JSON.stringify(path)})`).join(',\n');
271
- return `${markdown ? "import { MarkdownContext } from 'void-plugin-hono-jsx/markdown';" : ''}
279
+ return `${styles}\n${markdown ? "import { MarkdownContext } from 'void-plugin-hono-jsx/markdown';" : ''}
272
280
  import { initIslands } from 'void/pages-client';
273
281
  import { jsx } from 'hono/jsx/dom/jsx-runtime';
274
282
  import { render } from 'hono/jsx/dom';
@@ -1 +1 @@
1
- {"version":3,"file":"hono-islands.js","sourceRoot":"","sources":["../../src/plugins/hono-islands.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, realpathSync } from 'node:fs';\nimport { join, relative, resolve, dirname, basename } from 'node:path';\nimport { normalizePath, parseSync, type Plugin } from 'vite';\nimport { scanPages, resolveEffectiveLayoutChain, resolvePagesDir, type PageScanResult } from 'void/pages';\nimport { findIslandImports, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';\n\nimport { resolveComponent } from './resolve-component.ts';\n\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\n\n/** Hono mounting through Void's shared island scheduler. */\nexport function honoIslands(): Plugin {\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const islands = new Map<string, string>();\n const pageFiles = new Set<string>();\n let dependencyFiles = new Set<string>();\n const graph = new Map<string, Set<string>>();\n const directlyInteractive = new Set<string>();\n const interactivePages = new Set<string>();\n const scriptOnlyPages = new Set<string>();\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n function islandImports(code: string, filename: string, body = parseSync(filename, code).program.body) {\n const found = findIslandImports(code, filename);\n const attributed = body.filter((node) => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));\n if (attributed.length !== found.length) throw new Error(`Hono islands: use one default import with exactly one island attribute using load, visible, idle or media:query in ${filename}.`);\n return found;\n }\n\n function imports(code: string, filename: string, found = islandImports(code, filename)) {\n for (const entry of found) {\n if (!['load', 'visible', 'idle'].includes(entry.hydrate)) {\n const query = entry.hydrate.startsWith('media:') ? entry.hydrate.slice(6).trim() : '';\n let balance = 0;\n for (const character of query) { if (character === '(') balance++; if (character === ')') balance--; if (balance < 0) break; }\n if (!query || balance !== 0 || /[{};]/.test(query)) throw new Error(`Hono islands: unsupported policy or invalid media query '${entry.hydrate}' in ${filename}.`);\n }\n if (!entry.specifier.startsWith('.')) throw new Error(`Hono islands: use a relative TSX/JSX component import in ${filename}.`);\n const path = resolveComponent(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);\n if (!path || !/\\.[jt]sx$/.test(path)) throw new Error(`Hono islands: cannot resolve TSX/JSX component ${entry.specifier} in ${filename}.`);\n const canonical = realpathSync(path);\n const id = normalizePath(relative(root, canonical));\n islands.set(id, canonical);\n }\n return found;\n }\n\n // Refresh before graph analysis, regardless of Markdown hot-hook order.\n async function rescan() {\n markdown?.refresh();\n scan = await scanPages(root, { pagesDir });\n // Never pass Markdown text to the JavaScript static-graph parser.\n for (const file of [...scan.pages.map(page => page.componentPath), ...scan.layouts.map(layout => layout.filePath), ...scan.namedLayouts.map(layout => layout.filePath)]) {\n if (/\\.md$/.test(file) && !markdown) throw new Error(`${markdownDiagnostic} ${file}`);\n }\n islands.clear(); pageFiles.clear(); graph.clear(); directlyInteractive.clear(); interactivePages.clear(); scriptOnlyPages.clear();\n // Source and syntax results live for one analysis only, never across edits.\n type Analysis = { code: string; found: ReturnType<typeof findIslandImports>; edges: Array<{ specifier: string; target: string }> };\n const analyses = new Map<string, Analysis>();\n const watched = new Set<string>();\n const watchedBases = new Set<string>();\n const watch = (file: string) => { const path = normalizePath(file); watched.add(path); dependencyFiles.add(path); };\n const watchImport = (specifier: string, filename: string) => {\n const base = resolve(dirname(filename), specifier);\n if (watchedBases.has(base)) return; watchedBases.add(base);\n const bases = new Set([base]);\n // Keep missing targets observable through symlinked directories too.\n try { bases.add(join(realpathSync(dirname(base)), basename(base))); } catch {}\n try { bases.add(realpathSync(base)); } catch {}\n for (const candidate of bases) {\n watch(candidate);\n for (const extension of ['.tsx', '.jsx', '.ts', '.js']) { watch(candidate + extension); watch(join(candidate, 'index' + extension)); }\n }\n };\n const analyze = (canonical: string): Analysis => {\n const previous = analyses.get(canonical);\n if (previous) return previous;\n // Retain failed dependencies until recovery so an edit can trigger a rescan.\n watch(canonical);\n const code = canonical.endsWith('.md') && markdown ? markdown.getGraphSource(canonical) : readFileSync(canonical, 'utf8');\n const parsed = parseSync(canonical, code);\n if (parsed.errors.length) throw new Error(`Hono islands: cannot parse ${canonical}: ${parsed.errors.map(error => error.message).join('; ')}`);\n const body = parsed.program.body;\n const found = islandImports(code, canonical, body);\n const edges: Analysis['edges'] = [];\n for (const node of body) {\n const source = node.type === 'ImportDeclaration' ? node.source : node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration' ? node.source : undefined;\n const typeOnly = node.type === 'ImportDeclaration' ? node.importKind === 'type' || (node.specifiers.length > 0 && node.specifiers.every((entry) => entry.type === 'ImportSpecifier' && entry.importKind === 'type')) : (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') && node.exportKind === 'type';\n if (!source || typeOnly || !source.value.startsWith('.')) continue;\n const target = resolveComponent(source.value, join(canonical, '..'), ['.tsx', '.jsx', '.ts', '.js']);\n if (!target || /\\.[jt]sx?$/.test(target)) watchImport(source.value, canonical);\n if (target && /\\.[jt]sx?$/.test(target)) edges.push({ specifier: source.value, target: realpathSync(target) });\n }\n const analysis = { code, found, edges }; analyses.set(canonical, analysis); return analysis;\n };\n const visit = (filename: string) => {\n const canonical = realpathSync(filename);\n if (graph.has(canonical)) return;\n const dependencies = new Set<string>(); graph.set(canonical, dependencies); pageFiles.add(canonical);\n const { code, found, edges } = analyze(canonical);\n imports(code, canonical, found);\n if (found.length) {\n if (!/\\.[jt]sx$/.test(canonical) && !(canonical.endsWith('.md') && markdown)) throw new Error('Hono islands: attributed imports require a static TSX/JSX module.');\n directlyInteractive.add(canonical);\n }\n for (const edge of edges) {\n if (found.some(entry => entry.specifier === edge.specifier)) continue;\n dependencies.add(edge.target); visit(edge.target);\n }\n };\n for (const entry of [...scan.pages.filter((page) => page.island).map((page) => page.componentPath), ...scan.layouts.filter((layout) => layout.island).map((layout) => layout.filePath), ...scan.namedLayouts.filter((layout) => layout.island).map((layout) => layout.filePath)]) visit(join(pagesDir, entry));\n const validated = new Set<string>();\n const validateInteractive = (filename: string) => {\n const canonical = realpathSync(filename);\n if (validated.has(canonical)) return; validated.add(canonical);\n const { found, edges } = analyze(canonical);\n if (found.length) throw new Error('Hono islands: attributed imports inside an interactive component are unsupported; use ordinary component imports there.');\n for (const edge of edges) validateInteractive(edge.target);\n };\n for (const target of islands.values()) validateInteractive(target);\n for (const page of scan.pages.filter((page) => !page.island)) {\n for (const file of [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)]) validateInteractive(join(pagesDir, file));\n }\n dependencyFiles = watched;\n const needsJS = new Set(directlyInteractive);\n let changed = true;\n while (changed) {\n changed = false;\n for (const [file, dependencies] of graph) if (!needsJS.has(file) && [...dependencies].some((target) => needsJS.has(target))) { needsJS.add(file); changed = true; }\n }\n for (const page of scan.pages.filter((page) => page.island)) {\n const files = [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)];\n const hasIslands = files.some(file => needsJS.has(realpathSync(join(pagesDir, file))));\n const hasScript = markdown?.getClientScripts().has(page.componentId);\n if (hasIslands || hasScript) interactivePages.add(page.componentId);\n if (hasScript && !hasIslands) scriptOnlyPages.add(page.componentId);\n }\n }\n\n return {\n name: 'void-hono:islands',\n enforce: 'pre',\n configResolved(config) { markdown = markdownApi(config.plugins); },\n buildStart: rescan,\n async hotUpdate({ file, modules, timestamp }) {\n const inPages = normalizePath(file).startsWith(normalizePath(pagesDir) + '/');\n if (!inPages && !dependencyFiles.has(normalizePath(file))) return;\n await rescan();\n const invalidated = new Set<(typeof modules)[number]>();\n for (const id of [ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID, 'virtual:void-pages-renderer']) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n if (!inPages && this.environment.config.consumer === 'client') this.environment.hot.send({ type: 'full-reload' });\n },\n config() {\n return { build: { rollupOptions: { input: { 'islands-client': ISLANDS_CLIENT_ENTRY_ID } } } };\n },\n resolveId(id) {\n if (id === ISLANDS_RENDERER_ID || id === ISLANDS_CLIENT_ENTRY_ID) return `\\0${id}`;\n },\n transform(code, id) {\n const filename = id.split('?')[0];\n if (!/\\.[jt]sx$/.test(filename) || filename.includes('/node_modules/')) return;\n const canonical = realpathSync(filename);\n if ((pageFiles.has(canonical) || [...islands.values()].includes(canonical)) && parseSync(filename, code).program.body.some((node) => node.type === 'ImportDeclaration' && node.importKind !== 'type' && ['void-plugin-hono-jsx/form', 'void-plugin-hono-jsx/pages'].includes(node.source.value) && node.specifiers.some((entry) => entry.type !== 'ImportSpecifier' ? node.source.value.endsWith('/form') : entry.importKind !== 'type' && ['useForm', 'action', 'setActionRouter'].includes('name' in entry.imported ? entry.imported.name : entry.imported.value)))) {\n throw new Error('Hono islands: useForm/action require full Pages; use named useIslandForm/Form imports for islands.');\n }\n const found = islandImports(code, filename);\n if (!found.length) return;\n if (!pageFiles.has(canonical)) throw new Error('Hono islands: attributed imports require a static island page, layout or component graph; use ordinary imports inside interactive components.');\n imports(code, filename);\n // Void requests static modules in the client environment to collect CSS.\n // Actual interactive entry graphs were validated above; strip attributes\n // for that traversal rather than generating server-only marker wrappers.\n if (this.environment?.config.consumer === 'client') return editIslandSource(code, found.map((entry) => ({ start: entry.start, end: entry.end, text: `import ${entry.importName} from ${entry.specifierRaw};` })));\n return editIslandSource(code, found.map((entry) => {\n const path = resolveComponent(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);\n if (!path) throw new Error(`Hono islands: missing component ${entry.specifier}.`);\n const islandId = normalizePath(relative(root, realpathSync(path)));\n const component = `__honoIslandComponent${entry.start}`;\n return { start: entry.start, end: entry.end, text: `import ${component} from ${entry.specifierRaw};\nconst ${entry.importName} = (props) => __honoIslandJsx('div', { 'data-island': ${JSON.stringify(islandId)}, 'data-hydrate': ${JSON.stringify(entry.hydrate)}, 'data-props': JSON.stringify(props), children: __honoIslandJsx(${component}, props) });` };\n }), { prepend: \"import { jsx as __honoIslandJsx } from 'hono/jsx/jsx-runtime';\\n\" });\n },\n load(id) {\n if (id === `\\0${ISLANDS_RENDERER_ID}`) {\n if (!scan) throw new Error('Hono islands: page discovery has not completed.');\n const interactive = [...new Set([...computePagesNeedingClientJS(scan, pagesDir, null), ...interactivePages])];\n return `import { renderPage } from 'virtual:void-pages-renderer';\nconst interactive = new Set(${JSON.stringify(interactive)});\nconst scriptOnly = new Set(${JSON.stringify([...scriptOnlyPages])});\nconst markdownScripts = new Set(${JSON.stringify([...(markdown?.getClientScripts().keys() ?? [])])});\nexport function renderIslandPage(page, assets) {\n if (page.deferred?.length || page.deferredKeys) throw new Error('Hono islands: deferred props are unsupported.');\n if (!markdownScripts.has(page.component)) assets = { ...assets,\n body: assets.body.replace(/<script\\\\b[^>]*src=[\"'][^\"']*(?:void-hono-markdown-client|markdown-client-)[^\"']*[\"'][^>]*>\\\\s*<\\\\/script>/g, ''),\n preloads: assets.preloads.replace(/<link\\\\b[^>]*href=[\"'][^\"']*markdown-client-[^\"']*[\"'][^>]*>/g, ''),\n };\n if (!interactive.has(page.component)) return renderPage(page, { ...assets, preloads: '', body: '' });\n if (scriptOnly.has(page.component)) {\n // Keep the Markdown entry; its dynamic import loads only this page's code.\n // Framework preloads and the island scheduler have no work on this chain.\n const body = assets.body.replace(/<script\\\\b[^>]*src=[\"'][^\"']*(?:void-islands-client|islands-client-)[^\"']*[\"'][^>]*>\\\\s*<\\\\/script>/g, '');\n return renderPage(page, { ...assets, preloads: '', body });\n }\n return renderPage(page, assets);\n}`;\n }\n if (id === `\\0${ISLANDS_CLIENT_ENTRY_ID}`) {\n if (!islands.size || !interactivePages.size) return 'export {};';\n const loaders = [...islands].map(([name, path]) => `${JSON.stringify(name)}: () => import(${JSON.stringify(path)})`).join(',\\n');\n return `${markdown ? \"import { MarkdownContext } from 'void-plugin-hono-jsx/markdown';\" : ''}\nimport { initIslands } from 'void/pages-client';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { render } from 'hono/jsx/dom';\nfor (const element of document.querySelectorAll('[data-hydrate^=\"media:\"]')) {\n const query = element.getAttribute('data-hydrate').slice(6).trim();\n if (matchMedia(query).media === 'not all' && query !== 'not all') throw new Error('Hono islands: invalid or unsupported media query ' + query);\n}\ninitIslands({ ${loaders} }, (element, module, props) => {\n if (typeof module.default !== 'function') throw new Error('Hono islands: a component must export a default function.');\n let content = jsx(module.default, props);\n ${markdown ? `const metadata = JSON.parse(document.getElementById('app')?.getAttribute('data-hono-markdown') || '{}');\n const page = JSON.parse(document.getElementById('__VOID_PAGE_DATA__')?.textContent || '{}');\n content = jsx(MarkdownContext.Provider, { value: { frontmatter: metadata.frontmatter ?? {}, headings: metadata.headings ?? [], props: page.props ?? {} }, children: content });` : ''}\n render(content, element);\n element.setAttribute('data-hono-island', 'mounted');\n});`;\n }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"hono-islands.js","sourceRoot":"","sources":["../../src/plugins/hono-islands.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, realpathSync } from 'node:fs';\nimport { join, relative, resolve, dirname, basename } from 'node:path';\nimport { normalizePath, parseSync, type Plugin } from 'vite';\nimport { scanPages, resolveEffectiveLayoutChain, resolvePagesDir, type PageScanResult } from 'void/pages';\nimport { findIslandImports, findStaticCssImports, rewriteCssImportForVirtualModule, editIslandSource, computePagesNeedingClientJS, ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID } from 'void/pages-islands-plugin';\n\nimport { resolveComponent } from './resolve-component.ts';\n\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\n\n/** Hono mounting through Void's shared island scheduler. */\nexport function honoIslands(): Plugin {\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const islands = new Map<string, string>();\n const pageFiles = new Set<string>();\n let dependencyFiles = new Set<string>();\n let cssImports: string[] = [];\n const graph = new Map<string, Set<string>>();\n const directlyInteractive = new Set<string>();\n const interactivePages = new Set<string>();\n const scriptOnlyPages = new Set<string>();\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n function islandImports(code: string, filename: string, body = parseSync(filename, code).program.body) {\n const found = findIslandImports(code, filename);\n const attributed = body.filter((node) => node.type === 'ImportDeclaration' && node.attributes?.some(({ key }) => ('name' in key && key.name === 'island') || ('value' in key && key.value === 'island')));\n if (attributed.length !== found.length) throw new Error(`Hono islands: use one default import with exactly one island attribute using load, visible, idle or media:query in ${filename}.`);\n return found;\n }\n\n function imports(code: string, filename: string, found = islandImports(code, filename)) {\n for (const entry of found) {\n if (!['load', 'visible', 'idle'].includes(entry.hydrate)) {\n const query = entry.hydrate.startsWith('media:') ? entry.hydrate.slice(6).trim() : '';\n let balance = 0;\n for (const character of query) { if (character === '(') balance++; if (character === ')') balance--; if (balance < 0) break; }\n if (!query || balance !== 0 || /[{};]/.test(query)) throw new Error(`Hono islands: unsupported policy or invalid media query '${entry.hydrate}' in ${filename}.`);\n }\n if (!entry.specifier.startsWith('.')) throw new Error(`Hono islands: use a relative TSX/JSX component import in ${filename}.`);\n const path = resolveComponent(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);\n if (!path || !/\\.[jt]sx$/.test(path)) throw new Error(`Hono islands: cannot resolve TSX/JSX component ${entry.specifier} in ${filename}.`);\n const canonical = realpathSync(path);\n const id = normalizePath(relative(root, canonical));\n islands.set(id, canonical);\n }\n return found;\n }\n\n // Refresh before graph analysis, regardless of Markdown hot-hook order.\n async function rescan() {\n markdown?.refresh();\n scan = await scanPages(root, { pagesDir });\n // Never pass Markdown text to the JavaScript static-graph parser.\n for (const file of [...scan.pages.map(page => page.componentPath), ...scan.layouts.map(layout => layout.filePath), ...scan.namedLayouts.map(layout => layout.filePath)]) {\n if (/\\.md$/.test(file) && !markdown) throw new Error(`${markdownDiagnostic} ${file}`);\n }\n islands.clear(); pageFiles.clear(); graph.clear(); directlyInteractive.clear(); interactivePages.clear(); scriptOnlyPages.clear();\n // Source and syntax results live for one analysis only, never across edits.\n type Analysis = { code: string; found: ReturnType<typeof findIslandImports>; edges: Array<{ specifier: string; target: string }> };\n const analyses = new Map<string, Analysis>();\n const watched = new Set<string>();\n const watchedBases = new Set<string>();\n const watch = (file: string) => { const path = normalizePath(file); watched.add(path); dependencyFiles.add(path); };\n const watchImport = (specifier: string, filename: string) => {\n const base = resolve(dirname(filename), specifier);\n if (watchedBases.has(base)) return; watchedBases.add(base);\n const bases = new Set([base]);\n // Keep missing targets observable through symlinked directories too.\n try { bases.add(join(realpathSync(dirname(base)), basename(base))); } catch {}\n try { bases.add(realpathSync(base)); } catch {}\n for (const candidate of bases) {\n watch(candidate);\n for (const extension of ['.tsx', '.jsx', '.ts', '.js']) { watch(candidate + extension); watch(join(candidate, 'index' + extension)); }\n }\n };\n const analyze = (canonical: string): Analysis => {\n const previous = analyses.get(canonical);\n if (previous) return previous;\n // Retain failed dependencies until recovery so an edit can trigger a rescan.\n watch(canonical);\n const code = canonical.endsWith('.md') && markdown ? markdown.getGraphSource(canonical) : readFileSync(canonical, 'utf8');\n const parsed = parseSync(canonical, code);\n if (parsed.errors.length) throw new Error(`Hono islands: cannot parse ${canonical}: ${parsed.errors.map(error => error.message).join('; ')}`);\n const body = parsed.program.body;\n const found = islandImports(code, canonical, body);\n const edges: Analysis['edges'] = [];\n for (const node of body) {\n const source = node.type === 'ImportDeclaration' ? node.source : node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration' ? node.source : undefined;\n const typeOnly = node.type === 'ImportDeclaration' ? node.importKind === 'type' || (node.specifiers.length > 0 && node.specifiers.every((entry) => entry.type === 'ImportSpecifier' && entry.importKind === 'type')) : (node.type === 'ExportNamedDeclaration' || node.type === 'ExportAllDeclaration') && node.exportKind === 'type';\n if (!source || typeOnly || !source.value.startsWith('.')) continue;\n const target = resolveComponent(source.value, join(canonical, '..'), ['.tsx', '.jsx', '.ts', '.js']);\n if (!target || /\\.[jt]sx?$/.test(target)) watchImport(source.value, canonical);\n if (target && /\\.[jt]sx?$/.test(target)) edges.push({ specifier: source.value, target: realpathSync(target) });\n }\n const analysis = { code, found, edges }; analyses.set(canonical, analysis); return analysis;\n };\n const visit = (filename: string) => {\n const canonical = realpathSync(filename);\n if (graph.has(canonical)) return;\n const dependencies = new Set<string>(); graph.set(canonical, dependencies); pageFiles.add(canonical);\n const { code, found, edges } = analyze(canonical);\n imports(code, canonical, found);\n if (found.length) {\n if (!/\\.[jt]sx$/.test(canonical) && !(canonical.endsWith('.md') && markdown)) throw new Error('Hono islands: attributed imports require a static TSX/JSX module.');\n directlyInteractive.add(canonical);\n }\n for (const edge of edges) {\n if (found.some(entry => entry.specifier === edge.specifier)) continue;\n dependencies.add(edge.target); visit(edge.target);\n }\n };\n for (const entry of [...scan.pages.filter((page) => page.island).map((page) => page.componentPath), ...scan.layouts.filter((layout) => layout.island).map((layout) => layout.filePath), ...scan.namedLayouts.filter((layout) => layout.island).map((layout) => layout.filePath)]) visit(join(pagesDir, entry));\n const validated = new Set<string>();\n const validateInteractive = (filename: string) => {\n const canonical = realpathSync(filename);\n if (validated.has(canonical)) return; validated.add(canonical);\n const { found, edges } = analyze(canonical);\n if (found.length) throw new Error('Hono islands: attributed imports inside an interactive component are unsupported; use ordinary component imports there.');\n for (const edge of edges) validateInteractive(edge.target);\n };\n for (const target of islands.values()) validateInteractive(target);\n for (const page of scan.pages.filter((page) => !page.island)) {\n for (const file of [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)]) validateInteractive(join(pagesDir, file));\n }\n // Match the official adapters: retain static-layout CSS in the client build\n // even when the document itself needs no client-side JavaScript. Reuse the\n // analysis snapshot rather than rereading modules during entry generation.\n cssImports = [...new Set([...pageFiles].flatMap(file => findStaticCssImports(analyses.get(file)!.code, file).map(item => rewriteCssImportForVirtualModule(item.statement, item.specifier, file))))];\n dependencyFiles = watched;\n const needsJS = new Set(directlyInteractive);\n let changed = true;\n while (changed) {\n changed = false;\n for (const [file, dependencies] of graph) if (!needsJS.has(file) && [...dependencies].some((target) => needsJS.has(target))) { needsJS.add(file); changed = true; }\n }\n for (const page of scan.pages.filter((page) => page.island)) {\n const files = [page.componentPath, ...resolveEffectiveLayoutChain(page, scan.layouts, scan.namedLayouts).map((layout) => layout.filePath)];\n const hasIslands = files.some(file => needsJS.has(realpathSync(join(pagesDir, file))));\n const hasScript = markdown?.getClientScripts().has(page.componentId);\n if (hasIslands || hasScript) interactivePages.add(page.componentId);\n if (hasScript && !hasIslands) scriptOnlyPages.add(page.componentId);\n }\n }\n\n return {\n name: 'void-hono:islands',\n enforce: 'pre',\n configResolved(config) { markdown = markdownApi(config.plugins); },\n buildStart: rescan,\n async hotUpdate({ file, modules, timestamp }) {\n const inPages = normalizePath(file).startsWith(normalizePath(pagesDir) + '/');\n if (!inPages && !dependencyFiles.has(normalizePath(file))) return;\n await rescan();\n const invalidated = new Set<(typeof modules)[number]>();\n for (const id of [ISLANDS_RENDERER_ID, ISLANDS_CLIENT_ENTRY_ID, 'virtual:void-pages-renderer']) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n if (!inPages && this.environment.config.consumer === 'client') this.environment.hot.send({ type: 'full-reload' });\n },\n config() {\n return { build: { rollupOptions: { input: { 'islands-client': ISLANDS_CLIENT_ENTRY_ID } } } };\n },\n resolveId(id) {\n if (id === ISLANDS_RENDERER_ID || id === ISLANDS_CLIENT_ENTRY_ID) return `\\0${id}`;\n },\n transform(code, id) {\n const filename = id.split('?')[0];\n if (!/\\.[jt]sx$/.test(filename) || filename.includes('/node_modules/')) return;\n const canonical = realpathSync(filename);\n if ((pageFiles.has(canonical) || [...islands.values()].includes(canonical)) && parseSync(filename, code).program.body.some((node) => node.type === 'ImportDeclaration' && node.importKind !== 'type' && ['void-plugin-hono-jsx/form', 'void-plugin-hono-jsx/pages'].includes(node.source.value) && node.specifiers.some((entry) => entry.type !== 'ImportSpecifier' ? node.source.value.endsWith('/form') : entry.importKind !== 'type' && ['useForm', 'action', 'setActionRouter'].includes('name' in entry.imported ? entry.imported.name : entry.imported.value)))) {\n throw new Error('Hono islands: useForm/action require full Pages; use named useIslandForm/Form imports for islands.');\n }\n const found = islandImports(code, filename);\n if (!found.length) return;\n if (!pageFiles.has(canonical)) throw new Error('Hono islands: attributed imports require a static island page, layout or component graph; use ordinary imports inside interactive components.');\n imports(code, filename);\n // Void requests static modules in the client environment to collect CSS.\n // Actual interactive entry graphs were validated above; strip attributes\n // for that traversal rather than generating server-only marker wrappers.\n if (this.environment?.config.consumer === 'client') return editIslandSource(code, found.map((entry) => ({ start: entry.start, end: entry.end, text: `import ${entry.importName} from ${entry.specifierRaw};` })));\n return editIslandSource(code, found.map((entry) => {\n const path = resolveComponent(entry.specifier, join(filename, '..'), ['.tsx', '.jsx']);\n if (!path) throw new Error(`Hono islands: missing component ${entry.specifier}.`);\n const islandId = normalizePath(relative(root, realpathSync(path)));\n const component = `__honoIslandComponent${entry.start}`;\n return { start: entry.start, end: entry.end, text: `import ${component} from ${entry.specifierRaw};\nconst ${entry.importName} = (props) => __honoIslandJsx('div', { 'data-island': ${JSON.stringify(islandId)}, 'data-hydrate': ${JSON.stringify(entry.hydrate)}, 'data-props': JSON.stringify(props), children: __honoIslandJsx(${component}, props) });` };\n }), { prepend: \"import { jsx as __honoIslandJsx } from 'hono/jsx/jsx-runtime';\\n\" });\n },\n load(id) {\n if (id === `\\0${ISLANDS_RENDERER_ID}`) {\n if (!scan) throw new Error('Hono islands: page discovery has not completed.');\n const interactive = [...new Set([...computePagesNeedingClientJS(scan, pagesDir, null), ...interactivePages])];\n return `import { renderPage } from 'virtual:void-pages-renderer';\nconst interactive = new Set(${JSON.stringify(interactive)});\nconst scriptOnly = new Set(${JSON.stringify([...scriptOnlyPages])});\nconst markdownScripts = new Set(${JSON.stringify([...(markdown?.getClientScripts().keys() ?? [])])});\nexport function renderIslandPage(page, assets) {\n if (page.deferred?.length || page.deferredKeys) throw new Error('Hono islands: deferred props are unsupported.');\n if (!markdownScripts.has(page.component)) assets = { ...assets,\n body: assets.body.replace(/<script\\\\b[^>]*src=[\"'][^\"']*(?:void-hono-markdown-client|markdown-client-)[^\"']*[\"'][^>]*>\\\\s*<\\\\/script>/g, ''),\n preloads: assets.preloads.replace(/<link\\\\b[^>]*href=[\"'][^\"']*markdown-client-[^\"']*[\"'][^>]*>/g, ''),\n };\n if (!interactive.has(page.component)) return renderPage(page, { ...assets, preloads: '', body: '' });\n if (scriptOnly.has(page.component)) {\n // Keep the Markdown entry; its dynamic import loads only this page's code.\n // Framework preloads and the island scheduler have no work on this chain.\n const body = assets.body.replace(/<script\\\\b[^>]*src=[\"'][^\"']*(?:void-islands-client|islands-client-)[^\"']*[\"'][^>]*>\\\\s*<\\\\/script>/g, '');\n return renderPage(page, { ...assets, preloads: '', body });\n }\n return renderPage(page, assets);\n}`;\n }\n if (id === `\\0${ISLANDS_CLIENT_ENTRY_ID}`) {\n // Void owns dev first-paint CSS. Production needs the static imports\n // so its shared manifest asset collector can emit stylesheet links.\n const styles = this.environment?.mode === 'dev' ? '' : cssImports.join('\\n');\n if (!islands.size || !interactivePages.size) return styles || 'export {};';\n const loaders = [...islands].map(([name, path]) => `${JSON.stringify(name)}: () => import(${JSON.stringify(path)})`).join(',\\n');\n return `${styles}\\n${markdown ? \"import { MarkdownContext } from 'void-plugin-hono-jsx/markdown';\" : ''}\nimport { initIslands } from 'void/pages-client';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { render } from 'hono/jsx/dom';\nfor (const element of document.querySelectorAll('[data-hydrate^=\"media:\"]')) {\n const query = element.getAttribute('data-hydrate').slice(6).trim();\n if (matchMedia(query).media === 'not all' && query !== 'not all') throw new Error('Hono islands: invalid or unsupported media query ' + query);\n}\ninitIslands({ ${loaders} }, (element, module, props) => {\n if (typeof module.default !== 'function') throw new Error('Hono islands: a component must export a default function.');\n let content = jsx(module.default, props);\n ${markdown ? `const metadata = JSON.parse(document.getElementById('app')?.getAttribute('data-hono-markdown') || '{}');\n const page = JSON.parse(document.getElementById('__VOID_PAGE_DATA__')?.textContent || '{}');\n content = jsx(MarkdownContext.Provider, { value: { frontmatter: metadata.frontmatter ?? {}, headings: metadata.headings ?? [], props: page.props ?? {} }, children: content });` : ''}\n render(content, element);\n element.setAttribute('data-hono-island', 'mounted');\n});`;\n }\n },\n };\n}\n"]}
@@ -1,4 +1,6 @@
1
1
  import { type Plugin } from 'vite';
2
+ import type { HonoMarkdownOptions } from './markdown-features.ts';
3
+ export type { HonoMarkdownOptions } from './markdown-features.ts';
2
4
  /** Optional authored Markdown compiler; independent of @void/md private files. */
3
- export declare function voidHonoMarkdown(): Plugin;
5
+ export declare function voidHonoMarkdown(options?: HonoMarkdownOptions): Plugin;
4
6
  //# sourceMappingURL=hono-markdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hono-markdown.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-markdown.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAUlD,kFAAkF;AAClF,wBAAgB,gBAAgB,IAAI,MAAM,CA0EzC"}
1
+ {"version":3,"file":"hono-markdown.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-markdown.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,MAAM,CAAC;AAIlD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAElE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAOlE,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CA8E1E"}
@@ -3,12 +3,14 @@ import { join, relative, dirname } from 'node:path';
3
3
  import { normalizePath } from 'vite';
4
4
  import { resolvePagesDir } from 'void/pages';
5
5
  import { resolveComponent } from './resolve-component.js';
6
- import { compileMarkdown, extractMarkdown, renderChunks } from './markdown-compiler.js';
6
+ import { createMarkdownCompiler, renderChunks } from './markdown-compiler.js';
7
+ import { markdownCopyId, markdownCopyCode } from './markdown-copy.js';
7
8
  const clientId = 'virtual:void-hono-markdown-client';
8
9
  const scriptQuery = '?hono-markdown-script';
9
10
  const literal = (value) => `JSON.parse(${JSON.stringify(JSON.stringify(value))})`;
10
11
  /** Optional authored Markdown compiler; independent of @void/md private files. */
11
- export function voidHonoMarkdown() {
12
+ export function voidHonoMarkdown(options = {}) {
13
+ const compiler = createMarkdownCompiler(options);
12
14
  let root = process.cwd();
13
15
  let pagesDir = resolvePagesDir(root);
14
16
  let scripts = new Map();
@@ -24,7 +26,9 @@ export function voidHonoMarkdown() {
24
26
  const file = join(entry.parentPath, entry.name);
25
27
  const id = normalizePath(relative(pagesDir, file)).replace(/\.md$/, '').replace(/\.island$/, '').replace(/\/index$/, '').replace(/^index$/, '') || 'index';
26
28
  const canonical = realpathSync(file);
27
- const extracted = nextSources.get(canonical) ?? extractMarkdown(readFileSync(canonical, 'utf8'));
29
+ const extracted = nextSources.get(canonical) ?? compiler.parse(readFileSync(canonical, 'utf8'));
30
+ if (!nextSources.has(canonical) && extracted.hasCode)
31
+ extracted.clientCode = `import ${JSON.stringify(markdownCopyId)};\n` + extracted.clientCode;
28
32
  nextSources.set(canonical, extracted);
29
33
  if (extracted.clientCode) {
30
34
  nextScripts.set(id, extracted.clientCode);
@@ -58,9 +62,11 @@ export function voidHonoMarkdown() {
58
62
  if (entry)
59
63
  this.environment.moduleGraph.invalidateModule(entry, new Set(), timestamp, true);
60
64
  },
61
- resolveId(id) { if (id === clientId)
65
+ resolveId(id) { if (id === clientId || id === markdownCopyId)
62
66
  return `\0${id}`; },
63
67
  load(id) {
68
+ if (id === `\0${markdownCopyId}`)
69
+ return markdownCopyCode;
64
70
  if (id.endsWith(scriptQuery))
65
71
  return source(id.slice(0, -scriptQuery.length)).clientCode || 'export {};';
66
72
  if (id !== `\0${clientId}`)
@@ -73,8 +79,9 @@ if (id && scripts[id]) await scripts[id]();`;
73
79
  },
74
80
  transform: {
75
81
  filter: { id: /\.md$/ },
76
- handler(source, id) {
77
- const result = compileMarkdown(source);
82
+ async handler(source, id) {
83
+ const cached = sources.get(realpathSync(id));
84
+ const result = await compiler.render(cached?.source === source ? cached : compiler.parse(source));
78
85
  const imports = result.imports.map((entry, index) => {
79
86
  const target = resolveComponent(entry.specifier, dirname(id), ['.tsx', '.jsx']);
80
87
  if (!target || !entry.specifier.startsWith('.'))
@@ -1 +1 @@
1
- {"version":3,"file":"hono-markdown.js","sourceRoot":"","sources":["../../src/plugins/hono-markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, readdirSync, existsSync, realpathSync } from 'node:fs';\nimport { join, relative, dirname } from 'node:path';\nimport { normalizePath, type Plugin } from 'vite';\nimport { resolvePagesDir } from 'void/pages';\nimport { resolveComponent } from './resolve-component.ts';\nimport { compileMarkdown, extractMarkdown, renderChunks } from './markdown-compiler.ts';\nimport type { HonoMarkdownApi } from './markdown-api.ts';\n\nconst clientId = 'virtual:void-hono-markdown-client';\nconst scriptQuery = '?hono-markdown-script';\nconst literal = (value: unknown) => `JSON.parse(${JSON.stringify(JSON.stringify(value))})`;\n\n/** Optional authored Markdown compiler; independent of @void/md private files. */\nexport function voidHonoMarkdown(): Plugin {\n let root = process.cwd();\n let pagesDir = resolvePagesDir(root);\n let scripts = new Map<string, string>();\n let files = new Map<string, string>();\n let sources = new Map<string, ReturnType<typeof extractMarkdown>>();\n function rescan() {\n const nextScripts = new Map<string, string>();\n const nextFiles = new Map<string, string>();\n const nextSources = new Map<string, ReturnType<typeof extractMarkdown>>();\n for (const entry of existsSync(pagesDir) ? readdirSync(pagesDir, { recursive: true, withFileTypes: true }) : []) {\n if (!entry.isFile() || !entry.name.endsWith('.md')) continue;\n const file = join(entry.parentPath, entry.name);\n const id = normalizePath(relative(pagesDir, file)).replace(/\\.md$/, '').replace(/\\.island$/, '').replace(/\\/index$/, '').replace(/^index$/, '') || 'index';\n const canonical = realpathSync(file);\n const extracted = nextSources.get(canonical) ?? extractMarkdown(readFileSync(canonical, 'utf8'));\n nextSources.set(canonical, extracted);\n if (extracted.clientCode) { nextScripts.set(id, extracted.clientCode); nextFiles.set(id, file); }\n }\n // Commit complete generations only; a parse error must not publish partial data.\n scripts = nextScripts; files = nextFiles; sources = nextSources;\n }\n function source(file: string) {\n const extracted = sources.get(realpathSync(file));\n if (!extracted) throw new Error(`Hono Markdown: file is absent from the current page scan: ${file}`);\n return extracted;\n }\n const api: HonoMarkdownApi = { adapter: 'hono', clientEntryId: clientId, refresh: rescan, getClientScripts() { return scripts; }, getGraphSource(file) { return source(file).graphSource; } };\n return {\n // Void's Markdown entry/asset convention is shared with @void/md.\n name: 'void-md', enforce: 'pre', api,\n config() { return { build: { rollupOptions: { input: { 'markdown-client': clientId } } } }; },\n configResolved(config) { if (!config.plugins.some(plugin => plugin.name === 'void-hono:pages')) throw new Error('Hono Markdown: configure voidHonoJsx() before voidHonoMarkdown().'); root = realpathSync(config.root); pagesDir = resolvePagesDir(root); rescan(); },\n buildStart() { rescan(); },\n hotUpdate({ file, timestamp }) {\n if (!file.endsWith('.md') || !normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n rescan();\n const entry = this.environment.moduleGraph.getModuleById(`\\0${clientId}`);\n if (entry) this.environment.moduleGraph.invalidateModule(entry, new Set(), timestamp, true);\n },\n resolveId(id) { if (id === clientId) return `\\0${id}`; },\n load(id) {\n if (id.endsWith(scriptQuery)) return source(id.slice(0, -scriptQuery.length)).clientCode || 'export {};';\n if (id !== `\\0${clientId}`) return;\n if (!files.size) return 'export {};';\n return `const scripts = {${[...files].map(([id, file]) => `${JSON.stringify(id)}: () => import(${JSON.stringify(normalizePath(file) + scriptQuery)})`).join(',')}};\nconst id = document.getElementById('app')?.getAttribute('data-md-script');\nif (id && scripts[id]) await scripts[id]();`;\n },\n transform: {\n filter: { id: /\\.md$/ },\n handler(source, id) {\n const result = compileMarkdown(source);\n const imports = result.imports.map((entry, index) => {\n const target = resolveComponent(entry.specifier, dirname(id), ['.tsx', '.jsx']);\n if (!target || !entry.specifier.startsWith('.')) throw new Error(`Hono Markdown: cannot resolve relative TSX/JSX island ${entry.specifier} in ${id}.`);\n return { ...entry, alias: `__island${index}`, islandId: normalizePath(relative(root, realpathSync(target))) };\n });\n const chunks = renderChunks(result.html, new Set(imports.map(entry => entry.importName)));\n const children = chunks.map(chunk => {\n if ('html' in chunk) return `raw(${JSON.stringify(chunk.html)})`;\n const entry = imports.find(entry => entry.importName === chunk.name)!;\n const props = literal(chunk.props);\n return `jsx('div', { 'data-island': ${JSON.stringify(entry.islandId)}, 'data-hydrate': ${JSON.stringify(entry.hydrate)}, 'data-props': JSON.stringify(${props}), children: jsx(${entry.alias}, ${props}) })`;\n });\n return { code: `import { jsx, Fragment } from 'hono/jsx/jsx-runtime';\nimport { raw } from 'hono/html';\n${imports.map(entry => `import ${entry.alias} from ${JSON.stringify(entry.specifier)};`).join('\\n')}\nexport const frontmatter = ${literal(result.frontmatter)};\nexport const headings = ${literal(result.headings)};\nexport default function MarkdownPage() { return jsx(Fragment, { children: [${children.join(',')}] }); }`, map: null };\n },\n },\n };\n}\n"]}
1
+ {"version":3,"file":"hono-markdown.js","sourceRoot":"","sources":["../../src/plugins/hono-markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFileSync, readdirSync, existsSync, realpathSync } from 'node:fs';\nimport { join, relative, dirname } from 'node:path';\nimport { normalizePath, type Plugin } from 'vite';\nimport { resolvePagesDir } from 'void/pages';\nimport { resolveComponent } from './resolve-component.ts';\nimport { createMarkdownCompiler, renderChunks } from './markdown-compiler.ts';\nimport type { HonoMarkdownOptions } from './markdown-features.ts';\nimport { markdownCopyId, markdownCopyCode } from './markdown-copy.ts';\nexport type { HonoMarkdownOptions } from './markdown-features.ts';\nimport type { HonoMarkdownApi } from './markdown-api.ts';\n\nconst clientId = 'virtual:void-hono-markdown-client';\nconst scriptQuery = '?hono-markdown-script';\nconst literal = (value: unknown) => `JSON.parse(${JSON.stringify(JSON.stringify(value))})`;\n\n/** Optional authored Markdown compiler; independent of @void/md private files. */\nexport function voidHonoMarkdown(options: HonoMarkdownOptions = {}): Plugin {\n const compiler = createMarkdownCompiler(options);\n let root = process.cwd();\n let pagesDir = resolvePagesDir(root);\n let scripts = new Map<string, string>();\n let files = new Map<string, string>();\n let sources = new Map<string, ReturnType<typeof compiler.parse>>();\n function rescan() {\n const nextScripts = new Map<string, string>();\n const nextFiles = new Map<string, string>();\n const nextSources = new Map<string, ReturnType<typeof compiler.parse>>();\n for (const entry of existsSync(pagesDir) ? readdirSync(pagesDir, { recursive: true, withFileTypes: true }) : []) {\n if (!entry.isFile() || !entry.name.endsWith('.md')) continue;\n const file = join(entry.parentPath, entry.name);\n const id = normalizePath(relative(pagesDir, file)).replace(/\\.md$/, '').replace(/\\.island$/, '').replace(/\\/index$/, '').replace(/^index$/, '') || 'index';\n const canonical = realpathSync(file);\n const extracted = nextSources.get(canonical) ?? compiler.parse(readFileSync(canonical, 'utf8'));\n if (!nextSources.has(canonical) && extracted.hasCode) extracted.clientCode = `import ${JSON.stringify(markdownCopyId)};\\n` + extracted.clientCode;\n nextSources.set(canonical, extracted);\n if (extracted.clientCode) { nextScripts.set(id, extracted.clientCode); nextFiles.set(id, file); }\n }\n // Commit complete generations only; a parse error must not publish partial data.\n scripts = nextScripts; files = nextFiles; sources = nextSources;\n }\n function source(file: string) {\n const extracted = sources.get(realpathSync(file));\n if (!extracted) throw new Error(`Hono Markdown: file is absent from the current page scan: ${file}`);\n return extracted;\n }\n const api: HonoMarkdownApi = { adapter: 'hono', clientEntryId: clientId, refresh: rescan, getClientScripts() { return scripts; }, getGraphSource(file) { return source(file).graphSource; } };\n return {\n // Void's Markdown entry/asset convention is shared with @void/md.\n name: 'void-md', enforce: 'pre', api,\n config() { return { build: { rollupOptions: { input: { 'markdown-client': clientId } } } }; },\n configResolved(config) { if (!config.plugins.some(plugin => plugin.name === 'void-hono:pages')) throw new Error('Hono Markdown: configure voidHonoJsx() before voidHonoMarkdown().'); root = realpathSync(config.root); pagesDir = resolvePagesDir(root); rescan(); },\n buildStart() { rescan(); },\n hotUpdate({ file, timestamp }) {\n if (!file.endsWith('.md') || !normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n rescan();\n const entry = this.environment.moduleGraph.getModuleById(`\\0${clientId}`);\n if (entry) this.environment.moduleGraph.invalidateModule(entry, new Set(), timestamp, true);\n },\n resolveId(id) { if (id === clientId || id === markdownCopyId) return `\\0${id}`; },\n load(id) {\n if (id === `\\0${markdownCopyId}`) return markdownCopyCode;\n if (id.endsWith(scriptQuery)) return source(id.slice(0, -scriptQuery.length)).clientCode || 'export {};';\n if (id !== `\\0${clientId}`) return;\n if (!files.size) return 'export {};';\n return `const scripts = {${[...files].map(([id, file]) => `${JSON.stringify(id)}: () => import(${JSON.stringify(normalizePath(file) + scriptQuery)})`).join(',')}};\nconst id = document.getElementById('app')?.getAttribute('data-md-script');\nif (id && scripts[id]) await scripts[id]();`;\n },\n transform: {\n filter: { id: /\\.md$/ },\n async handler(source, id) {\n const cached = sources.get(realpathSync(id));\n const result = await compiler.render(cached?.source === source ? cached : compiler.parse(source));\n const imports = result.imports.map((entry, index) => {\n const target = resolveComponent(entry.specifier, dirname(id), ['.tsx', '.jsx']);\n if (!target || !entry.specifier.startsWith('.')) throw new Error(`Hono Markdown: cannot resolve relative TSX/JSX island ${entry.specifier} in ${id}.`);\n return { ...entry, alias: `__island${index}`, islandId: normalizePath(relative(root, realpathSync(target))) };\n });\n const chunks = renderChunks(result.html, new Set(imports.map(entry => entry.importName)));\n const children = chunks.map(chunk => {\n if ('html' in chunk) return `raw(${JSON.stringify(chunk.html)})`;\n const entry = imports.find(entry => entry.importName === chunk.name)!;\n const props = literal(chunk.props);\n return `jsx('div', { 'data-island': ${JSON.stringify(entry.islandId)}, 'data-hydrate': ${JSON.stringify(entry.hydrate)}, 'data-props': JSON.stringify(${props}), children: jsx(${entry.alias}, ${props}) })`;\n });\n return { code: `import { jsx, Fragment } from 'hono/jsx/jsx-runtime';\nimport { raw } from 'hono/html';\n${imports.map(entry => `import ${entry.alias} from ${JSON.stringify(entry.specifier)};`).join('\\n')}\nexport const frontmatter = ${literal(result.frontmatter)};\nexport const headings = ${literal(result.headings)};\nexport default function MarkdownPage() { return jsx(Fragment, { children: [${children.join(',')}] }); }`, map: null };\n },\n },\n };\n}\n"]}