Skip to content

Commit

Permalink
fix(noUnusedImports): don't report used val imported as type in an ex…
Browse files Browse the repository at this point in the history
…ternal module
  • Loading branch information
Conaclos committed Nov 19, 2024
1 parent 6b18387 commit ded21c0
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

- [noMisleadingCharacterClass](https://biomejs.dev/linter/rules/no-misleading-character-class/) no longer panics on malformed escape sequences that end with a multi-byte character ([#4587](https://github.com/biomejs/biome/issues/4587)). Contributed by @Conaclos

- [noUnusedImports](https://biomejs.dev/linter/rules/no-unused-imports/) no longer reports used values imported as types in an external module ([#3895])(https://github.com/biomejs/biome/issues/3895). Contributed by @Conaclos

### Parser

#### Bug fixes
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module "mod" {
import type { Ns } from "other";
export const C: { prop: Ns.prop };
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: valid-inner-imports.ts
snapshot_kind: text
---
# Input
```ts
declare module "mod" {
import type { Ns } from "other";
export const C: { prop: Ns.prop };
}
```
40 changes: 21 additions & 19 deletions crates/biome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,25 +1034,19 @@ impl SemanticEventExtractor {
};
self.stash.push_back(event);
}
} else if references.iter().all(|r| matches!(r, Reference::Export(_)))
&& self.bindings.contains_key(&name.clone().dual())
{
// Don't report an export that exports at least a binding.
} else if let Some(parent) = self.scopes.last_mut() {
// Promote these references to the parent scope
let parent_references = parent.references.entry(name).or_default();
parent_references.append(&mut references);
} else if let Some(info) = self.bindings.get(&name.dual()).cloned() {
// We are in the global scope.
// Try to bind some of these references to the dual binding of `name`,
// otherwise raide `UnresolvedReference`.
} else if let Some(info) = self.bindings.get(&name.clone().dual()) {
let mut parent_references = self
.scopes
.last_mut()
.map(|parent| parent.references.entry(name.clone()).or_default());
let is_dual_imported = info.is_imported();
for reference in references {
match reference {
Reference::Export(_) => {
// An export can export both a value and a type.
// If a dual binding exists, then it exports to the dual binding.
// If a dual binding exists, then it exports the dual binding.
}
Reference::AmbientRead(range) if info.is_imported() => {
Reference::AmbientRead(range) if is_dual_imported => {
// An ambient read can only read a value,
// but also an imported value as a type (with the `type` modifier)
let declaration_before_reference =
Expand All @@ -1072,14 +1066,22 @@ impl SemanticEventExtractor {
};
self.stash.push_back(event);
}
_ => {
self.stash.push_back(SemanticEvent::UnresolvedReference {
is_read: !reference.is_write(),
range: reference.range(),
});
reference => {
if let Some(parent_references) = &mut parent_references {
parent_references.push(reference);
} else {
self.stash.push_back(SemanticEvent::UnresolvedReference {
is_read: !reference.is_write(),
range: reference.range(),
});
}
}
}
}
} else if let Some(parent) = self.scopes.last_mut() {
// Promote these references to the parent scope
let parent_references = parent.references.entry(name).or_default();
parent_references.append(&mut references);
} else {
// We are in the global scope. Raise `UnresolvedReference`.
for reference in references {
Expand Down

0 comments on commit ded21c0

Please sign in to comment.