fix(svelte2tsx): don't treat <style>-like text in a script comment as a real style tag#3079
Conversation
…as a real style tag svelte-check reported a false `element_unclosed: <script> was left open` for a file whose `<script>` is correctly closed, when the literal token `<style>` appears inside the script (e.g. in a comment) *and* the file also contains a real `<style>` block. svelte/compiler accepts the same source. Root cause: the non-greedy `styleRegex` in `findVerbatimElements` can start matching at a `<style>` substring inside the script and run past the real `</script>` up to the next `</style>`. The existing `insideScript` guard only skipped style matches *strictly nested* in a script tag, so this partially overlapping match slipped through and `blankVerbatimContent` then blanked out the real `</script>`, making the compiler see an unclosed script. Relax the guard to also skip a style match that merely *starts* inside a script tag. Fixes sveltejs#3071 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: a26f7b8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
This won't work. The actual style tag should be removed. So the proper fix isn't to filter it out, but to properly recognise the actual start tag. |
…ing the false match The previous approach relaxed the insideScript guard to drop a style match that starts inside a script. That removed the false match but also dropped the real `<style>` block, because the non-greedy style regex had already swallowed everything from the `<style>` token in the script comment up to the real `</style>` into a single match. Instead, find the script containers first, blank them out (newlines preserved so character offsets stay put), then run the style regex on that masked text. The style regex can no longer see a `<style>` token sitting inside a script, so it matches the actual start tag. This covers the script-to-style direction from sveltejs#3071. The mirror case (a `<script>` token inside a `<style>` comment) has the same shape and is left as a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
You're right, filtering it out dropped the real One thing I hit while doing this: the mirror case breaks the same way on |
Fixes #3071
Problem
svelte-check(and the VS Code extension, same engine) reports a falseelement_unclosed: <script> was left openfor a file whose<script>is correctly closed. The trigger is the literal token<style>appearing inside the<script>(e.g. in a//comment) when the file also contains a real<style>block.svelte/compiler'scompile()accepts the exact same source without error, so this is asvelte2tsxfalse positive.Minimal reproduction:
Root cause
In
packages/svelte2tsx/src/utils/htmlxparser.ts,findVerbatimElementsuses a non-greedystyleRegexthat can start matching at a<style>substring inside the script and run past the real</script>up to the next</style>.The existing
insideScriptguard was meant to drop such false style matches, but it only skipped matches that are strictly nested inside a script tag (tag.start < style.start && tag.end > style.end). In the issue's case the false style match ends after the script tag, so the guard didn't fire.blankVerbatimContentthen blanked out the real</script>along with the fake style content, and the compiler correctly complained about an unclosed<script>in the now-broken text.Fix
Relax the guard to also skip a style match that merely starts inside a script tag:
Test plan
test/svelte2tsx/samples/style-tag-in-script-comment-with-real-stylecovering the exact reproduction (a<style>token in a script comment plus a real separate<style>block). It fails before the fix (<script> must have a closing tag) and passes after, emitting correct TSX with both the script comment and the real<style>preserved.svelte2tsxsample suite passes (371 tests), including the neighbouringstyle-in-script(a<style>...</style>string literal inside a script with no real style block — still correctly treated as inside-script) andts-style-and-script(a normal script followed by a separate style block — unaffected).pnpm lint(Prettier) passes.