Skip to content

Emanuele Stoppa

6 posts by Emanuele Stoppa

Biome v1.6

Update Biome using the following commands:

Terminal window
npm install --save-dev --save-exact @biomejs/biome@latest
npx @biomejs/biome migrate

Partial support for Astro, Svelte and Vue files

Section titled Partial support for Astro, Svelte and Vue files

In this release, we’re happy to provide partial support for Astro, Svelte and Vue files. What does partial support mean?

While the team is working on a unified data structure for HTML-ish languages, we discovered that we could provide Biome functionalities to those files with just a few changes, albeit with some limitations.

This means that Biome is able to analyze the JavaScript/TypeScript portion of said files, and all features are available: formatting, linting and import sorting! Here’s an example of what you should expect in terms of developer experience:

Screenshot of Biome linting in action for an Astro file in VSCode

Make sure to read the documentation about expectations and limitations.

Configuration, lighter and more powerful

Section titled Configuration, lighter and more powerful

Biome now accepts the biome.jsonc file as configuration! You can insert all the comments you want in there.

From this version, Biome can use the extends property to resolve other configuration files that are inside installed dependencies.

There are few important steps in order to make the configuration discoverable. The file must be exported from a "module" package, and the file should be exported in your package.json like this:

{
"name": "@shared-configs",
"type": "module",
"exports": {
"./biome": "./biome.json"
}
}

This set up allows to expose a specifier @shared-configs/biome, which you use inside your biome.json file.

{
"extends": ["@shared-configs/biome"]
}

The resolution of the dependencies is powered by the library oxc-resolver, one of the many libraries provided by the OXC project. It’s battle-tested and spec compliant!

We reduced the size our configuration by a factor of 6.5! This change might not have massive effects on the speed of the program, but it greatly reduced the memory used when running the CLI or the LSP.

Other than fixes, the formatter provides two new options that should improve the compatibility with Prettier.

When formatter.attributePosition has the value multiline, all attributes of HTML-ish languages (JSX/TSX as for time of writing) will be collapsed on multiple lines regardless of their numbers:

With variant auto (default)

The attributes are automatically formatted, and they will collapse in multiple lines only when they hit certain criteria.

file.jsx
<Button as="link" style="primary" href="https://example.com">
Hit me
</Button>

With variant multiline

The attributes are always formatted on multiple lines, regardless.

file.jsx
<Button
as="link"
style="primary"
href="https://example.com"
>
Hit me
</Button>

The contributor @octoshikari implemented this new feature by themselves! Huge thank you for helping the Biome project.

Option json.formatter.trailingCommas

Section titled Option json.formatter.trailingCommas

Previously, Biome parser introduced an option that would allow to parse JSON and JSONC files that contained a trailing comma. This was required to ease the friction caused by other tools that tolerate trailing commas by default (e.g. VSCode, Prettier, etc.).

Unfortunately, our formatter wasn’t as tolerant. But with this release, we’ve introduced the option json.formatter.trailingCommas. It allows you to apply the same rules as with js.formatter.trailingComma.

With variant none (default)

The formatter removes the trailing comma upon formatting.

file.json
{
"lorem": "ipsum",
"lorem": "ipsum",
"lorem": "ipsum",
"lorem": "ipsum_last"
}

With variant all

The formatter adds the trailing comma upon formatting.

file.json
{
"lorem": "ipsum",
"lorem": "ipsum",
"lorem": "ipsum",
"lorem": "ipsum_last",
}

Easier migration from Prettier

Section titled Easier migration from Prettier

This release introduces a new command called biome migrate prettier. This command will read your Prettier .prettierrc/prettier.json and .prettierignore, and attempt to port its options and globs in Biome.

Given a prettier.json file, Biome will modify the existing configuration file to match Prettier’s options:

prettier.json
{ "useTabs": false, "semi": true, "singleQuote": true }
biome.json
{
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 80,
"attributePosition": "auto"
},
"linter": { "enabled": true },
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "all",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSpacing": true,
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto"
}
}
}

New rules are incubated in the nursery group. Once stable, we promote them to a stable group. The following rules are promoted:

Additionally, the following rules are now recommended:

  • Remove nursery/useGroupedTypeImport. The rule style/useImportType covers the behavior of this rule.

New rules are now available:

  • We drastically reduced the number of protected files, which means you can now format your package.json, tsconfig.json, etc. with Biome. Lock files are still considered protected.
  • The CLI now does a better job at reporting the total number of files and the files that were really changed.
  • When a diagnostic shows a file name on the terminal that is integrated with your editor, you can click it and the editor will open the file for you.
  • The command biome rage now accepts two nice options: --formatter and --linter.
  • We removed some superfluous error diagnostic when running the biome check command.

Roadmap 2024

We are thrilled to share what the Core Contributors and Maintainers would like to focus on in 2024.

We want to remind you that Biome is a community-driven project, so we can only promise that some of the ideas outlined below will be shipped.

However, if you’re excited about some aspects of the project, and you want to see some of them developed faster than others, you can help us in many ways:

