ludo-technologies / ludo-technologies/polyscan

[BUG][auto] ts/barrel-re-export-not-counted-as-use: symbols re-exported from an entrypoint barrel are reported as unused exports

Open
#155 0 comments 0 reactions 0 assignees View on GitHub
auto-filed bug P1
Dominant language
Go
Stars
12
Forks
7
Avg merge
5h 46m
Merged PRs (30d)
49

Description

A symbol re-exported from a barrel is reported `unused_exported_function`. Neither form of re-export counts as a use of the re-exported symbol:

- `export * from './mod.js'`
- `export { named } from './mod2.js'`

This holds even when the re-exporting file is a recognised entrypoint (`index.ts`), so it is not the entrypoint-identification gap. The entrypoint is identified; the edge leaving it is not followed. `orphan_file` describes its own model as "not reachable from any entry point", and under that model a symbol the entrypoint re-exports is reachable.

The barrel is the standard way a TypeScript library publishes its API, so the whole public surface of such a project is reported dead. The failure is silent and scales with API size.

## Repro

`mod.ts`
```ts
export function usedByProd() { return 1; }
export function usedByBarrelOnly() { return 3; }
export function usedByNobody() { return 4; }
```

`mod2.ts`
```ts
export function named() { return 5; }
```

`index.ts`
```ts
export * from './mod.js';
export { named } from './mod2.js';
```

`prod.ts`
```ts
import { usedByProd } from './mod.js';
export function p() { return usedByProd(); }
```

```
polyscan analyze --select deadcode --format json .
```

## Expected

`usedByBarrelOnly` and `named` are reachable from the `index.ts` entrypoint and should not be reported.

## Actual

```
mod.ts:2 [unused_exported_function] Exported function 'usedByBarrelOnly' is not imported by any other analyzed file
mod2.ts:1 [unused_exported_function] Exported function 'named' is not imported by any other analyzed file
```

| symbol | reached by | reported |
|---|---|---|
| `usedByProd` | ordinary import from `prod.ts` | no — correct |
| `usedByBarrelOnly` | `export *` from `index.ts` | **yes — wrong** |
| `named` | `export { named } from` in `index.ts` | **yes — wrong** |
| `usedByNobody` | nothing | yes — correct |

`usedByProd` acts as the control: ordinary import edges resolve correctly in the same run, so this is specific to re-export edges. Not an extension-resolution problem either — `./mod` and `./mod.js` behave identically, and #126 resolves correctly.

## Impact

On `rogerpadilla/uql`, 279 of 280 `unused_exported_function` findings are in `packages/uql-orm`, which publishes its API entirely through barrels — 129 `export *` and 28 `export {` lines across its `index.ts` files. `unused_exported_function` is 72% of that run's 390 dead-code findings.

Isolating example: `packages/uql-orm/src/browser/http/bus.ts:11` reports `on` as "not imported by any other analyzed file" while it is re-exported at `browser/http/index.ts:1` (`export * from './bus.js'`). `notify`, in the same file but imported by the non-test `http.ts:4`, is correctly not reported — the contrast isolates the mechanism to the re-export edge.

Separable and noted only for the record: an import from a `*.spec.ts` / `*.test.ts` file does not count as a use either. Treating a symbol only tests touch as dead is a defensible policy, unlike the above, but the message reads "is not imported by any other analyzed file" when a test file in the run does import it.

## Priority

P1 per the rubric: a wrong finding on a common construct. It affects every barrel-published symbol in a library, which is most of a library's API, but not every file, so not P0.

polyscan version `0.4.0` (`be31afc`).

Found via the FP-audit skill in repo `rogerpadilla/uql@6252e1f`.

Contributor guide

Open the contributing guide

Research direction

Start with the provided mod.ts, mod2.ts, index.ts, and prod.ts reproduction and run `polyscan analyze --select deadcode --format json .`. Trace the deadcode analyzer's handling of `export *` and `export { named } from` edges from the index.ts entrypoint. Done means usedByBarrelOnly and named are no longer reported, while usedByNobody still is.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, typescript
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.