From bf7757762e28ff65ddc0159a5be102c478ba5c3e Mon Sep 17 00:00:00 2001 From: Wolfvin Date: Sun, 12 Jul 2026 01:23:49 +0700 Subject: [PATCH] fix(dead-code): re-exports not counted as usage, causing false positives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit export type {X} from './y' (and export {X} from './y' without 'type') consume X from the source module — but the import-collection regex only matched 'import {X} from', never 'export {X} from'. Any symbol only ever re-exported (never plain-imported) was incorrectly flagged unused. Found via real-codebase validation (Coretax-Auto-Downloader extension): ProductAccess/AuthUser defined in google-auth-cache.ts, re-exported via 'export type {...} from' in google-auth.ts, flagged unused despite being consumed downstream through the re-export. Also fixes the re-export regex itself, which required 'export {' and never matched 'export type {' at all. --- scripts/deadcode_engine.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/deadcode_engine.py b/scripts/deadcode_engine.py index d8e614d7..997731e7 100755 --- a/scripts/deadcode_engine.py +++ b/scripts/deadcode_engine.py @@ -930,10 +930,20 @@ def _collect_js_exports_imports( # Re-exports: export { X } from ... vs local exports: export { X } # export { X } without 'from' is a local definition being made public API. # export { X } from './other' is a re-export from another module. + # export type { X } from './other' is a TypeScript type-only re-export. # We distinguish these because local exports should not be flagged as unused # (they are intentionally public API), while re-exports from other modules # may be unnecessary if nothing imports them. - for m in re.finditer(r'export\s+\{([^}]+)\}(\s+from\s+[\'"\w./@-]+)?', content): + # + # Bug fix: a re-export ("export {X} from './y'" or "export type {X} from + # './y'") consumes X from the source module './y' — it IS a usage of X as + # far as the source file's own unused-exports check is concerned. Without + # recording these names in `imports`, any symbol that is only ever + # re-exported (never plain-imported) is incorrectly flagged as unused in + # its defining file (found via real-codebase validation: ProductAccess in + # google-auth-cache.ts, re-exported via `export type {...} from` in + # google-auth.ts, was a false positive). + for m in re.finditer(r'export\s+(?:type\s+)?\{([^}]+)\}(\s+from\s+[\'"\w./@-]+)?', content): has_from = m.group(2) is not None export_type = "re_export" if has_from else "local_export" names = [n.strip().split(' as ')[0].strip() for n in m.group(1).split(',')] @@ -944,6 +954,8 @@ def _collect_js_exports_imports( "type": export_type, "line": content[:m.start()].count('\n') + 1 }) + if has_from: + imports[rel_path].add(name) # Imports (including TypeScript type-only imports) for m in re.finditer(r'import\s+(?:type\s+)?(?:\{([^}]+)\}|\*\s+as\s+(\w+)|(\w+))\s+from', content):