The project is young and can’t compete against giants such as Prettier, ESLint, Webpack, Vite, ESBuild, etc. However, the recent events (sponsors, bounty challenge, Biome being a fork of Rome) showed that the users have interest in the project, and we showed those users that we have the tools to fulfil a need.

Moving small projects from ESLint/Prettier is easy, but moving **big ** code bases is challenging and time-consuming; this is a big friction point in Biome.

Users have different needs, though, so it will only be possible to satisfy some of them. We want to ensure that all features and contributions to our project embrace our philosophy and provide the best experience by default.

  1. Help users to move to Biome
  2. Expand Biome’s language support so Biome tools can span more of the web ecosystem
  3. Deepen Biome’s existing capabilities to offer more functionalities
  4. Plugins
  5. Transformations
  6. Community and content
  • Offer guides on our website to users who want to migrate from Prettier (CLI commands and configuration)
  • Offer guides on our website to users who want to migrate from ESlint (CLI commands and configuration)
  • Offer a section on our website that shows a mapping of the ESLint rules to our rules
  • Offer commands to ease the transition
    • A command called biome migrate prettier that will read .prettierrc and .prettierignore will update the biome.json file (or create it) with the configuration from the Prettier files.
    • A command called biome migrate eslint will read the JSON configuration of Eslint and the ignore file. There will be expectations and limitations.

Expand Biome’s language support

Section titled Expand Biome’s language support

CSS is our next language of focus, and we are making good progress. HTML and Markdown will follow. Follow our up-to-date page to keep up with the progress of our work.

The CSS language will enable much work and experimentation: CSS formatting and linting, and we will port some of the lint rules from stylelint. A new area of experimentation is cross-linting.

The idea of cross-linting can be explained with an example: compute the CSS styles/classes defined in a project and warn a user when said styles aren’t used inside JSX/HTML files.

Plus, we unlock another area of experimentation, which is embedded formatting.

HTML and Markdown will be our next languages of focus. HTML will enable us to parse other variants of HTML that are popular in the frontend ecosystem: Vue, Svelte and Astro, and this would require some exploration of how to represent super languages of HTML.

Deepen Biome’s existing capabilities to offer more functionalities.

Section titled Deepen Biome’s existing capabilities to offer more functionalities.
  • Project analysis and dependency resolution
  • Type system
  • CLI

Project analysis and dependency resolution

Section titled Project analysis and dependency resolution

We will provide lint rules to read the manifest and detect errors such as invalid licenses.

With project resolution, we will be able to provide more lint rules, some of which will be able to detect unused modules.

With dependency resolution, we can - for example - detect dependencies that aren’t used inside a project.

With this infrastructure, our LSP is going to be more powerful and provide more features, for example:

  • rename variables across a project;
  • auto-complete for imports;
  • in-line types

Building a full-fledged type system such as TypeScript is a massive effort; that’s why we decided to take a different direction and start by building a subset of the type system that requires stricter typing. This approach would allow us to build some important lint rules that users have been asking for.

This will come with a downside: we will have to rely on a stricter code and minimal type inference from the compiler.

Once we have something we can rely on, we can slowly widen the capabilities of our type system.

More features for the command line tool, such as:

  • Add the explain command for offline documentation;
  • Allow the output to be exported in different formats (JSON, etc.)
  • Auto-completion for other shells such as zsh;
  • Implement the --modified argument, which allows to format - for example - only the modified lines of a document;
  • Expose metrics for Biome’s operations and being able to track down possible performance bottlenecks;

We will explore plugins and come up with a design that fits Biome. Biome is different from other tools because Biome is a toolchain that has multiple tools in it, so we have to think out of the box and propose a design that might differ from the tools people are used to.

We don’t know yet what a Biome’s plugin will look like, although a plugin should be able to tap all the tools that Biome offers.

Some ideas that we will consider:

  • DSL
  • WASM
  • A Runtime

Transformations and code generation will be our first steps towards our compiler.

We will provide the ability to transform TypeScript and JSX files into JavaScript files.

Biome has a growing ecosystem, with an official VSCode extension, an official IntelliJ extension, and a Discord bot. We want to grow the features these tools provide and welcome anyone who wants to help us.

Our community is slowly growing, and we want to reward everyone who sticks around and contributes to Biome. At Biome, * *we value every contribution **, so you don’t need to be proficient in Rust to help us. Even participating in discussions and helping us to shape our features or helping other people are considered contributions. If you’d like to continue contributing to our ecosystem, we also encourage you to nominate yourself as a maintainer of the project.

Recently Biome started its own YouTube Channel. We will use this channel to share learning content with the community.

With this blog post, we also want to officially announce our new logo, homepage and rebranding of the website.

With this new logo, we want to give a different meaning to the project. Biome **isn’t ** a fork of Rome anymore, but a self-sufficient project ready to bloom.

The triangle of the logo represents the mountains - **soil ** -, and the curly shape on the bottom left represents a wave of the ocean - **water **. Two elements that are important in creating a self-sufficient ecosystem, so it can thrive and grow.

Biome v1.5

Along with the Roadmap for 2024, the new logo and homepage, we also published a new version. This version has few features around the CLI and many fixes in our formatter. Our TypeScript, JSX and JavaScript formatting has surpassed the 97% compatibility rate with Prettier. Biome now provides over 190 lint rules.

