refactor: use semantic model for module graph#9211
Conversation
🦋 Changeset detectedLatest commit: c9d2624 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Merging this PR will not alter performance
Comparing Footnotes
|
Parser conformance results onjs/262
jsx/babel
markdown/commonmark
symbols/microsoft
ts/babel
ts/microsoft
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughConst constructors and const accessors were added for Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/biome_module_graph/src/js_module_info/module_resolver.rs (1)
157-187:⚠️ Potential issue | 🟠 MajorUse
scope_for_rangeand handleTypeReference::Importvariants in type resolution.The
_rangeparameter is unused while the code hardcodes global scope (ScopeId::new(0)), so shadowed bindings won't resolve correctly. Additionally, onlyTypeReference::Resolvedis matched (lines 177–180), causingImportreferences to fall back toGLOBAL_UNKNOWN_ID. Use the semantic model'sscope_for_range(range)to get the innermost scope and callresolve_importfor import references.
🧹 Nitpick comments (1)
crates/biome_module_graph/src/js_module_info/collector.rs (1)
577-599: TODO comment flags incomplete migration — consider tracking this.The comment on lines 578-582 explains that type inference still uses the collector's temporary scopes rather than the semantic model directly. This is a reasonable incremental approach, but the TODO should be tracked to avoid becoming stale.
Would you like me to open an issue to track refactoring type inference to use
semantic_model's scopes directly?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info/collector.rs` around lines 577 - 599, The TODO in infer_all_types indicates a needed refactor to use semantic_model scopes but isn’t tracked; create a formal issue describing migrating infer_all_types to use semantic_model scopes (mention scope_range_by_start, scope_by_range, scope_id_for_range, binding_node_by_start, infer_type) and then update the TODO comment to reference that issue ID/URL (or add a TODO/FIXME with the issue number) so the work is discoverable and won't go stale.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_module_graph/src/js_module_info/module_resolver.rs`:
- Around line 421-454: The current logic checks
module.static_imports.contains_key(identifier.text()) regardless of whether
find_binding_in_scope returned a local binding, causing shadowed locals to be
treated as imports; update the branch to only treat the name as an import when
the binding returned by find_binding_in_scope actually corresponds to an import
declaration (e.g., inspect the returned binding or its declaration kind from
binding_range to ensure it's an import) or compare the binding_range to the
import's declaration range before calling resolve_import (otherwise fall back to
binding_type_data + resolve_reference); reference symbols:
find_binding_in_scope, binding_range, static_imports.contains_key,
static_import_paths, resolve_import, binding_type_data, resolve_reference,
semantic_scope_id.
In `@crates/biome_service/src/workspace/server.rs`:
- Around line 1016-1033: The update currently calls
self.module_graph.update_graph_for_js_paths with
services.semantic_model.expect(...), which can panic because
services.as_js_services() may not have a semantic_model when lint/assist are
disabled; change the call site (inside the
SendNode::into_language_root::<AnyJsRoot> / services.as_js_services() branch) to
handle the Option from services.semantic_model safely: either (a) construct or
obtain a lightweight fallback SemanticModel when semantic_model.is_none() and
pass that into update_graph_for_js_paths, or (b) skip/early-return the JS
module-graph update and log a debug message when semantic_model is missing;
ensure you reference services.semantic_model and update_graph_for_js_paths to
locate the code and avoid using expect() so no panic occurs.
---
Nitpick comments:
In `@crates/biome_module_graph/src/js_module_info/collector.rs`:
- Around line 577-599: The TODO in infer_all_types indicates a needed refactor
to use semantic_model scopes but isn’t tracked; create a formal issue describing
migrating infer_all_types to use semantic_model scopes (mention
scope_range_by_start, scope_by_range, scope_id_for_range, binding_node_by_start,
infer_type) and then update the TODO comment to reference that issue ID/URL (or
add a TODO/FIXME with the issue number) so the work is discoverable and won't go
stale.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
Cargo.lockis excluded by!**/*.lockand included by**crates/biome_module_graph/tests/snapshots/test_export_default_function_declaration.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_export_referenced_function.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_export_type_referencing_imported_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_export_types.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_exports.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_generic_return_value.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_generic_return_value_with_multiple_modules.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_import_as_namespace.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_merged_types.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_multiple_reexports.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_nested_function_call_with_namespace_in_return_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_promise_export.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_imported_promise_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_reexported_promise_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_recursive_looking_country_info.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_single_reexport.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_type_of_this_in_class_export.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (20)
crates/biome_js_semantic/src/semantic_model/model.rscrates/biome_js_type_info/Cargo.tomlcrates/biome_js_type_info/src/type_data.rscrates/biome_js_type_info/tests/local_inference.rscrates/biome_js_type_info/tests/resolver.rscrates/biome_module_graph/benches/module_graph.rscrates/biome_module_graph/src/format_module_graph.rscrates/biome_module_graph/src/js_module_info.rscrates/biome_module_graph/src/js_module_info/binding.rscrates/biome_module_graph/src/js_module_info/collector.rscrates/biome_module_graph/src/js_module_info/module_resolver.rscrates/biome_module_graph/src/js_module_info/scope.rscrates/biome_module_graph/src/js_module_info/visitor.rscrates/biome_module_graph/src/lib.rscrates/biome_module_graph/src/module_graph.rscrates/biome_module_graph/tests/snap/mod.rscrates/biome_module_graph/tests/spec_tests.rscrates/biome_service/src/workspace/server.rscrates/biome_test_utils/Cargo.tomlcrates/biome_test_utils/src/lib.rs
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/biome_module_graph/src/js_module_info/module_resolver.rs (1)
165-168: Consider using the global scope's ID directly.The
_global_scopevariable is fetched but never used. Ifglobal_scope()returns something with an accessible ID, you could use that instead of hardcodingScopeId::new(0).🔧 Potential simplification
If the semantic model's
Scopetype exposes its ID, consider:- let _global_scope = module.0.semantic_model.global_scope(); - // We need the internal ScopeId to pass to find_binding_in_scope - // SAFETY: The global scope is always at index 0 - let scope_id = biome_js_semantic::ScopeId::new(0); + let scope_id = module.0.semantic_model.global_scope().id();Otherwise, if this is intentional due to API limitations, removing the unused
_global_scopeassignment would tidy things up.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info/module_resolver.rs` around lines 165 - 168, The code fetches module.0.semantic_model.global_scope() into _global_scope but then hardcodes biome_js_semantic::ScopeId::new(0) for scope_id; either remove the unused _global_scope binding or, if the Scope object exposes its id, derive scope_id from that global scope (use the global scope's id instead of ScopeId::new(0)) so find_binding_in_scope gets the actual global scope id; update the code around module.0.semantic_model.global_scope(), scope_id, and the call to find_binding_in_scope accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_module_graph/src/js_module_info.rs`:
- Around line 104-111: The method scope_for_range should guard against empty
TextRange values before calling self.0.semantic_model.scope_for_range because
that method debug‑asserts on empty ranges; update scope_for_range to
early‑return JsScope { info: self.0.clone(), scope: self.0.global_scope() } (or
call an existing global_scope() helper) when range.is_empty() (or equivalent) is
true, otherwise delegate to semantic_model.scope_for_range(range) as before;
reference the scope_for_range function and semantic_model.scope_for_range in
your change.
---
Nitpick comments:
In `@crates/biome_module_graph/src/js_module_info/module_resolver.rs`:
- Around line 165-168: The code fetches module.0.semantic_model.global_scope()
into _global_scope but then hardcodes biome_js_semantic::ScopeId::new(0) for
scope_id; either remove the unused _global_scope binding or, if the Scope object
exposes its id, derive scope_id from that global scope (use the global scope's
id instead of ScopeId::new(0)) so find_binding_in_scope gets the actual global
scope id; update the code around module.0.semantic_model.global_scope(),
scope_id, and the call to find_binding_in_scope accordingly.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
crates/biome_module_graph/src/js_module_info.rscrates/biome_module_graph/src/js_module_info/module_resolver.rscrates/biome_service/src/workspace/server.rs
There was a problem hiding this comment.
🧹 Nitpick comments (1)
crates/biome_module_graph/src/js_module_info.rs (1)
304-324: Consider extracting the scope-walk helper.
The parent-scope traversal is duplicated inis_binding_imported; a shared helper would reduce drift.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info.rs` around lines 304 - 324, The scope-parent traversal logic in find_binding_in_scope is duplicated in is_binding_imported; extract a shared helper (e.g., iterate_scope_chain or find_in_scope_chain) that accepts a starting ScopeId and a closure/predicate to run against each Scope, then refactor find_binding_in_scope to call that helper and refactor is_binding_imported to use the same helper to check parent scopes; reference the existing symbols find_binding_in_scope and is_binding_imported and ensure the helper returns either the predicate result (Option<TextRange> for the binding case or bool for imported check) or a common enum/Result that both callers can use.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@crates/biome_module_graph/src/js_module_info.rs`:
- Around line 304-324: The scope-parent traversal logic in find_binding_in_scope
is duplicated in is_binding_imported; extract a shared helper (e.g.,
iterate_scope_chain or find_in_scope_chain) that accepts a starting ScopeId and
a closure/predicate to run against each Scope, then refactor
find_binding_in_scope to call that helper and refactor is_binding_imported to
use the same helper to check parent scopes; reference the existing symbols
find_binding_in_scope and is_binding_imported and ensure the helper returns
either the predicate result (Option<TextRange> for the binding case or bool for
imported check) or a common enum/Result that both callers can use.
5609292 to
0f3e0a5
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
crates/biome_service/src/workspace/server.rs (1)
1030-1033: Add a debug breadcrumb when JS graph updates are skipped.Line 1031 silently returns defaults; a small debug log here would save future “why didn’t it index?” archaeology.
🔎 Tiny observability tweak
} else { - // No semantic model available - return empty result + tracing::debug!( + path = %path, + "Skipping JS module graph update: semantic model unavailable" + ); Default::default() }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_service/src/workspace/server.rs` around lines 1030 - 1033, Add a debug breadcrumb before the silent return in the else branch that currently returns Default::default() so skipped JS graph updates are logged; locate the branch in workspace/server.rs where the code returns Default::default() for "No semantic model available" (the JS graph update path) and call the project's logger (e.g., tracing::debug! or log::debug!) with a short message like "Skipping JS graph update: no semantic model" and any contextual identifiers (workspace id, file path, or request id) available in scope to aid future debugging.crates/biome_module_graph/src/js_module_info/collector.rs (2)
1135-1158:_semantic_modelis a forward-declared parameter with no current use.The method builds
BindingTypeDatapurely fromself.bindingsand never touches_semantic_model. The_prefix suppresses the warning, which is fine for now — but consider dropping the parameter until it's actually needed, to avoid misleading callers about what drives the output.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info/collector.rs` around lines 1135 - 1158, The build_binding_type_data method on JsModuleInfoCollector currently takes an unused parameter _semantic_model; remove the unused parameter from the function signature (change fn build_binding_type_data(&self, _semantic_model: &biome_js_semantic::SemanticModel) -> ... to fn build_binding_type_data(&self) -> ...) and update all callers to call build_binding_type_data() without the extra argument; keep the body that maps self.bindings into BindingTypeData (ty, jsdoc, export_ranges) unchanged so behavior is preserved.
577-599: Acknowledged interim duplication — TODO is clear, just ensure it's tracked.
infer_all_typesrebuilds aLapperfromscope_range_by_starton every call while aSemanticModel(which already holds this data) is passed but ignored. The TODO comment is clear, but this meansscope_range_by_start(and all its memory) is still being kept alive for each module even though the semantic model holds equivalent scope data.Worth filing a follow-up issue to track the migration so it doesn't linger.
Want me to open a tracking issue for the
TODO: Refactor type inference to use semantic_model's scopes directly?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info/collector.rs` around lines 577 - 599, infer_all_types currently rebuilds a Lapper from the collector's scope_range_by_start each call even though a SemanticModel is passed in and contains equivalent scope data; file a follow-up issue tracking the TODO and update infer_all_types to use the scopes provided by the SemanticModel (use semantic_model's scope data instead of scope_range_by_start), remove/stop retaining collector-level scope_range_by_start where redundant, and update calls that rely on scope_id_for_range to accept the semantic_model-backed Lapper or lookup so the type inference (infer_type) uses the semantic model's scopes directly.crates/biome_module_graph/src/js_module_info/scope.rs (1)
14-27:pub rangeannotated dead — considerpub(crate)or removing the field for now.A
pubfield with#[expect(dead_code)]is a contradiction: public to the world, but nothing reads it. If it's genuinely unused externally too,pub(crate)is a better fit until the "future scope analysis" materialises.♻️ Suggested change
pub struct JsScopeData { - #[expect(dead_code, reason = "May be used in future for scope analysis")] - pub range: TextRange, + pub(crate) range: TextRange,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info/scope.rs` around lines 14 - 27, The field JsScopeData::range is publicly exported but annotated #[expect(dead_code)] — change its visibility to pub(crate) (or remove the field if you prefer) to avoid exposing an unused public API; locate the struct JsScopeData and update the range field's declaration (currently typed TextRange and carrying the expect attribute) to use pub(crate) instead of pub, and remove the expect(dead_code) attribute if you keep it as pub(crate).crates/biome_module_graph/src/js_module_info.rs (1)
306-348: Duplicated scope-walking loop — extract a shared private helper.
find_binding_in_scopeandis_binding_importedshare the exact same loop structure: start atscope_from_id, callget_binding(name), fall back toparent(). The only difference is what they do with theBindingonce found.♻️ Suggested refactor
+ /// Looks up a binding by name starting from `scope_id` and walking up the scope chain. + fn lookup_binding_in_scope( + &self, + name: &str, + scope_id: ScopeId, + ) -> Option<biome_js_semantic::Binding> { + let mut scope = self.semantic_model.scope_from_id(scope_id); + loop { + if let Some(binding) = scope.get_binding(name) { + return Some(binding); + } + match scope.parent() { + Some(parent) => scope = parent, + None => return None, + } + } + } + fn find_binding_in_scope(&self, name: &str, scope_id: ScopeId) -> Option<TextRange> { - let mut scope = self.semantic_model.scope_from_id(scope_id); - loop { - if let Some(binding) = scope.get_binding(name) { - return Some(binding.syntax().text_trimmed_range()); - } - match scope.parent() { - Some(parent) => scope = parent, - None => break, - } - } - None + self.lookup_binding_in_scope(name, scope_id) + .map(|b| b.syntax().text_trimmed_range()) } fn is_binding_imported(&self, name: &str, scope_id: ScopeId) -> bool { - let mut scope = self.semantic_model.scope_from_id(scope_id); - loop { - if let Some(binding) = scope.get_binding(name) { - return binding.is_imported(); - } - match scope.parent() { - Some(parent) => scope = parent, - None => break, - } - } - false + self.lookup_binding_in_scope(name, scope_id) + .is_some_and(|b| b.is_imported()) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_module_graph/src/js_module_info.rs` around lines 306 - 348, Both find_binding_in_scope and is_binding_imported repeat the same scope-walking loop; extract a private helper (e.g., walk_binding_in_scope or find_binding) that takes (&self, name: &str, scope_id: ScopeId) and returns Option<Binding> (or a reference/handle to the Binding) by starting from self.semantic_model.scope_from_id(scope_id), calling get_binding(name) and following parent() until None. Replace the loop in find_binding_in_scope to call the helper and then return binding.syntax().text_trimmed_range() mapped into Option<TextRange>, and replace the loop in is_binding_imported to call the helper and return binding.is_imported() or false if None. Ensure the helper and callers use the same Binding type and visibility (private) so behavior is unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_module_graph/benches/module_graph.rs`:
- Line 3: The benchmark constructs an incomplete model by calling
SemanticModelBuilder::new(root.clone()).build(); replace that direct builder
usage with the library helper that runs preorder traversal and event
extraction—call semantic_model(root.clone()) (importing semantic_model from
biome_js_semantic if needed) so the benchmark measures the fully constructed
semantic model instead of the incomplete build from
SemanticModelBuilder::new(...).build().
In `@crates/biome_module_graph/src/js_module_info/module_resolver.rs`:
- Around line 157-181: resolved_type_of_named_value currently ignores the
provided range and always uses module.0.semantic_model.global_scope() and a
hard-coded ScopeId(0); change it to lookup the scope at the given range (use the
semantic model's range-based scope lookup or find the node at range and derive
the scope id) instead of the global scope before calling find_binding_in_scope,
and when you retrieve binding_type_data use self.resolve_reference(&data.ty)
rather than only matching TypeReference::Resolved so import-based references are
correctly resolved; update references to find_binding_in_scope,
binding_type_data, and resolve_reference in resolved_type_of_named_value
accordingly.
---
Nitpick comments:
In `@crates/biome_module_graph/src/js_module_info.rs`:
- Around line 306-348: Both find_binding_in_scope and is_binding_imported repeat
the same scope-walking loop; extract a private helper (e.g.,
walk_binding_in_scope or find_binding) that takes (&self, name: &str, scope_id:
ScopeId) and returns Option<Binding> (or a reference/handle to the Binding) by
starting from self.semantic_model.scope_from_id(scope_id), calling
get_binding(name) and following parent() until None. Replace the loop in
find_binding_in_scope to call the helper and then return
binding.syntax().text_trimmed_range() mapped into Option<TextRange>, and replace
the loop in is_binding_imported to call the helper and return
binding.is_imported() or false if None. Ensure the helper and callers use the
same Binding type and visibility (private) so behavior is unchanged.
In `@crates/biome_module_graph/src/js_module_info/collector.rs`:
- Around line 1135-1158: The build_binding_type_data method on
JsModuleInfoCollector currently takes an unused parameter _semantic_model;
remove the unused parameter from the function signature (change fn
build_binding_type_data(&self, _semantic_model:
&biome_js_semantic::SemanticModel) -> ... to fn build_binding_type_data(&self)
-> ...) and update all callers to call build_binding_type_data() without the
extra argument; keep the body that maps self.bindings into BindingTypeData (ty,
jsdoc, export_ranges) unchanged so behavior is preserved.
- Around line 577-599: infer_all_types currently rebuilds a Lapper from the
collector's scope_range_by_start each call even though a SemanticModel is passed
in and contains equivalent scope data; file a follow-up issue tracking the TODO
and update infer_all_types to use the scopes provided by the SemanticModel (use
semantic_model's scope data instead of scope_range_by_start), remove/stop
retaining collector-level scope_range_by_start where redundant, and update calls
that rely on scope_id_for_range to accept the semantic_model-backed Lapper or
lookup so the type inference (infer_type) uses the semantic model's scopes
directly.
In `@crates/biome_module_graph/src/js_module_info/scope.rs`:
- Around line 14-27: The field JsScopeData::range is publicly exported but
annotated #[expect(dead_code)] — change its visibility to pub(crate) (or remove
the field if you prefer) to avoid exposing an unused public API; locate the
struct JsScopeData and update the range field's declaration (currently typed
TextRange and carrying the expect attribute) to use pub(crate) instead of pub,
and remove the expect(dead_code) attribute if you keep it as pub(crate).
In `@crates/biome_service/src/workspace/server.rs`:
- Around line 1030-1033: Add a debug breadcrumb before the silent return in the
else branch that currently returns Default::default() so skipped JS graph
updates are logged; locate the branch in workspace/server.rs where the code
returns Default::default() for "No semantic model available" (the JS graph
update path) and call the project's logger (e.g., tracing::debug! or
log::debug!) with a short message like "Skipping JS graph update: no semantic
model" and any contextual identifiers (workspace id, file path, or request id)
available in scope to aid future debugging.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
Cargo.lockis excluded by!**/*.lockand included by**crates/biome_module_graph/tests/snapshots/test_export_default_function_declaration.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_export_referenced_function.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_export_type_referencing_imported_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_export_types.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_exports.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_generic_return_value.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_generic_return_value_with_multiple_modules.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_import_as_namespace.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_merged_types.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_multiple_reexports.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_nested_function_call_with_namespace_in_return_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_promise_export.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_imported_promise_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_promise_from_imported_function_returning_reexported_promise_type.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_recursive_looking_country_info.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_single_reexport.snapis excluded by!**/*.snapand included by**crates/biome_module_graph/tests/snapshots/test_resolve_type_of_this_in_class_export.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (20)
crates/biome_js_semantic/src/semantic_model/model.rscrates/biome_js_type_info/Cargo.tomlcrates/biome_js_type_info/src/type_data.rscrates/biome_js_type_info/tests/local_inference.rscrates/biome_js_type_info/tests/resolver.rscrates/biome_module_graph/benches/module_graph.rscrates/biome_module_graph/src/format_module_graph.rscrates/biome_module_graph/src/js_module_info.rscrates/biome_module_graph/src/js_module_info/binding.rscrates/biome_module_graph/src/js_module_info/collector.rscrates/biome_module_graph/src/js_module_info/module_resolver.rscrates/biome_module_graph/src/js_module_info/scope.rscrates/biome_module_graph/src/js_module_info/visitor.rscrates/biome_module_graph/src/lib.rscrates/biome_module_graph/src/module_graph.rscrates/biome_module_graph/tests/snap/mod.rscrates/biome_module_graph/tests/spec_tests.rscrates/biome_service/src/workspace/server.rscrates/biome_test_utils/Cargo.tomlcrates/biome_test_utils/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (7)
- crates/biome_js_type_info/tests/resolver.rs
- crates/biome_js_type_info/Cargo.toml
- crates/biome_module_graph/tests/snap/mod.rs
- crates/biome_module_graph/src/lib.rs
- crates/biome_module_graph/src/js_module_info/visitor.rs
- crates/biome_module_graph/tests/spec_tests.rs
- crates/biome_js_semantic/src/semantic_model/model.rs
crates/biome_module_graph/src/js_module_info/module_resolver.rs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_module_graph/src/js_module_info/module_resolver.rs`:
- Around line 139-144: The export default path drops import-backed bindings
because resolved_type_for_reference(&data.ty) only handles
TypeReference::Resolved and returns Type::default() for TypeReference::Import;
update the binding handling (JsOwnExport::Binding) to match on data.ty and
explicitly handle TypeReference::Import by resolving the import reference (e.g.,
call the import-resolution routine or a new helper like
resolved_type_for_import_reference) instead of falling back to default, or fix
resolved_type_for_reference to recognize and resolve TypeReference::Import into
the correct Type (instead of returning default); ensure you still fall back to
resolved_type_for_id(GLOBAL_UNKNOWN_ID) only when resolution truly fails.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
crates/biome_js_semantic/src/semantic_model/scope.rscrates/biome_module_graph/benches/module_graph.rscrates/biome_module_graph/src/js_module_info/module_resolver.rs
Summary
Closes #7905
This PR refactors our module graph and type inference to use the same semantic model created in the workspace server.
This should speed things up and possibly reduce memory usage, since we don't duplicate anything. However, this is just an educated guess; I didn't test anything.
Since this is a refactor, it was a good use of AI. I made sure there hasn't been a regression in functionality. On the other hand, we have better information inside the module graph, as you can see from the updated snapshots.
Test Plan
Green CI
Docs