Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@ematipico
Copy link
Member

@ematipico ematipico commented Dec 16, 2025

Summary

This PR refactors the CLI infrastructure to be as flexible as possible. The refactor breaks down the command execution in five entities:

  • command: we had this trait before, so much isn't changed
  • crawler: responsible for crawling the file system
    • it crawls the given paths
    • it calls a function to process the output of the collector
  • collector: responsible for collecting information during the crawling
  • execution: before, it was an enum, now it's a trait and each command implements it
  • handler: responsible for checking if a path should be handled, and if so how
  • process_file: given a file, it applies core logic decided by the command (format, search, etc.)

Everything has been placed inside the runner folder.

Also, I created some default types, and that's where the existing functionality resides.

The only part that isn't very "generic" is the use of is_ci, is_format, is_check, is_search and is_lint. I decided to keep them and tackle them later.

I also fixed a bug where some info diagnostics weren't tracked.

Note

I mostly used AI to write the documentation inside runner/mod.rs and track the missing features during the developments. Towards the end, I asked it to do some trivial renaming and reactors. The bulk of the logic was written by me.

Test Plan

Updated the relevant snapshots.

Docs

N/A

@changeset-bot
Copy link

changeset-bot bot commented Dec 16, 2025

🦋 Changeset detected

Latest commit: e34489c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

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

@github-actions github-actions bot added the A-CLI Area: CLI label Dec 16, 2025
@ematipico ematipico marked this pull request as ready for review December 16, 2025 15:07
@ematipico ematipico requested review from a team December 16, 2025 15:07
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Walkthrough

This PR radically restructures the biome_cli command execution pipeline: it removes the old CommandRunner/TraversalMode/execute modules and per-file process_file/traverse/std_in implementations, and replaces them with a new runner framework (Execution, TraversalCommand, Crawler, Collector, Handler, Finalizer) plus concrete implementations for process-file variants (lint/format/check). Reporters now accept trait-object Execution references. Several command payloads were adapted to the TraversalCommand flow. Also adds runner impls, collectors, crawlers, finalizers, and a changeset; a previously included example was removed and CliOptions now derives Default. (≈85 words)

Possibly related PRs

Suggested labels

A-Core, A-Project, A-Linter, A-Parser, A-Formatter, A-Tooling, A-LSP, L-JavaScript, L-CSS, L-JSON, L-HTML

Suggested reviewers

  • arendjr
  • dyc3

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarises the main change: a refactor to make CLI commands more generic through a modular architecture.
Description check ✅ Passed The description clearly explains the motivation, the five-entity architecture (command, crawler, collector, execution, handler, process_file), and includes a note about AI usage and a bug fix.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/cli-infra

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66db47a and e34489c.

📒 Files selected for processing (1)
  • crates/biome_cli/src/diagnostics.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
crates/**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update inline rustdoc documentation for rules, assists, and their options when adding new features or changing existing features in Rust crates

Files:

  • crates/biome_cli/src/diagnostics.rs
🧠 Learnings (10)
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Implement the Diagnostic trait on types, or use the #[derive(Diagnostic)] procedural macro to implement the trait. Configure category, severity, description, message, location, and tags using the #[diagnostic] attribute

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/crates/biome_diagnostics_categories/src/categories.rs : Register all new diagnostic categories in crates/biome_diagnostics_categories/src/categories.rs

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Use `rule_category!()` macro instead of dynamic string parsing to refer to rule diagnostic categories for compile-time validation

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Ensure the type implementing Diagnostic derives Debug

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use #[derive(Diagnostic)] on enums when every variant contains a type that is itself a diagnostic

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : The `diagnostic` function must return a `RuleDiagnostic` that defines the message reported to the user using the `markup!` macro

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Use helper types from the biome_diagnostics::v2 module (CodeFrameAdvice, CommandAdvice, DiffAdvice, LogAdvice) or implement the Advices trait yourself for custom advice handling

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-24T18:04:57.309Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:04:57.309Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Fields with #[advice] or #[verbose_advice] attributes must implement the Advices trait to record advices on the diagnostic

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-11-27T23:04:02.022Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-11-27T23:04:02.022Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Document rules with a one-line brief description in the first paragraph of the doc comment, followed by detailed paragraphs, `## Examples` section with `### Invalid` and `### Valid` subsections, and optional `## Options` section

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
📚 Learning: 2025-12-12T10:11:05.549Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-12T10:11:05.549Z
Learning: Applies to crates/**/*.rs : Update inline rustdoc documentation for rules, assists, and their options when adding new features or changing existing features in Rust crates