Update Biome using the following commands:

Terminal window
npm install --save-dev --save-exact @biomejs/biome@latest
npx @biomejs/biome migrate
  • Process only the files that were changed.
  • The command biome ci now prints diagnostics in GitHub PRs.
  • A new command,biome explain.
  • The command biome migrate updates the $schema.
  • New lint rules.

Process only the files that were changed

Section titled Process only the files that were changed

If you enable the integration with VCS, you can tell Biome to process only the files that were changed. As for now, this feature computes the files that were changed by using a VCS, so Biome doesn’t know exactly which lines changed.

This feature practically makes some utilities such as lint-staged obsolete.

To take advantage of this feature, you have to tell Biome what’s the default branch in the configuration file, and then you’ll have to pass the option --changed via CLI:

biome.json
{
"vcs": {
"enabled": true,
"clientKind": "git",
"defaultBranch": "main"
}
}

Once you modified some files, use the new option to the command you need, for example the format command:

Terminal window
biome format --changed --write

The command biome ci now prints diagnostics in GitHub PRs

Section titled The command biome ci now prints diagnostics in GitHub PRs

For quite some time, users were confused by the difference between the commands check and cibecause, until now, their behaviours have been very similar. From this version, the command ci can detect the GitHub CI environment and print annotation in the PRs.

Screenshot of a GitHub annotation printed by Biome

It’s possible that you would need to change your permissions of your workflow files in case you don’t see the annotations:

.github/workflows/action.yml
permissions:
pull-requests: write

This command will serve as an “offline” documentation tool. In this release, the command supports the explanation of all the lint rules; for example you can request documentation for noAccumulatingSpread:

Terminal window
biome explain noAccumulatingSpread

Which will print the following Markdown:

# noAccumulatingSpread
No fix available.
This rule is recommended.
# Description
Disallow the use of spread (`...`) syntax on accumulators.
Spread syntax allows an iterable to be expanded into its individual elements.
Spread syntax should be avoided on accumulators (like those in `.reduce`)
because it causes a time complexity of `O(n^2)` instead of `O(n)`.
Source: https://prateeksurana.me/blog/why-using-object-spread-with-reduce-bad-idea/
## Examples
### Invalid
```js,expect_diagnostic
var a = ['a', 'b', 'c'];
a.reduce((acc, val) => [...acc, val], []);
```
```js,expect_diagnostic
var a = ['a', 'b', 'c'];
a.reduce((acc, val) => {return [...acc, val];}, []);
```
```js,expect_diagnostic
var a = ['a', 'b', 'c'];
a.reduce((acc, val) => ({...acc, [val]: val}), {});
```
## Valid
```js
var a = ['a', 'b', 'c'];
a.reduce((acc, val) => {acc.push(val); return acc}, []);
```

We plan to make this output more readable for terminals, as well as provide autocompletion for this command.

The command biome migrate updates the $schema

Section titled The command biome migrate updates the $schema

The command biome migrate now updates the $schema value inside the configuration file biome.json if you avail of the online schema. Run this command as soon as you update to Biome v1.5.0:

biome.json
{
"$schema": "https://biomejs.dev/schemas/1.4.1/schema.json"
"$schema": "https://biomejs.dev/schemas/1.5.0/schema.json"
}
interface I {
}
export {I};
nursery/useExportType.js:2:8 lint/nursery/useExportType  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   All exports are only types and should thus use export type.

    1 │ interface I {}
  > 2 │ export { I };
          ^^^^^^
    3 │ 

   Using export type allows transpilers to safely drop exports of types without looking for their definition.

   Safe fix: Use a grouped export type.

    2 │ export·type·{·I·};
         +++++
import {A} from "./mod.js";
type TypeOfA = typeof A;
let a: A;
nursery/useImportType.js:1:1 lint/nursery/useImportType  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   All these imports are only used as types.

  > 1 │ import { A } from "./mod.js";
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    2 │ type TypeOfA = typeof A;
    3 │ let a: A;

   Importing the types with import type ensures that they are removed by the transpilers and avoids loading unnecessary modules.

   Safe fix: Use import type.

    1 │ import·type·{·A·}·from·"./mod.js";
         +++++

Enforces naming conventions for JavaScript and TypeScript filenames.

import fs from 'fs';
nursery/useNodejsImportProtocol.js:1:16 lint/nursery/useNodejsImportProtocol  FIXABLE  ━━━━━━━━━━━━━━━━━

   Import from Node.js builtin module "fs" should use the "node:" protocol.

  > 1 │ import fs from 'fs';
                  ^^^^
    2 │ 

   Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.

   Unsafe fix: Change to "node:fs".

    1  - import·fs·from·'fs';
      1+ import·fs·from·"node:fs";
    2 2

import fs from "fs";
import path from "node:path";
nursery/noNodejsModules.js:1:16 lint/nursery/noNodejsModules ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   Using Node.js modules are forbidden.

  > 1 │ import fs from "fs";
                  ^^^^
    2 │ import path from "node:path";
    3 │ 

   Can be useful for client-side web projects that do not have access to those modules.

   Remove the import module.

