Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(js_semantic): import namespace handling #2812

Merged
merged 1 commit into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@ our [guidelines for writing a good changelog entry](https://github.com/biomejs/b

#### Bug fixes

- [noUndeclaredVariables](https://biomejs.dev/linter/rules/no-undeclared-variables/) and [noUnusedImports](https://biomejs.dev/linter/rules/no-unused-imports) now correctly handle import namespaces ([#2796](https://github.com/biomejs/biome/issues/2796)).

Previously, Biome bound unqualified type to import namespaces.
Import namespaces can only be used as qualified names in a type (ambient) context.

```ts
// Unused import
import * as Ns1 from "";
// This doesn't reference the import namespace `Ns1`
type T1 = Ns1; // Undeclared variable `Ns1`

// Unused import
import type * as Ns2 from "";
// This doesn't reference the import namespace `Ns2`
type T2 = Ns2; // Undeclared variable `Ns2`

import type * as Ns3 from "";
// This references the import namespace because it is a qualified name.
type T3 = Ns3.Inner;
// This also references the import namespace.
export type { Ns3 }
```

Contributed by @Conaclos

- `useJsxKeyInIterable` now handles more cases involving fragments. See the snippets below. Contributed by @dyc3
```jsx
// valid
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as Ns1 from "";
export type T1 = Ns1; // This doesn't reference the import namespace `Ns1`

import type * as Ns2 from "";
export type T2 = Ns2; // This doesn't reference the import namespace `Ns1`
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: invalidNamesapceReference.ts
---
# Input
```ts
import * as Ns1 from "";
export type T1 = Ns1; // This doesn't reference the import namespace `Ns1`

import type * as Ns2 from "";
export type T2 = Ns2; // This doesn't reference the import namespace `Ns1`
```

# Diagnostics
```
invalidNamesapceReference.ts:2:18 lint/correctness/noUndeclaredVariables ━━━━━━━━━━━━━━━━━━━━━━━━━━━

! The Ns1 variable is undeclared

1 │ import * as Ns1 from "";
> 2 │ export type T1 = Ns1; // This doesn't reference the import namespace `Ns1`
│ ^^^
3 │
4 │ import type * as Ns2 from "";


```

```
invalidNamesapceReference.ts:5:18 lint/correctness/noUndeclaredVariables ━━━━━━━━━━━━━━━━━━━━━━━━━━━

! The Ns2 variable is undeclared

4 │ import type * as Ns2 from "";
> 5 │ export type T2 = Ns2; // This doesn't reference the import namespace `Ns1`
│ ^^^


```
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import * as Ns1 from ""
export type T1 = Ns1;

import type * as Ns2 from ""
export type T2 = Ns2;
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: invalid-import-namespace.ts
---
# Input
```ts
import * as Ns1 from ""
export type T1 = Ns1;

import type * as Ns2 from ""
export type T2 = Ns2;
```

# Diagnostics
```
invalid-import-namespace.ts:1:13 lint/correctness/noUnusedImports FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━

! This import is unused.

> 1 │ import * as Ns1 from ""
│ ^^^
2 │ export type T1 = Ns1;
3 │

i Unused imports might be the result of an incomplete refactoring.

i Safe fix: Remove the unused import.

1 │ import·*·as·Ns1·from·""
│ -----------------------

```

```
invalid-import-namespace.ts:4:18 lint/correctness/noUnusedImports FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━

! This import is unused.

2 │ export type T1 = Ns1;
3 │
> 4 │ import type * as Ns2 from ""
│ ^^^
5 │ export type T2 = Ns2;

i Unused imports might be the result of an incomplete refactoring.

i Safe fix: Remove the unused import.

1 1 │ import * as Ns1 from ""
2 2 │ export type T1 = Ns1;
3 │ -
4 │ - import·type·*·as·Ns2·from·""
5 3 │ export type T2 = Ns2;


```
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
namespace Ns {}
export type { Ns }
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
source: crates/biome_js_analyze/tests/spec_tests.rs
expression: validNamesapceExportType.ts
---
# Input
```ts
namespace Ns {}
export type { Ns }
```
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ export type { f2, Class2, typeNs };
declare class AmbientClass {}
declare enum AmbientEnum {}
declare class AmbientFunction {}
export { AmbientClass, AmbientEnum, AmbientFunction }
export { AmbientClass, AmbientEnum, AmbientFunction }

import type * as Ns from ""
export { Ns }
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ declare class AmbientClass {}
declare enum AmbientEnum {}
declare class AmbientFunction {}
export { AmbientClass, AmbientEnum, AmbientFunction }

import type * as Ns from ""
export { Ns }
```

# Diagnostics
```
valid.ts:44:8 lint/style/useExportType FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! All exports are only types and should thus use export type.

43 │ import type * as Ns from ""
> 44 │ export { Ns }
│ ^^^^^^

i Using export type allows transpilers to safely drop exports of types without looking for their definition.

i Safe fix: Use a grouped export type.

44 │ export·type·{·Ns·}
│ +++++

```
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ function f<T, T>() {}

function g<T>() {
type T = number;
}
}

import * as Ns1 from ""
namespace Ns1 {}

import type * as Ns2 from ""
namespace Ns2 {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ function f<T, T>() {}
function g<T>() {
type T = number;
}

import * as Ns1 from ""
namespace Ns1 {}

import type * as Ns2 from ""
namespace Ns2 {}

```

# Diagnostics
Expand Down Expand Up @@ -76,6 +83,7 @@ invalid.ts:11:10 lint/suspicious/noRedeclare ━━━━━━━━━━━
> 11 │ type T = number;
│ ^
12 │ }
13 │

i 'T' is defined here:

Expand All @@ -88,3 +96,48 @@ invalid.ts:11:10 lint/suspicious/noRedeclare ━━━━━━━━━━━


```

```
invalid.ts:15:11 lint/suspicious/noRedeclare ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Shouldn't redeclare 'Ns1'. Consider to delete it or rename it.

14 │ import * as Ns1 from ""
> 15 │ namespace Ns1 {}
│ ^^^
16 │
17 │ import type * as Ns2 from ""

i 'Ns1' is defined here:

12 │ }
13 │
> 14 │ import * as Ns1 from ""
│ ^^^
15 │ namespace Ns1 {}
16 │


```

```
invalid.ts:18:11 lint/suspicious/noRedeclare ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

! Shouldn't redeclare 'Ns2'. Consider to delete it or rename it.

17 │ import type * as Ns2 from ""
> 18 │ namespace Ns2 {}
│ ^^^
19 │

i 'Ns2' is defined here:

15 │ namespace Ns1 {}
16 │
> 17 │ import type * as Ns2 from ""
│ ^^^
18 │ namespace Ns2 {}
19 │


```