Skip to content

Commit 1c4ef90

Browse files
author
DevForge Engineer
committed
cowork-bot: treat type-only named imports as used in dead-code scan
1 parent 0cc8c79 commit 1c4ef90

2 files changed

Lines changed: 31 additions & 2 deletions

File tree

src/deadcode/scanner.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,9 @@ def _parse_imports(
323323
names = [n.strip().split(" as ")[0].strip() for n in named_imports.split(",")]
324324
for name in names:
325325
if name:
326-
imports.setdefault(name, set()).add(rel_path)
326+
canonical = name[5:].strip() if name.startswith("type ") else name
327+
if canonical:
328+
imports.setdefault(canonical, set()).add(rel_path)
327329

328330
def _parse_css_classes(
329331
self, content: str, rel_path: str, css_classes: dict[str, list[tuple[str, int]]]

tests/test_scanner.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def test_type_import_counts_as_used(self, tmp_path):
199199
assert "Foo" not in unused_names
200200

201201
def test_mixed_default_and_named_import_counts_as_used(self, tmp_path):
202-
"""import默认 + named should mark both as used."""
202+
"""Default + named should mark both as used."""
203203
mod = tmp_path / "mod.ts"
204204
mod.write_text('export function myFunc() { return 1; }\n')
205205
app = tmp_path / "app.ts"
@@ -212,6 +212,33 @@ def test_mixed_default_and_named_import_counts_as_used(self, tmp_path):
212212
assert "myFunc" not in unused_names
213213
assert "Default" not in unused_names
214214

215+
def test_type_only_import_marks_as_used(self, tmp_path):
216+
"""`import { type Foo } from ...` should mark Foo as used."""
217+
mod = tmp_path / "mod.ts"
218+
mod.write_text('export type Foo = string;\n')
219+
app = tmp_path / "app.ts"
220+
app.write_text('import { type Foo } from "./mod";\nconst x: Foo = "hi";\n')
221+
222+
scanner = DeadCodeScanner(tmp_path)
223+
result = scanner.scan()
224+
225+
unused_names = {f.name for f in result.unused_exports}
226+
assert "Foo" not in unused_names
227+
228+
def test_mixed_default_and_type_only_import_marks_as_used(self, tmp_path):
229+
"""`import Default, { type Foo } from ...` should mark Foo as used."""
230+
mod = tmp_path / "mod.ts"
231+
mod.write_text('export default function Default() { return 1; }\nexport type Foo = string;\n')
232+
app = tmp_path / "app.ts"
233+
app.write_text('import Default, { type Foo } from "./mod";\nconst x: Foo = "hi";\n')
234+
235+
scanner = DeadCodeScanner(tmp_path)
236+
result = scanner.scan()
237+
238+
unused_names = {f.name for f in result.unused_exports}
239+
assert "Default" not in unused_names
240+
assert "Foo" not in unused_names
241+
215242

216243
class TestCSSParsing:
217244
def test_orphaned_css_detection(self, tmp_path):

0 commit comments

Comments
 (0)