function f() {
console.log(x);
const x;
}
nursery/noInvalidUseBeforeDeclaration.js:3:11 parse ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   Const declarations must have an initialized value.

    1 │ function f() {
    2 │     console.log(x);
  > 3 │     const x;
             ^
    4 │ }
    5 │ 

   This variable needs to be initialized.

eval("var a = 0");
nursery/noGlobalEval.js:1:1 lint/nursery/noGlobalEval ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   eval() exposes to security risks and performance issues.

  > 1 │ eval("var a = 0");
   ^^^^
    2 │ 

   See the MDN web docs for more details.

   Refactor the code so that it doesn't need to call eval().

Object = null;
nursery/noGlobalAssign.js:1:1 lint/nursery/noGlobalAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   A global variable should not be reassigned.

  > 1 │ Object = null;
   ^^^^^^^
    2 │ 

   Assigning to a global variable can override essential functionality.

/^[Á]$/u;
nursery/noMisleadingCharacterClass.js:1:1 lint/nursery/noMisleadingCharacterClass ━━━━━━━━━━━━━━━━━━

   Unexpected combined character in the character class.

  > 1 │ /^[Á]$/u;
   ^^^^^^^^
    2 │ 

const foo = {
then() {
}
};
nursery/noThenProperty.js:2:5 lint/nursery/noThenProperty ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   Do not add then to an object.

    1 │ const foo = {
  > 2 │     then() {}
       ^^^^
    3 │ };
    4 │ 

const foo = {
get then() {
}
};
var a = x ? true : true;
nursery/noUselessTernary.js:1:9 lint/nursery/noUselessTernary ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   Unnecessary use of boolean literals in conditional expression.

  > 1 │ var a = x ? true : true;
           ^^^^^^^^^^^^^^^
    2 │ 

   Simplify your code by directly assigning the result without using a ternary operator.

   If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
     Check for more details about NOT operator.

Biome formatter wins the Prettier challenge

With the release of Biome **v1.4.0 **, we claim the bounty of the Prettier challenge!

With v1.4.0, you’ll get a better formatter experience, more formatting options, new VSCode features, new sponsors and more!

You can upgrade Biome by running the following command:

Terminal window
npm install --save-dev --save-exact @biomejs/biome@1.4.0
pnpm update --save-exact @biomejs/biome@1.4.0
yarn upgrade --exact @biomejs/biome@1.4.0

Biome formatter has now **over 96% in terms of compatibility ** against Prettier! This score is computed for JavaScript, TypeScript, and JSX formatting.

Merit of challenge that was launched by Christopher Chedeau, one of the Prettier’s creators.

The challenge attracted the attention of many people, and some of them decided to contribute to Biome to claim part of the bounty. I did see something amazing: contributors had an amazing coordination, they took ownership of the tasks and delivered the solution in a matter of hours.

I believe the main factors that made this possible are three:

  1. Money. It’s a fact, and it’s completely fine if someone decides to contribute only for earning a small stipend out of it.
  2. Communication. We used GitHub as only medium of coordination. We provided information, instructions and help on how to deliver.
  3. Infrastructure. Biome relies on a solid testing infrastructure, built by previous Rome Tools employees and contributors. It’s able to catch every reformat bug, provide granular diffs and warn the user if the emitted output is the different from the one emitted by Prettier.

Before the challenge, Biome had roughly a compatibility rate of 85%, based on our internal metrics (JavaScript, TypeScript and JSX, on options parity). Even though 85% might seem high, the impact of a low number such as 15% on big code bases is huge, and people might feel intimidated by so many changes, causing early adopters to receive frictions when bring Biome to their team. A member of our community shared some insights:

As a great example of how much even just that last 5% has improved things for large codebases (and specifically with bracketSpacing and now bracketSameLine implemented) i ran it one project in our monorepo […].

Just last week, this number [diagnostics] was more than 6,000. Even with the bracket options ignored, it was still more than 1000, and now there are only 200 left!

Although the challenge is over, we are committed to improve even more the compatibility score with prettier. Any contribution in this regard is very welcome.

The challenge has also uncovered some cases in Prettier’s emitted output that we decided to not follow. We have created a new section in our website that explains them. Our hope is to make this section smaller with the time.

If there’s a divergence that isn’t documented in our website, you should consider that a bug and file an issue.

With this challenge, we added new options to the formatter:

  • lineEnding

    Use this option to match the line endings of your OS. We support lf (line feed - \n), cr (carriage return - \r) and crlf (carriage return line feed - \r\n).

  • bracketSameLine

    example.js
    // Existing behavior. Now also the default, meaning `bracketSameLine: false`.
    <Foo
    className={somethingReallyLongThatForcesThisToWrap}
    anotherReallyLongAttribute={withAValueThatsSurelyTooLong}
    soThatEverythingWraps
    >
    Hello
    </Foo>
    <Foo
    selfClosingTags={likeThisOne}
    stillPlaceTheBracket={onItsOwnLine}
    toIndicateThat={itClosesItself}
    />

    After formatting with "bracketSameLine": true:

    example.js
    // New behavior, with `bracketSameLine: true`.
    <Foo
    className={somethingReallyLongThatForcesThisToWrap}
    anotherReallyLongAttribute={withAValueThatsSurelyTooLong}
    soThatEverythingWraps>
    Hello
    </Foo>
    <Foo
    selfClosingTags={likeThisOne}
    stillPlaceTheBracket={onItsOwnLine}
    />
  • bracketSpacing

    example.js
    import { sort } from "sort.js";
    const value = { sort };

    After formatting with "bracketSpacing": false:

    example.js
    import {sort} from "sort.js";
    const value = {sort};

