Skip to content

feat(resolver): support baseUrl in tsconfig.json#7263

Merged
arendjr merged 7 commits intobiomejs:nextfrom
arendjr:support-baseUrl
Aug 19, 2025
Merged

feat(resolver): support baseUrl in tsconfig.json#7263
arendjr merged 7 commits intobiomejs:nextfrom
arendjr:support-baseUrl

Conversation

@arendjr
Copy link
Contributor

@arendjr arendjr commented Aug 18, 2025

Summary

Biome's resolver now supports baseUrl if specified in tsconfig.json. This
means that the following now resolves:

tsconfig.json

{
    "compilerOptions": {
        "baseUrl": "./src",
    }
}

index.ts

import { foo } from "foo"; // This will now work.

src/foo.ts

export function foo() {}

Fixes #6432.

Test Plan

Tests added.

Docs

N/A

@arendjr arendjr requested a review from a team August 18, 2025 11:34
@changeset-bot
Copy link

changeset-bot bot commented Aug 18, 2025

🦋 Changeset detected

Latest commit: b99716b

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

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

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 18, 2025

Walkthrough

Adds tsconfig-aware resolution and baseUrl support to the module resolver. ResolveOptions gains Clone; DiscoverableManifest gets Clone/Debug/Default. The resolver now optionally loads tsconfig (Auto/Explicit/Off), attempts an early baseUrl-based resolution, and uses tsconfig.compiler_options.paths_base for path-alias resolution. Tsconfig parsing now initialises normalized paths_base/base_url and exposes CompilerOptions.paths_base publicly. Manifest deserialisers/insertors and many call sites now accept an explicit Utf8Path. Tests, fixtures and a changeset documenting baseUrl support were added.

Assessment against linked issues

