-
-
Notifications
You must be signed in to change notification settings - Fork 713
chore: merge next
into main
#7167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…haustiveDependencies` configuration (#6398)
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: siketyan <12772118+siketyan@users.noreply.github.com> Co-authored-by: dyc3 <1808807+dyc3@users.noreply.github.com> Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com> Co-authored-by: Conaclos <2358560+Conaclos@users.noreply.github.com>
…utes (#6506) Co-authored-by: Arend van Beelen jr. <arend@arendjr.nl> Co-authored-by: dyc3 <1808807+dyc3@users.noreply.github.com> Co-authored-by: arendjr <533294+arendjr@users.noreply.github.com> Co-authored-by: Conaclos <2358560+Conaclos@users.noreply.github.com> Co-authored-by: matthewkeil <18608739+matthewkeil@users.noreply.github.com> Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com>
…ors (#6159) Co-authored-by: bavalpey <bavalpey@users.noreply.github.com> Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com> Co-authored-by: PointSingularity <56246797+PointSingularity@users.noreply.github.com> Co-authored-by: siketyan <12772118+siketyan@users.noreply.github.com>
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: ematipico <602478+ematipico@users.noreply.github.com> Co-authored-by: dyc3 <1808807+dyc3@users.noreply.github.com>
# Conflicts: # crates/biome_lsp/src/handlers/text_document.rs # packages/@biomejs/backend-jsonrpc/src/workspace.ts
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com> Co-authored-by: Naoki Ikeguchi <me@s6n.jp>
# Conflicts: # .changeset/shaky-experts-sit.md # crates/biome_module_graph/src/lib.rs
🦋 Changeset detectedLatest commit: a78e878 The changes in this PR will be included in the next version bump. This PR includes changesets to release 14 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
WalkthroughAdds HTML interpolation support and related parser/lexer/token-source changes driven by new HtmlParseOptions/HtmlParseOptions re-exports; expands HTML formatter to handle new text-expression variants and updates benchmarks/tests. Threads working-directory into reporters and reporter visitor APIs and refactors summary reporter to produce per-file counts and clickable file links. Introduces many lint promotions/renames and several new rules (including Qwik rule domains), adds sorting options for assist actions, adjusts CLI workspace APIs (watcher/scan_project/is_path_ignored params), exposes wasm module-graph utilities, and updates configuration schema/options and tests. Possibly related PRs
Suggested reviewers
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
Added new docs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 14
🔭 Outside diff range comments (12)
crates/biome_js_analyze/src/lint/correctness/use_exhaustive_dependencies.rs (1)
621-621
: Invalid return type:+ use<>
is not valid Rust.This won’t compile. The iterator bound should drop the stray
+ use<>
.Apply:
-fn into_member_iter(node: &JsSyntaxNode) -> impl Iterator<Item = String> + use<> { +fn into_member_iter(node: &JsSyntaxNode) -> impl Iterator<Item = String> {.github/workflows/repository_dispatch.yml (1)
73-78
: Bug: github.event.head_commit.id is undefined on workflow_dispatch.This will render an empty version (or fail semver validation) when manually dispatched.
Use github.sha for both push and workflow_dispatch:
- npm pkg set version='0.0.0-rev.${{ github.event.head_commit.id }}' + npm pkg set version='0.0.0-rev.${{ github.sha }}'crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs (2)
470-474
: Incorrect diagnostic decision for non-JSX createElement/cloneElement.If props contain a key, we should suppress the diagnostic, not emit it. The current logic returns Some(range) when a key-like prop is present.
Apply this diff to invert the condition:
- if has_key_prop(props) { - return Some(prop_argument.range()); - } - None + if has_key_prop(props) { + return None; + } + Some(prop_argument.range())
491-511
: Looks like a copy-paste bug: checking for "text" instead of "key".The React "key" prop should be named "key" in the props object, not "text". This prevents valid keys from being recognised.
Apply this diff to check for "key":
- name == "text" + name == "key" @@ - name == "text" + name == "key"crates/biome_js_analyze/src/lint/correctness/use_json_import_attributes.rs (4)
204-204
: Typo in variable name:seperators
should beseparators
.The variable name has a typo that should be corrected for consistency.
Apply this diff to fix the typo:
- let mut seperators = vec![]; + let mut separators = vec![];
208-211
: Fix typo in variable usage.Update the usage to match the corrected variable name.
Apply this diff:
- seperators.push( + separators.push(
223-223
: Fix typo in variable usage.Update the usage to match the corrected variable name.
Apply this diff:
- seperators.push(trailing_separator); + separators.push(trailing_separator);
228-228
: Fix typo in function argument.Update the function call to use the corrected variable name.
Apply this diff:
- .with_assertions(make::js_import_assertion_entry_list(items, seperators)) + .with_assertions(make::js_import_assertion_entry_list(items, separators))crates/biome_cli/src/reporter/github.rs (2)
44-52
: Verbose filtering logic drops non-verbose diagnostics when verbose=true.Currently, in verbose mode you only log diagnostics tagged as verbose; non-verbose diagnostics are skipped. We should log all diagnostics when verbose=true, and only non-verbose when verbose=false.
Apply this diff:
for diagnostic in &diagnostics_payload.diagnostics { if diagnostic.severity() >= diagnostics_payload.diagnostic_level { - if diagnostic.tags().is_verbose() && verbose { - self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}}); - } else if !verbose { - self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}}); - } + let is_verbose_diag = diagnostic.tags().is_verbose(); + if verbose || !is_verbose_diag { + self.0.log(markup! {{ PrintGitHubDiagnostic(diagnostic) }}); + } } }
37-43
: Relativise GitHub annotation file paths with working_directoryThe
working_directory
field inGithubReporter
is currently unused. GitHub Actions annotations expect file paths relative to the workspace root. To improve click-through:• In crates/biome_cli/src/reporter/github.rs (report_diagnostics, lines 37–43), pass
self.working_directory.as_deref()
into the printer.
• In crates/biome_diagnostics/src/display_github.rs (PrintGitHubDiagnostic impl), strip the base dir fromdiagnostic.location().resource().path()
viaUtf8Path::strip_prefix
when rendering thefile=
attribute in the annotation command.Suggested diff:
--- a/crates/biome_cli/src/reporter/github.rs +++ b/crates/biome_cli/src/reporter/github.rs @@ fn report_diagnostics( - self.0.log(markup! {{ PrintGitHubDiagnostic(diagnostic) }}); + self.0.log(markup! {{ + PrintGitHubDiagnostic { + diagnostic, + base: self.working_directory.as_deref(), + } + }});Then update
PrintGitHubDiagnostic
:--- a/crates/biome_diagnostics/src/display_github.rs +++ b/crates/biome_diagnostics/src/display_github.rs @@ pub struct PrintGitHubDiagnostic<'fmt, D: ?Sized>(pub &'fmt D); -pub struct PrintGitHubDiagnostic<'fmt, D: ?Sized>(pub &'fmt D); +pub struct PrintGitHubDiagnostic<'fmt, D: ?Sized> { + pub diagnostic: &'fmt D, + pub base: Option<&'fmt Utf8Path>, +} @@ impl<D: AsDiagnostic + ?Sized> fmt::Display for PrintGitHubDiagnostic<'_, D> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> io::Result<()> { let diagnostic = self.diagnostic.as_diagnostic(); let mut path = diagnostic.location().resource().path().to_path_buf(); + if let Some(base) = self.base { + if let Ok(rel) = path.strip_prefix(base) { + path = rel.to_path_buf(); + } + } // emit ::error file=path,...This ensures all GitHub annotations use repo-relative paths for correct click-through.
crates/biome_html_syntax/src/lib.rs (1)
48-53
: Missing HTML_BOGUS_TEXT_EXPRESSION in is_bogus()
to_bogus
can returnHTML_BOGUS_TEXT_EXPRESSION
, butis_bogus
doesn’t recognise it as bogus. This inconsistency can break downstream logic that relies onis_bogus()
(formatting, diagnostics, unions).Apply:
fn is_bogus(&self) -> bool { matches!( self, - HTML_BOGUS | HTML_BOGUS_ATTRIBUTE | HTML_BOGUS_ELEMENT | ASTRO_BOGUS_FRONTMATTER + HTML_BOGUS + | HTML_BOGUS_ATTRIBUTE + | HTML_BOGUS_ELEMENT + | HTML_BOGUS_TEXT_EXPRESSION + | ASTRO_BOGUS_FRONTMATTER ) }crates/biome_js_analyze/src/lint/correctness.rs (1)
1-4
: Remove duplicate generated file comment.Line 3 duplicates the comment from line 1. This appears to be a codegen issue.
//! Generated file, do not edit by hand, see `xtask/codegen` -//! Generated file, do not edit by hand, see `xtask/codegen` - use biome_analyze::declare_lint_group;
🧹 Nitpick comments (70)
.claude/settings.json (2)
5-6
: Consider replacinggrep
/find
with safer, faster tools.Minor, but
rg
(ripgrep) andfd
are faster and easier to keep scoped to the repo. If your runner provides them, prefer:"Bash(cargo insta:*)", - "Bash(grep:*)", - "Bash(find:*)", + "Bash(rg:*)", + "Bash(fd:*)",If you keep grep/find, ensure scripts consistently anchor searches at the repo root to avoid wandering the filesystem.
11-14
: Expand WebFetch allowlist for Rust ecosystem docs (optional).Fetching crate docs/changelogs is common during review. Consider adding docs.rs and crates.io; possibly biomejs.dev for project docs.
"WebFetch(domain:eslint.org)" + , + "WebFetch(domain:docs.rs)", + "WebFetch(domain:crates.io)", + "WebFetch(domain:biomejs.dev)"crates/biome_js_analyze/src/lint/nursery/use_max_params.rs (1)
159-166
: Nit: remove quotes around interpolated numbers in the diagnosticThe quotes around numbers read oddly in user messages.
Apply this diff:
- "Function has "{state.parameter_count}" parameters, but only "{options.max}" are allowed." + "Function has " {state.parameter_count} " parameters, but only " {options.max} " are allowed."crates/biome_js_analyze/src/lint/nursery/no_next_async_client_component.rs (1)
171-176
: Grammar nit in diagnostic“Async client component are not allowed.” → plural subject and verb agreement.
Apply this diff:
- "Async client component are not allowed." + "Async client components are not allowed."crates/biome_diagnostics/src/display.rs (3)
528-531
: Nit: align markup! style with the header block for consistencyThe header padding now uses the multi-line brace style; mirror it here for symmetry and readability.
Apply this diff:
- self.0 - .write_markup(markup! {{Padding::new(padding + extra_padding)}})?; + self.0.write_markup( + markup! { + {Padding::new(padding + extra_padding)} + }, + )?;
503-535
: Column width derives from a single cell; consider per-column widthsPadding is based on the very first data cell only (longest_cell), which can misalign columns when later cells or headers are wider. A per-column max width yields stable tables.
Example approach:
// Pre-compute max text length per column (including headers) let col_widths: Vec<usize> = (0..columns_number) .map(|col| { let mut max_len = headers[col].text_len(); for row in 0..rows_number { if let Some(cell) = columns[col].get(row) { max_len = max_len.max(cell.text_len()); } } max_len }) .collect(); // Print headers for (index, header_cell) in headers.iter().enumerate() { self.0.write_markup(markup!({ header_cell }))?; if index < headers.len() - 1 { let gap = col_widths[index].saturating_sub(header_cell.text_len()); self.0.write_markup(markup! {{ Padding::new(padding + gap) }})?; } } self.0.write_markup(markup! { "\n\n" })?; // Print rows for row in 0..rows_number { for col in 0..columns_number { if let Some(cell) = columns[col].get(row) { self.0.write_markup(markup!({ cell }))?; if col < columns_number - 1 { let gap = col_widths[col].saturating_sub(cell.text_len()); self.0.write_markup(markup! {{ Padding::new(padding + gap) }})?; } } } self.0.write_markup(markup!("\n"))?; }
490-493
: Tiny grammar tweak in debug assertionMessage reads oddly; “same length” is clearer.
Apply this diff:
- "headers and columns must have the same number length" + "headers and columns must have the same length"crates/biome_html_formatter/src/astro/auxiliary/expression.rs (2)
15-22
: Confirm intended behaviour: inner expression is emitted verbatimEmitting
expression_token.format()
will print the raw token unchanged. If the intent is to eventually normalise/pretty-print the inner expression (now or later), formatting a child node (e.g.expression.format()
) is the path. If verbatim is desired for Astro (e.g. unparsed interpolation), all good—just worth a short comment to prevent future “why not format this?” drive-bys.Suggested doc comment to clarify intent (add above fmt_fields):
/// Astro expressions are emitted verbatim: we format the braces and the inner token as-is. /// This intentionally diverges from HTML text expressions that format a child `expression` node.
8-24
: Add a minimal formatter test for AstroExpressionA golden test exercising spaced and unspaced forms (e.g.
{foo}
,{ foo }
, newlines) will guard against regressions in token ordering/spacing.I can draft a test snippet under crates/biome_html_formatter/tests covering AstroExpression with a few variants. Want me to push one?
crates/biome_js_analyze/src/lint/correctness/use_exhaustive_dependencies.rs (1)
981-983
: Grammar: “more specific than”, not “that”.Tiny polish for the diagnostic text.
- "This hook specifies a dependency more specific that its captures: "{dependency_text.as_ref()}"" + "This hook specifies a dependency more specific than its captures: "{dependency_text.as_ref()}"".changeset/thick-seas-draw.md (2)
5-5
: Word choice: “complement”, not “compliment”.Also prefer a period at sentence end per changeset style.
-Added support for tracking stable results in user-provided React hooks that return objects to [`useExhaustiveDependencies`](https://biomejs.dev/linter/rules/use-exhaustive-dependencies/) to compliment existing support for array return values. For example: +Added support for tracking stable results in user-provided React hooks that return objects to [`useExhaustiveDependencies`](https://biomejs.dev/linter/rules/use-exhaustive-dependencies/) to complement existing support for array return values. For example.
21-28
: Tense and punctuation per changeset guidelines.Use present tense for current behaviour and end sentences with a period.
-This will allow the following to be validated: +This allows the following to be validated.crates/biome_html_parser/tests/html_specs/ok/multiple_expressions.vue (1)
1-3
: Test name vs content mismatch — only one moustache present.Either add another expression or rename the fixture to avoid confusion. Adding a second expression also gives better coverage for adjacent text-expressions.
Apply this minimal change:
<template> - Foo {{xyz}} bar + Foo {{xyz}} and {{abc}} bar </template>CLAUDE.md (1)
136-140
: Make the contribution reference clickable.The
@CONTRIBUTING.md
hint may not render as a link in all viewers. Consider a standard Markdown link for portability.Proposed tweak:
-### Additional Instructions to know how to work inside the project - -- General contribution instructions @CONTRIBUTING.md +### Additional instructions for working in this project + +- General contribution instructions: [CONTRIBUTING.md](CONTRIBUTING.md).claude/agents/biome-lint-engineer.md (1)
9-9
: Add nursery placement guidance & verify link resolutionUnder “Lint Rule Development,” please add:
- Place new rules in the nursery group by default; promote to stable via `just move-rule stable ruleName` once mature.Also double-check that the
@../../crates/biome_analyze/CONTRIBUTING.md
path is recognised by your docs tooling—if not, switch to a standard Markdown link.
Location: .claude/agents/biome-lint-engineer.md, line 9.github/workflows/repository_dispatch.yml (2)
1-1
: Nit: rename workflow to reflect next as well.Name still says “on main” but it now runs on main and next.
Apply this diff to update the name:
-name: Repository dispatch on main +name: Repository dispatch on main and next
15-16
: Optional: event-type env name may now be misleading.If the website side interprets the event type literally as “push on main”, consider a neutral name (e.g., biome-push-event) to avoid confusion. This is cross-repo, so coordinate before changing.
Would you like me to open a follow-up PR in biomejs/website to accept a generic event type?
.changeset/ripe-eyes-fix.md (1)
5-12
: Polish changeset prose and punctuation.Minor style nits per repo guidelines (“end every sentence with a period”).
Apply this diff:
-Added Qwik Domain to Biome +Added Qwik domain to Biome. -This release introduces **Qwik domain support** in Biome, enabling Qwik developers to use Biome as a linter and formatter for their projects. +This release introduces **Qwik domain support** in Biome, enabling Qwik developers to use Biome as a linter and formatter for their projects. -- Added the Qwik domain infrastructure to Biome. -- Enabled the following rules for Qwik: +- Added the Qwik domain infrastructure to Biome. +- Enabled the following rules for Qwik: - [`useJsxKeyInIterable`](https://biomejs.dev/linter/rules/use-jsx-key-in-iterable) - [`noReactSpecificProps`](https://biomejs.dev/linter/rules/no-react-specific-props)Optional: add trailing periods to the rule bullets if you want to be strict.
.changeset/ignored-iguanodon-ignites.md (1)
7-9
: Tighten grammar: drop comma before “because”, add one before “and”, and use a gerund.Polish for readability and to match house style. Nits today, fewer docs PRs tomorrow.
-Previously, Biome sometimes failed to properly ignore the contents of a folder if you didn't specify the `/**` at the end of a glob pattern. This was unfortunate, because it meant we still had to traverse the folder and then apply the glob to every entry inside it. +Previously, Biome sometimes failed to properly ignore the contents of a folder if you didn't specify the `/**` at the end of a glob pattern. This was unfortunate because it meant we still had to traverse the folder and then apply the glob to every entry inside it. -This is no longer an issue and we now recommend to ignore folders without using the `/**` suffix. +This is no longer an issue, and we now recommend ignoring folders without using the `/**` suffix..changeset/brave-trees-push.md (1)
5-5
: Trim wording for clarity.Minor style tweak; no change in meaning.
-Added a new **experimental option** that allows parsing of `.html` files that contain interpolation syntax. +Added a new **experimental option** that allows parsing `.html` files containing interpolation syntax.crates/biome_html_formatter/src/html/auxiliary/text_expression.rs (1)
6-8
: Add a brief comment explaining the verbatim route.Future readers will thank you for the breadcrumb to the concrete rules.
impl FormatNodeRule<HtmlTextExpression> for FormatHtmlTextExpression { - fn fmt_fields(&self, node: &HtmlTextExpression, f: &mut HtmlFormatter) -> FormatResult<()> { + // Route the HtmlTextExpression sum type to verbatim; concrete nodes + // (HtmlSingleTextExpression, HtmlDoubleTextExpression, HtmlBogusTextExpression) + // have dedicated formatters. + fn fmt_fields(&self, node: &HtmlTextExpression, f: &mut HtmlFormatter) -> FormatResult<()> { format_html_verbatim_node(node.syntax()).fmt(f) } }.changeset/proud-olives-exist.md (2)
5-8
: Tighten prose and end sentences with periods (per repo changeset style).Current text repeats “This rule …” and ends with a colon. Suggested wording below addresses the LanguageTool hint and the style guide.
Apply this diff:
-Added the new rule `noBiomeFirstException`. This rule prevents the incorrect usage of patterns inside `files.includes`. - -This rule catches if the first element of the array contains `!`. This mistake will cause Biome to analyze no files: +Added the new rule `noBiomeFirstException`. The rule prevents the incorrect usage of patterns inside `files.includes`. + +Detects when the first element of `files.includes` starts with `!`. This causes Biome to analyze no files.
9-16
: Consider linking to the rule docs.Add a link to the documentation page for
noBiomeFirstException
(on the website PR once published) so users can learn remediation quickly.crates/biome_analyze/src/rule.rs (2)
969-972
: Arity bump to 116 is fine; update docs and watch compile-time.
- The tuple implementation range was extended to T115. Please update the nearby doc comments that still claim “size 1 to 29” to avoid confusing contributors.
- If you notice a compile-time hit, we can revisit generating impls more selectively.
Here is suggested wording for the two doc comments (outside this hunk):
/// This trait is implemented for tuples of [Rule] types (up to the arity /// supported below) if the query type of all the rules in the tuple share /// the same associated [Language] ... /// /// This trait is implemented for tuples of [RuleGroup] types (up to the arity /// supported below) if the language of all the groups in the tuple share /// the same associated [Language] ...
923-939
: Doc comment is outdated (claims 1–29).These two comments still say “size 1 to 29” but the macro now supports much larger tuples. Please adjust to reflect the new arity.
.changeset/mighty-seals-dance.md (3)
7-8
: End sentences with periods (repo changeset style).Small copy edit for consistency.
Apply this diff:
-For example, the following configuration: +For example, the following configuration.
19-19
: Prefer a declarative sentence over a trailing colon.Apply this diff:
-Will cause this JavaScript file: +For example, this JavaScript file.
29-30
: Similarly, finish the sentence with a period.Apply this diff:
-to be formatted like this: +is formatted like this..changeset/floppy-sloths-visit.md (2)
7-8
: Close the sentence with a period and tighten prose.Keeps changesets consistent and avoids the dangling colon.
Apply this diff:
-However, the correct pattern has changed. This rule attempts to detect incorrect usage, and promote the new pattern: +However, the correct pattern has changed. The rule detects incorrect usage and promotes the new pattern.
9-21
: Optional: link to the rule documentation.Add a link to the
useBiomeIgnoreFolder
rule docs so users can jump straight to rationale and fixes..coderabbit.yaml (1)
38-38
: CLAUDE.md in filePatterns is fine, albeit likely redundantCLAUDE.md is among commonly auto-included guideline files; keeping it explicit is harmless if you prefer clarity.
crates/biome_configuration/src/html.rs (1)
41-44
: Parser config field added correctly; consider a CLI toggle laterThe serde shape is right and Option keeps it non-breaking. If you plan CLI exposure, add a bpaf flag mirroring other formatter options when stable.
.changeset/sane-scanner-smiles.md (2)
16-16
: Minor grammar polish for readabilityAdd a couple of commas to improve flow.
Apply this diff:
-As a user you should notice better scanner performance (if you have project rules enabled), and hopefully you need to worry less about configuring [`files.experimentalScannerIgnores`](https://biomejs.dev/reference/configuration/#filesexperimentalscannerignores). Eventually our goal is still to deprecate that setting, so if you're using it today, we encourage you to see which ignores are still necessary there, and whether you can achieve the same effect by ignoring paths using `files.includes` instead. +As a user, you should notice better scanner performance (if you have project rules enabled), and hopefully, you need to worry less about configuring [`files.experimentalScannerIgnores`](https://biomejs.dev/reference/configuration/#filesexperimentalscannerignores). Eventually, our goal is still to deprecate that setting, so if you're using it today, we encourage you to see which ignores are still necessary there, and whether you can achieve the same effect by ignoring paths using `files.includes` instead.
9-15
: Add a tiny config snippet to exemplify includes/ignoresA short example helps users adopt the new behaviour quickly.
You can append something like:
{ "files": { "includes": ["src/**/*.ts", "!**/dist", "!**/build"] }, "vcs": { "useIgnoreFile": true } }crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs (1)
109-113
: Consider making the diagnostic note domain-agnostic (React + Qwik).The note links only to React docs. Given the rule now targets React and Qwik, a more generic note (or an additional Qwik-focused note) would avoid bias.
Apply this diff to make the message domain-neutral:
- ).note(markup! { - "The order of the items may change, and having a key can help React identify which item was moved." - }).note(markup! { - "Check the "<Hyperlink href="https://react.dev/learn/rendering-lists#why-does-react-need-keys">"React documentation"</Hyperlink>". " - }); + ).note(markup! { + "The order of items may change; a stable key helps the renderer identify which item moved." + }).note(markup! { + "If you're using React, see the "<Hyperlink href="https://react.dev/learn/rendering-lists#why-does-react-need-keys">"documentation on keys"</Hyperlink>"." + });.changeset/better-adults-roll.md (2)
34-35
: Tidy punctuation around the list of import names.Drop the stray spaces before commas; consider an Oxford comma for clarity.
Apply this diff:
-The following example restricts the import names that match `x` , `y` or `z` letters from modules under `import-foo/`. +The following example restricts the import names that match `x`, `y`, or `z` letters from modules under `import-foo/`.
57-59
: Same punctuation nit as above.Keeps style consistent within the changeset.
Apply this diff:
-When set to true, only the import names that match the `importNamePattern` will be allowed. The following configuration only allows the import names that match `x` , `y` or `z` letters from modules under `import-foo/`. +When set to true, only the import names that match the `importNamePattern` will be allowed. The following configuration allows only the import names that match `x`, `y`, or `z` from modules under `import-foo/`..changeset/six-corners-lay.md (1)
11-13
: Minor grammar clean-up for bullets.Avoid “it returns” and tighten phrasing.
Apply this diff:
-- `updateModuleGraph`: updates the internal module graph of the input path. -- `getModuleGraph`: it returns a serialized version of the internal module graph. +- `updateModuleGraph`: updates the internal module graph for the input path. +- `getModuleGraph`: returns a serialized version of the internal module graph.crates/biome_html_syntax/src/file_source.rs (1)
22-28
: Return by value instead of reference for a Copy enum.
HtmlTextExpressions
isCopy
; returningOption<&HtmlTextExpressions>
unnecessarily ties the caller’s borrow to&self
. Returning by value is simpler and avoids lifetime noise.Apply this diff:
- pub fn text_expressions(&self) -> Option<&HtmlTextExpressions> { - if let HtmlVariant::Standard(text_expressions) = &self.variant { - Some(text_expressions) - } else { - None - } - } + pub fn text_expressions(&self) -> Option<HtmlTextExpressions> { + if let HtmlVariant::Standard(text_expressions) = self.variant { + Some(text_expressions) + } else { + None + } + }crates/biome_analyze/src/utils.rs (3)
20-41
: Minor readability: avoid variable shadowing in closure.The closure parameter
previous_key
shadows the outer variable of the same name. Harmless, but mildly confusing. Rename it toprev
for clarity.Apply this diff:
- if previous_key.is_some_and(|previous_key| comparator(&previous_key, &key).is_gt()) + if previous_key.is_some_and(|prev| comparator(&prev, &key).is_gt()) {
11-12
: Docs: fix “chuck” → “chunk”.Two occurrences in the docs.
Apply this diff:
-/// Thus, a node without key acts as a chuck delimiter. +/// Thus, a node without key acts as a chunk delimiter.Repeat the same replacement in the later doc block.
Also applies to: 48-50
77-82
: SuperfluousNone
branches in sort_by.Because you split on
key.is_none()
, eachslice
should only containSome(_)
. TheNone
arms are unreachable. Keeping them is safe, but trimming them reduces noise.Apply this diff:
- slice.sort_by(|(key1, _, _), (key2, _, _)| match (key1, key2) { - (Some(k1), Some(k2)) => comparator(k1, k2), - (Some(_), None) => Ordering::Greater, - (None, Some(_)) => Ordering::Less, - (None, None) => Ordering::Equal, - }); + slice.sort_by(|(key1, _, _), (key2, _, _)| { + // SAFETY: split_mut ensured all keys in this slice are Some(_) + comparator(key1.as_ref().unwrap(), key2.as_ref().unwrap()) + });.changeset/promote-and-rename-rules.md (1)
7-15
: Content conforms to changeset guidelines; optional style tweak.
- Headers use allowed levels (####/#####).
- Sentences end with periods.
- User-facing and comprehensive. Nice work.
Optional: Many bullets start with “Promoted”/“Renamed”; you could vary phrasing to avoid repetition, but it’s not required.
Also applies to: 20-55, 56-75
.changeset/seven-trains-lie.md (2)
5-7
: Tighten wording; fix grammar and comma splice.
- “files that contains” → “files that contain”.
- Avoid the comma splice by splitting into two sentences.
- “Below an example…” → “Below is an example…”.
Apply this diff:
-The `--reporter=summary` has been greatly enhanced. It now shows the list of files that contains violations, the files shown are clickable and can be opened from the editor. +The `--reporter=summary` has been greatly enhanced. It now shows the list of files that contain violations. The files shown are clickable and can be opened from the editor. -Below an example of the new version: +Below is an example of the new version:
18-21
: Subject–verb agreement in example output.“files needs” should be “files need”.
Apply this diff:
- i The following files needs to be formatted. + i The following files need to be formatted.crates/biome_cli/tests/commands/format.rs (1)
3511-3535
: Deduplicate invalid source literal across tests.“while ) {}” appears in multiple tests; consider a shared const to keep tests DRY.
Apply this diff to use a shared constant here:
- let invalid = Utf8Path::new("invalid.js"); - fs.insert(invalid.into(), "while ) {}".as_bytes()); + let invalid = Utf8Path::new("invalid.js"); + fs.insert(invalid.into(), INVALID_JS.as_bytes()); @@ - assert_file_contents(&fs, invalid, "while ) {}"); + assert_file_contents(&fs, invalid, INVALID_JS);Then, add at the top of the file (near other test constants):
const INVALID_JS: &str = "while ) {}";.changeset/fancy-trains-happen.md (1)
5-13
: Align with changeset style guide; fix minor grammar.
- Start with past tense (“Added …”).
- End sentences with a period (bullets).
- “number are compared” → “numbers are compared”.
Apply this diff:
-Allow customization of the sort order for different sorting actions. These actions now support a sort option: +Added customization of the sort order for different sorting actions. These actions now support a sort option. -- [`assist/source/useSortedKeys`](https://biomejs.dev/assist/actions/use-sorted-keys/) now has a `sortOrder` option -- [`assist/source/useSortedAttributes`](https://biomejs.dev/assist/actions/use-sorted-attributes/) now has a `sortOrder` option -- [`assist/source/organizeImports`](https://biomejs.dev/assist/actions/organize-imports/) now has an `identifierOrder` option +- [`assist/source/useSortedKeys`](https://biomejs.dev/assist/actions/use-sorted-keys/) now has a `sortOrder` option. +- [`assist/source/useSortedAttributes`](https://biomejs.dev/assist/actions/use-sorted-attributes/) now has a `sortOrder` option. +- [`assist/source/organizeImports`](https://biomejs.dev/assist/actions/organize-imports/) now has an `identifierOrder` option. -For each of these options, the supported values are the same: +For each of these options, the supported values are the same: -1. **`natural`**. Compares two strings using a natural ASCII order. Uppercase letters come first (e.g. `A` < `a` < `B` < `b`) and number are compared in a human way (e.g. `9` < `10`). This is the default value. +1. **`natural`**. Compares two strings using a natural ASCII order. Uppercase letters come first (e.g. `A` < `a` < `B` < `b`), and numbers are compared in a human way (e.g. `9` < `10`). This is the default value.crates/biome_cli/examples/text_reporter.rs (1)
37-45
: Replace todo!() with a no-op to keep the example runnableAs an example, panicking on report_diagnostics isn’t ideal. Returning Ok(()) keeps the sample usable without affecting behaviour.
fn report_diagnostics( &mut self, _execution: &Execution, _payload: DiagnosticsPayload, _verbose: bool, _working_directory: Option<&Utf8Path>, ) -> std::io::Result<()> { - todo!() + Ok(()) }crates/biome_html_formatter/src/html/lists/attribute_list.rs (1)
63-65
: Confirm intent: bypassing HtmlAttribute options for HtmlDoubleTextExpressionThis routes HtmlDoubleTextExpression through its own formatter without the canonical/tag options applied to HtmlAttribute. If that’s intentional (text expressions shouldn’t be normalised), all good; otherwise, consider threading relevant context.
Would you like a brief comment in-code to document why options aren’t applied here for future readers?
crates/biome_cli/src/reporter/gitlab.rs (1)
83-84
: Clarify whyworking_directory
is unused in GitLab reporterIt’s fine to ignore
working_directory
for GitLab Code Quality since paths should be relative to the repository root. Add a short comment to make this explicit.Apply this diff:
- _working_directory: Option<&Utf8Path>, + // Intentionally unused: GitLab Code Quality expects repo-root-relative paths. + _working_directory: Option<&Utf8Path>,crates/biome_css_analyze/src/lint/complexity.rs (1)
1-4
: Duplicate “Generated file” bannerThe banner appears twice (Lines 1 and 3). Not harmful, but worth de-duplicating in the codegen to keep output tidy.
Would you like me to patch
xtask/codegen
to emit the header once?crates/biome_js_analyze/src/assist/source/use_sorted_keys.rs (2)
75-119
: Docs: small grammar clean-up for options sectionTighten the prose to avoid tiny nits. Suggested diff:
- /// ## Options - /// This actions accepts following options + /// ## Options + /// This action accepts the following options: @@ - /// ### `sortOrder` - /// This options supports `natural` and `lexicographic` values. Where as `natural` is the default. + /// ### `sortOrder` + /// This option supports `natural` and `lexicographic` values, with `natural` as the default. @@ - /// Following will apply the natural sort order. + /// The following applies the natural sort order. @@ - /// Following will apply the lexicographic sort order. + /// The following applies the lexicographic sort order.
137-143
: Avoid duplicating the comparator selectionMinor DRY: factor the match into a tiny helper to keep run/action in sync.
// Place near the top of the file (module-private helper) fn comparator_for(order: SortOrder) -> fn(&ComparableToken, &ComparableToken) -> std::cmp::Ordering { match order { SortOrder::Natural => ComparableToken::ascii_nat_cmp, SortOrder::Lexicographic => ComparableToken::lexicographic_cmp, } }Then:
- let sort_order = options.sort_order; - let comparator = match sort_order { - SortOrder::Natural => ComparableToken::ascii_nat_cmp, - SortOrder::Lexicographic => ComparableToken::lexicographic_cmp, - }; + let comparator = comparator_for(options.sort_order);Also applies to: 175-179
crates/biome_html_parser/src/syntax/parse_error.rs (1)
21-29
: Diagnostic text: minor phrasing/punctuation improvementsKeep it crisp and consistent with the rest of the file.
- p.err_builder( - "Found a text expression that doesn't have the closing expression:", + p.err_builder( + "Found a text expression that doesn't have a closing expression.", curr_range, ) - .with_detail( - opening_range, - "This is where the opening expression was found:", - ) + .with_detail(opening_range, "This is where the opening expression was found.")crates/biome_cli/src/execute/mod.rs (1)
640-641
: Propagating working_directory to reporters is a welcome additionThis will make relative paths in reports consistent. Tiny nit: consider hoisting fs.working_directory().clone() to a local variable before the match to avoid repeated calls/clone.
Example:
let working_directory = fs.working_directory().clone(); // then pass working_directory.clone() into each reporter initialiserAlso applies to: 681-681, 690-690, 703-703
crates/biome_cli/src/reporter/mod.rs (1)
61-67
: API surface updated to thread working_directory; consider documenting semantics.The signatures look right, but a short doc on expected values would help implementors:
- Is working_directory expected to be the project root/repo root?
- Should downstream render relative paths against it?
This prevents each reporter from guessing.
Apply this diff to add concise docs:
/// Writes the paths handled during a run. fn report_handled_paths( &mut self, _evaluated_paths: BTreeSet<BiomePath>, - _working_directory: Option<&Utf8Path>, + /// Optional working directory used to render file paths relative to it (e.g. repo root). + _working_directory: Option<&Utf8Path>, ) -> io::Result<()> { Ok(()) } /// Writes a diagnostics fn report_diagnostics( &mut self, _execution: &Execution, _payload: DiagnosticsPayload, _verbose: bool, - _working_directory: Option<&Utf8Path>, + /// Optional working directory used to render file paths relative to it (e.g. repo root). + _working_directory: Option<&Utf8Path>, ) -> io::Result<()>;Also applies to: 71-78
crates/biome_css_analyze/src/lint/suspicious/no_unknown_at_rules.rs (1)
61-66
: Consistency nit: pluralise the State type to match the rule.Purely cosmetic, but keeps types predictable across the codebase.
Apply this diff:
-pub struct NoUnknownAtRuleState { +pub struct NoUnknownAtRulesState { range: TextRange, name: String, } impl Rule for NoUnknownAtRules { type Query = Ast<AnyUnknownAtRule>; - type State = NoUnknownAtRuleState; + type State = NoUnknownAtRulesState; type Signals = Option<Self::State>; type Options = NoUnknownAtRulesOptions;And update construction:
- Some(NoUnknownAtRuleState { + Some(NoUnknownAtRulesState { range: rule.range(), name: rule.value_token().ok()?.text_trimmed().to_string(), })Also applies to: 56-59, 73-76
crates/biome_js_analyze/src/assist/source/organize_imports.rs (3)
621-648
: Docs: use “natural” consistently and fix a small typo.
- Prefer “natural” over “logical” for the mode name to match the actual option value.
- “incase” → “in case”.
Apply this diff:
-/// ## Change the sorting of import identifiers to lexicographic sorting +/// ## Change the sorting of import identifiers to lexicographic sorting /// This only applies to the named import/exports and not the source itself. @@ -/// ## Change the sorting of import identifiers to logical sorting -/// This is the default behavior incase you do not override. This only applies to the named import/exports and not the source itself. +/// ## Change the sorting of import identifiers to natural sorting +/// This is the default behaviour in case you do not override it. This only applies to the named import/exports and not the source itself. @@ -/// "identifierOrder": "natural" +/// "identifierOrder": "natural"Also applies to: 635-647
1096-1111
: Fix typos in variable names: meregd_ → merged_ for readability.**Minor, but worth tidying up.
Apply this diff:
- if let Some(meregd_specifiers) = - merge_export_specifiers(&specifiers1, &specifiers2, sort_order) - { - let meregd_clause = clause1.with_specifiers(meregd_specifiers); - let merged_item = item2.clone().with_export_clause(meregd_clause.into()); + if let Some(merged_specifiers) = + merge_export_specifiers(&specifiers1, &specifiers2, sort_order) + { + let merged_clause = clause1.with_specifiers(merged_specifiers); + let merged_item = item2.clone().with_export_clause(merged_clause.into()); @@ - if let Some(meregd_specifiers) = - merge_import_specifiers(specifiers1, &specifiers2, sort_order) + if let Some(merged_specifiers) = + merge_import_specifiers(specifiers1, &specifiers2, sort_order) { - let merged_clause = clause1.with_specifier(meregd_specifiers.into()); + let merged_clause = clause1.with_specifier(merged_specifiers.into()); let merged_item = item2.clone().with_import_clause(merged_clause.into()); @@ - if let Some(meregd_specifiers) = - merge_import_specifiers(specifiers1, &specifiers2, sort_order) + if let Some(merged_specifiers) = + merge_import_specifiers(specifiers1, &specifiers2, sort_order) { - let merged_clause = clause1.with_named_specifiers(meregd_specifiers); + let merged_clause = clause1.with_named_specifiers(merged_specifiers); let merged_item = item2.clone().with_import_clause(merged_clause.into());Also applies to: 1173-1188, 1194-1210
1091-1249
: Deduplicate “transfer leading trivia” code in merge() with a small helper.The same “preserve item1 leading trivia” block appears in multiple branches. Extracting it trims noise and reduces the chance of future drift.
Proposed helper (place near merge):
fn with_preserved_leading_trivia<T>( source: &AnyJsModuleItem, target: T, ) -> Option<T> where T: biome_rowan::AstNode + Clone + biome_rowan::TriviaOwner, { let trivia = source.syntax().first_leading_trivia()?; if trivia.is_empty() { Some(target) } else { target .trim_leading_trivia() .ok()? .prepend_trivia_pieces(trivia.pieces()) .ok() } }Then replace each block:
let merged_item = item2.clone().with_import_clause(merged_clause.into()); let merged_item = with_preserved_leading_trivia(&AnyJsModuleItem::JsImport(item1.clone().into()), merged_item)?; return Some(merged_item.into());Same idea for export branches, adjusting the enum variant passed to AnyJsModuleItem as needed.
crates/biome_html_parser/tests/spec_test.rs (1)
148-148
: Make the conversion explicit for readabilityTiny readability tweak: prefer an explicit From call over into() on a temporary.
Apply this diff:
- let root = parse_html(code, (&HtmlFileSource::astro()).into()); + let root = parse_html(code, HtmlParseOptions::from(&HtmlFileSource::astro()));crates/biome_html_parser/benches/html_parser.rs (3)
46-48
: Avoid per-iteration option construction in the hot pathCreating HtmlParseOptions inside b.iter adds overhead to the benchmark. Precompute once per test case to get a cleaner signal.
Apply this diff to the hot path:
- let result = - black_box(parse_html(code, HtmlParseOptions::from(&file_source))); + let result = black_box(parse_html(code, options));And add this (outside the selected lines), just after computing file_source:
let options = HtmlParseOptions::from(&file_source);
65-69
: Reuse precomputed options in the setup closureSame note for the warm-up parse in batched setup: reuse options rather than rebuilding.
Apply this diff:
- parse_html_with_cache( - code, - &mut cache, - HtmlParseOptions::from(&file_source), - ); + parse_html_with_cache(code, &mut cache, options);
73-77
: Reuse precomputed options in the measurement closureCarry the precomputed options into the measured parse as well.
Apply this diff:
- parse_html_with_cache( - code, - &mut cache, - HtmlParseOptions::from(&file_source), - ); + parse_html_with_cache(code, &mut cache, options);If HtmlParseOptions isn’t Copy/Clone, capture options by value in the closures (move) and re-create once per bench input, not per iteration.
crates/biome_html_parser/src/lib.rs (1)
36-40
: Nit: tighten the doc commentTiny wording tweak for clarity.
-/// Parses an HTML code with the provided options +/// Parses HTML with the provided options.crates/biome_cli/src/reporter/terminal.rs (1)
78-113
: DRY up path display mappingThe relative/absolute mapping logic is duplicated for evaluated and fixed lists. Consider a small local closure to keep it tidy.
let evaluated_paths_diagnostic = EvaluatedPathsDiagnostic { advice: ListAdvice { - list: evaluated_paths - .iter() - .map(|p| { - working_directory - .as_ref() - .and_then(|wd| { - p.strip_prefix(wd.as_str()) - .map(|path| path.to_string()) - .ok() - }) - .unwrap_or(p.to_string()) - }) - .collect(), + list: { + let to_display = |p: &BiomePath| { + working_directory + .and_then(|wd| p.strip_prefix(wd.as_str()).map(|path| path.to_string()).ok()) + .unwrap_or_else(|| p.to_string()) + }; + evaluated_paths.iter().map(to_display).collect() + }, }, }; @@ let fixed_paths_diagnostic = FixedPathsDiagnostic { advice: ListAdvice { - list: evaluated_paths - .iter() - .filter(|p| p.was_written()) - .map(|p| { - working_directory - .as_ref() - .and_then(|wd| { - p.strip_prefix(wd.as_str()) - .map(|path| path.to_string()) - .ok() - }) - .unwrap_or(p.to_string()) - }) - .collect(), + list: { + let to_display = |p: &BiomePath| { + working_directory + .and_then(|wd| p.strip_prefix(wd.as_str()).map(|path| path.to_string()).ok()) + .unwrap_or_else(|| p.to_string()) + }; + evaluated_paths.iter().filter(|p| p.was_written()).map(to_display).collect() + }, }, };crates/biome_cli/src/reporter/json.rs (1)
71-71
: Consider utilising the_working_directory
parameter in future iterations.The parameter is currently unused (prefixed with
_
). While this maintains API consistency across reporters, consider documenting the intended future use or implementing path resolution logic if needed.crates/biome_html_parser/src/lexer/mod.rs (1)
204-222
: Consider extracting common text expression logic.Both
consume_double_text_expression
andconsume_single_text_expression
share similar structure. The duplication could be reduced with a helper function.Consider refactoring to reduce duplication:
+fn consume_text_expression_common( + lexer: &mut HtmlLexer, + is_closing: impl Fn(&HtmlLexer) -> bool, + closing_token: impl FnOnce(&mut HtmlLexer) -> HtmlSyntaxKind, +) -> HtmlSyntaxKind { + while let Some(current) = lexer.current_byte() { + if is_closing(lexer) { + return closing_token(lexer); + } + lexer.advance(1); + } + HTML_LITERAL +} fn consume_double_text_expression(&mut self, current: u8) -> HtmlSyntaxKind { match current { - b'}' if self.at_closing_double_text_expression() => { - self.consume_r_double_text_expression() - } + b'}' if self.at_closing_double_text_expression() => self.consume_r_double_text_expression(), b'<' => self.consume_byte(T![<]), - _ => { - while let Some(current) = self.current_byte() { - match current { - b'}' if self.at_closing_double_text_expression() => break, - _ => { - self.advance(1); - } - } - } - HTML_LITERAL - } + _ => consume_text_expression_common( + self, + |l| l.at_closing_double_text_expression(), + |l| l.consume_r_double_text_expression(), + ), } }crates/biome_js_analyze/src/assist/source/organize_imports/specifiers_attributes.rs (1)
233-238
: Consider making the comparator selection more extensible.While the current implementation is correct, consider using a match expression that returns the function directly for better readability and future extensibility:
pub fn get_comparator(sort_order: SortOrder) -> fn(&ComparableToken, &ComparableToken) -> Ordering { match sort_order { - SortOrder::Lexicographic => ComparableToken::lexicographic_cmp, - SortOrder::Natural => ComparableToken::ascii_nat_cmp, + SortOrder::Lexicographic => |a, b| a.lexicographic_cmp(b), + SortOrder::Natural => |a, b| a.ascii_nat_cmp(b), } }This makes it clearer that we're returning closures and would make it easier to add more complex comparators in the future.
crates/biome_html_parser/src/syntax/mod.rs (1)
519-570
: Consider extracting common text expression parsing logic.The
TextExpression
struct and its parsing logic are well-structured. However, there's some duplication between the handling of single and double expressions in theparse_element
method. Consider extracting the common pattern:fn parse_element(&mut self, p: &mut HtmlParser) -> ParsedSyntax { if p.at(EOF) || p.at(T![<]) { return Absent; } let m = p.start(); + let (literal_token, context) = match self.kind { + TextExpressionKind::Single => (T!["}}"], HtmlLexContext::TextExpression(self.kind)), + TextExpressionKind::Double => (T!['}'], HtmlLexContext::TextExpression(self.kind)), + }; + + if p.at(literal_token) { + p.bump_remap_with_context(HTML_LITERAL, context); + } else { + p.bump_remap_any_with_context(context); + } - match self.kind { - TextExpressionKind::Single => { - if p.at(T!["}}"]) { - p.bump_remap_with_context( - HTML_LITERAL, - HtmlLexContext::TextExpression(self.kind), - ); - } else { - p.bump_remap_any_with_context(HtmlLexContext::TextExpression(self.kind)); - } - } - TextExpressionKind::Double => { - if p.at(T!['}']) { - p.bump_remap_with_context( - HTML_LITERAL, - HtmlLexContext::TextExpression(self.kind), - ) - } else { - p.bump_remap_any_with_context(HtmlLexContext::TextExpression(self.kind)) - } - } - } Present(m.complete(p, HTML_TEXT_EXPRESSION)) }
TIL that you can't use "Create merge commit" if you have merge commits from I rebased |
I don't think so 🤔 Can I reset to 7d00fdd and try merging? |
I think that's coming from this restriction in the branch protection rule. |
As merging |
With the restriction, we can't use merge commit anyway even if we removed merge commits from the |
Would you like to do that? I probably don't understand the solution, so it's best if you do the rebase since you understand what we need to remove |
@ematipico I restored the original state before you rebased the branch. Feel free to merge (bypassing rules) whenever you like :) |
With the previous release I also just ignored the restriction. Rebasing everything can be quite tedious, and there's really not much harm in having an occasional merge commit in the history. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
crates/biome_graphql_syntax/src/file_source.rs (1)
39-41
: Clarify intent: we treat .graphql and .graphqls the sameYou link to the difference, but the implementation maps both to the same variant. A short note avoids confusion for readers expecting different handling.
Apply this diff to add the note:
/// See the difference between .graphql and .graphqls files here: /// https://www.apollographql.com/docs/kotlin/essentials/file-types#sdl-schemas-graphqls - /// https://graphql.com/learn/schema/#inspecting-the-schema + /// https://graphql.com/learn/schema/#inspecting-the-schema + /// Note: Biome currently treats .graphql and .graphqls equivalently; no schema/operation distinction is made.Optional: consider swapping the second link to the official GraphQL docs (https://graphql.org/learn/schema/) for longevity.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
crates/biome_cli/tests/snapshots/main_commands_format/can_format_graphphs_files.snap
is excluded by!**/*.snap
and included by**
📒 Files selected for processing (3)
.changeset/legal-mugs-care.md
(1 hunks)crates/biome_cli/tests/commands/format.rs
(3 hunks)crates/biome_graphql_syntax/src/file_source.rs
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- .changeset/legal-mugs-care.md
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{rs,toml}
📄 CodeRabbit Inference Engine (CLAUDE.md)
Format code (Rust + TOML) using
just format
Format Rust and TOML files before committing (use
just f
/just format
).
Files:
crates/biome_graphql_syntax/src/file_source.rs
crates/biome_cli/tests/commands/format.rs
crates/biome_*/**/*
📄 CodeRabbit Inference Engine (CLAUDE.md)
Core crates must be located in
/crates/biome_*/
Files:
crates/biome_graphql_syntax/src/file_source.rs
crates/biome_cli/tests/commands/format.rs
🧠 Learnings (6)
📚 Learning: 2025-08-11T11:48:27.756Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.756Z
Learning: Applies to crates/biome_formatter/biome_html_formatter/tests/language.rs : Create tests/language.rs defining HtmlTestFormatLanguage and implement TestFormatLanguage for it
Applied to files:
crates/biome_cli/tests/commands/format.rs
📚 Learning: 2025-08-11T11:48:27.756Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.756Z
Learning: Applies to crates/biome_formatter/biome_html_formatter/tests/spec_test.rs : Create tests/spec_test.rs implementing the run(spec_input_file, _expected_file, test_directory, _file_type) function as shown and include!("language.rs")
Applied to files:
crates/biome_cli/tests/commands/format.rs
📚 Learning: 2025-08-11T11:48:27.756Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.756Z
Learning: Applies to crates/biome_formatter/biome_html_formatter/tests/spec_tests.rs : Create tests/spec_tests.rs in the biome_html_formatter crate that generates tests via tests_macros::gen_tests! for all HTML files at tests/specs/html/**/*.html
Applied to files:
crates/biome_cli/tests/commands/format.rs
📚 Learning: 2025-08-11T11:48:51.994Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:51.994Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the FormatNode trait and implement it for your Node
Applied to files:
crates/biome_cli/tests/commands/format.rs
📚 Learning: 2025-08-11T11:48:51.994Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:51.994Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Use the generic Format trait and FormatNode for AST nodes when implementing the formatter
Applied to files:
crates/biome_cli/tests/commands/format.rs
📚 Learning: 2025-08-05T13:25:32.395Z
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-05T13:25:32.395Z
Learning: Applies to benches/html_formatter.rs : Benchmark for HTML formatter must be in `benches/html_formatter.rs`
Applied to files:
crates/biome_cli/tests/commands/format.rs
🧬 Code Graph Analysis (1)
crates/biome_cli/tests/commands/format.rs (2)
crates/biome_cli/tests/main.rs (1)
run_cli
(332-347)crates/biome_cli/tests/snap_test.rs (2)
assert_cli_snapshot
(407-409)assert_file_contents
(438-449)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
- GitHub Check: Bench (biome_module_graph)
- GitHub Check: Bench (biome_html_formatter)
- GitHub Check: Bench (biome_configuration)
- GitHub Check: Bench (biome_html_parser)
- GitHub Check: Bench (biome_package)
- GitHub Check: Bench (biome_graphql_formatter)
- GitHub Check: Bench (biome_graphql_parser)
- GitHub Check: Bench (biome_json_formatter)
- GitHub Check: Bench (biome_json_analyze)
- GitHub Check: Bench (biome_css_analyze)
- GitHub Check: Bench (biome_json_parser)
- GitHub Check: Bench (biome_css_parser)
- GitHub Check: Bench (biome_js_analyze)
- GitHub Check: Bench (biome_js_parser)
- GitHub Check: Bench (biome_css_formatter)
- GitHub Check: Bench (biome_js_formatter)
- GitHub Check: Documentation
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Test Node.js API
- GitHub Check: Check Dependencies
- GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: autofix
- GitHub Check: Build @biomejs/wasm-web
🔇 Additional comments (4)
crates/biome_graphql_syntax/src/file_source.rs (1)
45-45
: LGTM: recognise .graphqls as an extensionGood call adding "graphqls" alongside "graphql" and "gql". Case-insensitivity is already handled upstream via to_ascii_lowercase_cow(), so this is consistent.
crates/biome_cli/tests/commands/format.rs (3)
160-161
: Whitespace-only change — no action neededLooks like a harmless newline tweak. Nothing to do here.
162-175
: Good addition: schema fixture for .graphqlsThe new SPACING_GRAPHQLS_SANITY_BEFORE fixture is clear and representative for a spacing sanity check.
3550-3575
: Nice coverage for write-mode syntax errorsGood to assert that --write fails on invalid syntax and leaves the file untouched. Complements format_shows_parse_diagnostics nicely.
#[test] | ||
fn can_format_graphphs_files() { | ||
let fs = MemoryFileSystem::default(); | ||
let mut console = BufferConsole::default(); | ||
|
||
let file_path = Utf8Path::new("file.graphqls"); | ||
fs.insert(file_path.into(), SPACING_GRAPHQLS_SANITY_BEFORE.as_bytes()); | ||
|
||
let (fs, result) = run_cli( | ||
fs, | ||
&mut console, | ||
Args::from(["format", "--write", file_path.as_str()].as_slice()), | ||
); | ||
|
||
assert!(result.is_ok(), "run_cli returned {result:?}"); | ||
|
||
assert_cli_snapshot(SnapshotPayload::new( | ||
module_path!(), | ||
"can_format_graphphs_files", | ||
fs, | ||
console, | ||
result, | ||
)); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Fix typo in test name and strengthen the assertion
Two tweaks:
- Typo: graphphs → graphqls (both function name and snapshot key)
- Optional: sanity-check that the file actually changed after formatting
Apply this diff within the shown range:
-#[test]
-fn can_format_graphphs_files() {
+#[test]
+fn can_format_graphqls_files() {
let fs = MemoryFileSystem::default();
let mut console = BufferConsole::default();
let file_path = Utf8Path::new("file.graphqls");
fs.insert(file_path.into(), SPACING_GRAPHQLS_SANITY_BEFORE.as_bytes());
let (fs, result) = run_cli(
fs,
&mut console,
Args::from(["format", "--write", file_path.as_str()].as_slice()),
);
assert!(result.is_ok(), "run_cli returned {result:?}");
+
+ // Sanity: ensure the formatter changed the file
+ let mut content = String::new();
+ fs.open(file_path).unwrap().read_to_string(&mut content).unwrap();
+ assert_ne!(
+ content,
+ SPACING_GRAPHQLS_SANITY_BEFORE,
+ "expected the GraphQL schema to be reformatted"
+ );
assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
- "can_format_graphphs_files",
+ "can_format_graphqls_files",
fs,
console,
result,
));
}
If there are any other lingering “graphphs” typos in the repo, a quick scan helps:
🏁 Script executed:
#!/bin/bash
# Find any misspellings of "graphphs" across the repo
rg -n --no-ignore-vcs --hidden 'graphphs'
Length of output: 205
Fix typo in test name and add sanity‐check in format test
In crates/biome_cli/tests/commands/format.rs
(lines 3382–3406):
- Rename occurrences of “graphphs” → “graphqls” (function name & snapshot key).
- After
run_cli
, read back the file and assert its contents differ from the unformatted input.
#[test]
-fn can_format_graphphs_files() {
+fn can_format_graphqls_files() {
let fs = MemoryFileSystem::default();
let mut console = BufferConsole::default();
let file_path = Utf8Path::new("file.graphqls");
fs.insert(file_path.into(), SPACING_GRAPHQLS_SANITY_BEFORE.as_bytes());
let (fs, result) = run_cli(
fs,
&mut console,
Args::from(["format", "--write", file_path.as_str()].as_slice()),
);
assert!(result.is_ok(), "run_cli returned {result:?}");
+ // Sanity check: ensure the formatter changed the file
+ let mut content = String::new();
+ fs.open(file_path).unwrap().read_to_string(&mut content).unwrap();
+ assert_ne!(
+ content,
+ SPACING_GRAPHQLS_SANITY_BEFORE,
+ "expected the GraphQL schema to be reformatted"
+ );
assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
- "can_format_graphphs_files",
+ "can_format_graphqls_files",
fs,
console,
result,
));
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
#[test] | |
fn can_format_graphphs_files() { | |
let fs = MemoryFileSystem::default(); | |
let mut console = BufferConsole::default(); | |
let file_path = Utf8Path::new("file.graphqls"); | |
fs.insert(file_path.into(), SPACING_GRAPHQLS_SANITY_BEFORE.as_bytes()); | |
let (fs, result) = run_cli( | |
fs, | |
&mut console, | |
Args::from(["format", "--write", file_path.as_str()].as_slice()), | |
); | |
assert!(result.is_ok(), "run_cli returned {result:?}"); | |
assert_cli_snapshot(SnapshotPayload::new( | |
module_path!(), | |
"can_format_graphphs_files", | |
fs, | |
console, | |
result, | |
)); | |
} | |
#[test] | |
fn can_format_graphqls_files() { | |
let fs = MemoryFileSystem::default(); | |
let mut console = BufferConsole::default(); | |
let file_path = Utf8Path::new("file.graphqls"); | |
fs.insert(file_path.into(), SPACING_GRAPHQLS_SANITY_BEFORE.as_bytes()); | |
let (fs, result) = run_cli( | |
fs, | |
&mut console, | |
Args::from(["format", "--write", file_path.as_str()].as_slice()), | |
); | |
assert!(result.is_ok(), "run_cli returned {result:?}"); | |
// Sanity check: ensure the formatter changed the file | |
let mut content = String::new(); | |
fs.open(file_path).unwrap().read_to_string(&mut content).unwrap(); | |
assert_ne!( | |
content, | |
SPACING_GRAPHQLS_SANITY_BEFORE, | |
"expected the GraphQL schema to be reformatted" | |
); | |
assert_cli_snapshot(SnapshotPayload::new( | |
module_path!(), | |
"can_format_graphqls_files", | |
fs, | |
console, | |
result, | |
)); | |
} |
pub fn try_from_language_id(language_id: &str) -> Result<Self, FileSourceError> { | ||
match language_id { | ||
"graphql" | "gql" => Ok(Self::default()), | ||
"graphqls" | "graphql" | "gql" => Ok(Self::default()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Sanity-check: is "graphqls" a widely used languageId?
Many editors/tools only emit "graphql" as the languageId. Accepting "graphqls" is harmless, but let’s confirm it’s used in the wild and ensure tests cover it.
Run this script to check where "graphqls" is referenced in the repo (tests, config, docs):
And, to confirm whether VS Code or LSP conventions include "graphqls" as a languageId, please run this web query:
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo 'Occurrences of "graphqls" across the repo:'
rg -n --pretty --hidden --glob '!.git' '"graphqls"'
echo
echo 'Callers/tests for try_from_language_id/try_from_extension:'
rg -n --pretty --hidden --glob '!.git' 'try_from_language_id|try_from_extension'
Length of output: 4527
🌐 Web query:
Does VS Code or common GraphQL extensions define "graphqls" as a language identifier (languageId), or is "graphql" the de-facto standard?
💡 Result:
The de-facto standard language identifier (languageId) for GraphQL in VS Code and its common extensions is "graphql". Neither VS Code core nor major GraphQL extensions define "graphqls" as a language identifier; "graphql" is used for both query documents and schema files.
Supporting details:
-
The official [VS Code language identifiers documentation][8] only mentions "graphql" as a recognized language mode; "graphqls" is not documented as a languageId.
-
The most popular and canonical GraphQL extensions—including GraphQL for VSCode[7], Apollo's editor extension[6], and vscode-graphql by GraphQL Foundation[2][5]—all use "graphql" as the languageId for syntax highlighting, autocompletion, and language server features.
-
File associations in the extensions typically map both
.graphql
and.gql
files (and sometimes.graphqls
) to the "graphql" languageId[2][4][5]. The naming "graphqls" as an extension for schema files (.graphqls) is a file extension convention in some codebases but does not imply a separate languageId. -
For example, the [vscode-graphql extension documentation][2][5] only references "graphql" as the language identifier—and "graphql" is the value used internally for language features, regardless of whether the file is a schema or a query.
-
Some developers use
.graphqls
as a filename extension for GraphQL schema files, but this is a convention at the file system level and does not affect the languageId, which remains "graphql"[2][4].
Summary table:
File Extensions | languageId used by VS Code/extensions |
---|---|
.graphql, .gql, .graphqls | graphql |
Conclusion:
Use "graphql" as the languageId for both GraphQL queries and schemas in VS Code and common extensions. The identifier "graphqls" is not registered as a languageId; it's only seen occasionally as a filename extension convention[2][5][8].
Citations:
- 1: https://community.apollographql.com/t/vs-code-extension-not-working-with-graphql-code-gen/5628
- 2: https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql
- 3: https://graphql.org/learn/schema/
- 4: https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql-syntax
- 5: https://github.com/graphql/vscode-graphql
- 6: https://www.apollographql.com/docs/ide-support/vs-code
- 7: https://marketplace.visualstudio.com/items?itemName=kumar-harsh.graphql-for-vscode
- 8: https://code.visualstudio.com/docs/languages/identifiers
Align GraphQL languageId with VS Code conventions
Our investigation shows that VS Code and major GraphQL extensions only emit “graphql” (not “graphqls”) as the languageId, while .graphqls
remains a file-extension convention. To bring our code in line:
• In crates/biome_graphql_syntax/src/file_source.rs
→ try_from_language_id
(around line 58), remove “graphqls” from the match arm:
- "graphqls" | "graphql" | "gql" => Ok(Self::default()),
+ "graphql" | "gql" => Ok(Self::default()),
• Leave the .graphqls
mapping in try_from_extension
(around line 45) so schema files still resolve correctly.
• Add a unit test in biome_graphql_syntax
to verify try_from_extension("graphqls")
returns the expected GraphqlFileSource
.
This change trims a redundant languageId while preserving support for the .graphqls
extension.
🤖 Prompt for AI Agents
In crates/biome_graphql_syntax/src/file_source.rs around line 58, the match arm
for try_from_language_id incorrectly includes "graphqls" as a languageId; remove
"graphqls" so only "graphql" | "gql" map to Ok(Self::default()). Keep the
existing ".graphqls" mapping in try_from_extension (around line 45) unchanged so
schema file extensions still resolve. Add a unit test in the
biome_graphql_syntax tests that calls try_from_extension("graphqls") and asserts
it returns the expected GraphqlFileSource variant to ensure .graphqls is still
supported.
Summary
Test Plan
Docs