Applied to files:

  • crates/biome_cli/src/diagnostics.rs
🧬 Code graph analysis (1)
crates/biome_cli/src/diagnostics.rs (4)
crates/biome_cli/src/execute/migrate.rs (1)
  • category (102-104)
crates/biome_suppression/src/lib.rs (1)
  • category (205-207)
crates/biome_cli/src/reporter/summary.rs (1)
  • from (454-456)
crates/biome_service/src/workspace.rs (1)
  • markup (1203-1205)
⏰ 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). (8)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Documentation
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Check Dependencies
  • GitHub Check: autofix
🔇 Additional comments (1)
crates/biome_cli/src/diagnostics.rs (1)

378-389: LGTM! Previous doc comment issue resolved.

The function correctly mirrors the check_error pattern with appropriate formatter-specific messaging. The doc comment now properly references the "format" command rather than "check".


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/biome_cli/src/reporter/github.rs (1)

46-54: Verbose logic appears inverted.

The condition at lines 48-52 seems backwards:

  • When verbose=true and diagnostic.tags().is_verbose(): logs the diagnostic
  • When verbose=false: logs all diagnostics regardless of tags

This means setting --verbose would show fewer diagnostics (only verbose-tagged ones), not more. Typically, verbose mode should show additional output, not restrict it.

         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 {
+                if diagnostic.tags().is_verbose() {
+                    if verbose {
+                        self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}});
+                    }
+                } else {
                     self.0.log(markup! {{PrintGitHubDiagnostic(diagnostic)}});
                 }
             }
         }
🧹 Nitpick comments (26)
.changeset/tiny-dodos-ask.md (1)

5-5: Clarify what Biome now does, rather than what wasn't happening.

The changeset describes a fix, but the phrasing is a bit passive. Following the changeset guidelines, consider rephrasing to be more explicit about the corrected behaviour — e.g., "Fixed an issue where Biome didn't track some info diagnostics in the final summary." This makes it clearer what users benefit from.

Suggested revision:

-Fixed an issue where some info diagnostics weren't tracked by the final summary.
+Fixed an issue where Biome wasn't tracking some info diagnostics in the final summary.