Objective Addressed Explanation
Ensure useImportExtensions flags and fixes missing extension in alias imports (#6432) The PR updates resolver tsconfig/baseUrl handling but does not modify the useImportExtensions linter rule or its autofix; no linter code or tests for useImportExtensions are present in the changes.

Out-of-scope changes

Code Change (file_path) Explanation
Public re-export of CompilerOptions (crates/biome_package/src/lib.rs) Exposes tsconfig types to consumers; unrelated to the linter rule in #6432.
Added path parameter to manifest deserializers/insertors (crates/biome_package/src/node_js_package/*.rs, crates/biome_package/src/lib.rs, crates/biome_package/src/node_js_package/package_json.rs) API wiring to carry file paths for manifests; not required by the linked lint objective.
Making paths_base public and normalisation logic (crates/biome_package/src/node_js_package/tsconfig_json.rs) Internal tsconfig normalisation to support resolver behaviour; does not change linter diagnostics or autofix.
Derive Clone/Debug/Default on resolver types (crates/biome_resolver/src/lib.rs) Trait derivations for ergonomics/debugging; unrelated to useImportExtensions behaviour.

Possibly related PRs

Suggested reviewers

  • ematipico
  • dyc3

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b134da1 and b99716b.

📒 Files selected for processing (1)
  • crates/biome_package/src/node_js_package/tsconfig_json.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
⏰ 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). (24)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: autofix
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Comment on lines -186 to +192
let tsconfig = fs.read_tsconfig_json(&package_path.join("tsconfig.json"));
if let Some(path) = tsconfig.as_ref().ok().and_then(|ts_config| {
resolve_paths_mapping(specifier, ts_config, package_path, fs, options).ok()
let tsconfig = match &options.tsconfig {
DiscoverableManifest::Auto => fs
.read_tsconfig_json(&package_path.join("tsconfig.json"))
.map(Cow::Owned),
DiscoverableManifest::Explicit { manifest, .. } => Ok(Cow::Borrowed(*manifest)),
DiscoverableManifest::Off => Err(ResolveError::NotFound),
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This fixes a slightly unrelated oversight: If an explicit manifest was configured for tsconfig.json, it would be ignored in favour of the one on disk.

This came to light as I added tests.

@github-actions github-actions bot added A-Project Area: project A-Resolver Area: resolver labels Aug 18, 2025
resolve_relative_path(specifier, base_dir, fs, options)
resolve_relative_path(
specifier,
&tsconfig_json.compiler_options.paths_base,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

paths_base was explicitly intended for this purpose, although it was unused until now. I noticed this as I extended the documentation comments.

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: 1

🔭 Outside diff range comments (1)
crates/biome_package/src/node_js_package/tsconfig_json.rs (1)

72-75: Bug: base_url becomes None if the tsconfig path has no parent

If path.parent() returns None, you drop a valid baseUrl by assigning None. Keep the original value (normalised) when the directory is unavailable.

Apply this diff:

-        if let Some(base_url) = tsconfig.compiler_options.base_url {
-            tsconfig.compiler_options.base_url =
-                directory.map(|dir| normalize_path(&dir.join(base_url)));
-        }
+        if let Some(base_url) = tsconfig.compiler_options.base_url {
+            tsconfig.compiler_options.base_url = Some(if let Some(dir) = directory {
+                normalize_path(dir.join(&base_url).as_path())
+            } else {
+                // Preserve the provided baseUrl (still normalised) if no parent directory is available
+                normalize_path(&base_url)
+            });
+        }
🧹 Nitpick comments (7)
crates/biome_package/src/node_js_package/tsconfig_json.rs (2)

76-82: Normalise paths_base when falling back to the tsconfig directory

The doc says this is an absolute, normalised path; the directory branch currently isn’t normalised. Normalising ensures consistent behaviour across relative invocations and platforms.

Apply this diff:

-            tsconfig.compiler_options.paths_base =
-                tsconfig.compiler_options.base_url.as_ref().map_or_else(
-                    || directory.map_or_else(Default::default, Utf8Path::to_path_buf),
-                    Clone::clone,
-                );
+            tsconfig.compiler_options.paths_base = tsconfig
+                .compiler_options
+                .base_url
+                .as_ref()
+                .map_or_else(
+                    || directory.map_or_else(Default::default, |dir| normalize_path(dir)),
+                    Clone::clone,
+                );

97-101: Clarify docs and invariant for paths_base

Minor: the comment references “base URL” but this field represents the base used for paths resolution. Also, consider initialising it unconditionally to a normalised tsconfig directory (so it’s always meaningful even when paths is absent), or keep it private to maintain the invariant that it’s a derived field.

Apply this diff to the doc comment:

-    /// The actual base from where path aliases are resolved.
-    ///
-    /// The base URL is normalised to an absolute path.
+    /// Base directory used to resolve entries in `compilerOptions.paths`.
+    ///
+    /// This is normalised to an absolute path after parsing.

If you’d like, I can follow up with a PR to make this field private again and expose an accessor.

crates/biome_resolver/tests/fixtures/resolver_cases_7/tsconfig.json (1)

1-5: Fixture looks good; consider an additional absolute-path case

Nice minimal fixture. Consider adding a companion case where baseUrl is absolute, and one where tsconfig lives in a subfolder, to guard path-join edge cases.

Happy to draft those fixtures and tests if helpful.

.changeset/based-bears-brawl.md (3)

5-8: Tighten prose to match changeset conventions (past tense + sentence endings).

Use past tense for what changed and end sentences with a period. Suggested tweak below also removes the dangling “This …” line break.

-Biome's resolver now supports `baseUrl` if specified in `tsconfig.json`. This
-means that the following now resolves:
+Added resolver support for `baseUrl` in `tsconfig.json`.
+The following now resolves.

9-15: Use jsonc for tsconfig examples (or remove trailing comma).

tsconfig.json supports JSON with comments/trailing commas (JSONC). Label the block as jsonc to avoid confusion or remove the trailing comma. I’d go with jsonc:

-```json
+```jsonc
 {
     "compilerOptions": {
         "baseUrl": "./src",
     }
 }

---

`27-27`: **Ensure a trailing period at the end.**

Changeset style guide asks every sentence to end with a period. If missing, add one.



```diff
-Fixes [#6432](https://github.com/biomejs/biome/issues/6432)
+Fixes [#6432](https://github.com/biomejs/biome/issues/6432).
crates/biome_resolver/tests/spec_tests.rs (1)

537-616: Great coverage for baseUrl; minor readability nits.

Solid assertions (explicit and auto tsconfig, different base dirs, subfolder, and no-baseUrl fallback). Two small nits:

  • Prefer join() over format! for paths.
  • Avoid a giant inline &TsConfigJson literal by introducing locals.
@@
 fn test_resolve_from_base_url() {
     let base_dir = get_fixtures_path("resolver_cases_7");
     let fs = OsFileSystem::new(base_dir.clone());
 
     let options = ResolveOptions {
         condition_names: &["default"],
         extensions: &["js", "ts"],
         ..Default::default()
     };
 
+    let tsconfig_path = base_dir.join("tsconfig.json");
+    let tsconfig_with_base = TsConfigJson {
+        compiler_options: CompilerOptions {
+            base_url: Some(base_dir.join("src")),
+            ..Default::default()
+        },
+        ..Default::default()
+    };
+
     // Make sure resolution works with explicitly specified `tsconfig.json`.
     assert_eq!(
         resolve(
             "bar",
             &base_dir.join("src"),
             &fs,
-            &options
-                .clone()
-                .with_tsconfig(DiscoverableManifest::Explicit {
-                    package_path: Utf8PathBuf::from(format!("{base_dir}/tsconfig.json")),
-                    manifest: &TsConfigJson {
-                        compiler_options: CompilerOptions {
-                            base_url: Some(base_dir.join("src")),
-                            ..Default::default()
-                        },
-                        ..Default::default()
-                    }
-                })
+            &options.clone().with_tsconfig(DiscoverableManifest::Explicit {
+                package_path: tsconfig_path.clone(),
+                manifest: &tsconfig_with_base,
+            })
         ),
-        Ok(Utf8PathBuf::from(format!("{base_dir}/src/bar.ts")))
+        Ok(base_dir.join("src/bar.ts"))
     );
@@
-    assert_eq!(
-        resolve("bar", &base_dir.join("src"), &fs, &options),
-        Ok(Utf8PathBuf::from(format!("{base_dir}/src/bar.ts")))
-    );
+    assert_eq!(
+        resolve("bar", &base_dir.join("src"), &fs, &options),
+        Ok(base_dir.join("src/bar.ts"))
+    );
@@
-    assert_eq!(
-        resolve("bar", &base_dir, &fs, &options),
-        Ok(Utf8PathBuf::from(format!("{base_dir}/src/bar.ts")))
-    );
+    assert_eq!(resolve("bar", &base_dir, &fs, &options), Ok(base_dir.join("src/bar.ts")));
     assert_eq!(
         resolve("bar", &base_dir.join("src/foo"), &fs, &options),
-        Ok(Utf8PathBuf::from(format!("{base_dir}/src/bar.ts")))
+        Ok(base_dir.join("src/bar.ts"))
     );
@@
-    assert_eq!(
-        resolve("foo/foo", &base_dir.join("src"), &fs, &options),
-        Ok(Utf8PathBuf::from(format!("{base_dir}/src/foo/foo.ts")))
-    );
+    assert_eq!(
+        resolve("foo/foo", &base_dir.join("src"), &fs, &options),
+        Ok(base_dir.join("src/foo/foo.ts"))
+    );
@@
+    let tsconfig_without_base = TsConfigJson {
+        compiler_options: CompilerOptions {
+            base_url: None,
+            ..Default::default()
+        },
+        ..Default::default()
+    };
     assert_eq!(
         resolve(
             "bar",
             &base_dir.join("src"),
             &fs,
             &options
                 .clone()
                 .with_tsconfig(DiscoverableManifest::Explicit {
-                    package_path: Utf8PathBuf::from(format!("{base_dir}/tsconfig.json")),
-                    manifest: &TsConfigJson {
-                        compiler_options: CompilerOptions {
-                            base_url: None,
-                            ..Default::default()
-                        },
-                        ..Default::default()
-                    }
+                    package_path: tsconfig_path,
+                    manifest: &tsconfig_without_base,
                 })
         ),
         Ok(Utf8PathBuf::from(format!(
             "{base_dir}/node_modules/bar/index.js"
         )))
     );
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b7aa111 and ffcbe88.

⛔ Files ignored due to path filters (2)
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/node_modules/bar/index.js is excluded by !**/node_modules/** and included by **
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/node_modules/bar/package.json is excluded by !**/node_modules/** and included by **
📒 Files selected for processing (8)
  • .changeset/based-bears-brawl.md (1 hunks)
  • crates/biome_package/src/lib.rs (1 hunks)
  • crates/biome_package/src/node_js_package/mod.rs (1 hunks)
  • crates/biome_package/src/node_js_package/tsconfig_json.rs (1 hunks)
  • crates/biome_resolver/src/lib.rs (5 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/package.json (1 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/tsconfig.json (1 hunks)
  • crates/biome_resolver/tests/spec_tests.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
crates/biome_*/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_resolver/tests/fixtures/resolver_cases_7/package.json
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/tsconfig.json
  • crates/biome_package/src/node_js_package/mod.rs
  • crates/biome_package/src/lib.rs
  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_resolver/src/lib.rs
**/tests/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_resolver/tests/fixtures/resolver_cases_7/package.json
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/tsconfig.json
  • crates/biome_resolver/tests/spec_tests.rs
**/*.{rs,toml}

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

Format Rust and TOML files before committing (use just f/just format).

Files:

  • crates/biome_package/src/node_js_package/mod.rs
  • crates/biome_package/src/lib.rs
  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_resolver/src/lib.rs
.changeset/*.md

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

.changeset/*.md: Create changesets with just new-changeset; store them in .changeset/ with correct frontmatter (package keys and change type).
In changeset descriptions, follow content conventions: user-facing changes only; past tense for what you did; present tense for current behavior; link issues for fixes; link rules/assists; include representative code blocks; end every sentence with a period.
When adding headers in a changeset, only use #### or ##### levels.

Files:

  • .changeset/based-bears-brawl.md
🧠 Learnings (13)
📚 Learning: 2025-08-17T08:56:30.822Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.822Z
Learning: Applies to crates/biome_analyze/crates/**/tests/specs/**/*.jsonc : `.jsonc` snapshot files must contain an array of code strings; they are interpreted in script mode (no ESM syntax)

Applied to files:

  • crates/biome_resolver/tests/fixtures/resolver_cases_7/package.json
  • crates/biome_resolver/tests/fixtures/resolver_cases_7/tsconfig.json
📚 Learning: 2025-08-17T08:56:30.822Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.822Z
Learning: Applies to crates/biome_analyze/crates/**/tests/specs/**/{invalid*,valid*}.{js,jsx,ts,tsx,css,graphql,jsonc} : Place snapshot test cases under `tests/specs/<group>/<ruleName>/` using files prefixed with `invalid` and `valid`

Applied to files:

  • crates/biome_resolver/tests/fixtures/resolver_cases_7/tsconfig.json
📚 Learning: 2025-08-11T11:50:12.090Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:50:12.090Z
Learning: Applies to crates/biome_js_type_info/{src,resolver,biome_module_graph/src}/**/*.rs : Implement and use type resolution via the TypeResolver trait; resolvers own TypeStore vectors and provide fast by-id and hashed lookups

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_resolver/src/lib.rs
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/../biome_lsp/src/server.tests.rs : Keep end-to-end LSP tests in biome_lsp’s server.tests.rs

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-11T11:50:12.090Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:50:12.090Z
Learning: Applies to crates/biome_js_type_info/{src,biome_module_graph/src}/**/*.rs : When pattern-matching on ResolvedTypeData via as_raw_data(), ensure any nested TypeReferences are subsequently resolved using the correct ResolverId; never use the raw data with a resolver without applying the right ResolverId to avoid panics

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_resolver/src/lib.rs
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Place watcher tests for workspace methods in src/workspace/watcher.tests.rs

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-17T08:56:30.822Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.822Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/tests/quick_test.rs : Use `biome_js_analyze/tests/quick_test.rs` for quick, ad-hoc testing; un-ignore the test and adjust the rule filter as needed

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-11T11:50:12.090Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:50:12.090Z
Learning: Applies to crates/biome_js_type_info/src/**/*.rs : Use TypeData::Unknown for unimplemented inference and TypeData::UnknownKeyword for the explicit TypeScript unknown keyword; treat them semantically the same but keep them distinct for measurement

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/Cargo.toml : Add biome_js_formatter as a path dependency in Cargo.toml: biome_js_formatter = { version = "0.0.1", path = "../biome_js_formatter" }

Applied to files:

  • crates/biome_resolver/tests/spec_tests.rs
📚 Learning: 2025-08-11T11:50:12.090Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:50:12.090Z
Learning: Applies to crates/biome_js_type_info/src/**/*.rs : Represent links between types using TypeReference (not Arc) to avoid cross-module retention and recursive structures; store type data in linear vectors

Applied to files:

  • crates/biome_resolver/src/lib.rs
📚 Learning: 2025-08-17T08:56:30.822Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-08-17T08:56:30.822Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Define per-rule options in the `biome_rule_options` crate under `lib/`, with serde- and schemars-compatible derives and `#[serde(rename_all = "camelCase", deny_unknown_fields, default)]`

Applied to files:

  • crates/biome_resolver/src/lib.rs
🧬 Code Graph Analysis (1)
crates/biome_resolver/tests/spec_tests.rs (1)
crates/biome_resolver/src/lib.rs (8)
  • new (807-819)
  • new (1036-1038)
  • default (800-802)
  • resolve (31-59)
  • with_tsconfig (873-876)
  • from (1018-1020)
  • from (1024-1026)
  • from (1030-1032)
⏰ 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). (27)
  • GitHub Check: Documentation
  • GitHub Check: End-to-end tests
  • GitHub Check: Check Dependencies
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Validate PR title
  • GitHub Check: autofix
  • GitHub Check: triage
  • GitHub Check: lint
🔇 Additional comments (10)
crates/biome_package/src/node_js_package/mod.rs (1)

5-5: LGTM: re-exporting CompilerOptions is a sensible API addition

Matches the resolver/tests changes and keeps consumers in one import path. Make sure it’s covered by a changeset (looks like it is).

crates/biome_package/src/lib.rs (1)

13-14: LGTM: crate-level re-export keeps the public surface coherent

This aligns with the module re-export and simplifies test imports.

crates/biome_resolver/tests/fixtures/resolver_cases_7/package.json (1)

1-3: LGTM: minimal package.json is sufficient for the fixture

No issues spotted.

crates/biome_resolver/tests/spec_tests.rs (1)

2-2: Import exposure looks good.

Re-export of CompilerOptions and TsConfigJson from biome_package is used correctly here.

crates/biome_resolver/src/lib.rs (6)

186-196: Neat: option-driven tsconfig handling and early paths mapping.

Reading tsconfig via DiscoverableManifest and trying compilerOptions.paths first is clean and keeps behaviour well-scoped.


231-241: baseUrl pre-resolution ordering — please confirm precedence.

You try package import aliases (“#…”) and self-exports before baseUrl. That’s likely sensible, but TypeScript’s baseUrl is a compile-time feature and some ecosystems expect it to precede package self-exports. Worth a quick confirmation to avoid surprising lookups.

Would you like me to add a spec asserting that a self-export doesn’t shadow a baseUrl file (or vice versa), documenting the intended precedence?


705-705: Deriving Clone on ResolveOptions is handy.

Enables ergonomic test composition (as used) and builder chaining without surprising moves.


919-928: DiscoverableManifest gains Clone/Debug/Default — 👍

Default to Auto and better debuggability are both welcome; aligns with test ergonomics.


173-193: Assumption: only resolve tsconfig when a package.json is present.

The comment and code mean Auto tsconfig is never consulted if no package.json is found up the tree. Some setups have a tsconfig without a package.json (e.g. pure TS libs). If that’s intentional: great. If not, consider allowing tsconfig discovery independent of package.json.

Happy to add an additional discovery path and a spec (e.g. baseUrl works in a fixture without package.json) if you want to support that case.


355-363: No non-rooted tsconfig “paths” targets found—optional refactor not needed.

I ran the scan across all tsconfig.json fixtures and didn’t find any non-rooted path targets, so this change wouldn’t affect existing configs. Treating “src/*” as dependencies remains safe in our codebase today.

Comment on lines +89 to 93
/// https://www.typescriptlang.org/tsconfig/#baseUrl
///
/// The base URL is normalised to an absolute path after parsing.
pub base_url: Option<Utf8PathBuf>,

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Ensure JSON key maps to base_url (baseUrl) during deserialisation

Unless the derive macro auto-maps camelCase to snake_case, base_url won’t deserialize from baseUrl. Adding an explicit rename is cheap insurance.

Apply this diff:

     /// https://www.typescriptlang.org/tsconfig/#baseUrl
     ///
     /// The base URL is normalised to an absolute path after parsing.
-    pub base_url: Option<Utf8PathBuf>,
+    #[deserializable(rename = "baseUrl")]
+    pub base_url: Option<Utf8PathBuf>,

To confirm whether auto-mapping is already handled, run:


🏁 Script executed:

#!/bin/bash
# Inspect how camelCase keys are handled elsewhere and if baseUrl mapping exists
rg -n -C2 --type=rust 'Deserializable.*rename' 
rg -n -C3 --type=rust '\bcompiler_options\b' 
rg -n -C2 --type=rust '"baseUrl"|base_url'

Length of output: 9285


I want to double-check how TsConfigJson is derived and whether there’s a rename_all = "camelCase" in place.


🏁 Script executed:

#!/bin/bash
# Inspect TsConfigJson derive and serde attributes
rg -n '#\[derive' crates/biome_package/src/node_js_package/tsconfig_json.rs
rg -n 'rename_all' -C2 --type=rust crates/biome_package/src/node_js_package/tsconfig_json.rs
rg -n 'serde' -C2 --type=rust crates/biome_package/src/node_js_package/tsconfig_json.rs

Length of output: 458


Let’s peek at the top of tsconfig_json.rs to see which derive and import paths Deserializable comes from:


🏁 Script executed:

#!/bin/bash
sed -n '1,30p' crates/biome_package/src/node_js_package/tsconfig_json.rs

Length of output: 1081


Explicitly rename base_url to match JSON baseUrl

The TsConfigJson derive has no rename_all, so base_url will map to "base_url", not "baseUrl". Add an explicit rename:

     /// The base URL is normalised to an absolute path after parsing.
-    pub base_url: Option<Utf8PathBuf>,
+    #[deserializable(rename = "baseUrl")]
+    pub base_url: Option<Utf8PathBuf>,
📝 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.

Suggested change
/// https://www.typescriptlang.org/tsconfig/#baseUrl
///
/// The base URL is normalised to an absolute path after parsing.
pub base_url: Option<Utf8PathBuf>,
/// https://www.typescriptlang.org/tsconfig/#baseUrl
///
/// The base URL is normalised to an absolute path after parsing.
#[deserializable(rename = "baseUrl")]
pub base_url: Option<Utf8PathBuf>,
🤖 Prompt for AI Agents
In crates/biome_package/src/node_js_package/tsconfig_json.rs around lines 89 to
93, the struct field `base_url` will serialize/deserialize as "base_url" because
the derive has no rename_all; add an explicit serde rename to match the
TypeScript tsconfig key by annotating the field with #[serde(rename =
"baseUrl")] so it maps to "baseUrl" for both serialization and deserialization.

@codspeed-hq
Copy link

codspeed-hq bot commented Aug 18, 2025

CodSpeed Performance Report

Merging #7263 will improve performances by ×2.7

Comparing arendjr:support-baseUrl (b99716b) with next (a78e878)1

Summary

⚡ 8 improvements
✅ 118 untouched benchmarks
🆕 5 new benchmarks
⁉️ 2 dropped benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
🆕 index_d_ts[@next/font/google/index.d.ts] N/A 305.5 ms N/A
🆕 index_d_ts[react/index.d.ts] N/A 33.4 ms N/A
⁉️ module_graph[@next/font/google/index.d.ts] 300.1 ms N/A N/A
⁉️ module_graph[react/index.d.ts] 32.6 ms N/A N/A
ranges[1.2.3 - 2.3.4] 5.7 µs 5.3 µs +7.74%
🆕 ranges[1.2] N/A 5.5 µs N/A
🆕 ranges[>=1.2.9 <2.0.0] N/A 5.9 µs N/A
🆕 ranges[^1.2.3] N/A 5.7 µs N/A
ranges[~1.2.3] 15.7 µs 5.8 µs ×2.7
versions[1.0.0-alpha.1] 3.7 µs 3.4 µs +6.68%
versions[1.0.0-alpha] 3.5 µs 3.3 µs +6.1%
versions[1.0.0-beta.11] 3.7 µs 3.5 µs +6.62%
versions[1.0.0-beta.2] 3.7 µs 3.5 µs +6.64%
versions[1.0.0-beta] 3.5 µs 3.3 µs +6.11%
versions[1.0.0-rc.1] 3.7 µs 3.4 µs +6.67%

Footnotes

  1. No successful run was found on next (b7aa111) during the generation of this report, so 5618826 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

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: 0

♻️ Duplicate comments (1)
crates/biome_package/src/node_js_package/tsconfig_json.rs (1)

104-111: baseUrl won’t deserialize without an explicit rename

CompilerOptions.base_url currently won’t map from "baseUrl" (no rename_all on the derive). This breaks the new feature end-to-end.

Add an explicit rename so "baseUrl" in tsconfig.json is deserialised:

     /// https://www.typescriptlang.org/tsconfig/#baseUrl
     ///
     /// The base URL is normalised to an absolute path after parsing.
-    pub base_url: Option<Utf8PathBuf>,
+    #[deserializable(rename = "baseUrl")]
+    pub base_url: Option<Utf8PathBuf>,

To confirm coverage after the change, I can help add/adjust a test asserting compiler_options.base_url.is_some() for a tsconfig containing "baseUrl".

🧹 Nitpick comments (2)
crates/biome_package/src/node_js_package/tsconfig_json.rs (2)

86-101: Avoid dropping baseUrl when the tsconfig has no parent directory

If path.parent() is None, the current code overwrites a present base_url with None. That’s surprising even if most call sites pass a file path with a parent.

Apply this to preserve the value when there’s no parent:

-        if let Some(base_url) = self.compiler_options.base_url.as_ref() {
-            self.compiler_options.base_url =
-                directory.map(|dir| normalize_path(&dir.join(base_url)));
-        }
+        if let Some(base_url) = self.compiler_options.base_url.as_ref() {
+            let resolved = directory
+                .map(|dir| normalize_path(&dir.join(base_url)))
+                .unwrap_or_else(|| base_url.clone());
+            self.compiler_options.base_url = Some(resolved);
+        }

115-119: Doc string nit: wrong field referenced

This comment sits on paths_base but talks about “The base URL”.

Tighten the wording:

-    ///
-    /// The base URL is normalised to an absolute path.
+    ///
+    /// Normalised to an absolute path.
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ffcbe88 and e57e171.

📒 Files selected for processing (6)
  • crates/biome_package/src/lib.rs (3 hunks)
  • crates/biome_package/src/node_js_package/mod.rs (3 hunks)
  • crates/biome_package/src/node_js_package/package_json.rs (1 hunks)
  • crates/biome_package/src/node_js_package/tsconfig_json.rs (3 hunks)
  • crates/biome_package/tests/manifest_spec_tests.rs (4 hunks)
  • crates/biome_project_layout/src/project_layout.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/biome_package/src/node_js_package/mod.rs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

Format Rust and TOML files before committing (use just f/just format).

Files:

  • crates/biome_package/src/node_js_package/package_json.rs
  • crates/biome_project_layout/src/project_layout.rs
  • crates/biome_package/tests/manifest_spec_tests.rs
  • crates/biome_package/src/lib.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
crates/biome_*/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_package/src/node_js_package/package_json.rs
  • crates/biome_project_layout/src/project_layout.rs
  • crates/biome_package/tests/manifest_spec_tests.rs
  • crates/biome_package/src/lib.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
**/tests/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
🧠 Learnings (6)
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/Cargo.toml : Add biome_js_formatter as a path dependency in Cargo.toml: biome_js_formatter = { version = "0.0.1", path = "../biome_js_formatter" }

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
  • crates/biome_package/src/lib.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/../biome_lsp/src/server.tests.rs : Keep end-to-end LSP tests in biome_lsp’s server.tests.rs

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/src/workspace/watcher.tests.rs : Place watcher tests for workspace methods in src/workspace/watcher.tests.rs

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Types implementing Diagnostic must also implement Debug (e.g., use #[derive(Debug, Diagnostic)])

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
🧬 Code Graph Analysis (1)
crates/biome_package/tests/manifest_spec_tests.rs (1)
crates/biome_module_graph/src/js_module_info/visitor.rs (1)
  • new (28-34)
⏰ 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). (24)
  • GitHub Check: Documentation
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: autofix
🔇 Additional comments (12)
crates/biome_package/src/node_js_package/package_json.rs (1)

109-113: Path-aware signature added: looks good

The extra _path: &Utf8Path parameter aligns this manifest with the new path-aware flow. Keeping it underscore-prefixed is fine until it’s needed.

crates/biome_project_layout/src/project_layout.rs (2)

129-129: Good: pass the concrete package.json file path into deserialisation

  • Using path.clone() for the map key while retaining path for the closures is the right move.
  • Passing &path.join("package.json") ensures the manifest gets the real file path, which improves downstream diagnostics and path normalisation.

Also applies to: 140-144, 151-155


167-167: Good: thread the concrete tsconfig.json path into insertion

Mirrors the manifest change; this will let TsConfigJson initialise baseUrl/paths_base correctly relative to the tsconfig’s directory.

Also applies to: 178-182, 189-193

crates/biome_package/tests/manifest_spec_tests.rs (4)

4-4: Using Utf8Path in tests is appropriate

Camino’s Utf8Path is consistent with the rest of the codebase and avoids encoding surprises on snapshots.


17-19: Manifest test pathing: all set

Converting input to Utf8Path and passing it into insert_serialized_manifest is in line with the new API. Unwrapping file_name() is safe in this harness.

Also applies to: 23-27


71-73: Invalid tsconfig tests: correct propagation of the tsconfig path

Forwarding input_file to insert_serialized_tsconfig ensures path-based initialisation happens during parsing. Comment/trailing comma options are preserved.

Also applies to: 77-84


128-130: Valid tsconfig tests: correct usage

Same as the invalid path: forwarding the concrete tsconfig path is essential for baseUrl normalisation. Looks good.

Also applies to: 134-141

crates/biome_package/src/lib.rs (2)

13-14: Re-exporting CompilerOptions is a sensible public API addition

This allows resolver/tests to depend on the canonical type. No concerns.


33-37: All insert_serialized_* calls now receive full file paths

I’ve checked every call site—for both insert_serialized_manifest and insert_serialized_tsconfig—and they all pass a path that includes the filename (never just the directory):

  • Manifest
    • crates/biome_project_layout/src/project_layout.rs:140,151 → &path.join("package.json")
    • crates/biome_package/tests/manifest_spec_tests.rs:26 → input_file (contains filename)
  • TSConfig
    • crates/biome_project_layout/src/project_layout.rs:178,189 → &path.join("tsconfig.json")
    • crates/biome_package/tests/manifest_spec_tests.rs:83 & 140 → input_file
    • crates/biome_module_graph/tests/spec_tests.rs:96 & 1503 → project layout joins internally
    • crates/biome_service/src/workspace/server.rs:686 → passes package directory into project layout, which appends "tsconfig.json"

No directories-only slips found—this is good to go.

crates/biome_package/src/node_js_package/tsconfig_json.rs (3)

42-53: Path-aware deserialisation + post-pass initialisation: good

Deserialising from the AST and then invoking initialise_paths(path) is the right layering for path-dependent fields.


58-60: read_manifest now defers to a path-aware parse: good

This keeps a single code path for normalising fields and reduces drift between in-memory and on-disk parsing.


67-82: parse(path, json): shape and options look correct

Allowing comments and trailing commas matches tsconfig reality. Using path.file_name().unwrap_or("tsconfig.json") for the parse context is fine.

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: 0

🧹 Nitpick comments (3)
crates/biome_package/tests/manifest_spec_tests.rs (3)

23-27: Prefer matching on "json" directly (ditch the byte conversion).

Utf8Path::extension() already returns Option<&str>, so comparing bytes is unnecessary. This trims noise and reads better.

Apply these diffs:

--- a
+++ b
@@
-    match input_file.extension().map(str::as_bytes) {
-        Some(b"json") => {
+    match input_file.extension() {
+        Some("json") => {
             let parsed = parse_json(input_code.as_str(), JsonParserOptions::default());
             package.insert_serialized_manifest(&parsed.tree(), input_file);
         }
         _ => {
             panic!("Extension not supported");
         }
     };
--- a
+++ b
@@
-    match input_file.extension().map(str::as_bytes) {
-        Some(b"json") => {
+    match input_file.extension() {
+        Some("json") => {
             let parsed = parse_json(
                 input_code.as_str(),
                 JsonParserOptions::default().with_allow_comments(),
             );
             project.insert_serialized_tsconfig(&parsed.tree(), input_file);
         }
         _ => {
             panic!("Extension not supported");
         }
     };
--- a
+++ b
@@
-    match input_file.extension().map(str::as_bytes) {
-        Some(b"json") => {
+    match input_file.extension() {
+        Some("json") => {
             let parsed = parse_json(
                 input_code.as_str(),
                 JsonParserOptions::default().with_allow_comments(),
             );
             project.insert_serialized_tsconfig(&parsed.tree(), input_file);
         }
         _ => {
             panic!("Extension not supported");
         }
     };

Also applies to: 77-85, 135-141


156-169: Make strip_prefix resilient to unexpected inputs.

assert!(path.is_absolute()) will panic if a path slips through that isn’t absolute, which is brittle in a test harness. Downgrade to a debug assertion and early-return to avoid spurious panics. Behaviour remains the same for correct fixtures.

-    let strip_prefix = |path: &mut Utf8PathBuf| {
-        assert!(path.is_absolute());
+    let strip_prefix = |path: &mut Utf8PathBuf| {
+        debug_assert!(path.is_absolute(), "expected absolute path in fixtures");
+        if !path.is_absolute() {
+            return;
+        }
         let mut stripped_path = Utf8PathBuf::from("<PREFIX>");
         let mut past_prefix = false;
         for component in path.components() {
             if past_prefix {
                 stripped_path.push(component);
             } else if component == Utf8Component::Normal("tests") {
                 past_prefix = true;
             }
         }
         *path = stripped_path;
     };

170-178: Prefer expect over unwrap; avoid using map for side-effects.

  • unwrap() produces a vague panic; expect() documents intent.
  • Using Option::map for mutation is a code smell; if let Some(..) reads clearer.
-    let mut tsconfig = project.tsconfig.unwrap();
+    let mut tsconfig = project
+        .tsconfig
+        .expect("expected tsconfig to be present for valid fixtures");
@@
-    tsconfig
-        .compiler_options
-        .base_url
-        .as_mut()
-        .map(strip_prefix);
+    if let Some(base_url) = tsconfig.compiler_options.base_url.as_mut() {
+        strip_prefix(base_url);
+    }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e57e171 and ca80f42.

⛔ Files ignored due to path filters (2)
  • crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (1)
  • crates/biome_package/tests/manifest_spec_tests.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

Format Rust and TOML files before committing (use just f/just format).

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
crates/biome_*/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
**/tests/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
🧠 Learnings (6)
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/Cargo.toml : Add biome_js_formatter as a path dependency in Cargo.toml: biome_js_formatter = { version = "0.0.1", path = "../biome_js_formatter" }

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/../biome_lsp/src/server.tests.rs : Keep end-to-end LSP tests in biome_lsp’s server.tests.rs

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-17T08:55:30.109Z
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-17T08:55:30.109Z
Learning: Applies to **/tests/specs/**/*.snap : Use snapshot spec tests stored as .snap files under tests/specs/ (via cargo insta)

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Types implementing Diagnostic must also implement Debug (e.g., use #[derive(Debug, Diagnostic)])

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
🧬 Code Graph Analysis (1)
crates/biome_package/tests/manifest_spec_tests.rs (4)
crates/biome_module_graph/src/js_module_info/visitor.rs (1)
  • new (28-34)
crates/biome_module_graph/src/module_graph/fs_proxy.rs (1)
  • new (15-25)
crates/biome_json_parser/src/lib.rs (1)
  • parse_json (23-26)
crates/biome_module_graph/src/module_graph.rs (1)
  • from (251-253)
⏰ 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). (23)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Documentation
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: autofix
🔇 Additional comments (6)
crates/biome_package/tests/manifest_spec_tests.rs (6)

4-4: Good call switching to Camino’s Utf8 types.

Using Utf8Path/Utf8PathBuf makes these tests cross-platform and avoids OsStr churn. Nice.


17-18: LGTM on path handling initialisation.

Constructing Utf8Path and deriving file_name early keeps things tidy and avoids platform quirks.


26-26: API updates wired correctly.

Passing the path into insert_serialized_* aligns with the new path-aware APIs. All good here.

Also applies to: 83-83, 140-140


71-73: LGTM on tsconfig invalid harness updates.

Consistent with the manifest changes; keeps snapshots stable.


128-130: LGTM on tsconfig valid harness updates.

Same tidy path initialisation; consistent across test suites.


183-183: Snapshotting the structured tsconfig is a win.

Using pretty Debug output ensures stable, reviewable snapshots post path sanitisation.

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: 0

♻️ Duplicate comments (4)
crates/biome_package/tests/manifest_spec_tests.rs (4)

71-72: Repeat: swap unwrap for expect here too

Same rationale as above; better panic message if something’s off in the generated path.

-    let file_name = input_file.file_name().unwrap();
+    let file_name = input_file
+        .file_name()
+        .expect("expected a file name in generated test path");

77-85: Repeat: simplify extension check here as well

Stick to the &str returned by Utf8Path::extension.

-    match input_file.extension().map(str::as_bytes) {
-        Some(b"json") => {
+    match input_file.extension() {
+        Some("json") => {
             let parsed = parse_json(
                 input_code.as_str(),
                 JsonParserOptions::default().with_allow_comments(),
             );
             project.insert_serialized_tsconfig(&parsed.tree(), input_file);
         }

128-129: Repeat: favour expect over unwrap

Consistent, readable test failures.

-    let file_name = input_file.file_name().unwrap();
+    let file_name = input_file
+        .file_name()
+        .expect("expected a file name in generated test path");

134-141: Repeat: extension check can stay in &str land

Minor cleanup for consistency and readability.

-    match input_file.extension().map(str::as_bytes) {
-        Some(b"json") => {
+    match input_file.extension() {
+        Some("json") => {
             let parsed = parse_json(
                 input_code.as_str(),
                 JsonParserOptions::default().with_allow_comments(),
             );
             project.insert_serialized_tsconfig(&parsed.tree(), input_file);
         }
🧹 Nitpick comments (5)
crates/biome_package/tests/manifest_spec_tests.rs (5)

17-18: Prefer expect over unwrap for clearer failures

If a test path ever misses a file name, this will panic without context. Expect reads better in test output.

-    let file_name = input_file.file_name().unwrap();
+    let file_name = input_file
+        .file_name()
+        .expect("expected a file name in generated test path");

23-27: Simplify extension check with Utf8Path

Utf8Path::extension returns Option<&str>, so there’s no need to hop through bytes.

-    match input_file.extension().map(str::as_bytes) {
-        Some(b"json") => {
+    match input_file.extension() {
+        Some("json") => {
             let parsed = parse_json(input_code.as_str(), JsonParserOptions::default());
             package.insert_serialized_manifest(&parsed.tree(), input_file);
         }

156-160: Avoid allocation in empty-path check

to_string() allocates; you can query the underlying &str directly.

-        if path.to_string().is_empty() {
+        if path.as_str().is_empty() {
             return;
         }

161-172: Consider a fallback when "tests" isn’t in the path

If "tests" isn’t present, you end up with "" and lose useful context in the snapshot. Not urgent, but a small guard would make this future‑proof if paths ever change.

One approach:

  • Detect if the "tests" component was found; if not, append the last 2 components so snapshots still show a stable, informative tail.

Sketch:

let mut found = false;
for component in path.components() {
    if past_prefix { stripped_path.push(component); }
    else if component == Utf8Component::Normal("tests") { past_prefix = true; found = true; }
}
if !found {
    if let Some(parent) = path.parent() { stripped_path.push(parent.file_name().unwrap_or_default()); }
    if let Some(name) = path.file_name() { stripped_path.push(name); }
}

178-181: Don’t use Option::map for side effects

map is for transformations; if let reads better for mutation/side‑effects.

-    tsconfig
-        .compiler_options
-        .base_url
-        .as_mut()
-        .map(strip_prefix);
+    if let Some(base) = tsconfig.compiler_options.base_url.as_mut() {
+        strip_prefix(base);
+    }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ca80f42 and afba8bc.

⛔ Files ignored due to path filters (2)
  • crates/biome_package/tests/tsconfig/valid/tsconfig.valid.baseUrl.json.snap is excluded by !**/*.snap and included by **
  • crates/biome_package/tests/tsconfig/valid/tsconfig.valid.paths.json.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (1)
  • crates/biome_package/tests/manifest_spec_tests.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{rs,toml}

📄 CodeRabbit Inference Engine (CONTRIBUTING.md)

Format Rust and TOML files before committing (use just f/just format).

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
crates/biome_*/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
**/tests/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Place test files under a tests/ directory in each crate

Files:

  • crates/biome_package/tests/manifest_spec_tests.rs
🧠 Learnings (5)
📚 Learning: 2025-08-11T11:48:27.774Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:27.774Z
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_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:48:52.001Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:48:52.001Z
Learning: Applies to crates/biome_js_formatter/**/Cargo.toml : Add biome_js_formatter as a path dependency in Cargo.toml: biome_js_formatter = { version = "0.0.1", path = "../biome_js_formatter" }

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:53:15.299Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_service/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:53:15.299Z
Learning: Applies to crates/biome_service/../biome_lsp/src/server.tests.rs : Keep end-to-end LSP tests in biome_lsp’s server.tests.rs

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-11T11:46:05.836Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_diagnostics/CONTRIBUTING.md:0-0
Timestamp: 2025-08-11T11:46:05.836Z
Learning: Applies to crates/biome_diagnostics/**/*.rs : Types implementing Diagnostic must also implement Debug (e.g., use #[derive(Debug, Diagnostic)])

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
📚 Learning: 2025-08-17T08:55:30.109Z
Learnt from: CR
PR: biomejs/biome#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-17T08:55:30.109Z
Learning: Applies to **/tests/specs/**/*.snap : Use snapshot spec tests stored as .snap files under tests/specs/ (via cargo insta)

Applied to files:

  • crates/biome_package/tests/manifest_spec_tests.rs
⏰ 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). (24)
  • GitHub Check: Documentation
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: End-to-end tests
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: autofix
🔇 Additional comments (3)
crates/biome_package/tests/manifest_spec_tests.rs (3)

4-4: LGTM: Camino path types are a solid cross‑platform choice

Nice move to Utf8Path/Utf8PathBuf/Utf8Component. This simplifies string handling and avoids OsStr pain, especially on Windows.


187-188: LGTM: Pretty Debug in snapshots improves DX

Snapshotting the full tsconfig with {:#?} is great for reviewing path sanitisation and compiler options.


174-181: Verify resolver rule coverage for baseUrl + useImportExtensions autofix

I couldn’t spot any spec test in crates/biome_resolver/tests/spec_tests.rs that enables compilerOptions.baseUrl, imports a module without an extension, and asserts the autofix appends .ts/.tsx/.js. Please manually confirm (or add) a case that:

  • Sets baseUrl in the tsconfig fixture.
  • Imports a path with no extension.
  • Includes an assertion or snapshot verifying the autofix appends the correct extension.


/// Initialises the paths stored in the manifest.
///
/// `path` must be an absolute path to the `tsconfig.json` file itself.
Copy link
Member

Choose a reason for hiding this comment

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

What does it mean to be absolute to a file? Can we add a debug_assert! that checks it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It means the path is absolute, i.e. not relative.

Added a debug_assert!.

}
}
```

Copy link
Member

Choose a reason for hiding this comment

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

Can you add a paragraph that explains the example below? That's the format that we try with the docs. E.g. "Given the following file structure ..., when importing a "foo" from index.ts, Biome will automatically pick up src/foo.ts"

@ematipico
Copy link
Member

ematipico commented Aug 19, 2025

Shouldn't we mention this somewhere in the docs once we land it? Since we're are slowly adding support for more TS features (baseUrl, .js aliasing, etc.), maybe we should consider a paragraph in the docs that lists the features that Biome supports from tsconfig.json.

It will help users to understand the expectations of the tool and its interop with tsconfig.json

@arendjr
Copy link
Contributor Author

arendjr commented Aug 19, 2025

Shouldn't we mention this somewhere in the docs once we land it? Since we're are slowly adding support for more TS features (baseUrl, .js aliasing, etc.), maybe we should consider a paragraph in the docs that lists the features that Biome supports from tsconfig.json.

I wouldn't be opposed to it, but I don't think I have the bandwidth to maintain such a list. We don't do it for type features in general either, so I would prefer not to do it. Things should "just work", and if users report issues, we'll do our best to resolve it.

@arendjr arendjr merged commit a3e3369 into biomejs:next Aug 19, 2025
28 of 29 checks passed
dyc3 pushed a commit that referenced this pull request Aug 20, 2025
dyc3 pushed a commit that referenced this pull request Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Project Area: project A-Resolver Area: resolver

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants