Skip to content

fix: namespaced wildcard exports should not be flagged as duplicate identifiers#3243

Draft
whatfontisthis wants to merge 1 commit intoimport-js:mainfrom
whatfontisthis:fix/namespaced-wildcard-export-false-positive
Draft

fix: namespaced wildcard exports should not be flagged as duplicate identifiers#3243
whatfontisthis wants to merge 1 commit intoimport-js:mainfrom
whatfontisthis:fix/namespaced-wildcard-export-false-positive

Conversation

@whatfontisthis
Copy link
Copy Markdown

Summary

Fixes #3220.

When a module uses export * as NS from '...', its internal names are bound under the NS namespace (i.e. NS.A, NS.B), not re-exported into the flat namespace of the current module. However, the ExportMap builder was unconditionally adding the dependency to exportMap.dependencies even for namespaced wildcard re-exports. Since dependencies is iterated as flat star-exports in ExportMap.forEach, this caused the export rule to see the internal names (e.g. A, B) as if they were directly re-exported — leading to false-positive "duplicate identifier" errors.

Example that was incorrectly reported as an error:

// AB.ts
export type A = {};
export type B = {};

// ABFeature.ts
export type * as AB from "./AB";  // A and B are under AB.*, not flat

// foo.ts
export type A = {};

// index.ts (was incorrectly flagged: "Multiple exports of name 'A'")
export * from "./ABFeature";
export * from "./foo";

Root Cause

In /src/exportMap/visitor.js, ExportAllDeclaration always added the getter to this.exportMap.dependencies. For export * as NS from '...', this is wrong — the module is aliased as a namespace, not star-re-exported. The namespace binding is correctly handled separately by processSpecifier.

Fix

Only add to dependencies when there is no exported alias on the ExportAllDeclaration node. When astNode.exported is set, it's a namespace re-export handled by processSpecifier and should not be added to flat star-export dependencies.

Test Plan

  • Added fixture files: tests/files/issue-3220-namespace-re-export/{AB.ts,ABFeature.ts,foo.ts}
  • Added a valid test case in the TypeScript context of tests/src/rules/export.js that re-exports a file containing export type * as AB from "./AB" alongside another file exporting type A — previously this triggered a false positive, now it passes cleanly
  • All 3013 existing tests continue to pass

🤖 Generated with Claude Code

…espace

When a module uses `export * as NS from '...'`, the re-exported module's
internal names are namespaced under NS (e.g. NS.A), NOT re-exported into
the flat namespace. Previously, `captureDependency` was adding such modules
to `exportMap.dependencies`, which are iterated as flat star-exports.
This caused the `export` rule to incorrectly report duplicate identifiers
when a parent module did `export * from` a file containing `export * as NS`.

Fix: in `ExportAllDeclaration` visitor, only add the getter to `dependencies`
when there is no `exported` alias. When `astNode.exported` is present, the
binding is a namespace alias handled by `processSpecifier`, not a flat re-export.

Fixes import-js#3220

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Namespaced exports reported as duplicate identifiers

1 participant