Based on coding guidelines for .changeset/*.md, use past tense for actions taken and present tense for Biome's behaviour to maintain consistency across changesets.

crates/biome_cli/src/runner/impls/process_file/check.rs (1)

53-55: Consider inverting the condition to avoid an empty branch.

The empty if block with a comment is a bit awkward. Negating the condition improves readability.

-            if execution.should_skip_parse_errors() && skipped_parse_error {
-                // Parse errors are already skipped during the analyze phase, so no need to do it here.
-            } else {
+            // Parse errors are already skipped during the analyze phase, so no need to do it here.
+            if !(execution.should_skip_parse_errors() && skipped_parse_error) {
                 let format_result =
                     FormatProcessFile::process_file(ctx, workspace_file, features_supported);
                 // ... rest of the block
-            }
+            }
crates/biome_cli/src/runner/impls/commands/custom_execution.rs (3)

14-17: Consider adding rustdoc to explain the wrapper's purpose.

Whilst the struct is crate-private, a doc comment explaining that this wrapper adapts commands that don't require crawling into the CommandRunner framework would aid maintainability.


38-78: Consider adding rustdoc to clarify the trait's role.

The trait encapsulates the contract for non-crawling commands, but lacks explanation of when and why to use it versus implementing CommandRunner directly. A brief doc comment would help future contributors.


147-154: Minor: Inconsistent parameter naming.

Parameters are prefixed with _ but then used in the method body. Other delegating methods (lines 91-92, 99-100, etc.) don't use this prefix. Consider removing the underscore prefix for consistency.

crates/biome_cli/src/runner/run.rs (1)

10-13: Redundant rebinding.

The let command = &mut command; on line 12 is unnecessary — command is already declared mut, so you can call command.run(...) directly.

 pub(crate) fn run_command(
     session: CliSession,
     log_options: &LogOptions,
     cli_options: &CliOptions,
     mut command: impl CommandRunner,
 ) -> Result<(), CliDiagnostic> {
-    let command = &mut command;
     command.run(session, log_options, cli_options)
 }
crates/biome_cli/src/commands/migrate.rs (1)

125-148: Consider using expect() with an informative message instead of unwrap().

The // SAFETY comment on line 142 is helpful, but expect() would provide a clearer panic message if the invariant is ever violated during future refactoring.

-            // SAFETY: checked during get_execution
-            configuration_file_path: self.configuration_file_path.clone().unwrap(),
+            configuration_file_path: self
+                .configuration_file_path
+                .clone()
+                .expect("configuration_file_path must be Some; checked during get_execution"),
crates/biome_cli/src/runner/impls/finalizers/default.rs (1)

258-274: Minor inconsistency: GitLab {} vs other unit variants.

Line 269 uses Self::GitLab {} with empty braces whilst other unit-like variants (e.g., Self::GitHub, Self::Junit) don't. This is valid Rust but inconsistent with the rest of the match arm.

-            CliReporter::GitLab => Self::GitLab {},
+            CliReporter::GitLab => Self::GitLab,
crates/biome_cli/src/reporter/gitlab.rs (1)

71-98: Minor naming inconsistency in unused parameters.

Line 74 uses _ whilst line 83 uses _execution for the same unused parameter type. Consider aligning them for consistency, though this is purely cosmetic.

crates/biome_cli/src/runner/impls/process_file/format.rs (2)

36-42: Technical debt marker detected.

The NOTE: probably to revisit comment suggests this boolean value needs review. Consider creating a tracking issue or adding more context about what specifically needs revisiting.

Would you like me to open an issue to track this?


81-104: Consider consolidating the repeated empty-output check.

The pattern of checking if output.is_empty() { return Ok(FileStatus::Unchanged); } is duplicated for astro, vue, and svelte. A helper or early match could reduce repetition.

+        let maybe_output = |ext: &str, input: &str, output: &str| -> Option<String> {
+            if output.is_empty() {
+                return None;
+            }
+            match ext {
+                "astro" => Some(AstroFileHandler::output(input, output)),
+                "vue" => Some(VueFileHandler::output(input, output)),
+                "svelte" => Some(SvelteFileHandler::output(input, output)),
+                _ => Some(output.to_string()),
+            }
+        };
+
         if !features_supported.supports_full_html_support() {
-            match workspace_file.as_extension() {
-                Some("astro") => {
-                    if output.is_empty() {
-                        return Ok(FileStatus::Unchanged);
-                    }
-                    output = AstroFileHandler::output(input.as_str(), output.as_str());
-                }
-                // ... similar for vue and svelte
+            if let Some(ext) = workspace_file.as_extension() {
+                if let Some(processed) = maybe_output(ext, input.as_str(), output.as_str()) {
+                    output = processed;
+                } else {
+                    return Ok(FileStatus::Unchanged);
+                }
+            }
         }
crates/biome_cli/src/runner/handler.rs (1)

103-105: Doc comment style: use backticks for code references.

The rustdoc convention is to use backticks for inline code, e.g., `process_file` and `catch_unwind`, rather than square brackets (which are for linking to items in scope).

-    /// This function wraps the [process_file] function implementing the traversal
-    /// in a [catch_unwind] block and emit diagnostics in case of error (either the
+    /// This function wraps the `process_file` function implementing the traversal
+    /// in a `catch_unwind` block and emit diagnostics in case of error (either the
crates/biome_cli/src/runner/finalizer.rs (1)

14-15: Minor typo: "finalise" should be "finalize".

For consistency with the trait and method naming, the comment should use "finalize".

     /// Optional hook to run before finalization. Useful for commands that need
-    /// to work with the Workspace before finally finalise the command.
+    /// to work with the Workspace before finally finalizing the command.
crates/biome_cli/src/reporter/json.rs (1)

33-39: Public visibility on struct fields.

The JsonReporter struct has pub fields (not pub(crate)), making them accessible outside the crate. If this is intentional for external API usage, that's fine. Otherwise, consider pub(crate) for consistency with GithubReporter.

crates/biome_cli/src/commands/check.rs (1)

250-265: Potential silent fallback when VCS options yield no files.

When get_files_to_process_with_cli_options returns Ok(None), the code falls back to self.paths.clone(). If self.paths is empty and no VCS files are found, this silently proceeds with an empty list rather than warning the user.

Consider logging or warning when both VCS targeting and explicit paths result in no files to process, to help users debug unexpected "0 files checked" scenarios.

crates/biome_cli/src/commands/ci.rs (1)

42-51: Unused _environment field.

The _environment field is populated but never read. If this is intended for future use, consider adding a TODO comment. Otherwise, it could be removed to avoid dead code.

 struct CiExecution {
-    /// Whether the CI is running in a specific environment, e.g. GitHub, GitLab, etc.
-    _environment: Option<ExecutionEnvironment>,
     /// A flag to know vcs integrated options such as `--staged` or `--changed` are enabled
     vcs_targeted: VcsTargeted,

If planned for future use, add a comment explaining the intent.

crates/biome_cli/src/commands/search.rs (1)

116-129: Language compatibility check could be extended.

The is_file_compatible_with_pattern method currently handles JS and CSS. If Grit adds support for more languages (JSON, HTML, GraphQL), this will need updating.

Consider adding a // TODO: extend when GritTargetLanguage adds new variants comment, or use a more exhaustive match to catch new variants at compile time:

-        match pattern_language {
+        #[deny(clippy::wildcard_enum_match_arm)]
+        match pattern_language {
crates/biome_cli/src/reporter/summary.rs (1)

194-199: Consider adding a trailing slash check for "plugin" prefix.

The "plugin" prefix check at line 198 doesn't include a trailing delimiter, which could match unintended categories like "pluginmanager/". The other prefixes use "/" as a delimiter.

 fn should_report_lint_diagnostic(category: &Category) -> bool {
     category.name().starts_with("lint/")
         || category.name().starts_with("suppressions/")
         || category.name().starts_with("assist/")
-        || category.name().starts_with("plugin")
+        || category.name().starts_with("plugin/")
 }
crates/biome_cli/src/runner/execution.rs (2)

43-47: Minor rustdoc typo.

Line 46 has "It should returns" — should be "It should return".

-    /// It should returns the value of `--stdin-file-path`
+    /// It should return the value of `--stdin-file-path`
     fn get_stdin_file_path(&self) -> Option<&str>;

166-189: Consider adding rustdoc for Stdin methods.

As per coding guidelines, inline rustdoc documentation should be updated when adding new features in Rust crates.

 impl Stdin {
+    /// Returns the virtual path associated with this stdin input.
     pub(crate) fn as_path(&self) -> &Utf8Path {
         self.0.as_path()
     }

+    /// Returns the content read from stdin.
     pub(crate) fn as_content(&self) -> &str {
         self.1.as_str()
     }
 }
crates/biome_cli/src/runner/impls/commands/traversal.rs (1)

120-120: Minor typo in doc comment.

Line 120 references CommanderRunner but should be CommandRunner.

-    /// Alias of [CommanderRunner::get_files_to_process]
+    /// Alias of [CommandRunner::get_files_to_process]
     fn get_files_to_process(
crates/biome_cli/src/reporter/terminal.rs (2)

165-186: Comments indicate deferred generalisation — consider tracking.

Lines 174-176 note that the assumption about fixes "can be refined later". This is fine for the current refactor scope, but worth tracking to avoid stale assumptions as new execution types are added.


234-242: Assumption about search detection via match count.

The comment on lines 235-237 indicates the code infers a search command by checking summary.matches > 0. This works but couples the display logic to an implicit heuristic rather than querying execution.is_search() directly, which is already available.

Consider using execution.is_search() for consistency with the rest of the file:

-        // For now, we'll assume this is a search command if there are matches
-        // This can be refined later when we have more specific execution types
-        if summary.matches > 0 {
+        if execution.is_search() && summary.matches > 0 {
crates/biome_cli/src/runner/process_file.rs (3)

64-69: Remove commented-out code or track with an issue.

The DiagnosticsWithActions variant is commented out. Either remove it entirely or open a tracking issue if this is planned functionality.


120-127: Trait methods lack rustdoc.

As per coding guidelines, consider adding inline rustdoc for the ProcessFile trait methods to document their purpose and expected behaviour.


163-177: Remove large commented-out TODO block.

This block contains old TraversalMode matching logic that's been superseded by the new design. Dead code in comments tends to rot; either remove it or extract to a tracking issue.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@ematipico ematipico merged commit bf02ba6 into next Dec 19, 2025
12 checks passed
@ematipico ematipico deleted the refactor/cli-infra branch December 19, 2025 16:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants