Skip to content

feat: add the no-wildcard-exports rule - #252

Open
Gaic4o wants to merge 2 commits into
feature-sliced:masterfrom
Gaic4o:feat/no-wildcard-exports
Open

feat: add the no-wildcard-exports rule#252
Gaic4o wants to merge 2 commits into
feature-sliced:masterfrom
Gaic4o:feat/no-wildcard-exports

Conversation

@Gaic4o

@Gaic4o Gaic4o commented Aug 25, 2026

Copy link
Copy Markdown
Member

Background

Added a no-wildcard-exports rule that detects wildcard re-exports in public APIs.

It reports the following patterns:

export * from "./foo";
export type * from "./foo";
export * as foo from "./foo";
export type * as foo from "./foo";

Explicit re-exports are still allowed:

export { foo } from "./foo";
export { foo as bar } from "./foo";

To support this, _language-tools was refactored to analyze imports and re-exports together and reuse the same FS cache. The behavior of existing import-based rules remains unchanged.

@changeset-bot

changeset-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3074622

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@feature-sliced/steiger-plugin Minor
steiger Patch
@steiger/integration-tests Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Gaic4o
Gaic4o marked this pull request as draft August 25, 2026 10:37

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like how we can add many new rules now using tree-sitter, but I don't think adding random flags and queries into extractors is the way to go. As this API was created specifically for getting imports only, and it doesn't really scale up to exports (especially with wildcards and namespaces). I propose we refactor this part a bit first to make sure that it handles both imports and exports simultaneously, and then add export-based rules on top of it. (this is also the case for #251)

  1. make extractDependencies return something like
function extractDependencies(): Statement[]

// I'm not sure if the types are correct, need to veryfy how wildcards and namespaces work together
// this also doesn't take into account import renaming and import attributes
type Statement = Import | Export;
interface Import {
  specifier: string
  path: string;
}
interface Export {
  namespace?: string
  specifier: string
  path: string
}
  1. save all import/export information back to the FS cache so we don't have to re-parse the file
  2. add framework-specific logic for exports: for example, Vue files with the setup attribute by default have one implicit default export (I believe this is also the case for svelte)
  3. (optionally) change the querying options for the extractDependencies so we don't have to add too much filtering logic into the rules

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve updated the implementation based on your feedback, and namespace re-exports are now reported by this rule as well.

One thing I noticed while working on this is that issue #5 currently lists the following as an example that should pass:

export * as positions from "./tooltip-positions";

This seems to conflict with the direction of the current review. For now, I’ve followed the current review and included namespace re-exports in the rule, but could you confirm whether this is the intended behavior?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also looked into the framework specific implicit exports you mentioned. To implement this properly, I think I would need to spend some additional time looking into and verifying the behavior of Vue, Svelte.

Would you prefer to include this in the scope of this PR as well, or would it be better to keep this PR focused on the shared analysis structure and handle framework-specific implicit exports separately in a follow up?

/**
* Find the wildcard re-exports (`export * from`) in a file.
*
* Namespace re-exports (`export * as ns from`) are not reported. They add one name to the module's

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be a bit destructive; for example this file will be considered a valid public API file, while not providing any of contract/abstraction

// index.ts
export * as ui from "./ui";
export * as model from "./model";
export * as api from "./api";

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

export * as foo from "./foo";
export type * as foo from "./foo";

After hearing your feedback, I think it would be better to handle this part as well. Thank you for the review.

@Gaic4o
Gaic4o marked this pull request as ready for review September 1, 2026 03:10
@Gaic4o Gaic4o changed the title [WIP] feat: add the no-wildcard-exports rule feat: add the no-wildcard-exports rule Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants