fix(render): unwrap a bare shiki class on pre back to a plain fence#259
Merged
farnabaz merged 9 commits intoJun 30, 2026
Merged
Conversation
The `::pre{attr}` block-attribute wrapper form treats any surviving `class`
on a `pre` node as a user attribute. `userBlockAttrs` strips shiki's injected
class so highlighted code blocks round-trip to a plain fence, but the guard
only matched `class="shiki ..."` (with trailing theme tokens). Single-theme
shiki emits a bare `class="shiki"`, which slipped through and forced every
highlighted code block to serialize as `::pre{.shiki}\n```…```\n::` instead
of a clean fence — including code blocks nested inside component slots.
Widen the guard to `/^shiki(?:\s|$)/` so the bare-`shiki` case is recognized
and dropped like the multi-token form.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@hendrikheil is attempting to deploy a commit to the NuxtLabs Team on Vercel. A member of the Team first needs to authorize it. |
comark
@comark/angular
@comark/ansi
@comark/html
@comark/nuxt
@comark/react
@comark/svelte
@comark/vue
commit: |
`highlightCodeBlocks` merged any existing `pre` class as a user class via the
`shiki … . <user>` form. Running it twice on the same tree (e.g. a stored,
already-highlighted block re-highlighted after an edit round-trip) treated the
prior `shiki` class as a user class, accumulating `shiki . shiki` — which then
leaked back out as a `::pre{.shiki}` wrapper on render.
Recover the real user class from a previously-injected class before re-merging,
so the result is stable across passes. Genuine user classes are still preserved.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The idempotency helper and the widened guard add ~1k to comark's published size, crossing the rounded-kilobyte boundary in the bundle-size snapshot. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `pre` handler reads `node[1].code` as the fence body when present (editors
preserve the raw source there while children hold highlighted spans). Since it
rides in the fence, `code` must not also echo back as a `::pre{code="…"}`
block-attribute wrapper. Add it to the `pre` implicit-attr drop list alongside
`language`/`filename`/etc. Also bump the bundle-size snapshot accordingly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move shiki-codeblock-roundtrip.test.ts to plugins/highlight.test.ts to match the per-plugin test convention. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Trimming the verbose comments shrank the (unminified, tsc-built) dist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the three hard-coded `.`/` . ` sentinels (highlight plugin write + re-highlight read, stringify read) with HIGHLIGHT_CLASS_SEPARATOR from the stringify module. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collaborator
|
Thanks for the PR @hendrikheil - if (key === 'class' && tag === 'pre' && typeof value === 'string' && value.startsWith('shiki ')) {
+ if (key === 'class' && tag === 'pre' && typeof value === 'string' && value.startsWith('shiki')) {But as for |
Collaborator
|
We can keep |
Contributor
Author
|
The PR really contains two fixes:
|
Drop the highlight idempotency change — re-highlighting can't accumulate
`shiki . shiki` in practice, since highlightCodeBlocks only selects `pre >
code` nodes whose code child is still a string and skips already-highlighted
blocks. Collapse the render-side guard to `startsWith('shiki')` and keep the
`code` drop (nuxt-studio stores the raw source there). Revert highlight.ts and
the bundle-size snapshot to match.
Drop the `code` attribute change — the `code`-on-`pre` leak will be fixed at
the source in nuxt-studio instead. Leaves only the render-side guard widening
(`startsWith('shiki ')` -> `startsWith('shiki')`) so a single-theme `shiki`
class unwraps to a plain fence, plus the test covering it.
Contributor
Author
|
Actually, I'll just fix the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Keeps shiki-highlighted code blocks round-tripping to a plain fence instead of leaking a
::pre{.shiki}block-attribute wrapper.The leak was introduced in #214, which added the
::pre{attr}wrapper form together with theuserBlockAttrsstrip guard — that guard never matched the bareshikiclass.The fix
The
::pre{attr}wrapper form treats anyclassthat survivesuserBlockAttrsas a user attribute.userBlockAttrsstrips shiki's injectedclass, but the guard only matchedclass="shiki "with a trailing space (the multi-token dual-theme form). Single-theme shiki emits a bareclass="shiki", which slipped through and forced every highlighted code block to serialize as a::pre{.shiki}wrapper — especially visible for code blocks nested in component slots (which also produced a duplicate closing::).Widened the guard from
value.startsWith('shiki ')tovalue.startsWith('shiki').Tests
packages/comark/test/plugins/highlight.test.ts:class="shiki"→ plain fenceclass="shiki shiki-themes … dark:…"→ plain fence (unchanged)::preFull suite green (1079 passed, 2 todo); existing shiki SPEC fixtures unaffected.
🤖 Generated with Claude Code