+
Skip to content

Conversation

siketyan
Copy link
Member

Summary

Revamps #7158 and enables it only if the moduleResolution option is set to Node16 or NodeNext in tsconfig.json.

Test Plan

Added tests.

Docs

N/A

@siketyan siketyan requested review from a team September 21, 2025 09:28
@siketyan siketyan self-assigned this Sep 21, 2025
Copy link

changeset-bot bot commented Sep 21, 2025

🦋 Changeset detected

Latest commit: f3b2fc7

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 A-Project Area: project A-Resolver Area: resolver labels Sep 21, 2025
Copy link
Contributor

coderabbitai bot commented Sep 21, 2025

Walkthrough

This PR adds case-insensitive enum deserialization support in biome_deserialize_macros; introduces Module and ModuleResolution (and adds module/moduleResolution to CompilerOptions) in biome_package; expands the public resolver API with ResolveOptions.extension_aliases and a builder, threads extension aliasing into resolution flows (including new resolve_extension_aliases and passing base_dir through resolve_module_with_package_json); wires extension aliases into the module-graph visitor; and adds fixtures and tests exercising .js→.ts/.tsx/.d.ts/.mts alias resolution for Node16/NodeNext-style configs. No public ABI removals.

Possibly related PRs

Suggested reviewers

  • arendjr
  • ematipico

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat(resolver): resolve extension alias" is concise and directly describes the primary change (resolver support for extension aliases); it matches the resolver-focused code and tests in the changeset and is neither vague nor off-topic.
Description Check ✅ Passed The description plainly summarises the PR intent: it revamps the prior PR, restricts the behaviour to moduleResolution = Node16/NodeNext, and notes added tests; this aligns with the resolver, tsconfig and test updates in the changeset. The description is related to the changeset and meets the lenient criteria for this check.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 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 bde7fcf and f3b2fc7.

📒 Files selected for processing (4)
  • crates/biome_module_graph/src/js_module_info/visitor.rs (3 hunks)
  • crates/biome_resolver/src/lib.rs (11 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir/index.tsx (1 hunks)
  • crates/biome_resolver/tests/spec_tests.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir/index.tsx
  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_module_graph/src/js_module_info/visitor.rs
🧰 Additional context used
📓 Path-based instructions (2)
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_resolver/src/lib.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format all Rust source files before committing (just f)

Files:

  • crates/biome_resolver/src/lib.rs
🧠 Learnings (3)
📓 Common learnings
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
📚 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/src/lib.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/src/lib.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). (20)
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: lint
  • GitHub Check: triage
  • GitHub Check: Validate PR title
🔇 Additional comments (9)
crates/biome_resolver/src/lib.rs (9)

11-11: LGTM! Public API expanded correctly.

The Module and ModuleResolution imports correctly map to Node16/NodeNext module resolution modes as per TypeScript's specifications.


48-52: LGTM! Error-handling flow improved.

Continuing resolution after NotFound allows extension alias resolution to be attempted, which is the correct behaviour for TypeScript Node16/NodeNext compatibility.


163-170: LGTM! Function signature correctly updated.

All call sites properly pass base_dir to support extension alias resolution.

Also applies to: 176-183


192-193: Documentation improvement addressed.

The docstring update correctly reflects the base_dir parameter's purpose for extension alias resolution.


233-242: LGTM! Extension alias integration implemented correctly.

The relative specifier handling properly integrates extension alias resolution with the tsconfig context. The early return pattern is appropriate when extension alias resolution succeeds.


430-480: Solid implementation with proper guards.

The function correctly checks for Node16/NodeNext module resolution modes and handles the extension alias mapping logic properly. The error handling follows the established pattern in the codebase.


833-841: Documentation is clear and accurate.

The documentation correctly explains that extension aliases are only applicable for Node16/NodeNext module resolution modes, matching TypeScript's behaviour for handling extension resolution in ESM contexts.


951-958: Builder method implemented correctly.

The with_extension_aliases method follows the same pattern as other builder methods in the struct. The parameter naming is consistent with the field name.


912-912: Field initialisation handled consistently.

The extension_aliases field is properly initialised in new() and correctly preserved in option transformations.

Also applies to: 999-999, 1014-1014

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

🧹 Nitpick comments (7)
crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs (3)

