ludo-technologies / ludo-technologies/polyscan
[BUG][auto] ts/import-counted-twice-as-module-and-constructor-name: new X() on an imported class double-counts the import in CBO
- Dominant language
- Go
- Stars
- 12
- Forks
- 7
- Avg merge
- 5h 46m
- Merged PRs (30d)
- 49
Description
## Summary
For JS/TS, a single import is counted **twice** in `cbo.classes[].metrics.dependent_classes` when the imported binding is used as a constructor: once under the normalized module name and once under the raw constructor identifier.
## Repro
`src/dep.ts`:
```ts
export class Widget {
render(): string { return 'w' }
}
```
`src/main.ts`:
```ts
import { Widget } from './dep'
export function run(): string {
return new Widget().render()
}
```
```
polyscan analyze --select cbo --format json .
```
## Expected
One import, one dependency: `deps=dep`, `coupling_count: 1`.
## Actual
```
file=main.ts coupling_count=2 deps=Widget,dep
```
Both `dep` and `Widget` appear for the same `import { Widget } from './dep'` statement.
## Real-world impact
In `rayriffy/elysia-rate-limit@ecb2515`:
- `src/services/defaultContext.ts` — `import AllocQuickLRU from '@alloc/quick-lru'` (L1), instantiated at L33, yields both `"@alloc/quick-lru"` and `"AllocQuickLRU"`:
```json
{"name":"defaultContext","metrics":{"coupling_count":6,"dependent_classes":["@alloc/quick-lru","@types/Context","@types/Options","AllocQuickLRU","item","logger"]}}
```
- `src/services/plugin.ts` — `import Elysia from 'elysia'` yields both `"elysia"` and `"Elysia"`; `import { DefaultContext } from './defaultContext'` yields both `"defaultContext"` and `"DefaultContext"`.
## Suspected cause
`extractInstantiationDependencies` in `polyscan/internal/js/analyzer/cbo.go` (~L149-160) records the raw constructor identifier without resolving it through the `importedIdentifiers` local-name to module map that `extractAttributeAccessDependencies` already builds and uses (~L232-244). Routing the constructor name through that same map should be enough.
## Priority
P1 — a wrong metric on a very common construct (`new X()` on an imported class). Local to one function, so likely a good first issue.
Found via the FP-audit skill in repo `rayriffy/elysia-rate-limit@ecb2515`.
polyscan version: `polyscan version 0.4.0`
Contributor guide
Research direction
Read extractInstantiationDependencies in polyscan/internal/js/analyzer/cbo.go and compare its handling with extractAttributeAccessDependencies, especially the importedIdentifiers map. Run the provided TypeScript repro with polyscan analyze --select cbo --format json .; done means the imported class appears once as dep and coupling_count is 1 rather than listing both dep and Widget.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, typescript
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100