The VSCode has been moved to a new repository.

We removed the bundled binary from the extension, and you’ll be able to download the version that you want. Here’s a small video of how it works:

From today, we release a **nightly ** version of the extension. This is a version meant for early adopters and to test things before they are officially released.

People that rely on Biome LSP will be pleased that they can now pass a custom configuration to the command lsp-proxy, using the option --config-path. The same option is accepted by the command start:

Terminal window
biome --config-path=../path/where/config/is lsp-proxy
biome --config-path=../path/where/config/is start

The CLI now exposes the option --diagnostic-level, that allows to filter the kind of diagnostics printed to terminal.

Terminal window
biome check --diagnostic-level=error ./src

New lint rules, and promoted rule

Section titled New lint rules, and promoted rule

Biome is a linter too, and it features 177 rules! In this release, some rules are promoted and new ones are available.

  • noDefaultExport

    export default function f() {}
    nursery/noDefaultExport.js:1:8 lint/nursery/noDefaultExport ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
       Avoid default exports.
    
      > 1 │ export default function f() {};
              ^^^^^^^
        2 │ 
    
       Default exports cannot be easily discovered inside an editor and don't encourage the use of consistent names through a code base.
    
       Use a named export instead.
    
    
  • noAriaHiddenOnFocusable

    <div aria-hidden="true" tabIndex="0" />
    nursery/noAriaHiddenOnFocusable.js:1:1 lint/nursery/noAriaHiddenOnFocusable  FIXABLE  ━━━━━━━━━━━━━━
    
       Disallow aria-hidden="true" from being set on focusable elements.
    
      > 1 │ <div aria-hidden="true" tabIndex="0" />
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        2 │ 
    
       aria-hidden should not be set to true on focusable elements because this can lead to confusing behavior for screen reader users.
    
       Unsafe fix: Remove the aria-hidden attribute from the element.
    
        1 │ <div·aria-hidden="true"·tabIndex="0"·/>
           -------------------
    
  • noImplicitAnyLet

    var a;
    a = 2;
    nursery/noImplicitAnyLet.js:1:5 lint/nursery/noImplicitAnyLet ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
       This variable implicitly has the any type.
    
      > 1 │ var a;
           ^
        2 │ a = 2;
        3 │ 
    
       Variable declarations without type annotation and initialization have implicitly the any type. Declare type or initialize the variable with some value.
    
    
  • useAwait

    async function fetchData() {
    // Missing `await` for the promise returned by `fetch`
    return fetch("/data");
    }
    nursery/useAwait.js:1:1 lint/nursery/useAwait ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
       This async function lacks an await expression.
    
      > 1 │ async function fetchData() {
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      > 2 │ // Missing `await` for the promise returned by `fetch`
      > 3 │   return fetch('/data');
      > 4 │ }
       ^
        5 │ 
    
       Remove this async modifier, or add an await expression in the function.
    
      > 1 │ async function fetchData() {
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      > 2 │ // Missing `await` for the promise returned by `fetch`
      > 3 │   return fetch('/data');
      > 4 │ }
       ^
        5 │ 
    
       Async functions without await expressions may not need to be declared async.
    
    
  • useValidAriaRole

    <div role="datepicker"></div>
    nursery/useValidAriaRole.js:1:1 lint/nursery/useValidAriaRole  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
       Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role.
    
      > 1 │ <div role="datepicker"></div>
       ^^^^^^^^^^^^^^^^^^^^^^^
        2 │ 
    
       Check WAI-ARIA for valid roles or provide options accordingly.
    
       Unsafe fix: Remove the invalid role attribute.
         Check the list of all valid role attributes.
    
        1 │ <div·role="datepicker"></div>
           -----------------
    
  • useRegexLiterals

new RegExp("abc", "u");
nursery/useRegexLiterals.js:1:1 lint/nursery/useRegexLiterals  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━

   Use a regular expression literal instead of the RegExp constructor.

  > 1 │ new RegExp("abc", "u");
   ^^^^^^^^^^^^^^^^^^^^^^
    2 │ 

   Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.

   Safe fix: Use a literal notation instead.

    1  - new·RegExp("abc",·"u");
      1+ /abc/u;
    2 2

  • a11y/noAccessKey

    <input type="submit" accessKey="s" value="Submit" />
    a11y/noAccessKey.js:1:22 lint/a11y/noAccessKey  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
       Avoid the accessKey attribute to reduce inconsistencies between keyboard shortcuts and screen reader keyboard comments.
    
      > 1 │ <input type="submit" accessKey="s" value="Submit" />
                            ^^^^^^^^^^^^^
        2 │ 
    
       Assigning keyboard shortcuts using the accessKey attribute leads to inconsistent keyboard actions across applications.
    
       Unsafe fix: Remove the accessKey attribute.
    
        1 │ <input·type="submit"·accessKey="s"·value="Submit"·/>
                           --------------
    
  • a11y/useHeadingContent

    <h1 />
    a11y/useHeadingContent.js:1:1 lint/a11y/useHeadingContent ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
       Provide screen reader accessible content when using heading  elements.
    
      > 1 │ <h1 />
       ^^^^^^
        2 │ 
    
       All headings on a page should have content that is accessible to screen readers.
    
    
  • complexity/useSimpleNumberKeys

    ({ 0x1: 1 });
    complexity/useSimpleNumberKeys.js:1:4 lint/complexity/useSimpleNumberKeys  FIXABLE  ━━━━━━━━━━━━━━━━
    
       Hexadecimal number literal is not allowed here.
    
      > 1 │ ({ 0x1: 1 });
          ^^^
        2 │ 
    
       Safe fix: Replace 0x1 with 1
    
    1  - ({·0x1:·1·});
      1+ ({·1:·1·});
    2 2
    
    

The rule is replaced by correctness/noInvalidNewBuiltin

Since Biome was forked, new people joined the project. They have been helping with in so many ways that you can’t even imagine: new features, side projects, engaging with the community, support, documentation, and more. OSS is not just about coding.

Thank you to:

And a big welcome to our new joined maintainer:

Last but not least, we are proud to announce that we have two new sponsors:

If you want to economically contribute to the project and help it to ship more features, you can do so from the GitHub Sponsorship page or the Open Collective page.

The project is thriving, with more people curious about the project and contributors that want to be involved.

In the next months we will focus on:

  • Publishing a Roadmap. Keep an eye on it, it will involve a lot of interesting work.
  • Rebranding the website with a new logo.
  • Translate the website in Japanese.

Announcing Biome

We are happy to announce Biome, toolchain of the web.

Biome is the official fork of Rome and it will continue to be Rome’s legacy.

Biome is led and maintained by the same people that maintained Rome so far.

Follow us:

I want to give you some background and context, which could help you to get why the core team created a new project with a new name. If you’re not interested, feel free to jump to the next section

Before explaining the reasons for the fork, I’d like to give you some background and context; this would help you understand the reasons that led to this decision.

When I joined the Rome project, the project was still young and written in TypeScript. A long time passed, and the project underwent many transitions.

Rome was initially released and licensed under the Meta OSS umbrella. Meta is an excellent incubator for OSS projects, but some people didn’t like it. At least, my impression was that they didn’t.

The npm package rome belonged to another person, so when ownership changed, there were already a lot of version numbers used. The team always struggled with versioning. It shouldn’t be hard to version a software!

After a few months, the project got out of Meta’s OSS umbrella. In six months, the creator Sebastian McKenzie created the company Rome Tools Inc., to keep working on the Rome project so to eventually became sustainable.

I was excited about the news because I believed in Rome’s mission, so I decided to quit my job and join the adventure. In a few weeks, I joined Rome Tools Inc. as a full-time employee to work on developer tools as my daily job. For me, it was like a dream coming true!

Not all startups manage to succeed, and Rome Tools Inc. wasn’t one of the lucky ones. Eventually, all the employees were laid off.

My adventure with Rome Tools Inc. sadly ended, but fortunately, my career working with developer tools continued! A few months later, I joined the Astro Technology Company working full-time. It’s a great place to work, and I get to do what I love every day with fantastic people. I love it!

Part of me was still charmed by Rome’s mission though. However, it wasn’t just that. I like working on parsers/compilers in my free time. I love the Rust language, and Rome is the perfect OSS project where I can use it.

So, in my free time, I continued with my contributions to Rome as much as possible; luckily, I still had some rights that allowed me to publish new versions of the project. Despite the unsuccessful adventure with Rome Tools Inc., I wanted to keep the project alive.

A few new OSS contributors joined the cause and helped in contributing to the project. I wasn’t alone, and that’s the great thing about OSS. You eventually find people who like the project and want to contribute too.

In June, I gave a talk about Rome at JsNation 2023.

Emanuele Stoppa on the stage of JsNation

So, the project is still alive, but maintaining it has become challenging:

  • I don’t have admin rights on Discord, so I can’t delegate moderation rights to other people;
  • I don’t have access to the hosting platform of the website;
  • I don’t have access to any registry (npm, VSCode, etc.);
  • the project is still under the MIT license of Rome Tools Inc., which makes attributions and contributions seem foggy from a legal point of view (where’s the company? I don’t know).

Many attempts to reach out to the current owner were all void. There was only one thing I could do. We could do.

We created Biome. After weeks of discussions among the members of the core team and conversations with some friends, we thought that a clean slate was the best course of action.

We pondered the idea of keeping the “rome” name in the new fork, but that was proven difficult:

  • Sebastian has registered tons of stuff with the “rome” name (GitHub organizations, website domains, open collectives, npm organizations). Finding the right combination wasn’t easy;
  • without the proper rights in the Discord server, we couldn’t delegate the moderation rights. Discord is a very important asset for community building;
  • keeping the name would have caused some attribution to Rome Tools Inc., making things still foggy when it comes to the legal aspects of the source code;
  • we don’t know if the “rome” name is registered; if it turns out it is, we could have incurred some legal troubles;
  • “Rome” has a lot of historical baggage, as explained before (Meta and, fail as a startup);

