2.5.0
Minor Changes
-
#9539
f0615fdThanks @ematipico! - Added a new reporter calledconcise. When--reporter=conciseis passed the commandsformat,lint,checkandci, the diagnostics are printed in a compact manner:! index.ts:2:10: lint/correctness/noUnusedImports: Several of these imports are unused. ! main.ts:9:7: lint/correctness/noUnusedVariables: This variable f is unused. × index.ts:8:5: lint/suspicious/noImplicitAnyLet: This variable implicitly has the any type. × main.ts:2:10: lint/suspicious/noRedeclare: Shouldn't redeclare 'z'. Consider to delete it or rename it. -
#9495
2056b23Thanks @aviraldua93! - Added theuseKeyWithClickEventsa11y lint rule for HTML files (.html,.vue,.svelte,.astro). This is a port of the existing JSX rule. The rule enforces that elements with anonclickhandler also have at least one keyboard event handler (onkeydown,onkeyup, oronkeypress) to ensure keyboard accessibility.Inherently keyboard-accessible elements (
<a>,<button>,<input>,<select>,<textarea>,<option>) are excluded, as are elements hidden from assistive technologies (aria-hidden) or withrole="presentation"/role="none".<!-- Invalid: no keyboard handler --> <div onclick="handleClick()">Click me</div> <!-- Valid: has keyboard handler --> <div onclick="handleClick()" onkeydown="handleKeyDown()">Click me</div> <!-- Valid: inherently keyboard-accessible --> <button onclick="handleClick()">Submit</button>
-
#9152
9ec8500Thanks @ematipico! - Added new nursery lint rulenoUndeclaredClassesfor HTML, JSX, and SFC files (Vue, Astro, Svelte). The rule detects CSS class names used inclass="..."(orclassName) attributes that are not defined in any<style>block or linked stylesheet reachable from the file.<!-- .typo is used but never defined --> <html> <head> <style> .button { color: blue; } </style> </head> <body> <div class="button typo"></div> </body> </html>
-
#9152
9ec8500Thanks @ematipico! - Added new nursery lint rulenoUnusedClassesfor CSS. The rule detects CSS class selectors that are never referenced in any HTML or JSX file that imports the stylesheet. This is a project-domain rule that requires the module graph./* styles.css — .ghost is never used in any importing file */ .button { color: blue; } .ghost { color: red; }
/* App.jsx */ import "./styles.css"; export default () => <div className="button" />;
-
#9546
6567efaThanks @nhedger! - Added abiome upgradecommand for standalone installations. It upgrades Homebrew installs withbrew upgrade biome, updates manually installed binaries from the latest GitHub release, and tells npm users to upgrade with their package manager instead. -
#9716
701767aThanks @faizkhairi! - Added the HTML version of theuseHeadingContentrule. The rule now enforces that heading elements (h1-h6) have content accessible to screen readers in HTML, Vue, Svelte, and Astro files.<!-- Invalid: empty heading --> <h1></h1> <!-- Invalid: heading hidden from screen readers --> <h1 aria-hidden="true">invisible content</h1> <!-- Valid: heading with text content --> <h1>heading</h1> <!-- Valid: heading with accessible name --> <h1 aria-label="Screen reader content"></h1>
-
#9582
f437ef8Thanks @rahuld109! - Added the HTML version of theuseKeyWithMouseEventsrule. The rule now enforces thatonmouseoveris accompanied byonfocusandonmouseoutis accompanied byonblurin HTML, Vue, Svelte, and Astro files.<!-- Invalid: onmouseover without onfocus --> <div onmouseover="handleMouseOver()"></div> <!-- Valid: onmouseover paired with onfocus --> <div onmouseover="handleMouseOver()" onfocus="handleFocus()"></div>
-
#9275
1fdbceeThanks @ff1451! - Added the new assist actionuseSortedTypeFields, which sorts the fields of GraphQL object types, interface types and input object types alphabetically, e.g.name, age, idbecomesage, id, name. -
#10561
78075b7Thanks @Conaclos! - Added a newstyleoption to useExportType,
which enforces a style for exporting types.
This is the same option as the one provided byuseImportType. -
#8987
d16e32bThanks @DerTimonius! - Ported theuseValidAnchorrule to HTML. This rule enforces that all anchors are valid and that they are navigable elements. -
#9533
4d251d4Thanks @ematipico! - Theinitcommand now prints the Biome logo. -
#10069
0eb9310Thanks @Netail! - Added the HTML lint rulenoStaticElementInteractions, which enforces that static, visible elements (such as<div>) that have click handlers use the valid role attribute.Invalid:
<div onclick="myFunction()"></div>
-
#9134
2a43488Thanks @ematipico! - Added the assist actionuseSortedPackageJson.This action organizes package.json fields according to the same conventions as the popular sort-package-json tool.
-
#9309
7daa18bThanks @Bertie690! - TheallowDoubleNegationoption has been added tonoImplicitCoercionsto allow ignoring double negations inside code.With the option enabled, the following example is considered valid and is ignored by the rule:
const truthy = !!value;
-
#9700
894f3fbThanks @ematipico! - The Biome Language server now supports the "go-to definition" feature.When the cursor of the mouse is hovering an entity (variable, CSS class, type, etc.), and the command CTRL + click is triggered, the editor jumps to where this entity is defined, if the language server can find it.
Here's what Biome is able to resolve:
- Variables and types used in JavaScript modules, defined in the same file or imported from another module.
- JSX Components used in JavaScript modules, defined in the same file or imported from another module.
- CSS classes used in JSX and HTML-ish files (Vue, Svelte and Astro), and defined in CSS files.
- Components used in HTML-ish files and defined in other HTML-ish.
- Variables used in HTML-ish files and defined in the same file or imported from another module (JavaScript or HTML-ish).
-
#10070
bae0710Thanks @Conaclos! - Added the:STYLE:group matcher fororganizeImportsthat matches style imports.For example, the following configuration...
{ "assist": { "actions": { "source": { "organizeImports": { "level": "on", "options": { "groups": ["**", "!:STYLE:"], "sortBareImports": true } } } } } }...places style imports last:
- import "./style.css" import A from "./a.js" + import "./style.css"
-
#9170
e3107deThanks @mdrobny! - AddedbundleDependenciesoption to NoUndeclaredDependencies rule.This rule now supports imports of packages that are defined only in
bundleDependenciesandbundledDependenciesarrays. -
#9547
01f8473Thanks @mujpao! - Added new assist ruleuseSortedAttributesfor HTML, porting the existing JSX rule. This rule enforces sorted HTML attributes.Invalid
<input type="text" id="name" name="name" />
-
#9366
2ca1117Thanks @dyc3! - Added thehtml.parser.vueconfiguration option. When enabled, it adds support for the parsing of Vue in.htmlfiles. Most Vue users don't need to enable this option since Vue files typically use the.vueextension, but it can be useful for projects that embed Vue syntax in regular HTML files. -
#9073
74b20eeThanks @chocky335! - Added support for applying GritQL plugin rewrites as code actions. GritQL plugins that use the rewrite operator (=>) now produce fixable diagnostics for JavaScript, CSS, and JSON files. By default, plugin rewrites are treated as unsafe fixes and require--write --unsafeto apply. Plugin authors can passfix_kind = "safe"toregister_diagnostic()to mark a fix as safe, allowing it to be applied with just--write.Example plugin (
useConsoleInfo.grit):language js `console.log($msg)` as $call where { register_diagnostic(span = $call, message = "Use console.info instead of console.log.", severity = "warn", fix_kind = "safe"), $call => `console.info($msg)` }Running
biome check --writeapplies safe rewrites. Unsafe rewrites (the default, orfix_kind = "unsafe") still require--write --unsafe. -
#9384
f4c9edcThanks @Conaclos! - Added thesortBareImportsoption toorganizeImports,
which allows bare imports to be sorted within other imports when set tofalse.{ "assist": { "actions": { "source": { "organizeImports": { "level": "on", "options": { "sortBareImports": true } } } } } }- import "b"; import "a"; + import "b"; import { A } from "a"; + import "./file"; import { Local } from "./file"; - import "./file";
-
#8731
e7872bfThanks @siketyan! - Added the watch mode (--watch) to the CLI forcheck/format/lintcommands. By enabling this option, Biome will re-run the check automatically when any file in the workspace has changed after the first run. -
#10106
9b35f78Thanks @ematipico! - Biome can now format and lint.svgfiles. -
#9967
e9b6c17Thanks @dyc3! - Added HTML support fornoExcessiveLinesPerFile. Biome now reports HTML files that exceed the configured line limit, including whenskipBlankLinesis enabled. -
#9491
b3eb63cThanks @IxxyDev! - Added the HTML lint rulenoAriaUnsupportedElements. This rule enforces that elements that do not support ARIA roles, states, and properties (meta,html,script,style) do not haveroleoraria-*attributes.<!-- Invalid: meta does not support aria attributes --> <meta charset="UTF-8" role="meta" />
-
#9306
afd57a6Thanks @viraxslot! - Added thenoNoninteractiveTabindexlint rule for HTML. This rule enforces thattabindexis not used on non-interactive elements, as it can cause usability issues for keyboard users.<div tabindex="0">Invalid: non-interactive element</div> `
-
#9276
6d041d9Thanks @IxxyDev! - Added the HTML lint rulenoRedundantRoles. This rule enforces that explicitroleattributes are not the same as the implicit/default role of an HTML element. It supports HTML, Vue, Svelte, and Astro files.<!-- Invalid: role="button" is redundant on <button> --> <button role="button"></button>
-
#9813
69aadc2Thanks @ematipico! - Added a new linter configuration calledpreset. With the new option, users can enable different kinds of rules at once.The following presets are available:
"recommended": it enables all Biome-recommended rules, or recommended rules of a group;"all": it enables all Biome rules, or enables all rules of a group;"none": it disables all Biome rules, or disable all rules of a group.
You can enable recommended rules:
{ "linter": { "rules": { "preset": "recommended" } } }You can enable all rules at once:
{ linter: { rules: { preset: "all", // enables all rules }, }, }
Or enable all rules for a group:
{ linter: { rules: { style: { preset: "all", // enables all rules in the style group }, }, }, }
This new option, however, doesn't affect how nursery rules work. Nursery rules must be enabled singularly, due to their nature.
This new option is meant to replace
recommended, so make sure to run themigratecommand. -
#10022
3422d71Thanks @Netail! - Added the HTML lint rulenoNoninteractiveElementToInteractiveRole, which enforces that interactive ARIA roles are not assigned to non-interactive HTML elements.Invalid:
<h1 role="checkbox"></h1>
-
#8396
13785fcThanks @apple-yagi! - Biome now supports pnpm catalogs (default and named) when resolving dependencies for linting. This behavior is opt-in and requires settingjavascript.resolver.experimentalPnpmCatalogstotrue. -
#10028
1009414Thanks @Netail! - Added the HTML lint rulenoInteractiveElementToNoninteractiveRole, which enforces that non-interactive ARIA roles are not assigned to interactive HTML elements.Invalid:
<input role="img" />
-
#9853
816302fThanks @Netail! - Added the new assist actionuseSortedSelectionSet, which sorts GraphQL selection sets alphabetically, e.g.name, age, idbecomesage, id, name.Invalid:
query { name age id }
-
#10074
9c7c6ebThanks @georgephillips! - Added akindfield to theImportMatcherused by theorganizeImportsassist action. The new field selects imports by their syntactic kind and currently supportsbare(matching side-effect imports such asimport "polyfill") with optional!negation (!bare). The matcher composes with the existingtypeandsourcefields, so users can express patterns such as "only bare imports that import a CSS file" ({ "kind": "bare", "source": "**/*.css" }).For example, with the following configuration:
{ "assist": { "actions": { "source": { "organizeImports": { "level": "on", "options": { "sortBareImports": true, "groups": [ { "kind": "!bare" }, ":BLANK_LINE:", { "kind": "bare" } ] } } } } } }...the following code:
import "./register-my-component"; import { render } from "react-dom"; import "./polyfill"; import { Button } from "@/components/Button";
...is organized as:
import { render } from "react-dom"; import { Button } from "@/components/Button"; import "./polyfill"; import "./register-my-component";
-
#9171
ce65710Thanks @chocky335! - Addedincludesoption for plugin file scoping. Plugins can now be configured with glob patterns to restrict which files they run on. Use negated globs for exclusions.{ "plugins": [ "global-plugin.grit", { "path": "scoped-plugin.grit", "includes": ["src/**/*.ts", "!**/*.test.ts"] } ] } -
#9617
dcb99efThanks @faizkhairi! - PorteduseAriaActivedescendantWithTabindexa11y rule to HTML. -
#9496
1dfb829Thanks @aviraldua93! - Added HTML support for thenoAriaHiddenOnFocusableaccessibility lint rule, which enforces thataria-hidden="true"is not set on focusable elements. Focusable elements include native interactive elements (<button>,<input>,<select>,<textarea>), elements withhref(<a>,<area>), elements withtabindex >= 0, and editing hosts (contenteditable). Includes an unsafe fix to remove thearia-hiddenattribute.<!-- Invalid: aria-hidden on a focusable element --> <button aria-hidden="true">Submit</button> <!-- Valid: aria-hidden on a non-focusable element --> <div aria-hidden="true">decorative content</div>
-
#9792
f516854Thanks @Maximiliano-Zeballos! - Added theuseSemanticElementslint rule for HTML. The rule now detects the use ofroleattributes in HTML elements and suggests using semantic elements instead.For example, the following code is now flagged:
<div role="navigation"></div>
The rule suggests using
<nav>instead. -
#9761
cbbb7d5Thanks @Maximiliano-Zeballos! - Ported theuseValidAriaPropslint rule to HTML. This rule checks that allaria-*attributes used in HTML elements are valid ARIA attributes as defined by the WAI-ARIA specification. -
#9928
aa82576Thanks @aviraldua93! - PorteduseValidAriaValuesto HTML. Biome now validates staticaria-*attribute values in HTML elements against WAI-ARIA types, catching invalid values such asaria-hidden="yes". -
#10562
6642895Thanks @ematipico! - Promoted 73 nursery rules to stable groups.Four rules were renamed as part of the promotion:
noFloatingClassesis nownoUnusedInstantiation, because the rule checks any discardednewexpression, not only classes.noMultiStris nownoMultilineString.useFindis nowuseArrayFind.useSpreadis nowuseSpreadOverApply, because the rule enforces spread call arguments overFunction.apply(), not array or object spread.
Correctness
Promoted the following rules to the
correctnessgroup:noBeforeInteractiveScriptOutsideDocumentnoUnusedInstantiationuseInlineScriptId(recommended, Next.js domain)noVueVIfWithVFor(recommended, Vue domain)useVueValidVBind(recommended, Vue domain)useVueValidVElse(recommended, Vue domain)useVueValidVElseIf(recommended, Vue domain)useVueValidVHtml(recommended, Vue domain)useVueValidVIf(recommended, Vue domain)useVueValidVOn(recommended, Vue domain)useVueValidVText(recommended, Vue domain)useVueValidTemplateRoot(recommended, Vue domain)useVueValidVCloak(recommended, Vue domain)useVueValidVOnce(recommended, Vue domain)useVueValidVPre(recommended, Vue domain)useVueVForKey(recommended, Vue domain)noDuplicateAttributes(recommended)noDuplicateArgumentNames(recommended)noDuplicateInputFieldNames(recommended)noDuplicateVariableNames(recommended)noDuplicateEnumValueNames(recommended)useLoneAnonymousOperation(recommended)
Suspicious
Promoted the following rules to the
suspiciousgroup:noShadownoUnnecessaryConditionsnoParametersOnlyUsedInRecursionnoUnknownAttributeuseArraySortComparenoForInnoDuplicatedSpreadPropsnoEqualsToNullnoProto(recommended)noUndeclaredEnvVars(recommended, Turborepo domain)noReturnAssign(default severity:error)noDuplicateEnumValues(recommended)noVueArrowFuncInWatch(recommended, Vue domain)noNestedPromisesnoLeakedRendernoDeprecatedMediaType(recommended)noDuplicateGraphqlOperationNameuseRequiredScripts
Style
Promoted the following rules to the
stylegroup:useVueMultiWordComponentNames(recommended, Vue domain)useVueDefineMacrosOrdernoIncrementDecrementnoContinueuseSpreadOverApplynoTernarynoMultilineStringnoMultiAssignnoExcessiveClassesPerFilenoExcessiveLinesPerFilenoVueOptionsApiuseErrorCauseuseConsistentEnumValueTypeuseConsistentMethodSignaturesuseGlobalThis(default severity:warn)useDestructuringuseVueHyphenatedAttributes(recommended, Vue domain)useVueConsistentVBindStyle(recommended, Vue domain)useVueConsistentVOnStyle(recommended, Vue domain)noHexColorsuseConsistentGraphqlDescriptionsnoRootTypeuseLoneExecutableDefinitionuseInputName
Complexity
Promoted the following rules to the
complexitygroup:useArrayFindnoRedundantDefaultExport(default severity:warn)noUselessReturnnoDivRegex
Performance
Promoted the following rules to the
performancegroup:Security
Promoted the following rules to the
securitygroup:noScriptUrl(recommended)
A11y
Promoted the following rules to the
a11ygroup:noAmbiguousAnchorText(recommended)
-
#10121
450f8e1Thanks @jongwan56! - Biome now applies Git's local exclude file when VCS ignore files are enabled. Files listed in.git/info/excludeare skipped the same way as files listed in.gitignore, including in linked worktrees. -
#9397
d5913c9Thanks @mvarendorff! - Addedignoreoption to the noUnusedVariables rule. The option allows excluding identifiers by providing a list of ignored names. It also allows excluding kinds of identifiers from this rule entirely, which may be useful when loading classes dynamically.For example, unused classes as well as all unused variables, functions, etc. called "unused" may be ignored entirely with the following configuration:
{ "ignore": { "*": ["unused"], "class": ["*"] } } -
#10089
71a21f0Thanks @Netail! - Added the lint rulenoLabelWithoutControlto HTML, which enforces that a label element or component has a text label and an associated input.<label></label>
-
#10015
1828261Thanks @Netail! - Added the HTML lint ruleuseAriaPropsSupportedByRole, which enforces that ARIA properties are valid for the roles that are supported by the element.<a href="#" aria-checked></a>
-
#10234
1a51569Thanks @ematipico! - Added thedelimiterSpacingformatter option. This option inserts spaces inside delimiters (after the opening delimiter and before the closing delimiter) when the content fits on a single line. Empty delimiters are not affected, and no space is added before the opening delimiter. The specific delimiters affected depend on the language. It can be configured globally viaformatter.delimiterSpacingor per-language viajavascript.formatter.delimiterSpacing,json.formatter.delimiterSpacing, andcss.formatter.delimiterSpacing. Defaults tofalse.- callFn(foo) + callFn( foo )
- const arr = [1, 2, 3]; + const arr = [ 1, 2, 3 ];
JavaScript
When enabled, Biome inserts spaces inside parentheses (e.g.,
foo( a, b )), square brackets (e.g.,[ a, b ]), template literal interpolations (e.g.,${ expr }), and the logical NOT operator (e.g.,! x, but in chains only after the last one:!! x). Only applies when the content fits on a single line. Empty delimiters and the space before the opening delimiter are not affected.- if (condition) {} + if ( condition ) {}
- `Hello ${name}!` + `Hello ${ name }!`
JSX
When enabled, Biome inserts spaces inside JSX expression braces (e.g.,
attr={ value }) and spread attributes (e.g.,{ ...props }). Only applies when the content fits on a single line. Empty delimiters are not affected.- <Foo bar={value} /> + <Foo bar={ value } />
TypeScript
When enabled, Biome inserts spaces inside TypeScript angle brackets (e.g.,
foo< T >()), indexed access types (e.g.,T[ K ]), mapped types, tuple types, type parameters, and index signatures. Only applies when the content fits on a single line. Empty delimiters are not affected.- type Result = Map<string, number>; + type Result = Map< string, number >;
JSON
When enabled, Biome inserts spaces inside square brackets when the content fits on a single line. Empty brackets are not affected.
- [1, 2, 3] + [ 1, 2, 3 ]
CSS
When enabled, Biome inserts spaces inside parentheses and square brackets when the content fits on a single line. Empty delimiters are not affected.
- rgba(0, 0, 0, 1) + rgba( 0, 0, 0, 1 )
- [data-attr] + [ data-attr ]
-
#10461
6bac1c3Thanks @TXWSLYF! - Implements #9445. Added theallowImplicitoption touseIterableCallbackReturn. When enabled, callbacks can usereturn;to implicitly returnundefined, matching ESLint'sarray-callback-returnrule. -
#9571
5a8eb75Thanks @dyc3! - Added configurable options to theuseNumericSeparatorsrule. Users can now customize the minimum number of digits required before adding separators and the group length for each type of numeric literal (binary,octal,decimal,hexadecimal).{ "linter": { "rules": { "style": { "useNumericSeparators": { "level": "error", "options": { "decimal": { "minimumDigits": 7, "groupLength": 3 }, "hexadecimal": { "minimumDigits": 4, "groupLength": 2 } } } } } } } -
#10067
6064312Thanks @Netail! - Added the lint ruleuseFocusableInteractiveto HTML, which enforces elements with an interactive role and interaction handler to be focusable.Invalid:
<div role="button"></div>
-
#10026
fb42ac4Thanks @Netail! - Added the HTML lint rulenoNoninteractiveElementInteractions, which disallows use event handlers on non-interactive elements.Invalid:
<div onclick="myFunction()">button</div>
-
#10000
2093e3eThanks @Netail! - Added the new assist actionuseSortedEnumMembers, which sorts TypeScript & GraphQL enum members.Invalid:
enum Role { SUPER_ADMIN ADMIN USER GOD }
-
#10013
ad01d3dThanks @Netail! - Added the HTML lint ruleuseValidAutocomplete, which enforces using valid values for theautocompleteattribute oninputelements.<input autocomplete="incorrect" />
Patch Changes
-
#10498
995c1ffThanks @citadelgrad! - Added the nursery ruleuseReactFunctionComponentDefinition, which enforces a consistent function type for named React function components.For example, the following snippet triggers the rule by default.
const MyComponent = (props) => { return <div>{props.name}</div>; };
-
#9974
ff635a9Thanks @pkallos! - AddedignoreMixedLogicalExpressionsto useNullishCoalescing, partially addressing #9232. When enabled, Biome ignores||and||=mixed with&&in the same expression tree. -
#10503
c656679Thanks @Mokto! - Added the new nursery ruleuseSvelteRequireEachKey, a Svelte lint rule that reports{#each}blocks with item bindings that are missing a key. -
#10516
0f29b83Thanks @Dotify71! - AddeduseIncludesto the nursery group. This rule flags comparisons ofString.prototype.indexOf()orArray.prototype.indexOf()against-1and suggests replacing them with the clearerincludes()/!includes()form. -
#10487
0c03ee3Thanks @Mokto! - Fixed a Svelte parser error that incorrectly required a binding variable after{:then}and{:catch}. Biome now correctly accepts{:then}and{:catch}without a binding, as well as the{#await expr then}and{#await expr catch}shorthand forms. -
#10566
a4a294cThanks @dyc3! - FixeduseVueHyphenatedAttributes: The rule now only reports diagnostics in Vue files and ignores SVG elements. -
#10565
72ccf3bThanks @dyc3! - FixeduseVueConsistentVBindStyle: The rule no longer reports argument-lessv-binddirectives because they cannot be converted to shorthand syntax. -
#10591
6e8557bThanks @xsourabhsharma! - Fixed #10563: Biome now parses comma-separated CSS Modulescomposesvalues, such ascomposes: classA from "./a.css", classB from "./b.css";. -
#10603
174b21bThanks @denbezrukov! - Fixed CSS formatting forgrid-template-areasdeclarations with comments before multiline values. Biome now keeps grid area rows aligned instead of adding an extra declaration-boundary indent..grid { grid-template-areas: /* row */ - "header header" - "footer footer"; + "header header" + "footer footer"; } -
#10542
c3f07f7Thanks @dyc3! - Fixed #10513: Biome no longer rejects literal\usequences in quoted HTML attribute values. -
#10108
24e51d6Thanks @IxxyDev! - Fixed #6611:noUnnecessaryConditionsnow uses type information to detect more redundant conditions, including?.,??,||,&&, comparisons againstnull/undefinedon non-nullish operands, andcaseclauses that can never match theswitchvalue. -
#10568
eb1ed0eThanks @harsha-cpp! - Fixed #10564:useAriaPropsForRoleno longer reports false positives for Vue v-bind shorthand bindings (:aria-checked,:aria-level, etc.). -
#10570
2ceb4feThanks @Conaclos! - ImprovednoTsIgnore.
The rule now reports more precisely the range of the@ts-ignorecomment. -
#10520
b55d10fThanks @dyc3! - Fixed #10519: Vuev-onevent handlers with multiple inline statements are now parsed consistently with Vue. -
#10204
ebbf0bdThanks @ematipico! - Improved the performance of the Biome linter. The improvements are more visible in bigger projects that have more than ~1k files. Early tests showed that in a code base with ~2k files, Biome took less than 26% of time to finish the command. -
#10546
e39bb2cThanks @tim-we! - Fixed#10536: noUnknownFunction no longer flagged CSScontrast-color()as unknown.contrast-color()is Baseline 2026. -
#8012
2be0264Thanks @denbezrukov! - Improved the performance of the formatter in some cases. The formatter is now up to ~20% faster at formatting files. -
#10467
9a5855eThanks @Netail! - Added a new nursery rulenoRestrictedDependencies, which flags imports andpackage.jsondependency entries that have better alternatives in e18e's module replacement data.For example, the package
globbyis reported because there's a better alternative:import glob from "globby";
{ "dependencies": { "globby": "x.x.x" } } -
#10470
84b43c5Thanks @ShaharAviram1! - Fixed #10447: now the rulenoProcessEnvdetects the use ofenvwhen it's imported fromprocessandnode:process. -
#10556
7ff6b16Thanks @ematipico! - Fixed #10492: Biome no longer crashes with a stack overflow on certain code when a type-aware rule such asnoFloatingPromises,noMisusedPromises, ornoUnnecessaryConditionsis enabled. For example, the following code used to crash Biome:function f(visitor) { let ctrl = visitor(); for (const x of [0]) ctrl = ctrl(); }
-
#10532
1da3c75Thanks @denbezrukov! - CSS declarations with comments before:or after!importantnow preserve spaces before:and;..selector { - padding/* name */: 1px; - color: red !important /* note */; + padding/* name */ : 1px; + color: red !important /* note */ ; } -
#10491
a1b5834Thanks @Mokto! - Fixed the Svelte parser rejecting{#each}blocks where the binding uses object destructuring with property renaming, e.g.{#each items as { id, component: Filter }}. Biome now correctly parses and formats these rename bindings. -
#10490
99bc7dfThanks @Mokto! - Fixed the CSS parser rejecting comma-separated selector lists inside:global()and:local()pseudo-class functions. Biome now correctly parses:global(.foo, .bar). -
#10543
c394faeThanks @mangod12! - Fixed #10477: The RDJSON reporter now emits code replacement text for fix suggestions instead of the human-readable fix description. -
#10530
e8e1e6aThanks @Conaclos! - Fixed #10493:useImportTypenow correctly separates types from a default named import when all imports are types and thestyleoption is set toseparatedType. -
#10555
263c7ccThanks @Mokto! - Improved Svelte lint rule accuracy for quoted attribute values containing{expression}interpolations.noRedundantAltno longer emits false positives when the alt text contains an interpolation, e.g.alt="image of {person}".useButtonTypeno longer emits false positives for dynamic button types written astype="{dynamicType}".noScriptUrlno longer emits false positives for dynamic hrefs such ashref="{url}".
-
#10489
96ef9a4Thanks @Mokto! - Fixed Svelte{#each}parser incorrectly rejecting TypeScriptas consttype assertions in the iterable expression. Biome now correctly parses{#each arr as const as item}. -
#10539
935c59aThanks @dyc3! - Improved how diagnostics print long lines of code, for example minified files where the entire source code is printed in one line.
What's Changed
- feat(css): support SCSS qualified names in values and function calls by @denbezrukov in #9096
- feat(css): add unary expression parsing by @denbezrukov in #9093
- feat(css): support scss nesting declarations in declaration lists by @denbezrukov in #9135
- feat(css): allow scss declarations in @page blocks by @denbezrukov in #9139
- feat(css): allow delimiters in bracketed value lists by @denbezrukov in #9145
- feat(analyze/json): useSortedPackageJson by @ematipico in #9134
- feat: two new cross language rules by @ematipico in #9152
- feat(js-api): add spanInBytesToSpanInCodeUnits helper function by @ash1day in #8944
- feat: collect local and global styles for
noUndeclearedClassesby @ematipico in #9297 - feat(organizeImports): add
sortBareImportsoption by @Conaclos in #9384 - chore: merge main to next by @ematipico in #9443
- feat(linter): add includes option for plugin file scoping by @chocky335 in #9171
- feat(cli): add ANSI art Biome logo by @ematipico in #9533
- feat(biome_service): support applying GritQL plugin rewrites via --write by @chocky335 in #9073
- feat(lint): add ignore option to no-unused-variables by @mvarendorff in #9397
- feat(biome_html_analyze): port noRedundantRoles a11y rule to HTML in #9564
- revert: feat(biome_html_analyze): port noRedundantRoles a11y rule to HTML by @dyc3 in #9587
- feat(html/a11y): add noRedundantRoles rule for HTML by @IxxyDev in #9276
- feat(cli): concise reporter by @ematipico in #9539
- feat(biome_html_analyze): port useKeyWithMouseEvents a11y rule to HTML by @rahuld109 in #9582
- chore: fix
nextfailures by @dyc3 in #9633 - feat(biome_html_analyze): port useAriaActivedescendantWithTabindex to HTML by @faizkhairi in #9617
- feat(lint): port useValidAnchor to html by @DerTimonius in #8987
- feat: improve noUndeclaredClasses by @ematipico in #9503
- feat(biome_html_analyze): port useHeadingContent a11y rule to HTML by @faizkhairi in #9716
- feat(formatter): add delimiterSpacing option by @luisherranz in #9718
- feat(assist): implement useSortedAttributes for HTML by @mujpao in #9547
- feat(html/a11y): port noAriaUnsupportedElements to HTML by @IxxyDev in #9491
- feat(assist): use sorted type fields 9137 by @ff1451 in #9275
- feat(html_analyze): port useValidAriaProps rule to HTML by @Maximiliano-Zeballos in #9761
- feat(html): port noAriaHiddenOnFocusable a11y rule to HTML by @aviraldua93 in #9496
- docs: remove duplicate sentence by @Netail in #9832
- fix: assist generator by @Netail in #9831
- feat(cli): add watch mode (--watch) to the CLI for check/format/lint commands by @siketyan in #8731
- refactor: improve watch mode by @ematipico in #9859
- feat(cli): add
upgradecommand by @nhedger in #9546 - chore: extra rule sources by @Netail in #9872
- feat(graphql_analyze): implement useSortedSelectionSet by @Netail in #9853
- feat(html): port useValidAriaValues a11y rule to HTML by @aviraldua93 in #9928
- chore: merge
mainintonextby @dyc3 in #9945 - feat(lint/html): port noExcessiveLinesPerFile to html by @dyc3 in #9967
- docs(organizeImports): revamp user-facing docs by @Conaclos in #9887
- ci: update snapshots by @Conaclos in #9986
- chore: abstract html tag matcher (main into next) by @Netail in #9993
- feat(linter): add noNonInteractiveTabIndex for HTML by @viraxslot in #9306
- feat(html_analyze): implement noNoninteractiveElementToInteractiveRole by @Netail in #10022
- feat(html_analyze): implement noInteractiveElementToNoninteractiveRole by @Netail in #10028
- feat(html_analyze): implement useValidAutocomplete by @Netail in #10013
- feat(html_analyze): implement noNoninteractiveElementInteractions by @Netail in #10026
- feat(js-formatter): implement delimiterSpacing for JavaScript by @luisherranz in #9719
- fix: next branch ci (+ main into next) by @Netail in #10051
- feat(html_analyze): implement useAriaPropsSupportedByRole by @Netail in #10015
- feat(linter): preset by @ematipico in #9813
- feat(organizeImports): add :STYLE: group matcher by @Conaclos in #10070
- feat(lint): support pnpm catalogs by @apple-yagi in #8396
- feat(html_analyze): implement useFocusableInteractive by @Netail in #10067
- feat(html): port useKeyWithClickEvents a11y rule to HTML by @aviraldua93 in #9495
- feat(html_analyze): port useSemanticElements a11y rule to HTML by @Maximiliano-Zeballos in #9792
- feat(js-formatter): implement delimiterSpacing for JSX by @luisherranz in #9720
- feat(js-formatter): implement delimiterSpacing for TypeScript by @luisherranz in #9721
- feat(json-formatter): implement delimiterSpacing for JSON by @luisherranz in #9723
- feat(html_analyze): port noLabelWithoutControl by @Netail in #10089
- chore: merge main into next by @Netail in #10104
- feat(migrate): map ESLint spacing rules to delimiterSpacing by @luisherranz in #9724
- feat(css-formatter): implement delimiterSpacing for CSS by @luisherranz in #9722
- feat(biome_js_analyze): add
bundleDependenciesoption toNoUndeclaredDependenciesrule by @mdrobny in #9170 - fix: workspace generation by @Netail in #10107
- feat(html_analyze): implement noStaticElementInteractions by @Netail in #10069
- feat: implement useSortedEnumMembers by @Netail in #10000
- feat(organizeImports): add
kindfield to import matcher by @georgephillips in #10074 - chore: main into next by @Netail in #10142
- chore: changeset corrections by @Netail in #10145
- fix: align HTML & JS a11y sources by @Netail in #10120
- feat(lint): add rule options for
noImplicitCoercionsto ignore double negations by @Bertie690 in #9309 - docs: incorrect markdown by @ematipico in #10186
- feat(core): handle svg files by @ematipico in #10106
- feat(config): expose
html.parser.vueby @dyc3 in #9366 - chore: refactor delimiterSpacing changesets by @ematipico in #10234
- perf(core): cache analyzer visitor by @ematipico in #10204
- feat: go-to definition (#9619) by @ematipico in #9700
- chore: merge main into next by @ematipico in #10316
- feat(core): respect git info exclude files by @jongwan56 in #10121
- feat(useNumericSeparators): add options for minimum digits and group length by @dyc3 in #9571
- chore: merge into next by @ematipico in #10435
- refactor: use salsa by @ematipico in #10315
- chore: merge main into next by @ematipico in #10453
- chore: enable unstable features on preview builds for playground by @siketyan in #10485
- ci: enable automation jobs by @ematipico in #10443
- feat(lint): add ignoreMixedLogicalExpressions option to useNullishCoa… by @pkallos in #9974
- fix(parser/yaml): correctly lex anchor/tag properties followed by a sequence by @siketyan in #10481
- fix(markdown_parser): keep loose list across empty item before blank line by @jfmcdowell in #10483
- fix(lint/noUnnecessaryConditions): extend detection coverage by @IxxyDev in #10108
- chore: merge main into next by @ematipico in #10500
- fix(html-parser): allow omitting binding in Svelte {:then} and {:catch} blocks by @Mokto in #10487
- ci: correct token for removing label by @ematipico in #10511
- fix(css_parser): parse semicolonless scss rules by @denbezrukov in #10509
- chore(deps): update rust crate jiff to 0.2.28 by @renovate[bot] in #10521
- chore(deps): update rust crate serde_json to 1.0.150 by @renovate[bot] in #10522
- chore(deps): update github-actions by @renovate[bot] in #10524
- chore(deps): update pnpm to v11.4.0 by @renovate[bot] in #10525
- ci: remove cli benchmark by @ematipico in #10526
- fix(css_parser): support interpolated dashed identifiers in function at-rules by @denbezrukov in #10518
- fix(parser/yaml): lex DIRECTIVE_END in stream by @siketyan in #10480
- fix(parser/yaml): lex directives by @siketyan in #10484
- fix(parse/js/vue): allow v-on directives with multiple inline statements by @dyc3 in #10520
- feat(core): implement YAML file handler by @siketyan in #10527
- fix(useImportType): always separate types from default named imports by @Conaclos in #10530
- fix(css_formatter): preserve declaration comment boundaries by @denbezrukov in #10532
- feat(formatter/yaml): initial implementation for simple block mappings by @siketyan in #10528
- feat(formatter/yaml): initial implementation for block sequences by @siketyan in #10529
- feat(tailwind_parser): parse Tailwind variant expressions by @jiwon79 in #10448
- chore(deps): update github-actions (major) by @renovate[bot] in #10538
- fix(svelte_parser): support destructuring rename bindings in {#each} blocks by @Mokto in #10491
- perf: reduce allocations in noExcessiveLinesPerFile rules by @ematipico in #10506
- feat(html/nursery): add useSvelteRequireEachKey rule by @Mokto in #10503
- fix(diagnostics): truncate diagnostics that are super long to keep output readable by @dyc3 in #10539
- feat(lint/useIterableCallbackReturn): add allowImplicit option #9445 by @TXWSLYF in #10461
- fix(css-parser): allow comma-separated selector lists inside :global() and :local() by @Mokto in #10490
- fix(linter): recognize contrast-color() as a known CSS function by @tim-we in #10546
- fix(parse/html): don't bother tracking unicode escape sequences by @dyc3 in #10542
- fix(cli): emit rdjson code suggestion replacements by @mangod12 in #10543
- refactor(organizeImports): require
sortBareImportsfor bare matchers by @Conaclos in #10517 - feat(linter): implement useIncludes rule by @Dotify71 in #10516
- fix(html-parser): allow TypeScript as const in Svelte {#each} expressions by @Mokto in #10489
- chore: add SCSS in unstable wasm build by @denbezrukov in #10551
- test(css_formatter): sync Prettier CSS and SCSS fixtures by @denbezrukov in #10554
- chore: merge main into next by @ematipico in #10553
- chore: biome v2.5 by @ematipico in #9277
- fix: avoid infinite recursion by passing depth to resolve_callee_to_function by @ematipico in #10556
- fix(css_formatter): add spacing SCSS binary expressions by @denbezrukov in #10537
- feat: noRestrictedDependencies by @Netail in #10467
- feat: rule promotion for v2.5 by @ematipico in #10562
- fix(useVueConsistentVBindStyle): don't flag v-bind directives that don't have arguments by @dyc3 in #10565
- fix(useVueHyphenatedAttributes): only run in vue files, exclude svgs and their children by @dyc3 in #10566
- docs: replace "allows to" with "allows you to" in formatter comments by @dfedoryshchev in #10507
- feat(useExportType): add style option by @Conaclos in #10561
- refactor(useExportType): improve docs and code by @Conaclos in #10569
- refactor(noTsIgnore): avoid one alloc, improve range reporting by @Conaclos in #10570
- fix(css_parser): parse SCSS bracketed expression lists by @denbezrukov in #10567
- fix(a11y): useAriaPropsForRole no longer false-positives on Vue v-bind shorthand 🤖🤖🤖 by @harsha-cpp in #10568
- fix(css_formatter): indent broken SCSS string concatenation by @denbezrukov in #10571
- fix(css_formatter): preserve SCSS grid template rows by @denbezrukov in #10572
- feat(css_parser): parse interpolated scss media conditions by @denbezrukov in #10573
- feat(css_formatter): expand compound SCSS variable lists by @denbezrukov in #10577
- fix: docs and readme by @ematipico in #10584
- feat(css): parse dynamic SCSS keyframes names by @denbezrukov in #10587
- fix(markdown): remove unused hard_line slot from MdParagraph by @jfmcdowell in #10593
- feat(css_parser): parse SCSS variables in keyframes by @denbezrukov in #10598
- feat(css_formatter): improve SCSS variable declaration formatting by @denbezrukov in #10597
- chore(deps): update dependency @types/node to v24.13.1 by @renovate[bot] in #10579
- chore(deps): update github-actions by @renovate[bot] in #10580
- chore(deps): update rust to v1.96.0 by @renovate[bot] in #10582
- chore(deps): update pnpm to v11.5.2 by @renovate[bot] in #10581
- test(md): cover loose list + mixed space-tab sublist in fuzz corpus by @jfmcdowell in #10594
- feat(css_formatter): keep SCSS scalar parentheses inline by @denbezrukov in #10599
- fix(markdown): remove dead syntax kinds and fix bogus node handling by @jfmcdowell in #10600
- fix(markdown): reset link-definition continuation when a block quote opens by @jfmcdowell in #10601
- fix(css_parser): parse comma-separated composes values by @xsourabhsharma in #10591
- fix(biome_configuration): avoid Markdown links in JSON schema descriptions by @mvanhorn in #10589
- fix(lint): detect imported process env usage by @ShaharAviram1 in #10470
- feat(fmt/md): improve formatting of list against prettier by @ematipico in #10383
- feat(html_parser): parse Svelte interpolations in quoted attribute values by @Mokto in #10555
- refactor: removes mutex from salsa db by @ematipico in #10608
- feat(css_parser): parse interpolated SCSS supports conditions by @denbezrukov in #10602
- fix(css_formatter): align grid-template-areas rows after comments by @denbezrukov in #10603
- refactor(formatter): introduce the SourcePosition element and remove source position from Text and LocatedTokenText variant by @denbezrukov in #8012
- feat(lint): add useFunctionComponentDefinition rule by @citadelgrad in #10498
- ci: release by @github-actions[bot] in #10499
New Contributors
- @ash1day made their first contribution in #8944
- @mvarendorff made their first contribution in #9397
- @IxxyDev made their first contribution in #9276
- @faizkhairi made their first contribution in #9617
- @luisherranz made their first contribution in #9718
- @Maximiliano-Zeballos made their first contribution in #9761
- @aviraldua93 made their first contribution in #9496
- @apple-yagi made their first contribution in #8396
- @mdrobny made their first contribution in #9170
- @georgephillips made their first contribution in #10074
- @jongwan56 made their first contribution in #10121
- @Mokto made their first contribution in #10487
- @TXWSLYF made their first contribution in #10461
- @mangod12 made their first contribution in #10543
- @harsha-cpp made their first contribution in #10568
- @xsourabhsharma made their first contribution in #10591
- @ShaharAviram1 made their first contribution in #10470
- @citadelgrad made their first contribution in #10498
Full Changelog: https://github.com/biomejs/biome/compare/@biomejs/biome@2.4.16...@biomejs/biome@2.5.0