23-24: Enum-only flag: add validation (don’t silently noop on structs).

Field addition looks good. Given it’s “only supported in enums”, please enforce this upstream (e.g. abort when used on structs) to avoid confusing no-ops.

Happy to wire an abort in the struct branch of deserializable_derive.rs if you want.


27-27: Typo in doc comment.

“unkinown” → “unknown”.

-/// Attributes for struct that control how unkinown fields are handled.
+/// Attributes for struct that control how unknown fields are handled.

42-42: User-facing error string typo.

“amomg” → “among”.

-            _ => Err("unknown_fields takes a value amomg `deny`, `warn`, and `allow`."),
+            _ => Err("unknown_fields takes a value among `deny`, `warn`, and `allow`."),
crates/biome_deserialize_macros/src/deserializable_derive.rs (1)

73-76: Gate misuse: error if case_insensitive is set on structs.

Currently it’s silently ignored on structs. Abort early to guide users.

 Data::Struct(data) => {
+    if attrs.case_insensitive {
+        abort!(
+            data.fields,
+            "#[deserializable(case_insensitive)] is only supported on enums"
+        )
+    }
crates/biome_resolver/tests/fixtures/resolver_cases_8/dir2/index.js (1)

1-1: Empty fixture is fine; make the intent explicit.

Add a one‑liner so future you doesn’t “clean it up” during a refactor.

+// Intentionally empty: resolver fixture.
.changeset/petite-waves-love.md (1)

5-5: Changeset voice: start with past‑tense summary; minor grammar tweak.

Begin with what you did (past tense), then state current behaviour (present). Also fix “if exists” → “if it exists”.

-The resolver can now correctly resolve `.ts`, `.tsx`, `.d.ts`, `.js` files by `.js` extension if exists, based on [the file extension substitution in TypeScript](https://www.typescriptlang.org/docs/handbook/modules/reference.html#file-extension-substitution), if the `moduleResolution` option is set to `Node16` or `NodeNext`.
+Added support for resolving `.js` specifiers to `.ts`, `.tsx`, `.d.ts`, or `.js` files (TypeScript’s file‑extension substitution) when `moduleResolution` is `Node16` or `NodeNext`. Biome now resolves these imports accordingly.
crates/biome_resolver/tests/fixtures/resolver_cases_8/package.json (1)

1-3: Confirm ESM/CJS intent.

If tests assume ESM semantics for .js, consider adding "type": "module"; otherwise this is fine as CJS.

📜 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 ea23d15 and 278ac33.

📒 Files selected for processing (12)
  • .changeset/petite-waves-love.md (1 hunks)
  • crates/biome_deserialize_macros/src/deserializable_derive.rs (6 hunks)
  • crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs (2 hunks)
  • crates/biome_module_graph/src/js_module_info/visitor.rs (3 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 (11 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir2/index.js (1 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/package.json (1 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json (1 hunks)
  • crates/biome_resolver/tests/spec_tests.rs (1 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_8/package.json
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir2/index.js
  • crates/biome_deserialize_macros/src/deserializable_derive.rs
  • crates/biome_package/src/node_js_package/mod.rs
  • crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json
  • crates/biome_resolver/src/lib.rs
  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_module_graph/src/js_module_info/visitor.rs
  • crates/biome_package/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_8/package.json
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir2/index.js
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json
  • crates/biome_resolver/tests/spec_tests.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format all Rust source files before committing (just f)

Files:

  • crates/biome_deserialize_macros/src/deserializable_derive.rs
  • crates/biome_package/src/node_js_package/mod.rs
  • crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs
  • crates/biome_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_resolver/src/lib.rs
  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_module_graph/src/js_module_info/visitor.rs
  • crates/biome_package/src/lib.rs
.changeset/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

.changeset/*.md: In changeset files, only use #### or ##### headers; avoid other header levels
Changeset descriptions should use past tense for what you did (e.g., "Added...")
Describe current Biome behavior in present tense within changesets (e.g., "Biome now supports...")
For bug fixes in changesets, start with a link to the issue (e.g., "Fixed #1234: ...")
When referencing rules or assists in changesets, include links to their documentation pages
Include a minimal code block in the changeset when applicable to demonstrate the change
End every sentence in the changeset description with a period

Files:

  • .changeset/petite-waves-love.md
🧠 Learnings (10)
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/**/tests/specs/**/*.jsonc : Snapshot test `.jsonc` files must contain an array of code snippets (strings); these run in script mode (no ESM syntax)

Applied to files:

  • crates/biome_resolver/tests/fixtures/resolver_cases_8/package.json
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json
📚 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/src/node_js_package/mod.rs
  • crates/biome_resolver/src/lib.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,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_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json
  • crates/biome_resolver/src/lib.rs
  • crates/biome_resolver/tests/spec_tests.rs
  • crates/biome_module_graph/src/js_module_info/visitor.rs
  • crates/biome_package/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_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: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_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-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
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/biome_js_analyze/tests/quick_test.rs : Quick test: edit `tests/quick_test.rs`, remove or comment `#[ignore]`, set `SOURCE`, and adjust `RuleFilter`

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/biome_module_graph/src/js_module_info/collector.rs : Thin (module-level) inference may resolve qualifiers to local declarations or globals (TypeReference::Resolved), mark imported bindings as TypeReference::Import, and set unresolved to TypeReference::Unknown; it must not look beyond the current module

Applied to files:

  • crates/biome_module_graph/src/js_module_info/visitor.rs
🧬 Code graph analysis (2)
crates/biome_resolver/tests/spec_tests.rs (2)
crates/biome_resolver/src/lib.rs (7)
  • new (905-918)
  • new (1146-1148)
  • default (898-900)
  • resolve (31-62)
  • from (1128-1130)
  • from (1134-1136)
  • from (1140-1142)
crates/biome_fs/src/fs/os.rs (1)
  • default (41-46)
crates/biome_package/src/lib.rs (1)
packages/@biomejs/js-api/src/wasm.ts (1)
  • Module (110-117)
⏰ 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). (21)
  • GitHub Check: Bench (biome_package)
  • GitHub Check: autofix
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Documentation
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Check Dependencies
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
🔇 Additional comments (24)
crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs (1)

79-81: Attribute parsing LGTM.

deserializable(case_insensitive) is parsed correctly and defaults remain intact.

crates/biome_deserialize_macros/src/deserializable_derive.rs (4)

69-71: Wiring through the flag: looks good.

case_insensitive is correctly propagated into enum data.


171-173: Struct shape update LGTM.

Adding case_insensitive: bool to DeserializableEnumData is straightforward and non-breaking here.


245-251: Nice touch: lowercase allowed variants for diagnostics.

Ensures suggestions match the normalised comparison set.


262-266: Key normalisation for matching LGTM.

Per-variant keys are lowercased when enabled; matches the diagnostics behaviour.

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

1-5: LGTM: focused Node16 fixture.

Reads clean and minimal for the test intent.

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

140-142: Case‑insensitive enum deserialisation: nice touch.

This matches real‑world tsconfig usage variability.


153-156: Module includes Node18/Node20 which TypeScript doesn’t accept.

TS compilerOptions.module supports Node16/NodeNext but not Node18/Node20. Keeping unsupported variants invites invalid configs.

     ESNext,
     Node16,
-    Node18,
-    Node20,
     NodeNext,
     Preserve,

Likely an incorrect or invalid review comment.

.changeset/petite-waves-love.md (1)

7-7: Add docs link for noFloatingPromises

In .changeset/petite-waves-love.md (line 7) include the Biome rule docs URL: https://biomejs.dev/linter/rules/no-floating-promises/

crates/biome_module_graph/src/js_module_info/visitor.rs (3)

21-27: LGTM! Extension alias mapping properly configured.

The constant correctly maps the TypeScript module resolution extension alias behaviour, enabling .js imports to resolve to .ts/.tsx/.d.ts/.js/.jsx files under Node16/NodeNext resolution.


453-453: Extension alias correctly wired into resolve options.

The extension alias is properly integrated into the ResolveOptions, enabling the module resolution to use TypeScript extension aliasing.


404-404: Minor formatting alignment - no functional change.

This is just a whitespace adjustment to maintain consistent indentation.

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

13-14: Module and ModuleResolution types now publicly exposed.

These new exports allow consumers to access the Module and ModuleResolution enums needed for TypeScript extension alias resolution configuration.

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

688-723: Comprehensive extension alias testing.

Good coverage of extension alias behaviour including:

  • Fully specified files with alias fallbacks
  • Multiple alias options with priority ordering
  • Different extension mappings (js → ts/js, mjs → mts)

The test assertions properly verify both successful resolutions and fallback behaviour.


725-748: Edge case coverage for non-applicable scenarios.

Properly tests that extension aliases don't apply to directory resolution or extension-less file resolution, ensuring the feature only affects fully-specified imports as intended.

crates/biome_package/src/node_js_package/mod.rs (1)

6-6: Module and ModuleResolution added to public exports.

The new types are correctly exposed for consumers requiring TypeScript module resolution configuration.

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

11-11: TypeScript module resolution types imported.

Module and ModuleResolution imports enable the extension alias logic to check tsconfig module resolution settings.


48-51: Graceful fallback on relative path resolution failure.

The change allows the resolver to continue to module resolution when relative path resolution fails, improving resilience.


163-170: Base directory propagated for extension alias support.

The base_dir parameter is now correctly passed through to enable extension alias resolution logic in the module resolution flow.

Also applies to: 176-183


258-262: Extension alias resolution integrated into module flow.

The extension alias resolution is correctly positioned after path mapping but before dependency resolution, providing the right precedence order.


424-479: Robust extension alias implementation.

The implementation correctly:

  • Validates Node16/NodeNext module resolution requirements
  • Only applies to relative specifiers with extensions
  • Tries each alias in order with proper error handling
  • Returns early on first successful resolution

832-840: Clear documentation for extension alias option.

The documentation properly explains the purpose, behaviour, and constraints of the extension_alias field, including the Node16/NodeNext requirement.


911-911: Extension alias field and builder method added.

The ResolveOptions struct is properly extended with the extension_alias field and corresponding builder method for configuration.

Also applies to: 950-957


998-998: Extension alias propagated in options constructors.

The extension_alias field is correctly copied in internal option constructor methods, ensuring consistency across resolution contexts.

Also applies to: 1013-1013

@siketyan siketyan force-pushed the feat/extension-alias branch from 278ac33 to 7713368 Compare September 21, 2025 09:39
Copy link

codspeed-hq bot commented Sep 21, 2025

CodSpeed Performance Report

Merging #7551 will not alter performance

Comparing siketyan:feat/extension-alias (f3b2fc7) with next (85d3a3a)

Summary

✅ 4 untouched
⏩ 136 skipped1

Footnotes

  1. 136 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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 (5)
crates/biome_deserialize_macros/src/deserializable_derive.rs (1)

245-251: Avoid extra allocations; emit string literals explicitly; pre-empt normalisation collisions.

  • Drop the unnecessary to_string() and build a string literal via LitStr to avoid repeated parsing by the quote machinery.
  • Minor alloc win and clearer intent (ties in with our prior learning to avoid avoidable string allocations).
  • Optional but worthwhile: detect duplicate keys after lowercasing and abort with a friendly message.

Apply this diff:

-        .map(|DeserializableVariantData { key, .. }| {
-            let mut key = key.to_string();
-            if data.case_insensitive {
-                key = key.to_ascii_lowercase();
-            }
-            quote! { #key }
-        })
+        .map(|DeserializableVariantData { key, .. }| {
+            let key_str = if data.case_insensitive {
+                key.to_ascii_lowercase()
+            } else {
+                key.clone()
+            };
+            let key_lit = syn::LitStr::new(&key_str, proc_macro2::Span::call_site());
+            quote! { #key_lit }
+        })
-            |DeserializableVariantData {
-                 ident: variant_ident,
-                 key,
-             }| {
-                let mut key = key.to_string();
-                if data.case_insensitive {
-                    key = key.to_ascii_lowercase();
-                }
-                quote! { #key => Self::#variant_ident }
-            },
+            |DeserializableVariantData { ident: variant_ident, key }| {
+                let key_str = if data.case_insensitive {
+                    key.to_ascii_lowercase()
+                } else {
+                    key.clone()
+                };
+                let key_lit = syn::LitStr::new(&key_str, proc_macro2::Span::call_site());
+                quote! { #key_lit => Self::#variant_ident }
+            },

Add the missing imports (outside this hunk):

use proc_macro2::Span;
use syn::LitStr;

Optionally detect collisions (outside this hunk, near the start of generate_deserializable_enum):

if data.case_insensitive {
    use std::collections::{BTreeSet, HashSet};
    let mut seen = HashSet::new();
    let mut dupes = BTreeSet::new();
    for v in &data.variants {
        let k = v.key.to_ascii_lowercase();
        if !seen.insert(k.clone()) {
            dupes.insert(k);
        }
    }
    if !dupes.is_empty() {
        abort_call_site!(
            "case_insensitive enum deserialisation produces duplicate keys after normalisation: {}",
            dupes.into_iter().collect::<Vec<_>>().join(", ")
        );
    }
}

Also applies to: 262-266

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

449-454: Alias applies only to relative specifiers — clarify docs or broaden scope.

Functionally fine, but it contradicts the field docs (which mention absolute paths). Either update the docs (preferred) or support absolute paths here.


456-468: Avoid redundant re‑resolves when aliasing doesn’t apply.

resolve_absolute_path() was already tried earlier; rerunning it here repeats filesystem work.

Apply this diff to just signal “no alias match” and let callers continue:

-    // Skip if no extension is in the path.
-    let Some(extension) = path.extension() else {
-        return resolve_absolute_path(path, fs, options);
-    };
+    // Skip if no extension is in the path.
+    let Some(extension) = path.extension() else {
+        return Err(ResolveError::NotFound);
+    };
@@
-    else {
-        return resolve_absolute_path(path, fs, options);
-    };
+    else {
+        return Err(ResolveError::NotFound);
+    };

832-841: Doc fix: alias applies to relative specifiers only (and not within exports/imports).

Small tweak to match behaviour and avoid surprises.

Apply this doc update:

-    /// List of extension aliases to search for in absolute or relative paths.
+    /// List of extension aliases to try for relative specifiers.
@@
-    /// Note that this option is applicable only if the `moduleResolution` option in tsconfig.json
-    /// is set to `Node16` or `NodeNext`.
+    /// Applied only when `tsconfig.compilerOptions.moduleResolution` is `Node16` or `NodeNext`
+    /// (or when that field is omitted and `compilerOptions.module` is `Node16`/`NodeNext`).
+    /// Not used for `package.json` `exports`/`imports` resolutions.

432-445: Tighten applicability check — drop Node18/Node20

TypeScript defaults moduleResolution to node16/nodenext when module is Node16/NodeNext, so only Node16/NodeNext should imply the Node resolution mode.

-    let is_applicable = matches!(
-        (
-            tsconfig_json.compiler_options.module,
-            tsconfig_json.compiler_options.module_resolution,
-        ),
-        (
-            Some(Module::Node16 | Module::Node18 | Module::Node20 | Module::NodeNext),
-            None,
-        ) | (
-            _,
-            Some(ModuleResolution::Node16 | ModuleResolution::NodeNext),
-        )
-    );
+    let is_applicable = match tsconfig_json.compiler_options.module_resolution {
+        Some(ModuleResolution::Node16 | ModuleResolution::NodeNext) => true,
+        None => matches!(
+            tsconfig_json.compiler_options.module,
+            Some(Module::Node16 | Module::NodeNext)
+        ),
+        _ => false,
+    };
📜 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 278ac33 and 7713368.

📒 Files selected for processing (12)
  • .changeset/petite-waves-love.md (1 hunks)
  • crates/biome_deserialize_macros/src/deserializable_derive.rs (6 hunks)
  • crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs (2 hunks)
  • crates/biome_module_graph/src/js_module_info/visitor.rs (3 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 (11 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir2/index.js (1 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/package.json (1 hunks)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json (1 hunks)
  • crates/biome_resolver/tests/spec_tests.rs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/package.json
🚧 Files skipped from review as they are similar to previous changes (8)
  • crates/biome_package/src/node_js_package/mod.rs
  • crates/biome_deserialize_macros/src/deserializable_derive/container_attrs.rs
  • .changeset/petite-waves-love.md
  • crates/biome_package/src/lib.rs
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/dir2/index.js
  • crates/biome_module_graph/src/js_module_info/visitor.rs
  • crates/biome_resolver/tests/fixtures/resolver_cases_8/tsconfig.json
  • crates/biome_resolver/tests/spec_tests.rs
🧰 Additional context used
📓 Path-based instructions (2)
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_deserialize_macros/src/deserializable_derive.rs
  • crates/biome_resolver/src/lib.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format all Rust source files before committing (just f)

Files:

  • crates/biome_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_deserialize_macros/src/deserializable_derive.rs
  • crates/biome_resolver/src/lib.rs
🧠 Learnings (4)
📚 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_package/src/node_js_package/tsconfig_json.rs
  • crates/biome_resolver/src/lib.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/crates/biome_rule_options/lib/**/*.rs : Options types must implement serialization/deserialization and schema support using derives: `Serialize`, `Deserialize`, `Deserializable`, and `#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]`

Applied to files:

  • crates/biome_package/src/node_js_package/tsconfig_json.rs
📚 Learning: 2025-09-10T08:05:22.867Z
Learnt from: CR
PR: biomejs/biome#0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-09-10T08:05:22.867Z
Learning: Applies to crates/biome_analyze/**/src/{lint,assist}/**/*.rs : Avoid avoidable string allocations: prefer comparing `&str` or using `TokenText` over calling `to_string()`

Applied to files:

  • crates/biome_deserialize_macros/src/deserializable_derive.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/src/lib.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). (20)
  • GitHub Check: Bench (biome_css_formatter)
  • GitHub Check: Bench (biome_json_formatter)
  • GitHub Check: Bench (biome_module_graph)
  • GitHub Check: Bench (biome_json_parser)
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Bench (biome_html_formatter)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: Bench (biome_json_analyze)
  • GitHub Check: Bench (biome_graphql_parser)
  • GitHub Check: Bench (biome_graphql_formatter)
  • GitHub Check: Bench (biome_html_parser)
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_css_analyze)
  • GitHub Check: Bench (biome_css_parser)
  • GitHub Check: Documentation
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Check Dependencies
  • GitHub Check: autofix
🔇 Additional comments (12)
crates/biome_deserialize_macros/src/deserializable_derive.rs (3)

67-71: Enum wiring for case_insensitive looks sound.

Plumbs the attr cleanly into the enum data. No blocking issues here.

Please confirm the new #[deserializable(case_insensitive)] is documented and only applied to enums (struct/newtype paths ignore it).


169-173: Struct field addition: OK.

Private bool is fine and carried through correctly.


281-288: Don’t rely on Deref quirks; match on an explicit &str and preserve the original for diagnostics.

Shadowing text and then matching via Deref is brittle and loses the user’s original input when case_insensitive is on.

Apply this diff:

-    let to_lowercase = if data.case_insensitive {
-        quote! {
-            let text = text.text().to_ascii_lowercase();
-        }
-    } else {
-        quote! {}
-    };
+    let prepare_needle = if data.case_insensitive {
+        quote! {
+            let original = text.text();
+            let lowered_owned = original.to_ascii_lowercase();
+            let needle: &str = &lowered_owned;
+        }
+    } else {
+        quote! {
+            let original = text.text();
+            let needle: &str = original;
+        }
+    };
-                let text = biome_deserialize::Text::deserialize(ctx, value, name)?;
-                #to_lowercase
-                let mut result = match std::ops::Deref::deref(&text) {
+                let text = biome_deserialize::Text::deserialize(ctx, value, name)?;
+                #prepare_needle
+                let mut result = match needle {

Optional polish (outside this hunk): in the unknown arm, report original rather than the lowercased needle.

-                    unknown_variant => {
+                    _ => {
                         const ALLOWED_VARIANTS: &[&str] = &[#(#allowed_variants),*];
-                        ctx.report(biome_deserialize::DeserializationDiagnostic::new_unknown_value(
-                            unknown_variant,
+                        ctx.report(biome_deserialize::DeserializationDiagnostic::new_unknown_value(
+                            original,
                             value.range(),
                             ALLOWED_VARIANTS,
                         ));
                         return None;
                     }

Also applies to: 298-301

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

135-136: Serde rename for moduleResolution: spot‑on.

This addresses the earlier deserialisation mismatch; field will populate correctly from tsconfig.


161-170: moduleResolution enum looks good.

Case‑insensitive deserialisation matches TS; set is complete.


141-159: Keep Node18/Node20 — they’re valid TS module options (TS 5.8 / 5.9)
TypeScript added "node18" in 5.8 and "node20" in 5.9, so these are valid compilerOptions.module values; retain the enum variants but ensure serialization emits the lowercase TS names and that downstream gating explicitly handles Node16/Node18/Node20 (or document a minimum TS version).

Likely an incorrect or invalid review comment.

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

11-11: Re‑export of Module/ModuleResolution: good integration point.


48-51: Graceful fallback on relative NotFound is 👍.

Ensures we still try package/tsconfig resolution before bailing.


258-263: Extension‑alias hook is placed sensibly.

Runs after tsconfig paths/baseUrl checks and before deps.

Please confirm we have tests for both:

  • moduleResolution omitted but module=Node16/NodeNext → alias applies
  • moduleResolution=Classic/Node/Node10 → alias does not apply

950-958: Builder for extension_alias looks tidy.

API is consistent with existing builders.


998-999: Nice: carry extension_alias across type‑roots cloning.


1013-1014: Good call to zero extension_alias when disabling manifests.

Prevents unintended aliasing inside exports/imports.

@siketyan siketyan force-pushed the feat/extension-alias branch from 7713368 to 6390529 Compare September 21, 2025 09:58
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

📜 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 6390529 and 97052bc.

📒 Files selected for processing (1)
  • crates/biome_resolver/src/lib.rs (11 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
crates/biome_*/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place core crates under /crates/biome_*/

Files:

  • crates/biome_resolver/src/lib.rs
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Format all Rust source files before committing (just f)

Files:

  • crates/biome_resolver/src/lib.rs
🧠 Learnings (2)
📚 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/src/lib.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/src/lib.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). (3)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
🔇 Additional comments (8)
crates/biome_resolver/src/lib.rs (8)

11-11: LGTM! Clean extension of public imports.

The imports align with the new public re-exports in the package system and support the extension alias functionality.


163-170: Function signature updated correctly.

The addition of base_dir parameter to resolve_module_with_package_json is properly propagated to all call sites.

Also applies to: 176-183


258-263: Extension alias integration looks solid.

The integration point is well-placed after paths mapping but before dependency resolution, maintaining the correct precedence order.


424-479: Well-implemented extension alias resolution.

The logic correctly:

  • Checks for Node16/NodeNext module resolution
  • Handles only relative specifiers
  • Tries each alias extension in order
  • Falls back gracefully on NotFound

The implementation matches the TypeScript behaviour described in the PR objectives.


829-829: Minor documentation correction.

Good catch on the wording - "without a leading dot" is clearer than "without the leading dot".


832-840: Extension alias API design is consistent.

The new field and builder method follow the same patterns as existing options. The documentation clearly explains the Node16/NodeNext requirement.

Also applies to: 950-957


911-911: Extension alias properly propagated through option transformations.

The field is correctly included in all option transformation methods, ensuring consistency across the resolver's internal state transitions.

Also applies to: 998-998, 1013-1013


48-52: Verify fallback logic for relative specifier resolution (crates/biome_resolver/src/lib.rs:48–56)

resolve_relative_path merely delegates to resolve_absolute_path(base_dir.join(path)), so Err(ResolveError::NotFound) is intentionally allowed to fall through into tsconfig/alias/extension/module resolution — the same pattern is used elsewhere in this module. Confirm no tests or external callers rely on an immediate NotFound for relative specifiers and add/update tests if this change alters observable behaviour.

Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

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

Nice one!

@siketyan siketyan requested a review from arendjr September 22, 2025 08:28
Co-authored-by: Arend van Beelen jr. <arend@arendjr.nl>
@siketyan siketyan force-pushed the feat/extension-alias branch from bde7fcf to f3b2fc7 Compare September 22, 2025 08:36
return resolve_import_alias(specifier, package_path, package_json, fs, options);
}

if is_relative_specifier(specifier) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is_relative_specifier() check belongs here. It may break the use of extension aliases in combination with path aliases, I believe. Just in case I would suggest adding a test for that scenario.

@siketyan siketyan closed this Sep 22, 2025
@siketyan siketyan deleted the feat/extension-alias branch September 22, 2025 10:00
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.

3 participants

点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载