Given all these difficulties, the core team settled for a new project.

Biome will embrace the same philosophy of the old Rome and the same mission. Although, the roadmap will likely change, and the core team could decide to focus on making the current features more stable instead of releasing new ones.

Still, the primary mission is alive, and Biome wants to be a 360° toolchain; we recently started working on transformations, which will eventually set up the foundations of the compiler.

The team wanted to create a second “Rome”, a second version of it. So we fused the words “Bis” and “Rome”. **Biome"".

I still use the rome package. What should I do?

Section titled I still use the rome package. What should I do?

The rome package won’t be maintained anymore by the core team, so you won’t get any more releases.

  1. You should use the @biomejs/biome package. Note that Biome also comes with a lot of new features and fixes. We’ve just prepared a blog post for that.

    {
    "rome": "12.1.3"
    "@biomejs/biome": "1.0.0"
    }
  2. And change the CLI name in your scripts:

    {
    "scripts": {
    "format": "rome format --write ./src",
    "format": "biome format --write ./src"
    }
    }
  3. In your rome.json file, update the URL of the $schema field:

    {
    "$schema": "https://docs.rome.tools/schemas/12.1.3/schema.json",
    "$schema": "https://biomejs.dev/schemas/1.0.0/schema.json"
    }
  4. Then install the new official VSCode or open VSX extension. That’s an important step if you use these extensions.

  5. After the installation of the extension, open the settings.json. If you have some Rome related settings there, you’ll have to update them:

    {
    "[javascript]": {
    "editor.defaultFormatter": "rome.rome"
    "editor.defaultFormatter": "biomejs.biome"
    },
    "editor.codeActionsOnSave": {
    "quickfix.rome": true,
    "source.organizeImports.rome": true
    "quickfix.biome": true,
    "source.organizeImports.biome": true
    }
    }

Biome still accepts the rome.json file as a configuration, so you don’t need to do anything yet. Biome also takes biome.json as a configuration file.

We will eventually sunset the rome.json configuration file for biome.json, but Biome will do that for you in the subsequent releases. So, don’t worry about updating everything unless you want to.

  • Emanuele Stoppa: me, the lead of the project 🤓
  • Denis Bezrukov: Denis has contributed to the project for a long time He made contributions to many tools like formatter and parser;
  • Victorien Elvinger: Victorien is very passionate, and he’s made tons of contributions to the Biome linter by creating new rules and optimising the ones that were already there when he joined;
  • Daiki Nishikawa: Daiki worked on linter and parser, by adding new rules, fixing the existing ones, improving the internal semantic model, and adding new grammar to the JavaScript/TypeScript parser;
  • unvalley: unvalley added a lot of value to the linter and parser. They tackled some complex rules, for example, especially the ones around regex;
  • Strager: his inputs and constructive criticisms to the project are what helped Biome to arrive to this point;
  • Boshen: one of the greatest admirers of the project since the Rust rewrite; he joined the Biome community to learn from us and contribute as much as possible. He now leads a similar project to Biome, oxc. Check it out.
  • Micha: ex-employee of Rome Tools Inc., he is now a full-time developer of the project Ruff, he gave a lot of good pieces of advice, and he was a good listener when I was struggling to make the right decisions.

Biome v1

In Biome v1, the formatter has options for JSX quotes and parentheses in the arrow functions; the CLI adds a new command biome lint, .jsonc files are supported, and it’s possible to extend the configuration file.

You can upgrade Biome by running the following command:

Terminal window
npm install --save-dev --save-exact @biomejs/biome@1.0.0
pnpm update --save-exact @biomejs/biome@1.0.0
yarn upgrade --exact @biomejs/biome@1.0.0

Or install the VS Code extension to integrate Biome into your editor.

Biome now supports two new, long-awaited options:

  • support for formatting the preferred quote kind in JSX;
  • support for formatting parenthesis in arrow functions only when they are needed;

You can use this option via CLI or via biome.json file:

biome.json
{
"javascript": {
"formatter": {
"jsxQuoteStyle": "single"
}
}
}
Terminal window
biome format --jsx-quote-style=single --write ./src

And Biome will apply single quotes when defining attributes in JSX code:

import Item from "./item.jsx";
const Header = () => {
return <Item title="Docs" />;
};

You can decide not to print parenthesis in arrow functions. You can customize the option via CLI or via biome.json:

biome.json
{
"javascript": {
"formatter": {
"arrowParentheses": "asNeeded"
}
}
}
Terminal window
biome format --arrow-parentheses=as-needed --write ./src

And Biome will print parenthesis only for those arrow functions that require them:

// no need for parentheses
const filter = (term) => {};
// needs parentheses
const filterBy = (term, fn) => {};

The CLI was heavily reworked to guarantee consistent behaviour when handling files, diagnostics emitted and commands.

