biomejs / biome

A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.
https://biomejs.dev
Apache License 2.0
15.28k stars 475 forks source link

☂️ Partial support for `.vue`, `.svelte` and `.astro` files #1719

Closed ematipico closed 8 months ago

ematipico commented 9 months ago

Description

What does partial support mean? It means that the objective is to parse only the JavaScript portions of the files, and ignore the rest.

Since everything works at workspace level, the support of these three files is pretty straightforward:

Astro

Parsing and capabilities

It's safe to assume that Astro files are always TypeScript files. So it should be parsed and handled as a JsFileSource::ts()

Vue

Parsing and capabilities

The JavaScript code is inside the ` tag. Let's use a regex to compile the start/end of the tags.

Let's use a simple check to understand the language, e.g. <script lang="ts">. Based on its value, we can compute the correct JsFileSource

Svelte

Parsing and capabilities

The JavaScript code is inside the ` tag. Let's use a regex to compile the start/end of the tags.

Let's use a simple check to understand the language, e.g. <script lang="ts">. Based on its value, we can compute the correct JsFileSource

How to help/contribute

First, each language must have implemented capabilities and parsing. With those two, we can implement the rest of the features.

Use this PR as a blueprint to understand how to add handling of files with a particular extension: https://github.com/biomejs/biome/pull/1718

Please comment if you want to help, and with what. We want to have only one person working on the same thing.

For testing, use https://github.com/biomejs/biome/pull/1718 as a reference. And if you require more information, you can create a draft PR and follow up there with questions you might have.

nhedger commented 9 months ago

Vue files can have multiple script tags afaik. Not sure about the others.

nhedger commented 9 months ago

I will try implementing the Vue support. I'll open a draft PR soon

pijusz commented 9 months ago

Is it safe to assume, that Astro JS Files are always Typescript? If you include something like define:vars prop to script, it becomes client-side only -> js. https://docs.astro.build/en/reference/directives-reference/#isinline

ematipico commented 9 months ago

Is it safe to assume, that Astro JS Files are always Typescript?

The initial objective is to parse only the frontmatter of the file, which is TypeScript. I got confirmation from Nate, who wrote the compiler.

The <script> tag will require more thoughts and care

varna commented 8 months ago

All of them (Vue, Svelte and Astro) uses Volar. They might have solutions for most of your problems.

ematipico commented 8 months ago

All of them (Vue, Svelte and Astro) uses Volar. They might have solutions for most of your problems.

Do you have more information to help us understand how Volar can help us?

nhedger commented 8 months ago

@ematipico While updating the VS Code extension to handle the additional file types, I've discovered that formatting works correctly when using the CLI, but does not work as expected when going through the LSP.

Given the following Astro file (but applies to others too), the formatted, when invoked via the LSP will return only the "script" part, and remove everything else from the file.

- ---
- statement ( );
- statement();
- ---
- 
- <div></div>
+ statement();
+ statement();

Not sure if something more needs to be done here

https://github.com/biomejs/biome/blob/8ea90d9ad3f1b21472830bdd8017b52785b14e6d/crates/biome_lsp/src/handlers/formatting.rs#L14-L54

ematipico commented 8 months ago

Yeah that makes sense. We still need to update the LSP side to stitch up the original content with the new content, like we do in the CLI

ematipico commented 8 months ago

Now the LSP supports diagnostics and code actions for these files.

We just need to implement the rest of the features, which is going to be very straightforward.

If anyone wants help, this is going be very easy, even for new contributors. Feel free to comment here and I'll tell you how to land the support of the missing features.

tom751 commented 8 months ago

I wouldn't mind helping out with the above, not sure where to start though

ematipico commented 8 months ago

You could start with format_range and/or format_on_type for any of those files. The handlers of those files can be found here

https://github.com/biomejs/biome/tree/main/crates/biome_service/src/file_handlers

To implement the handler for a file - for example Astro, we have to create the new handlers. Let's do it for format_range. Create a new function here:

https://github.com/biomejs/biome/blob/06e6476ddad21f23be2659af3d787c2f921fcfb4/crates/biome_service/src/file_handlers/astro.rs#L134

And update the capabilities here, with Some(format_range)

https://github.com/biomejs/biome/blob/06e6476ddad21f23be2659af3d787c2f921fcfb4/crates/biome_service/src/file_handlers/astro.rs#L92

The types of the functions can be found here:

https://github.com/biomejs/biome/blob/06e6476ddad21f23be2659af3d787c2f921fcfb4/crates/biome_service/src/file_handlers/mod.rs#L376-L380

The content of this new format_range function are slim. We just need to call what the JS handler does. So let's export this handler using pub(crate):

https://github.com/biomejs/biome/blob/06e6476ddad21f23be2659af3d787c2f921fcfb4/crates/biome_service/src/file_handlers/javascript.rs#L659

The content of the function format_range in the astro.rs file will look like this:

javascript::format_range( ) // pass the payload here

Take inspiration from this function:

https://github.com/biomejs/biome/blob/06e6476ddad21f23be2659af3d787c2f921fcfb4/crates/biome_service/src/file_handlers/astro.rs#L127-L133

j commented 8 months ago

@ematipico quick question. Svelte script code blocks should have everything spaced but these changes move the entire block back a space to the start of the line. Can I have it add a space to the block?

<script>
  const foo = …
</script>

Instead of

<script>
const foo = …
</script>
ematipico commented 8 months ago

@j

That's part of the limitations and expectations. This will get solved once we will support these files fully

Shyam-Chen commented 8 months ago

Has it been released?

// package.json
    "@biomejs/biome": "^1.5.3-nightly.69f9031",
// biome.json
{
  "formatter": {
    "indentStyle": "space",
    "lineWidth": 120
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single"
    }
  }
}
> biome check --apply ./src

Fixed 4 file(s) in 16ms

Only able to scan .ts files, not .vue files.

j commented 8 months ago

@j

That's part of the limitations and expectations. This will get solved once we will support these files fully

@ematipico okay. I just gave this a try out of excitement and noticed it as the PR references what I'd expect out of the formatting.

ematipico commented 8 months ago

@Shyam-Chen No, it will be released in the next minor

twonil-jordan-stout commented 7 months ago

@ematipico Svelte files still are getting formatting without the leading indentation:

<script>
const foo = …
</script>
ematipico commented 7 months ago

@twonil-jordan-stout that's expected, please find more here: https://biomejs.dev/internals/language-support/#html-super-languages-support

tanoc commented 4 months ago

Couldn't this be an option? or changed for .svelte files? I think in Svelte the common style has indentation: https://svelte.dev/examples/hello-world

MaxSvargal commented 3 months ago

Still waiting for the full support of svelte. Until then, I cannot use this wonderful tool :(