@biomejs/biome@2.4.12
biomejs/biome@biomejs/biome@2.4.12Apr 14, 2026by github-actions[bot]
AI Summary
This patch release introduces new nursery rules for testing and general linting, makes `lint --write` idempotent on HTML files, and improves CSS parsing within embedded snippets.
Key Highlights
- Added `noIdenticalTestTitle` rule to disallow duplicate test titles.
- Added `noComponentHookFactories` rule for React components.
- Added `useIframeSandbox` rule to enforce `sandbox` attributes.
- Added `useVarsOnTop` rule for `var` declarations.
- Fixed `lint --write` to be idempotent on HTML files with embedded scripts/styles.
New Features
- Added `noIdenticalTestTitle` rule.
- Added `noComponentHookFactories` rule.
- Added `useIframeSandbox` rule.
- Added `noJsxNamespace` rule.
- Added `useVarsOnTop` rule.
Full Release Notes
## 2.4.12
### Patch Changes
- [#9376](https://github.com/biomejs/biome/pull/9376) [`9701a33`](https://github.com/biomejs/biome/commit/9701a336af701c36d0fe4892f53de049f63f46f4) Thanks [@dyc3](https://github.com/dyc3)! - Added the [`nursery/noIdenticalTestTitle`](https://biomejs.dev/linter/rules/no-identical-test-title) lint rule. This rule disallows using the same title for two `describe` blocks or two test cases at the same nesting level.
```js
describe("foo", () => {});
describe("foo", () => {
// invalid: same title as previous describe block
test("baz", () => {});
test("baz", () => {}); // invalid: same title as previous test case
});
```
- [#9889](https://github.com/biomejs/biome/pull/9889) [`7ae83f2`](https://github.com/biomejs/biome/commit/7ae83f2f60dc83eae6ef72e4cb1d6f06f3a882de) Thanks [@dyc3](https://github.com/dyc3)! - Improved the diagnostics for [`useForOf`](https://biomejs.dev/linter/rules/use-for-of/) to better explain the problem, why it matters, and how to fix it.
- [#9916](https://github.com/biomejs/biome/pull/9916) [`27dd7b1`](https://github.com/biomejs/biome/commit/27dd7b156b3bf9c461051b9997b277e1fee6fcb2) Thanks [@Jayllyz](https://github.com/Jayllyz)! - Added a new nursery rule [`noComponentHookFactories`](https://biomejs.dev/linter/rules/no-component-hook-factories/), that disallows defining React components or custom hooks inside other functions.
For example, the following snippets trigger the rule:
```jsx
function createComponent(label) {
function MyComponent() {
return <div>{label}</div>;
}
return MyComponent;
}
```
```jsx
function Parent() {
function Child() {
return <div />;
}
return <Child />;
}
```
- [#9980](https://github.com/biomejs/biome/pull/9980) [`098f1ff`](https://github.com/biomejs/biome/commit/098f1fff71e2500da57200a28870f6d6e3d4201d) Thanks [@ematipico](https://github.com/ematipico)! - Fixed [#9941](https://github.com/biomejs/biome/issues/9941): Biome now emits a `warning` diagnostic when a file exceed the `files.maxSize` limit.
- [#9942](https://github.com/biomejs/biome/pull/9942) [`9956f1d`](https://github.com/biomejs/biome/commit/9956f1d1b53168f8b33792c004f741368c883ff7) Thanks [@dyc3](https://github.com/dyc3)! - Fixed [#9918](https://github.com/biomejs/biome/issues/9918): [`useConsistentTestIt`](https://biomejs.dev/linter/rules/use-consistent-test-it/) no longer panics when applying fixes to chained calls such as `test.for([])("x", () => {});`.
- [#9891](https://github.com/biomejs/biome/pull/9891) [`4d9ac51`](https://github.com/biomejs/biome/commit/4d9ac51352482d72d3438f2d514dbeef0edc63e0) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noGlobalObjectCalls` diagnostic to better explain why calling global objects like `Math` or `JSON` is invalid and how to fix it.
- [#9902](https://github.com/biomejs/biome/pull/9902) [`3f4d103`](https://github.com/biomejs/biome/commit/3f4d1033f7f672be2adba11bb8b7de5d8d3532fc) Thanks [@ematipico](https://github.com/ematipico)! - Fixed [#9901](https://github.com/biomejs/biome/issues/9901): the command `lint --write` is now idempotent when it's run against HTML-ish files that contains scripts and styles.
- [#9891](https://github.com/biomejs/biome/pull/9891) [`4d9ac51`](https://github.com/biomejs/biome/commit/4d9ac51352482d72d3438f2d514dbeef0edc63e0) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noMultiStr` diagnostic to explain why escaped multiline strings are discouraged and what to use instead.
- [#9966](https://github.com/biomejs/biome/pull/9966) [`322675e`](https://github.com/biomejs/biome/commit/322675ed97b10b088f6af3ad7843326d2888e9d8) Thanks [@siketyan](https://github.com/siketyan)! - Fixed [#9113](https://github.com/biomejs/biome/issues/9113): Biome now parses and formats `@media` and other conditional blocks correctly inside embedded CSS snippets.
- [#9835](https://github.com/biomejs/biome/pull/9835) [`f8d49d9`](https://github.com/biomejs/biome/commit/f8d49d9ea27ffcfefc993449f56dd2b6572a77d6) Thanks [@bmish](https://github.com/bmish)! - The [`noFloatingPromises`](https://biomejs.dev/linter/rules/no-floating-promises/) rule now detects floating promises through cross-module generic wrapper functions. Previously, patterns like `export const fn = trace(asyncFn)` — where `trace` preserves the function signature via a generic `<F>(fn: F): F` — were invisible to the rule when the wrapper was defined in a different file.
- [#9981](https://github.com/biomejs/biome/pull/9981) [`02bd8dd`](https://github.com/biomejs/biome/commit/02bd8dd97163281b78b840d7ae79361e26637de9) Thanks [@siketyan](https://github.com/siketyan)! - Fixed [#9975](https://github.com/biomejs/biome/issues/9975): Biome now parses nested CSS selectors correctly inside embedded snippets without requiring an explicit `&`.
- [#9949](https://github.com/biomejs/biome/pull/9949) [`e0ba71d`](https://github.com/biomejs/biome/commit/e0ba71d9dceec6db371c79833855e0ca4ce44a61) Thanks [@Netail](https://github.com/Netail)! - Added the nursery rule [`useIframeSandbox`](https://biomejs.dev/linter/rules/use-iframe-sandbox), which enforces the `sandbox` attribute for `iframe` tags.
**Invalid**:
```html
<iframe></iframe>
```
- [#9913](https://github.com/biomejs/biome/pull/9913) [`d417803`](https://github.com/biomejs/biome/commit/d417803eb451f3423deb8f3bf6925d76629d271f) Thanks [@Netail](https://github.com/Netail)! - Added the nursery rule [`noJsxNamespace`](https://biomejs.dev/linter/rules/no-jsx-namespace), which disallows JSX namespace syntax.
**Invalid**:
```jsx
<ns:testcomponent />
```
- [#9892](https://github.com/biomejs/biome/pull/9892) [`e75d70e`](https://github.com/biomejs/biome/commit/e75d70ef48297604b9371db5c281f6ef6a8d2a38) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noSelfCompare` diagnostic to better explain why comparing a value to itself is suspicious and what to use for NaN checks.
- [#9861](https://github.com/biomejs/biome/pull/9861) [`2cff700`](https://github.com/biomejs/biome/commit/2cff7004182d21fb2f39b218f9fecf351210f938) Thanks [@dyc3](https://github.com/dyc3)! - Added the new nursery rule [`useVarsOnTop`](https://biomejs.dev/linter/rules/use-vars-on-top/), which requires `var` declarations to appear at the top of their containing scope.
For example, the following code now triggers the rule:
```js
function f() {
doSomething();
var value = 1;
}
```
- [#9892](https://github.com/biomejs/biome/pull/9892) [`e75d70e`](https://github.com/biomejs/biome/commit/e75d70ef48297604b9371db5c281f6ef6a8d2a38) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noThenProperty` diagnostic to better explain why exposing `then` can create thenable behavior and how to avoid it.
- [#9892](https://github.com/biomejs/biome/pull/9892) [`e75d70e`](https://github.com/biomejs/biome/commit/e75d70ef48297604b9371db5c281f6ef6a8d2a38) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noShorthandPropertyOverrides` diagnostic to explain why later shorthand declarations can unintentionally overwrite earlier longhand properties.
- [#9978](https://github.com/biomejs/biome/pull/9978) [`4847715`](https://github.com/biomejs/biome/commit/484771541c1a27747012f6f27809a30b0e0eec08) Thanks [@mdevils](https://github.com/mdevils)! - Fixed [#9744](https://github.com/biomejs/biome/issues/9744): [`useExhaustiveDependencies`](https://biomejs.dev/linter/rules/use-exhaustive-dependencies/) no longer reports false positives for variables obtained via object destructuring with computed keys, e.g. `const { [KEY]: key1 } = props`.
- [#9892](https://github.com/biomejs/biome/pull/9892) [`e75d70e`](https://github.com/biomejs/biome/commit/e75d70ef48297604b9371db5c281f6ef6a8d2a38) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noRootType` diagnostic to better explain that the reported root type is disallowed by project configuration and how to proceed.
- [#9927](https://github.com/biomejs/biome/pull/9927) [`7974ab7`](https://github.com/biomejs/biome/commit/7974ab71d298b04f12c7536e1f4e0b14a9f0a74a) Thanks [@dyc3](https://github.com/dyc3)! - Added eslint-plugin-unicorn's `no-nested-ternary` as a rule source for [`noNestedTernary`](https://biomejs.dev/linter/rules/no-nested-ternary/)
- [#9873](https://github.com/biomejs/biome/pull/9873) [`19ff706`](https://github.com/biomejs/biome/commit/19ff70667001258104645abdc6015958bc8826ec) Thanks [@minseong0324](https://github.com/minseong0324)! - [`noMisleadingReturnType`](https://biomejs.dev/linter/rules/no-misleading-return-type/) now checks class methods, object methods, and getters in addition to functions.
- [#9888](https://github.com/biomejs/biome/pull/9888) [`362b638`](https://github.com/biomejs/biome/commit/362b638b99d09c09456943668c7627a81c40b644) Thanks [@dyc3](https://github.com/dyc3)! - Updated metadata for `biome migrate eslint` to better reflect which ESLint rules are redundant versus unsupported versus unimplemented.
- [#9892](https://github.com/biomejs/biome/pull/9892) [`e75d70e`](https://github.com/biomejs/biome/commit/e75d70ef48297604b9371db5c281f6ef6a8d2a38) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noAutofocus` diagnostic to better explain why autofocus harms accessibility outside allowed modal contexts.
- [#9982](https://github.com/biomejs/biome/pull/9982) [`d6bdf4a`](https://github.com/biomejs/biome/commit/d6bdf4a91df0cf638946009d97d7555b11f2fd8c) Thanks [@dyc3](https://github.com/dyc3)! - Improved performance of [noMagicNumbers](https://biomejs.dev/linter/rules/no-magic-numbers/).
Biome now maps ESLint `no-magic-numbers` sources more accurately during `biome migrate eslint`.
- [#9889](https://github.com/biomejs/biome/pull/9889) [`7ae83f2`](https://github.com/biomejs/biome/commit/7ae83f2f60dc83eae6ef72e4cb1d6f06f3a882de) Thanks [@dyc3](https://github.com/dyc3)! - Improved the diagnostics for [`noConstantCondition`](https://biomejs.dev/linter/rules/no-constant-condition/) to better explain the problem, why it matters, and how to fix it.
- [#9866](https://github.com/biomejs/biome/pull/9866) [`40bd180`](https://github.com/biomejs/biome/commit/40bd18090895046c34105c4d5671f7c27461e18a) Thanks [@dyc3](https://github.com/dyc3)! - Added a new nursery rule [`noExcessiveSelectorClasses`](https://biomejs.dev/linter/rules/no-excessive-selector-classes/), which limits how many class selectors can appear in a single CSS selector.
- [#9796](https://github.com/biomejs/biome/pull/9796) [`f1c1363`](https://github.com/biomejs/biome/commit/f1c136340f46e5c749337a4600a560c11612d789) Thanks [@dyc3](https://github.com/dyc3)! - Added a new nursery rule [`useStringStartsEndsWith`](https://biomejs.dev/linter/rules/use-string-starts-ends-with/), which prefers `startsWith()` and `endsWith()` over verbose string prefix and suffix checks.
The rule uses type information, so it only reports on strings and skips array lookups such as `items[0] === "a"`.
- [#9942](https://github.com/biomejs/biome/pull/9942) [`9956f1d`](https://github.com/biomejs/biome/commit/9956f1d1b53168f8b33792c004f741368c883ff7) Thanks [@dyc3](https://github.com/dyc3)! - Fixed the safe fix for [`noSkippedTests`](https://biomejs.dev/linter/rules/no-skipped-tests/) so it no longer panics when rewriting skipped test function names such as `xit()`, `xtest()`, and `xdescribe()`.
- [#9874](https://github.com/biomejs/biome/pull/9874) [`9e570d1`](https://github.com/biomejs/biome/commit/9e570d1b431d3326f6b6e9062dd8fdcf28bf0d84) Thanks [@minseong0324](https://github.com/minseong0324)! - Type-aware lint rules now resolve members through `Pick<T, K>` and `Omit<T, K>` utility types.
- [#9909](https://github.com/biomejs/biome/pull/9909) [`0d0e611`](https://github.com/biomejs/biome/commit/0d0e6118ff1ffb93d0c5d59c10abf57cecf46ccd) Thanks [@Netail](https://github.com/Netail)! - Added the nursery rule [`useReactAsyncServerFunction`](https://biomejs.dev/linter/rules/use-react-async-server-function), which requires React server actions to be async.
**Invalid:**
```js
function serverFunction() {
"use server";
// ...
}
```
- [#9925](https://github.com/biomejs/biome/pull/9925) [`29accb3`](https://github.com/biomejs/biome/commit/29accb3e455c7d833e3fd179c3a5400eb972b339) Thanks [@ematipico](https://github.com/ematipico)! - Fixed [#9910](https://github.com/biomejs/biome/issues/9910): added support for parsing member expressions in Svelte directive properties. Biome now correctly parses directives like `in:renderer.in|global`, `use:obj.action`, and deeply nested forms like `in:a.b.c|global`.
- [#9904](https://github.com/biomejs/biome/pull/9904) [`e7775a5`](https://github.com/biomejs/biome/commit/e7775a5c7f26bc808302e6646a1ffd702ec59fce) Thanks [@ematipico](https://github.com/ematipico)! - Fixed [#9626](https://github.com/biomejs/biome/issues/9626): [`noUnresolvedImports`](https://biomejs.dev/linter/rules/no-unresolved-imports/) no longer reports false positives for named imports from packages that have a corresponding `@types/*` package installed. For example, `import { useState } from "react"` with `@types/react` installed is now correctly recognised.
- [#9942](https://github.com/biomejs/biome/pull/9942) [`9956f1d`](https://github.com/biomejs/biome/commit/9956f1d1b53168f8b33792c004f741368c883ff7) Thanks [@dyc3](https://github.com/dyc3)! - Fixed the safe fix for [`noFocusedTests`](https://biomejs.dev/linter/rules/no-focused-tests/) so it no longer panics when rewriting focused test function names such as `fit()` and `fdescribe()`.
- [#9577](https://github.com/biomejs/biome/pull/9577) [`c499f46`](https://github.com/biomejs/biome/commit/c499f4609912b76fb5a7071a9e9c6a35bb26827a) Thanks [@tt-a1i](https://github.com/tt-a1i)! - Added the nursery rule [`useReduceTypeParameter`](https://biomejs.dev/linter/rules/use-reduce-type-parameter/). It flags type assertions on the initial value passed to `Array#reduce` and `Array#reduceRight` and recommends using a type parameter instead.
```ts
// before: type assertion on initial value
arr.reduce((sum, num) => sum + num, [] as number[]);
// after: type parameter on the call
arr.reduce<number[]>((sum, num) => sum + num, []);
```
- [#9895](https://github.com/biomejs/biome/pull/9895) [`1c8e1ef`](https://github.com/biomejs/biome/commit/1c8e1ef86882faabe4a461d29ab8643c18bfa83f) Thanks [@Netail](https://github.com/Netail)! - Added extra rule sources from react-xyz. `biome migrate eslint` should do a bit better detecting rules in your eslint configurations.
- [#9891](https://github.com/biomejs/biome/pull/9891) [`4d9ac51`](https://github.com/biomejs/biome/commit/4d9ac51352482d72d3438f2d514dbeef0edc63e0) Thanks [@dyc3](https://github.com/dyc3)! - Improved the `noInvalidUseBeforeDeclaration` diagnostic to better explain why using a declaration too early is problematic and how to fix it.
- [#9889](https://github.com/biomejs/biome/pull/9889) [`7ae83f2`](https://github.com/biomejs/biome/commit/7ae83f2f60dc83eae6ef72e4cb1d6f06f3a882de) Thanks [@dyc3](https://github.com/dyc3)! - Improved the diagnostics for [`noRedeclare`](https://biomejs.dev/linter/rules/no-redeclare/) to better explain the problem, why it matters, and how to fix it.
- [#9875](https://github.com/biomejs/biome/pull/9875) [`a951586`](https://github.com/biomejs/biome/commit/a951586fa9cfc0a1826b1c695f12b5cfdd921245) Thanks [@minseong0324](https://github.com/minseong0324)! - Type-aware lint rules now resolve members through `Partial<T>`, `Required<T>`, and `Readonly<T>` utility types, preserving optional, readonly, and nullable member flags.
## What's Changed
* fix(migrate): update some more rule metadata by @dyc3 in https://github.com/biomejs/biome/pull/9888
* chore: extra rule sources by @Netail in https://github.com/biomejs/biome/pull/9895
* fix(core): idempotent lint write by @ematipico in https://github.com/biomejs/biome/pull/9902
* chore: just a small harness to prevent markdown leaking by @ematipico in https://github.com/biomejs/biome/pull/9906
* fix(lint/js): improve diagnostics for `noConstantCondition`, `useForOf`, `noRedeclare` by @dyc3 in https://github.com/biomejs/biome/pull/9889
* fix(resolver): resolution of namespace members by @ematipico in https://github.com/biomejs/biome/pull/9904
* feat(lint/js): add `noExcessiveSelectorClasses` by @dyc3 in https://github.com/biomejs/biome/pull/9866
* fix(lint/js): improve diagnostics for `noSelfCompare`, `noThenProperty`, `noShorthandPropertyOverrides`, `noRootType`, `noAutofocus` by @dyc3 in https://github.com/biomejs/biome/pull/9892
* fix(lint/js): improve diagnostics for `noGlobalObjectCalls`, `noMultiStr`, `noInvalidUseBeforeDeclaration` by @dyc3 in https://github.com/biomejs/biome/pull/9891
* feat(lint): implement useReduceTypeParameter nursery rule by @tt-a1i in https://github.com/biomejs/biome/pull/9577
* feat(css): extend SCSS parsing with function names, interpolated values by @denbezrukov in https://github.com/biomejs/biome/pull/9837
* chore: ignore rand unsoundness advisory by @dyc3 in https://github.com/biomejs/biome/pull/9923
* feat(lint/js): add `noIdenticalTestTitle` by @dyc3 in https://github.com/biomejs/biome/pull/9376
* feat(js_analyze): implement noJsxNamespace by @Netail in https://github.com/biomejs/biome/pull/9913
* fix: main release by @Netail in https://github.com/biomejs/biome/pull/9924
* feat(lint/js): add `useStringStartsEndsWith` by @dyc3 in https://github.com/biomejs/biome/pull/9796
* feat(md/fmt): better formatting for some cases by @ematipico in https://github.com/biomejs/biome/pull/9917
* fix(parse/html): svelte directive member expression by @ematipico in https://github.com/biomejs/biome/pull/9925
* feat(js_analyze): implement useReactAsyncServerFunction by @Netail in https://github.com/biomejs/biome/pull/9909
* feat(react/js): add noComponentHookFactories by @Jayllyz in https://github.com/biomejs/biome/pull/9916
* chore: add rule source for noNestedTernary by @dyc3 in https://github.com/biomejs/biome/pull/9927
* refactor(conf): opt-in bpaf by @ematipico in https://github.com/biomejs/biome/pull/9920
* feat(lint): support class methods, object methods, and getters in noMisleadingReturnType by @minseong0324 in https://github.com/biomejs/biome/pull/9873
* fix(markdown_parser): paragraph with trailing hard break absorbs following blank line by @jfmcdowell in https://github.com/biomejs/biome/pull/9931
* fix(markdown_parser): mixed bullet markers and lazy continuation in lists by @jfmcdowell in https://github.com/biomejs/biome/pull/9933
* fix(useConsistentTestIt): fix panic when applying code fix by @dyc3 in https://github.com/biomejs/biome/pull/9942
* fix(markdown_parser): restore leading-space stripping after hard line breaks by @jfmcdowell in https://github.com/biomejs/biome/pull/9934
* chore(deps): update dependency @types/node to v24.12.2 by @renovate[bot] in https://github.com/biomejs/biome/pull/9954
* chore(deps): update dependency tombi to v0.9.16 by @renovate[bot] in https://github.com/biomejs/biome/pull/9955
* feat(type-info): add Partial, Required, and Readonly type synthesis by @minseong0324 in https://github.com/biomejs/biome/pull/9875
* chore(deps): update docker/dockerfile:1 docker digest to 2780b5c by @renovate[bot] in https://github.com/biomejs/biome/pull/9951
* chore(deps): update rust:1.94.1-bullseye docker digest to f4f82b8 by @renovate[bot] in https://github.com/biomejs/biome/pull/9952
* chore(deps): update rust:1.94.1-trixie docker digest to e8e2bb5 by @renovate[bot] in https://github.com/biomejs/biome/pull/9953
* chore(deps): update github-actions by @renovate[bot] in https://github.com/biomejs/biome/pull/9956
* chore(deps): update rust crate tokio to 1.51.1 by @renovate[bot] in https://github.com/biomejs/biome/pull/9957
* chore(deps): update rust crate ureq to 3.3.0 by @renovate[bot] in https://github.com/biomejs/biome/pull/9958
* refactor(core): semantic model in collector by @ematipico in https://github.com/biomejs/biome/pull/9905
* feat(type-info): add Pick and Omit type synthesis by @minseong0324 in https://github.com/biomejs/biome/pull/9874
* chore: combine attribute impl by @Netail in https://github.com/biomejs/biome/pull/9950
* ci: combine benchmark jobs back into one workflow by @dyc3 in https://github.com/biomejs/biome/pull/9963
* fix(parser/css): parse conditional block correctly inside embedded snippets by @siketyan in https://github.com/biomejs/biome/pull/9966
* feat(lint/js): add `useVarsOnTop` by @dyc3 in https://github.com/biomejs/biome/pull/9861
* fix(ci): checkout repository before benchmark path filtering on push by @dyc3 in https://github.com/biomejs/biome/pull/9973
* fix(linter): detect floating promises through cross-module generic wrappers by @bmish in https://github.com/biomejs/biome/pull/9835
* feat(md/fmt): autolink, setext header by @ematipico in https://github.com/biomejs/biome/pull/9929
* fix(core): file size diagnostic severity by @ematipico in https://github.com/biomejs/biome/pull/9980
* chore(skills): common mistakes in lint rules by @dyc3 in https://github.com/biomejs/biome/pull/9972
* perf(noMagicNumbers): reduce allocations by @dyc3 in https://github.com/biomejs/biome/pull/9982
* feat: implement useIframeSandbox by @Netail in https://github.com/biomejs/biome/pull/9949
* fix(parser/css): nested selectors in embedded snippets by @siketyan in https://github.com/biomejs/biome/pull/9981
* fix(linter): `useExhaustiveDependencies` proper handling of computed keys when destructuring, fixes #9744 by @mdevils in https://github.com/biomejs/biome/pull/9978
* ci: release by @github-actions[bot] in https://github.com/biomejs/biome/pull/9890
## New Contributors
* @bmish made their first contribution in https://github.com/biomejs/biome/pull/9835
**Full Changelog**: https://github.com/biomejs/biome/compare/@biomejs/biome@2.4.11...@biomejs/biome@2.4.12