Skip to content

fix: scan default class exports as default imports#544

Open
pupuking723 wants to merge 2 commits into
unjs:mainfrom
pupuking723:fix/default-class-scan-import
Open

fix: scan default class exports as default imports#544
pupuking723 wants to merge 2 commits into
unjs:mainfrom
pupuking723:fix/default-class-scan-import

Conversation

@pupuking723

@pupuking723 pupuking723 commented Jun 12, 2026

Copy link
Copy Markdown

Fixes #541.

mlly.findExports() reports a named default class declaration twice: once as the real default export and once as a declaration named after the class. scanExports() then registered both imports, and the later dedupe step could keep the named import instead of the default import.

This skips declaration entries that come from export default ... so export default class MyClass {} is scanned as:

import MyClass from './MyClass.js'

instead of:

import { MyClass } from './MyClass.js'

Verification:

  • pnpm exec vitest run test/scan-dirs.test.ts
  • pnpm test -- --run
  • pnpm lint
  • pnpm typecheck
  • pnpm build
  • git diff --check

pnpm build completed successfully with the existing Browserslist database warning.

Summary by CodeRabbit

  • Bug Fixes
    • Corrected directory export scanning for default-export class declarations to avoid duplicate or incorrect import/export entries.
  • Tests
    • Added coverage for default-exported classes to ensure only the default import is recorded and the class isn’t additionally registered as a named export.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 92e99890-6b13-4873-b51c-d50259502cf3

📥 Commits

Reviewing files that changed from the base of the PR and between fc44172 and 8df82a5.

📒 Files selected for processing (1)
  • test/scan-dirs.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/scan-dirs.test.ts

📝 Walkthrough

Walkthrough

This PR fixes incorrect import generation for default class declarations. The scanExports function now skips mlly-generated declaration-type export entries that represent default exports, preventing spurious named export entries. A new test fixture and case validate that export default class MyClass is correctly reported as a default import only.

Changes

Default Class Declaration Export Handling

Layer / File(s) Summary
Skip spurious default declaration exports
src/node/scan-dirs.ts, test/fixtures/default-class/MyClass.js, test/scan-dirs.test.ts
scanExports now skips mlly-generated 'declaration'-type exports whose code starts with 'export default ', preventing them from being processed as named exports. A new fixture and test case validate that default class declarations produce only a default import entry, not spurious named imports.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops through exports bright, 🐰
Default classes were handled not right,
Now mlly's duplicates skip on by,
One import true, no false alibi! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: scan default class exports as default imports' clearly and specifically summarizes the main change: modifying how default class exports are scanned to produce default imports instead of named imports.
Linked Issues check ✅ Passed The pull request successfully addresses issue #541 by modifying scanExports to skip declaration entries where exp.type is 'declaration' and code begins with 'export default', preventing duplicate named imports and ensuring default class exports are correctly scanned as default imports.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the default class export scanning issue: the core fix in scan-dirs.ts, a test fixture for default class exports, and a test case validating the correct behavior. No out-of-scope changes were introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
test/scan-dirs.test.ts (1)

304-313: ⚡ Quick win

Tighten this regression test to assert exact output.

On Line 304-313, the test checks include/exclude conditions but still passes if extra exports are emitted. Assert exact equality to a single-item result to lock the behavior.

Suggested test tightening
-    expect(exports).toContainEqual({
-      name: 'default',
-      as: 'MyClass',
-      from: filepath,
-    })
-    expect(exports).not.toContainEqual({
-      name: 'MyClass',
-      as: 'MyClass',
-      from: filepath,
-    })
+    expect(exports).toEqual([
+      {
+        name: 'default',
+        as: 'MyClass',
+        from: filepath,
+      },
+    ])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/scan-dirs.test.ts` around lines 304 - 313, The test currently uses
expect(exports).toContainEqual(...) and expect(...).not.toContainEqual(...)
which allows extra entries; tighten it to assert exact output by replacing those
two assertions with a single strict equality/assertion that exports equals
exactly an array with one object { name: 'default', as: 'MyClass', from:
filepath } (i.e., assert deep equality of the exports array to that single-item
array) so no extra exports can be present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/scan-dirs.test.ts`:
- Around line 304-313: The test currently uses
expect(exports).toContainEqual(...) and expect(...).not.toContainEqual(...)
which allows extra entries; tighten it to assert exact output by replacing those
two assertions with a single strict equality/assertion that exports equals
exactly an array with one object { name: 'default', as: 'MyClass', from:
filepath } (i.e., assert deep equality of the exports array to that single-item
array) so no extra exports can be present.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9a4eeaa8-92e4-455f-8fbf-2a074ccc5376

📥 Commits

Reviewing files that changed from the base of the PR and between e3c4752 and fc44172.

📒 Files selected for processing (3)
  • src/node/scan-dirs.ts
  • test/fixtures/default-class/MyClass.js
  • test/scan-dirs.test.ts

@GrantGryczan

Copy link
Copy Markdown

Since this is an issue caused by a bad upstream change (unjs/mlly#320), I'd recommend instead merging unjs/mlly#354 (which reverts that change) and, when ready, #542 (which re-fixes the issue the original bad change was intended to fix). I haven't looked into this too in-depth, so I could be wrong, but I assume this fix would be considered more of a workaround for the upstream problem rather than a sound solution to the underlying problem.

@pupuking723

Copy link
Copy Markdown
Author

Thanks, that makes sense. I will wait for maintainers to decide whether this local guard is still useful after the mlly fix path.

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.

export default class is always imported wrong

2 participants