sveltejs/language-tools

Intellisense suggests Javascript inside style tag

TheIcyColdPenguin opened this issue · 2 comments

Describe the bug

Intellisense suggests Javascript objects instead of CSS properties when Ctrl+Space is pressed.

This is the minimal amount of code I could reproduce the issue with.
Even changing the comparison from <= to < resolves the issue.

image

Reproduction

  • Create a new svelte project using vite
  • replace App.svelte with the following code
<button
    on:mousedown={(e) => {
        if ({ x: 1 }.x <= 0) {
        }
    }}
/>

<style>
    button {
    }
</style>

Expected behaviour

Should display CSS properties when Ctrl-Space is pressed

System Info

  • OS: Windows 11
  • IDE: VSCode 1.89.1 (Running in WSL 2)
  • Extension: Svelte For VSCode v108.5.0

Which package is the issue about?

Svelte for VS Code extension

Additional Information, eg. Screenshots

dependencies in package.json

"devDependencies": {
    "@sveltejs/vite-plugin-svelte": "^3.0.2",
    "svelte": "^4.2.12",
    "vite": "^5.2.0"
  }

Investigation

This bug occurs because the vscode-html-languageservice HTMLParser is not meant to parse Svelte, and interprets the '<' character in JS as starting tag character.

When it happens, <style> is no longer a root node in parsed node tree, but a child of another node that starts from the '<' character. As root <style> can't be found, during autocomplete, the caret position is not determined to be inside <style> tag. (this.styleInfo == null in below code)

this.styleInfo = this.addDefaultLanguage(
config,
extractStyleTag(this.content, this.html),
'style'
);

This bug does not trigger often because usually the vscode lsp's HTMLParser manages to generate a good-enough tree even when given a very incorrect (Svelte) HTML code.

Reproduction

Here is an even more minimal reproducable code:

<button on:click={() => {console.log({x:1}.x < 2)}}></button>
 
<style>
  /* autocomplete here returns js/ts autocomplete */
</style>

I am closing this in favour of #2155. As pointed out, the problem is the moustache tag is not strictly compliant with HTML. Both cases have an end bracket that looks like it ends the moustache and a > or < that looks like a start or end tag. A proper fix would need a js/ts parser to determine where the expression ends. But It might be slower in large files and could also have problems when the expression has syntax errors. You can workaround it by wrapping the expression with double-quote or move it to the script tag.

<button
    on:mousedown="{(e) => {
        if ({ x: 1 }.x <= 0) {
        }
    }}"
/>

<style>
    button {
    }
</style>