All versions since 2.2.5
2.2.5
Patch Changes
-
#7597
5c3d542
Thanks @arendjr! - Fixed #6432:useImportExtensions
now works correctly with aliased paths. -
#7269
f18dac1
Thanks @CDGardner! - Fixed #6648, where Biome’snoUselessFragments
contained inconsistencies with ESLint for fragments only containing text.Previously, Biome would report that fragments with only text were unnecessary under the
noUselessFragments
rule. Further analysis of ESLint’s behavior towards these cases revealed that text-only fragments (<>A</a>
,<React.Fragment>B</React.Fragment>
,<RenamedFragment>B</RenamedFragment>
) would not havenoUselessFragments
emitted for them.On the Biome side, instances such as these would emit
noUselessFragments
, and applying the suggested fix would turn the text content into a proper JS string.// Ended up as: - const t = "Text"const t = <>Text</>// Ended up as: - const e = t ? "Option A" : "Option B"const e = t ? <>Option A</> : <>Option B</>/* Ended up as:function someFunc() {return "Content desired to be a multi-line block of text."}*/function someFunc() {return <>Content desired to be a multi-lineblock of text.<>}The proposed update was to align Biome’s reaction to this rule with ESLint’s; the aforementioned examples will now be supported from Biome’s perspective, thus valid use of fragments.
// These instances are now valid and won't be called out by noUselessFragments.const t = <>Text</>const e = t ? <>Option A</> : <>Option B</>function someFunc() {return <>Content desired to be a multi-lineblock of text.<>} -
#7498
002cded
Thanks @siketyan! - Fixed #6893: TheuseExhaustiveDependencies
rule now correctly adds a dependency that is captured in a shorthand object member. For example:useEffect(() => {console.log({ firstId, secondId });}, []);is now correctly fixed to:
useEffect(() => {console.log({ firstId, secondId });}, [firstId, secondId]); -
#7509
1b61631
Thanks @siketyan! - Added a new lint rulenoReactForwardRef
, which detects usages offorwardRef
that is no longer needed and deprecated in React 19.For example:
export const Component = forwardRef(function Component(props, ref) {return <div ref={ref} />;});will be fixed to:
export const Component = function Component({ ref, ...props }) {return <div ref={ref} />;};Note that the rule provides an unsafe fix, which may break the code. Don’t forget to review the code after applying the fix.
-
#7520
3f06e19
Thanks @arendjr! - Added new nursery rulenoDeprecatedImports
to flag imports of deprecated symbols.Invalid example
foo.js import { oldUtility } from "./utils.js";utils.js /*** @deprecated*/export function oldUtility() {}Valid examples
foo.js import { newUtility, oldUtility } from "./utils.js";utils.js export function newUtility() {}// @deprecated (this is not a JSDoc comment)export function oldUtility() {} -
#7457
9637f93
Thanks @kedevked! - Addedstyle
andrequireForObjectLiteral
options to the lint ruleuseConsistentArrowReturn
.This rule enforces a consistent return style for arrow functions. It can be configured with the following options:
style
: (default:asNeeded
)always
: enforces that arrow functions always have a block body.never
: enforces that arrow functions never have a block body, when possible.asNeeded
: enforces that arrow functions have a block body only when necessary (e.g. for object literals).
style: "always"
Invalid:
const f = () => 1;Valid:
const f = () => {return 1;};style: "never"
Invalid:
const f = () => {return 1;};Valid:
const f = () => 1;style: "asNeeded"
Invalid:
const f = () => {return 1;};Valid:
const f = () => 1;style: "asNeeded"
andrequireForObjectLiteral: true
Valid:
const f = () => {return { a: 1 };}; -
#7510
527cec2
Thanks @rriski! - Implements #7339. GritQL patterns can now use native Biome AST nodes using theirPascalCase
names, in addition to the existing TreeSitter-compatiblesnake_case
names.engine biome(1.0)language js(typescript,jsx)or {// TreeSitter-compatible patternif_statement(),// Native Biome AST node patternJsIfStatement()} as $stmt where {register_diagnostic(span=$stmt,message="Found an if statement")} -
#7574
47907e7
Thanks @kedevked! - Fixed 7574. The diagnostic message for the ruleuseSolidForComponent
now correctly emphasizes<For />
and provides a working hyperlink to the Solid documentation. -
#7497
bd70f40
Thanks @siketyan! - Fixed #7320: TheuseConsistentCurlyBraces
rule now correctly detects a string literal including"
inside a JSX attribute value. -
#7522
1af9931
Thanks @Netail! - Added extra references to external rules to improve migration for the following rules:noUselessFragments
&noNestedComponentDefinitions
-
#7597
5c3d542
Thanks @arendjr! - Fixed an issue wherepackage.json
manifests would not be correctly discovered when evaluating files in the same directory. -
#7565
38d2098
Thanks @siketyan! - The resolver can now correctly resolve.ts
,.tsx
,.d.ts
,.js
files by.js
extension if exists, based on the file extension substitution in TypeScript.For example, the linter can now detect the floating promise in the following situation, if you have enabled the
noFloatingPromises
rule.foo.ts
export async function doSomething(): Promise<void> {}bar.ts
import { doSomething } from "./foo.js"; // doesn't exist actually, but it is resolved to `foo.ts`doSomething(); // floating promise! -
#7542
cadad2c
Thanks @mdevils! - Added the rulenoVueDuplicateKeys
, which prevents duplicate keys in Vue component definitions.This rule prevents the use of duplicate keys across different Vue component options such as
props
,data
,computed
,methods
, andsetup
. Even if keys don’t conflict in the script tag, they may cause issues in the template since Vue allows direct access to these keys.Invalid examples
<script>export default {props: ["foo"],data() {return {foo: "bar",};},};</script><script>export default {data() {return {message: "hello",};},methods: {message() {console.log("duplicate key");},},};</script><script>export default {computed: {count() {return this.value * 2;},},methods: {count() {this.value++;},},};</script>Valid examples
<script>export default {props: ["foo"],data() {return {bar: "baz",};},methods: {handleClick() {console.log("unique key");},},};</script><script>export default {computed: {displayMessage() {return this.message.toUpperCase();},},methods: {clearMessage() {this.message = "";},},};</script> -
#7546
a683acc
Thanks @siketyan! - Internal data for Unicode strings have been updated to Unicode 17.0. -
#7497
bd70f40
Thanks @siketyan! - Fixed #7256: TheuseConsistentCurlyBraces
rule now correctly ignores a string literal with braces that contains only whitespaces. Previously, literals that contains single whitespace were only allowed. -
#7565
38d2098
Thanks @siketyan! - TheuseImportExtensions
rule now correctly detects imports with an invalid extension. For example, importing.ts
file with.js
extension is flagged by default. If you are using TypeScript with neither theallowImportingTsExtensions
option nor therewriteRelativeImportExtensions
option, it’s recommended to turn on theforceJsExtensions
option of the rule. -
#7581
8653921
Thanks @lucasweng! - Fixed #7470: solved a false positive fornoDuplicateProperties
. Previously, declarations in@container
and@starting-style
at-rules were incorrectly flagged as duplicates of identical declarations at the root selector.For example, the linter no longer flags the
display
declaration in@container
or theopacity
declaration in@starting-style
.a {display: block;@container (min-width: 600px) {display: none;}}[popover]:popover-open {opacity: 1;@starting-style {opacity: 0;}} -
#7529
fea905f
Thanks @qraqras! - Fixed #7517: theuseOptionalChain
rule no longer suggests changes for typeof checks on global objects.// oktypeof window !== "undefined" && window.location; -
#7476
c015765
Thanks @ematipico! - Fixed a bug where the suppression action fornoPositiveTabindex
didn’t place the suppression comment in the correct position. -
#7511
a0039fd
Thanks @arendjr! - Added nursery rulenoUnusedExpressions
to flag expressions used as a statement that is neither an assignment nor a function call.Invalid examples
f; // intended to call `f()` insteadfunction foo() {0; // intended to `return 0` instead}Valid examples
f();function foo() {return 0;} -
#7564
40e515f
Thanks @turbocrime! - Fixed #6617: improveduseIterableCallbackReturn
to correctly handle arrow functions with a single-expressionvoid
body.Now the following code doesn’t trigger the rule anymore:
[].forEach(() => void null);
2.2.6 Latest
Patch Changes
-
#7071
a8e7301
Thanks @ptkagori! - Added theuseQwikMethodUsage
lint rule for the Qwik domain.This rule validates Qwik hook usage. Identifiers matching
useXxx
must be called only within serialisable reactive contexts (for example, insidecomponent$
, route loaders/actions, or within other Qwik hooks), preventing common Qwik antipatterns.Invalid:
// Top-level hook call is invalid.const state = useStore({ count: 0 });function helper() {// Calling a hook in a non-reactive function is invalid.const loc = useLocation();}Valid:
component$(() => {const state = useStore({ count: 0 }); // OK inside component$.return <div>{state.count}</div>;});const handler = $(() => {const loc = useLocation(); // OK inside a $-wrapped closure.console.log(loc.params);}); -
#7685
52071f5
Thanks @denbezrukov! - Fixed #6981: The NoUnknownPseudoClass rule no longer reports local pseudo-classes when CSS Modules are used. -
#7640
899f7b2
Thanks @arendjr! - Fixed #7638:useImportExtensions
no longer emits diagnostics on valid import paths that end with a query or hash.Example
// This no longer warns if `index.css` exists:import style from "../theme/index.css?inline"; -
#7071
a8e7301
Thanks @ptkagori! - Added theuseQwikValidLexicalScope
rule to the Qwik domain.This rule helps you avoid common bugs in Qwik components by checking that your variables and functions are declared in the correct place.
Invalid:
// Invalid: state defined outside the component's lexical scope.let state = useStore({ count: 0 });const Component = component$(() => {return (<button onClick$={() => state.count++}>Invalid: {state.count}</button>);});Valid:
// Valid: state initialised within the component's lexical scope and captured by the event.const Component = component$(() => {const state = useStore({ count: 0 });return <button onClick$={() => state.count++}>Valid: {state.count}</button>;}); -
#7620
5beb1ee
Thanks @Netail! - Added the ruleuseDeprecatedDate
, which makes a deprecation date required for the graphql@deprecated
directive.Invalid
query {member @deprecated(reason: "Use `members` instead") {id}}Valid
query {member@deprecated(reason: "Use `members` instead", deletionDate: "2099-12-25") {id}} -
#7709
d6da4d5
Thanks @siketyan! - Fixed #7704: TheuseExhaustiveDependencies
rule now correctly adds an object dependency when its method is called within the closure.For example:
function Component(props) {useEffect(() => {props.foo();}, []);}will now be fixed to:
function Component(props) {useEffect(() => {props.foo();}, [props]);} -
#7624
309ae41
Thanks @lucasweng! - Fixed #7595:noUselessEscapeInString
no longer reports$\{
escape in template literals. -
#7665
29e4229
Thanks @ryan-m-walker! - Fixed #7619: Added support for parsing the CSS:state()
pseudo-class.custom-selector:state(checked) {} -
#7608
41df59b
Thanks @ritoban23! - Fixed #7604: theuseMaxParams
rule now highlights parameter lists instead of entire function bodies. This provides more precise error highlighting. Previously, the entire function was highlighted; now only the parameter list is highlighted, such as(a, b, c, d, e, f, g, h)
. -
#7643
459a6ac
Thanks @daivinhtran! - Fixed #7580: Include plugin in summary report
Copyright (c) 2023-present Biome Developers and Contributors.