Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f2581b8
refactor(core): embed detectors (#9416)
ematipico Mar 9, 2026
a1c46af
fix(noUselessEscapeInString): correctly flag chars (#9420)
ematipico Mar 9, 2026
725e6bb
chore: accept snapshot on main (#9422)
dyc3 Mar 9, 2026
ecd00e8
feat(css): add support for SCSS `@for` at-rule (#9421)
denbezrukov Mar 9, 2026
61e2a02
fix(parse/css): parse tailwind `@utility` with slash in the name (#9043)
dyc3 Mar 9, 2026
dccc7ae
feat(css): add support for SCSS `@mixin` at-rule (#9423)
denbezrukov Mar 9, 2026
2669381
feat(css): add support for SCSS `@include` at-rule (#9424)
denbezrukov Mar 9, 2026
2de8362
feat(lint): add nursery rule `useImportsFirst` (#9272)
terror Mar 10, 2026
1555948
feat(css): add support for SCSS `@content` at-rule (#9425)
denbezrukov Mar 10, 2026
f98dee2
fix(useOptionalChain): regression (#9430)
ematipico Mar 10, 2026
795bad4
feat(css): add support for SCSS `@function` and `@return` at-rules (#…
denbezrukov Mar 10, 2026
f5c8bf0
feat(inference): infer `Recored<K, V>` (#9383)
ematipico Mar 10, 2026
73205b9
feat(ast): increase `SyntaxKindSet` bitfield size to 6 elements for e…
denbezrukov Mar 10, 2026
78c4e9b
fix(a11y): only use baseConcepts in useSemanticElements rule (#9245) …
ruidosujeira Mar 10, 2026
6c5a8f2
fix(core): detect JSX reference identifiers in Astro/Vue/Svelte templ…
siketyan Mar 11, 2026
bf12092
fix(lint/noBlankTarget): still report when the href attribute is dyna…
siketyan Mar 11, 2026
71a19b9
ci: publish to pkg pr new before disatpch event (#9439)
ematipico Mar 11, 2026
3ac98eb
feat(css/lint): useBaseline (#9318)
ematipico Mar 11, 2026
8475d90
fix: compilation issue due to merge (#9442)
ematipico Mar 11, 2026
2f8656b
Merge branch 'main' into chore/merge-next-to-main
ematipico Mar 11, 2026
9df0386
[autofix.ci] apply automated fixes
autofix-ci[bot] Mar 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/add-use-baseline-css-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@biomejs/biome": patch
---

Added new nursery lint rule `useBaseline` for CSS. The rule reports when CSS properties, property values, at-rules, media conditions, functions, or pseudo-selectors are not part of the configured [Baseline](https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility) tier.

For example, *at the time of writing*, the rule will trigger for the use of `accent-color` because it has limited availability:

```css
a { accent-color: bar; }
Comment on lines +5 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use a valid CSS example in the release note.

accent-color: bar is invalid CSS regardless of Baseline support, so it muddies what useBaseline is actually adding. A valid declaration such as accent-color: red would demonstrate the new rule cleanly.

Based on learnings: “For rule changes in changesets, clearly demonstrate what is now invalid that wasn't before.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/add-use-baseline-css-rule.md around lines 5 - 10, The release
note example uses an invalid CSS declaration (`accent-color: bar`) which
confuses the purpose of the new rule `useBaseline`; update the changeset text to
show a syntactically valid example that demonstrates Baseline-level
incompatibility (e.g., replace the invalid `accent-color: bar` example with a
valid declaration such as `accent-color: red`) and ensure the surrounding
sentence explains that `useBaseline` will flag valid CSS properties/values like
`accent-color` when they are outside the configured Baseline tier; keep
reference to the rule name `useBaseline` and the exact problematic snippet
`accent-color: bar` so the change is easy to locate.

```
17 changes: 17 additions & 0 deletions .changeset/add-use-imports-first.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@biomejs/biome": patch
---

Added the nursery rule [`useImportsFirst`](https://biomejs.dev/linter/rules/use-imports-first/) that enforces all import statements appear before any non-import statements in a module. Inspired by the eslint-plugin-import [`import/first`](https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/first.md) rule.

```js
// Invalid
import { foo } from "foo";
const bar = 1;
import { baz } from "baz"; // ← flagged

// Valid
import { foo } from "foo";
import { baz } from "baz";
const bar = 1;
```
5 changes: 5 additions & 0 deletions .changeset/curly-games-follow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#9432](https://github.com/biomejs/biome/issues/9432): Values referenced as a JSX element in Astro/Vue/Svelte templates are now correctly detected; `noUnusedImports` and `useImportType` rules no longer reports these values as false positives.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the changeset a bit more user-facing.

Line 5 reads a touch implementation-heavy, and “rules no longer reports” should be “rules no longer report”. I’d rephrase it around the user impact, e.g. imports used only in Astro/Vue/Svelte template JSX no longer trigger false positives from noUnusedImports and useImportType. As per coding guidelines, changeset descriptions must be written for end users and bug fix changesets should start with Fixed [#NUMBER](issue link): ....

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.changeset/curly-games-follow.md at line 5, Edit the changeset summary line
so it starts with "Fixed [`#9432`](https://github.com/biomejs/biome/issues/9432):"
and rewrite the rest to be user-facing and grammatically correct; for example:
"Fixed [`#9432`]: Imports referenced only as JSX elements inside Astro, Vue, or
Svelte templates no longer trigger false positives from the noUnusedImports and
useImportType rules." Ensure you reference the rule names noUnusedImports and
useImportType exactly as shown and replace the current implementation-heavy
sentence on that line with this user-oriented phrasing.

5 changes: 5 additions & 0 deletions .changeset/fix-css-unicode-escape-in-string.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#9385](https://github.com/biomejs/biome/issues/9385): [`noUselessEscapeInString`](https://biomejs.dev/linter/rules/no-useless-escape-in-string/) no longer incorrectly flags valid CSS hex escapes (e.g. `\e7bb`) as useless. The rule now recognizes all hex digits (`0-9`, `a-f`, `A-F`) as valid escape characters in CSS strings.
5 changes: 5 additions & 0 deletions .changeset/fix-embedded-template-crash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#9131](https://github.com/biomejs/biome/issues/9131), [#9112](https://github.com/biomejs/biome/issues/9112), [#9166](https://github.com/biomejs/biome/issues/9166): the formatter no longer crashes or produces corrupt output when a JS file with `experimentalEmbeddedSnippetsEnabled` contains non-embedded template literals alongside embedded ones (e.g. `console.log(\`test\`)` next to `graphql(\`...\`)`).
5 changes: 5 additions & 0 deletions .changeset/fix-tailwind-utility-slash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#8897](https://github.com/biomejs/biome/issues/8897): Biome now parses `@utility` names containing `/` when Tailwind directives are enabled.
5 changes: 5 additions & 0 deletions .changeset/fix-use-semantic-elements-base-concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#9245](https://github.com/biomejs/biome/issues/9245): the [`useSemanticElements`](https://biomejs.dev/linter/rules/use-semantic-elements/) rule no longer suggests `<output>` for `role="status"` and `role="alert"`. The `<output>` element is only a `relatedConcept` of these roles, not a direct semantic equivalent. These roles are now excluded from suggestions, aligning with the intended behavior of the upstream `prefer-tag-over-role` rule.
5 changes: 5 additions & 0 deletions .changeset/lovely-clouds-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#9433](https://github.com/biomejs/biome/issues/9433): [`noBlankTarget`](https://biomejs.dev/linter/rules/no-blank-target/) now correctly handles dynamic href attributes, such as `<a href={company?.website} target="_blank">`.
5 changes: 5 additions & 0 deletions .changeset/resolve-record-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed [#6606](https://github.com/biomejs/biome/issues/6606): The type inference engine now resolves `Record<K, V>` types, synthesizing them as object types with index signatures. This improves accuracy for type-aware lint rules such as `noFloatingPromises`, `noMisusedPromises`, `useAwaitThenable`, and `useArraySortCompare` when operating on Record-typed values.
57 changes: 50 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,6 @@ jobs:
path: |
./packages/@biomejs/js-api/dist
if-no-files-found: error

# Publishing jobs

publish-cli:
Expand All @@ -357,6 +356,8 @@ jobs:
- build-binaries-gnu
- build-wasm
if: needs.build-binaries.outputs.version
outputs:
version: ${{ needs.build-binaries.outputs.version }}
environment: npm-publish
permissions:
contents: write
Expand Down Expand Up @@ -416,20 +417,62 @@ jobs:
fail_on_unmatched_files: true
generate_release_notes: true

- name: Codegen website schema
- name: Generate docker images
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
with:
token: ${{ secrets.BIOME_REPOSITORY_DISPATCH }}
repository: ${{ env.BIOME_WEBSITE_REPO }}
repository: ${{ env.BIOME_DOCKER_REPO }}
event-type: ${{ env.BIOME_RELEASE_CLI_EVENT }}
client-payload: |
{ "sha": "${{ github.sha }}", "tag": "@biomejs/biome@${{ needs.build-binaries.outputs.version }}", "version": "${{ needs.build-binaries.outputs.version }}" }
- name: Generate docker images


# Publish wasm-web on pkg-pr-new and dispatch event to website repo.
# This job is intentionally not required by any other job so it cannot block the release.
publish-wasm-web:
name: Publish wasm-web preview
runs-on: depot-ubuntu-24.04-arm-small
needs:
- build-wasm
- publish-cli
# Run after the release is published; never block the release pipeline.
if: always() && needs.build-wasm.result == 'success' && needs.publish-cli.result == 'success'
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Download wasm-web artifact
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: wasm-web-artefact
path: packages/@biomejs

- name: Install pnpm
run: npm i -g --force corepack && corepack enable

- name: Setup node
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
with:
node-version: 24.13.1
cache: pnpm

- name: Update package.json
working-directory: packages/@biomejs/wasm-web
run: |
npm pkg set name='@biomejs/wasm-web'
npm pkg set version='0.0.0-rev.${{ github.sha }}'

- name: Publish on pkg-pr-new
working-directory: packages/@biomejs/wasm-web
run: pnpx pkg-pr-new publish

- name: Dispatch event to website repo
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1
with:
token: ${{ secrets.BIOME_REPOSITORY_DISPATCH }}
repository: ${{ env.BIOME_DOCKER_REPO }}
repository: ${{ env.BIOME_WEBSITE_REPO }}
event-type: ${{ env.BIOME_RELEASE_CLI_EVENT }}
client-payload: |
{ "sha": "${{ github.sha }}", "tag": "@biomejs/biome@${{ needs.publish-cli.outputs.version }}", "version": "${{ needs.publish-cli.outputs.version }}" }

publish-js-api:
name: Publish JS API
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions crates/biome_analyze/src/rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ pub enum RuleSource<'a> {
EslintMarkdown(&'a str),
/// Rules from [Eslint Plugin Yml](https://ota-meshi.github.io/eslint-plugin-yml/)
EslintYml(&'a str),
/// Rules from [Eslint CSS](https://github.com/eslint/css)
EslintCss(&'a str),
/// Action for https://github.com/keithamus/sort-package-json
SortPackageJson,
}
Expand Down Expand Up @@ -241,6 +243,7 @@ impl<'a> std::fmt::Display for RuleSource<'a> {
Self::EslintJson(_) => write!(f, "@eslint/json"),
Self::EslintMarkdown(_) => write!(f, "@eslint/markdown"),
Self::EslintYml(_) => write!(f, "eslint-plugin-yml"),
Self::EslintCss(_) => write!(f, "@eslint/css"),
Self::SortPackageJson => write!(f, "sort-package-json"),
}
}
Expand Down Expand Up @@ -306,8 +309,8 @@ impl<'a> RuleSource<'a> {
Self::EslintJson(_) => 41,
Self::EslintMarkdown(_) => 42,
Self::EslintYml(_) => 43,
Self::SortPackageJson => 44,

Self::EslintCss(_) => 44,
Self::SortPackageJson => 45,
}
}

Expand Down Expand Up @@ -367,6 +370,7 @@ impl<'a> RuleSource<'a> {
| Self::Stylelint(rule_name)
| Self::EslintTurbo(rule_name)
| Self::HtmlEslint(rule_name)
| Self::EslintCss(rule_name)
| Self::EslintPlaywright(rule_name)
| Self::EslintJson(rule_name)
| Self::EslintMarkdown(rule_name)
Expand Down Expand Up @@ -422,6 +426,7 @@ impl<'a> RuleSource<'a> {
Self::EslintJson(_) => "json",
Self::EslintMarkdown(_) => "markdown",
Self::EslintYml(_) => "yml",
Self::EslintCss(_) => "css",
}
}

Expand Down Expand Up @@ -479,6 +484,7 @@ impl<'a> RuleSource<'a> {
Self::EslintJson(rule_name) => format!("https://github.com/eslint/json/blob/main/docs/rules/{rule_name}.md"),
Self::EslintMarkdown(rule_name) => format!("https://github.com/eslint/markdown/blob/main/docs/rules/{rule_name}.md"),
Self::EslintYml(rule_name) => format!("https://ota-meshi.github.io/eslint-plugin-yml/rules/{rule_name}.html"),
Self::EslintCss(rule_name) => format!("https://github.com/eslint/css/blob/main/docs/rules/{rule_name}.md"),
Self::SortPackageJson => "https://github.com/keithamus/sort-package-json".to_string(),
}
}
Expand Down
28 changes: 28 additions & 0 deletions crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions crates/biome_cli/tests/cases/handle_astro_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,54 @@ let {
));
}

#[test]
fn use_import_type_not_triggered_for_components_in_template() {
let fs = MemoryFileSystem::default();
let mut console = BufferConsole::default();

fs.insert(
"biome.json".into(),
r#"{ "html": { "linter": {"enabled": true}, "experimentalFullSupportEnabled": true } }"#
.as_bytes(),
);

let file = Utf8Path::new("file.astro");
fs.insert(
file.into(),
r#"---
import type { ComponentProps } from "astro/types";

import Badge from "@/components/mdx-components/Badge.astro";

interface Props {
badge?: ComponentProps<typeof Badge>;
}

const { badge } = Astro.props;
---

{badge && <Badge text={badge.text} variant={badge.variant} />}
"#
.as_bytes(),
);

let (fs, result) = run_cli(
fs,
&mut console,
Args::from(["lint", "--only=useImportType", file.as_str()].as_slice()),
);

assert!(result.is_ok(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"use_import_type_not_triggered_for_components_in_template",
fs,
console,
result,
));
}

#[test]
fn no_useless_lone_block_statements_is_not_triggered() {
let fs = MemoryFileSystem::default();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: redactor(content)
---
## `biome.json`

```json
{
"html": {
"linter": { "enabled": true },
"experimentalFullSupportEnabled": true
}
}
```

## `file.astro`

```astro
---
import type { ComponentProps } from "astro/types";

import Badge from "@/components/mdx-components/Badge.astro";

interface Props {
badge?: ComponentProps<typeof Badge>;
}

const { badge } = Astro.props;
---

{badge && <Badge text={badge.text} variant={badge.variant} />}

```

# Emitted Messages

```block
Checked 1 file in <TIME>. No fixes applied.
```
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ test.jsx:6:5 lint/correctness/useExhaustiveDependencies FIXABLE ━━━━

i Either include it or remove the dependency array.

i Unsafe fix: Add the missing dependency to the list.
i Unsafe fix: Add the missing dependency local to the list.

8 │ ····},·[local]);
│ +++++
Expand Down
Loading