Among those changes, there are some breaking changes in its behaviour.

  • The CLI exits with an error code if the configuration file contains errors; while Biome can parse the configuration successfully - even with errors - this was a hazard for our users. A typo in the configuration file would have resulted in Biome applying its defaults, and executing Biome with a different behaviour compared to the one set by the user.
  • The command biome check will now emit error diagnostics for code not formatted and exits with an error code. This behaviour aligns with the semantics meant for this command.

The command biome check is meant to run multiple tools, which sometimes can overwhelm the users. With biome lint, Biome will only run lint rules against files.

As for now, the command accepts almost all the CLI arguments of the biome check. In the future, this command will specialize and tweak its behaviour around linting.

By default, when Biome sees a file that can’t handle, it fires a diagnostic and will exit with an error code.

With --files-ignore-unknown option, the CLI won’t emit diagnostics and will continue processing files.

You can define this behaviour in the biome.json too:

biome.json
{
"files": {
"ignoreUnknown": true
}
}

When Biome doesn’t process files during a command, it exits with an error code and emits an error diagnostic.

Now, with --no-errors-on-unmatched, Biome will exist with a successful code and doesn’t emit any diagnostics.

This new option allows users to use Biome with tools like lint-staged.

In Biome, you can change the configuration of rules and allow them to emit diagnostics. This behaviour was limited, and now with --error-on-warnings option, you can tell Biome to exit with an error code if a warning is emitted.

Here’s an example, let’s change the diagnostic level of a rule via biome.json:

biome.json
{
"linter": {
"recommended": true,
"rules": {
"a11y": {
"useAltText": "warn"
}
}
}
}

Here’s a sample code that will trigger the rule:

const Image = () => {
return <img src="https://example.com/image.png" />;
};

And now, run the CLI using the new option:

Terminal window
biome lint --error-on-warnings ./src

Biome’s JSON parser now supports comments, so we enabled these exciting new features.

Biome can now format and lint .jsonc files.

Biome can parse comments inside JSON files. You can opt-in to this feature via the configuration file:

biome.json
{
"json": {
"parser": {
"allowComments": true
}
}
}

Plus, Biome now recognizes some known files as “JSON files that can have comments”. For example, now Biome can format your tsconfig.json file with comments without emitting errors!

You can now break down your configuration file into different files and join them using the new extends property.

biome.json
{
"extends": ["./formatter.json", "./linter.json"]
}

Check the documentation to understand how it works.

We deleted two rules:

  • useCamelCase, which is replaced by useNamingConvention;
  • noExtraSemicolon, not needed; the formatter takes care of it;
  • noDuplicateJsonKeys

    This rule disallows duplicate keys in a JSON object.

  • noExcessiveComplexity

    This rule computes a complexity score and reports code with a score above a configurable threshold.

  • noFallthroughSwitchClause

    This rule disallows switch cases that fall through to the next case.

  • noGlobalIsFinite

    This rule recommends using Number.isFinite instead of the global and unsafe isFinite that attempts a type of coercion.

  • noGlobalIsNan

    This rule recommends using Number.isNaN instead of the global and unsafe isNaN that attempts a type of coercion.

  • noNonoctalDecimalEscape

    This rule disallows \8 and \9 escape sequences in string literals.

  • noUnsafeDeclarationMerging

    This rule disallows declaration merging between an interface and a class.

  • noUselessEmptyExport

    This rule disallows useless export {}.

  • noUselessThisAlias

    This rule disallows useless aliasing of this in arrow functions.

  • noVoid

    This rule disallows the use of void.

  • useArrowFunction

    This rule proposes turning function expressions into arrow functions. Function expressions that use this are ignored.

  • useGetterReturn

    This rule enforces get methods to always return a value.

  • useImportRestrictions

    Enables restrictions on how local imports should be imported.

  • useIsArray

    This rule proposes using Array.isArray() instead of instanceof Array.

  • useNamingConvention

    The rule enforces wide-spread naming conventions of Javascript and TypeScript across a codebase.

New rules are promoted, please check #4750 for more details:

The following rules are now recommended:

Support for function class parameter decorators

Section titled Support for function class parameter decorators

In the last release, Biome introduced support for Stage 3 decorators. Although, this final proposal doesn’t support the function class parameter decorators:

class Controller {
get(@Param("id") id: string) {}
// ^^^^^^^^^^^^ syntax not covered by the official and final decorators spec
}

Some users were dissatisfied because they couldn’t use Biome inside their Angular/NestJS project. Now you can do it via configuration:

biome.json
{
"javascript": {
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
}
}

Big thank you to the following contributors:

  • denbezrukov, they implemented the new decorator parameter, the new option jsxQuoteStyle in the formatter, and started the works for our new CSS parser;
  • Conaclos, they continued creating new rules, making the existing ones smarter and adding tons of value to Biome;
  • SuperchupuDev, they implemented the new option arrowParentheses in the formatter;
  • nissy-dev, they fixed a bunch of issues around the linter;
  • unvalley, they fixed a bunch of issues around the linter and implemented new rules;
  • arendjr, they implemented new rules in the linter and implemented the new import sorting strategy;
  • ddanielsantos, for their first contribution to the project;
  • nikeee, for their first contribution to the project;