Skip to content

Conversation

ndelangen
Copy link
Member

@ndelangen ndelangen commented Sep 25, 2025

What I did

This ensures 2 things:

  1. the upgrade command does not fail when trying to load an faux-ESM file
    The work around is: we create a temp copy of the main config file, prepend a compat-banner, load and then delete it.
  2. add an auto-migration to turn the faux ESM file into valid ESM-file by adding a header adding a reference to require

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-32558-sha-aadcab7f. Try it out in a new sandbox by running npx [email protected] sandbox or in an existing project with npx [email protected] upgrade.

More information
Published version 0.0.0-pr-32558-sha-aadcab7f
Triggered by @ndelangen
Repository storybookjs/storybook
Branch norbert/sb10-upgrade-with-require-in-main
Commit aadcab7f
Datetime Thu Sep 25 13:47:52 UTC 2025 (1758808072)
Workflow run 18009620740

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=32558

Summary by CodeRabbit

  • New Features

    • CLI automigrate can detect ESM main configs that use legacy require and offer/apply a compatibility banner to restore compatibility.
  • Bug Fixes

    • Added a temporary compatibility fallback to avoid startup failures when require is not available while loading the main config.
  • Tests

    • Added tests for detection, banner insertion, dry-run behavior, and edge cases.

Copy link

coderabbitai bot commented Sep 25, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Added a runtime fallback in loadMainConfig to handle "require is not defined" errors by reading the main config, detecting whether a compatibility banner is already present, and when absent creating a temporary file that prepends an ES-module-compatible header (providing __filename, __dirname, and a require shim via createRequire), dynamically importing the temp file, and deleting it; if the banner exists the original error is rethrown. Introduced an automigrate fix fix-faux-esm-require (check/prompt/run), companion helpers for detecting ESM and require usage and generating the banner (containsESMUsage, containsRequireUsage, hasRequireBanner, getRequireBanner, bannerComment), tests for the fix, added the fix to the fixes index, and removed an unused jscodeshift import in one test. No public API signature changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Caller as Caller
  participant Loader as loadMainConfig
  participant FS as FS (readFile/writeFile/rm)
  participant Node as Node Runtime (import/eval)

  Caller->>Loader: loadMainConfig(mainPath)
  activate Loader
  Loader->>Node: dynamic import(mainPath)
  alt Import succeeds
    Node-->>Loader: module
    Loader-->>Caller: return module
  else Error includes "require is not defined"
    Note right of Loader #f6f8ff: Read main file and\ncheck for existing banner
    Loader->>FS: readFile(mainPath)
    FS-->>Loader: originalContent
    alt Banner already present
      Loader-->>Caller: throw MainFileEvaluationError
    else Banner absent
      Note right of Loader #e8f5e9: Create header with __filename,\n__dirname, and createRequire shim
      Loader->>FS: writeFile(tempPath = mainPath + ".tmp.<ext>", modifiedContent)
      FS-->>Loader: ok
      Loader->>Node: dynamic import(tempPath)
      Node-->>Loader: module
      Loader->>FS: rm(tempPath)
      FS-->>Loader: ok
      Loader-->>Caller: return module
    end
  else Other error
    Loader-->>Caller: propagate error
  end
  deactivate Loader
Loading
sequenceDiagram
  autonumber
  participant CLI as Automigrate CLI
  participant Fix as fix-faux-esm-require
  participant FS as FS (readFile/writeFile)

  CLI->>Fix: check({ mainConfigPath })
  alt no path / not ESM / no require / already bannered
    Fix-->>CLI: null
  else applicable
    Fix-->>CLI: { storybookVersion, opts }
    CLI->>Fix: prompt()
    Fix-->>CLI: user message
    CLI->>Fix: run({ dryRun, mainConfigPath })
    alt dryRun
      Fix-->>CLI: report (no file write)
    else apply
      Fix->>FS: readFile(mainConfigPath)
      FS-->>Fix: content
      Fix->>FS: writeFile(mainConfigPath, bannerComment + getRequireBanner() + content)
      FS-->>Fix: ok
      Fix-->>CLI: applied
    end
  end
Loading

Suggested labels

maintenance, core

Suggested reviewers

  • shilman

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the key change by indicating that the auto-migration for SB10 now properly handles main configuration files containing require. It’s concise, clear, and directly reflects the PR’s primary purpose without extraneous detail.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch norbert/sb10-upgrade-with-require-in-main

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

Copy link

nx-cloud bot commented Sep 25, 2025

View your CI Pipeline Execution ↗ for commit f635045

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 50s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-26 11:37:53 UTC

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)

3-11: Remove unused import loadMainConfig.

Now that readConfig is used, loadMainConfig is unused in this module.

Apply:

   getStorybookInfo,
-  loadMainConfig,
   rendererPackages,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1a31c48 and 24f1e61.

📒 Files selected for processing (2)
  • code/lib/cli-storybook/src/automigrate/fixes/index.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
code/lib/cli-storybook/src/automigrate/fixes/index.ts (1)
code/lib/cli-storybook/src/automigrate/fixes/wrap-getAbsolutePath.ts (1)
  • wrapGetAbsolutePath (24-84)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)
code/core/src/csf-tools/ConfigFile.ts (1)
  • ConfigFile (147-1160)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)

207-230: updateMainConfig flow LGTM.

Using readConfig/writeConfig with the ConfigFile callback is consistent with other fixes and safely guarded with logging.

code/lib/cli-storybook/src/automigrate/fixes/index.ts (1)

22-39: No ordering dependencies found; moving wrapGetAbsolutePath first is safe.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24f1e61 and 2e9a5c9.

📒 Files selected for processing (1)
  • code/core/src/common/utils/load-main-config.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/core/src/common/utils/load-main-config.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/core/src/common/utils/load-main-config.ts
🧬 Code graph analysis (1)
code/core/src/common/utils/load-main-config.ts (2)
scripts/utils/tools.ts (1)
  • dedent (118-118)
code/frameworks/svelte-vite/src/plugins/generateDocgen.ts (2)
  • readFile (276-287)
  • writeFile (387-389)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/core/src/common/utils/load-main-config.ts (1)

1-1: LGTM on fs/promises usage

Importing readFile/writeFile from node:fs/promises is appropriate for the async I/O below.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
code/core/src/common/utils/load-main-config.ts (2)

51-56: Ensure the temp main file is always cleaned up.

If importModule(modifiedMainPath) throws, we never reach the rm call, so the stray main.tmp..* file lingers in the config directory. Wrap the import in a try/finally and always attempt to delete the temp file (best-effort) to avoid leaving debris around failed runs.

Apply this diff:

-        const out = await importModule(modifiedMainPath);
-        await rm(modifiedMainPath);
-        return out;
+        try {
+          return await importModule(modifiedMainPath);
+        } finally {
+          await rm(modifiedMainPath).catch(() => {});
+        }

52-52: Tidy up the temporary filename.

path.parse().ext already contains the leading dot, so interpolating it as ${name}.tmp.${ext} produces main.tmp..ts. It still works, but tightening it to ${name}.tmp${ext} avoids the awkward double dot and keeps the extension exactly what downstream tooling expects.

Apply this diff:

-        const modifiedMainPath = join(dir, `${name}.tmp.${ext}`);
+        const modifiedMainPath = join(dir, `${name}.tmp${ext}`);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e9a5c9 and 58ca51f.

📒 Files selected for processing (1)
  • code/core/src/common/utils/load-main-config.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/core/src/common/utils/load-main-config.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/core/src/common/utils/load-main-config.ts
🧠 Learnings (1)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to **/*.{ts,tsx} : Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Applied to files:

  • code/core/src/common/utils/load-main-config.ts
🧬 Code graph analysis (1)
code/core/src/common/utils/load-main-config.ts (1)
code/core/src/shared/utils/module.ts (1)
  • importModule (54-81)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/core/src/common/utils/load-main-config.ts (1)

8-8: Fix the ts-dedent import (default export).

ts-dedent only exposes a default export; the named import resolves to undefined at runtime and will trip strict TS configs. Please switch to the default import.

Apply this diff:

-import { dedent } from 'ts-dedent';
+import dedent from 'ts-dedent';

- Introduced `fix-faux-esm-require` utility to handle ESM files with require references.
- Added tests for the new utility to ensure correct behavior in various scenarios.
- Updated main configuration helpers to include functions for ESM detection and require usage checks.
- Removed unused import from `addon-a11y-addon-test.test.ts`.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58ca51f and 414611f.

📒 Files selected for processing (5)
  • code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts (0 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/index.ts (2 hunks)
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/index.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/index.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
code/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

code/**/*.{test,spec}.{ts,tsx}: Place all test files under the code/ directory
Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access mocked functions
Implement mock behaviors in beforeEach blocks
Mock all required dependencies that the test subject uses
Mock implementations should be placed in beforeEach blocks
Each mock implementation should return a Promise for async functions
Mock implementations should match the expected return type of the original function
Use vi.mocked() to access and implement mock behaviors
Mock all required properties and methods that the test subject uses
Avoid direct function mocking without vi.mocked()
Avoid mock implementations outside of beforeEach blocks
Avoid mocking without the spy: true option
Avoid inline mock implementations within test cases
Avoid mocking only a subset of required dependencies
Mock at the highest level of abstraction needed
Keep mock implementations simple and focused
Use type-safe mocking with vi.mocked()
Document complex mock behaviors
Group related mocks together

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
🧠 Learnings (10)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required dependencies that the test subject uses

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of beforeEach blocks

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in beforeEach blocks

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without vi.mocked()

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock implementations should be placed in beforeEach blocks

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
🧬 Code graph analysis (4)
code/lib/cli-storybook/src/automigrate/fixes/index.ts (1)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1)
  • fixFauxEsmRequire (18-68)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (4)
  • containsESMUsage (233-260)
  • hasRequireBanner (275-279)
  • containsRequireUsage (263-272)
  • getRequireBanner (282-292)
code/lib/cli-storybook/src/automigrate/types.ts (1)
  • Fix (52-60)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (2)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1)
  • fixFauxEsmRequire (18-68)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (4)
  • containsESMUsage (233-260)
  • containsRequireUsage (263-272)
  • hasRequireBanner (275-279)
  • getRequireBanner (282-292)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)
scripts/utils/tools.ts (1)
  • dedent (118-118)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (1)
code/lib/cli-storybook/src/automigrate/fixes/index.ts (1)

10-41: New fix wired into automigrations correctly.

Importing and registering fixFauxEsmRequire in allFixes ensures it runs with the rest of the suite. Looks good.

- Updated `containsESMUsage` function to accept only content as an argument, removing file path dependency.
- Enhanced `fixFauxEsmRequire` to streamline checks for ESM syntax and require usage.
- Removed unnecessary `isConfigTypescript` option from `FixFauxEsmRequireRunOptions` as it is no longer needed.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1)

33-33: Remove stray console.log or switch to logger.debug.

Avoid noisy stdout in migrations.

Apply:

-    console.log({ isESM, isWithRequire, isWithBanner });
+    // optional: use logger.debug if needed
+    // logger.debug(`fix-faux-esm-require flags: ${JSON.stringify({ isESM, isWithRequire, isWithBanner })}`);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 414611f and 384cbd0.

📒 Files selected for processing (3)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
code/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

code/**/*.{test,spec}.{ts,tsx}: Place all test files under the code/ directory
Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/spy-mocking.mdc)

**/*.test.{ts,tsx,js,jsx}: Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests
Place all mocks at the top of the test file before any test cases
Use vi.mocked() to type and access mocked functions
Implement mock behaviors in beforeEach blocks
Mock all required dependencies that the test subject uses
Mock implementations should be placed in beforeEach blocks
Each mock implementation should return a Promise for async functions
Mock implementations should match the expected return type of the original function
Use vi.mocked() to access and implement mock behaviors
Mock all required properties and methods that the test subject uses
Avoid direct function mocking without vi.mocked()
Avoid mock implementations outside of beforeEach blocks
Avoid mocking without the spy: true option
Avoid inline mock implementations within test cases
Avoid mocking only a subset of required dependencies
Mock at the highest level of abstraction needed
Keep mock implementations simple and focused
Use type-safe mocking with vi.mocked()
Document complex mock behaviors
Group related mocks together

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
🧠 Learnings (17)
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking only a subset of required dependencies

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Document complex mock behaviors

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid inline mock implementations within test cases

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required dependencies that the test subject uses

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Group related mocks together

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Keep mock implementations simple and focused

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock all required properties and methods that the test subject uses

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mock implementations outside of beforeEach blocks

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Implement mock behaviors in beforeEach blocks

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mock() with the spy: true option for all package and file mocks in Vitest tests

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid mocking without the spy: true option

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Avoid direct function mocking without vi.mocked()

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mocked() to access and implement mock behaviors

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vi.mocked() to type and access mocked functions

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.197Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.197Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use type-safe mocking with vi.mocked()

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
📚 Learning: 2025-09-17T08:11:47.196Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursor/rules/spy-mocking.mdc:0-0
Timestamp: 2025-09-17T08:11:47.196Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Mock implementations should be placed in beforeEach blocks

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
🧬 Code graph analysis (2)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (1)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1)
  • fixFauxEsmRequire (17-71)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (4)
  • containsESMUsage (233-248)
  • containsRequireUsage (251-260)
  • hasRequireBanner (263-267)
  • getRequireBanner (270-280)
code/lib/cli-storybook/src/automigrate/types.ts (1)
  • Fix (52-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (1)

13-22: Add spy: true to vi.mock() per our Vitest policy.

Ensures spies behave correctly with vi.mocked().

Apply:

-vi.mock('node:fs/promises', async (importOriginal) => ({
-  ...(await importOriginal<typeof import('node:fs/promises')>()),
-  readFile: vi.fn(),
-  writeFile: vi.fn(),
-}));
+vi.mock(
+  'node:fs/promises',
+  async (importOriginal) => ({
+    ...(await importOriginal<typeof import('node:fs/promises')>()),
+    readFile: vi.fn(),
+    writeFile: vi.fn(),
+  }),
+  { spy: true }
+);
 
-vi.mock('storybook/internal/csf-tools', async (importOriginal) => ({
-  ...(await importOriginal<typeof import('storybook/internal/csf-tools')>()),
-  readConfig: vi.fn(),
-}));
+vi.mock(
+  'storybook/internal/csf-tools',
+  async (importOriginal) => ({
+    ...(await importOriginal<typeof import('storybook/internal/csf-tools')>()),
+    readConfig: vi.fn(),
+  }),
+  { spy: true }
+);
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)

262-267: Detect both banner phrasings to avoid duplicate header insertions.

Currently only the legacy phrasing is recognized; the fixer writes a different text.

Apply:

 export function hasRequireBanner(content: string): boolean {
-  const comment =
-    '// end of storybook 10 migration assistant header, you can delete the above code';
-  return content.includes(comment);
+  const legacyComment =
+    '// end of storybook 10 migration assistant header, you can delete the above code';
+  const newComment =
+    '// end of storybook 10 migration assistant header, delete this if you are not using require';
+  return content.includes(legacyComment) || content.includes(newComment);
 }
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1)

64-66: Align banner marker with detection logic to prevent duplicates.

Use the same text as hasRequireBanner’s legacy phrase.

Apply:

-    const comment =
-      '// end of storybook 10 migration assistant header, delete this if you are not using require';
+    const comment =
+      '// end of storybook 10 migration assistant header, you can delete the above code';

- Introduced `bannerComment` constant in `mainConfigFile` to standardize the migration assistant header.
- Updated `fix-faux-esm-require` utility to utilize the new `bannerComment` for consistency.
- Simplified test cases to reflect changes in banner handling.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (2)

232-248: Add extension-based ESM detection and optional path param.

Short-circuit on .mjs/.mts/.cjs/.cts and keep content heuristics as fallback. This avoids false negatives/positives and lets callers pass the path when available.

-/** Check if a file is in ESM format based on its content */
-export function containsESMUsage(content: string): boolean {
+/** Check if a file is in ESM format based on its path and/or content */
+export function containsESMUsage(pathOrContent: string, maybeContent?: string): boolean {
+  const content = maybeContent ?? pathOrContent;
+  const filePath = maybeContent ? pathOrContent : undefined;
+  // Prefer decisive detection by extension when path is known
+  if (filePath) {
+    const lower = filePath.toLowerCase();
+    if (lower.endsWith('.mjs') || lower.endsWith('.mts')) return true;
+    if (lower.endsWith('.cjs') || lower.endsWith('.cts')) return false;
+  }
   // For .js/.ts files, check the content for ESM syntax
   // Check for ESM syntax indicators (multiline aware)
   const hasImportStatement =
     /^\s*import\s+/m.test(content) ||
     /^\s*import\s*{/m.test(content) ||
     /^\s*import\s*\(/m.test(content);
   const hasExportStatement =
     /^\s*export\s+/m.test(content) ||
     /^\s*export\s*{/m.test(content) ||
     /^\s*export\s*default/m.test(content);
   const hasImportMeta = /import\.meta/.test(content);
 
   // If any ESM syntax is found, it's likely an ESM file
   return hasImportStatement || hasExportStatement || hasImportMeta;
 }

262-267: Detect both legacy and alternate banner phrasings.

Prevents duplicate headers if an older/newer banner variant already exists.

 /** Check if the file already has the require banner */
 export const bannerComment =
   '// end of storybook 10 migration assistant header, you can delete the above code';
 export function hasRequireBanner(content: string): boolean {
-  return content.includes(bannerComment);
+  const alt =
+    '// end of storybook 10 migration assistant header, delete this if you are not using require';
+  return content.includes(bannerComment) || content.includes(alt);
 }
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)

22-52: Leverage path-aware ESM detection and return isConfigTypescript.

Also passes path to containsESMUsage after helper update.

   async check({ storybookVersion, mainConfigPath }) {
     if (!mainConfigPath) {
       return null;
     }
 
     // Read the raw file content to check for ESM syntax and require usage
     const content = await readFile(mainConfigPath, 'utf-8');
 
-    const isESM = containsESMUsage(content);
+    const isESM = containsESMUsage(mainConfigPath, content);
     const isWithRequire = containsRequireUsage(content);
     const isWithBanner = hasRequireBanner(content);
 
-    logger.debug({ isESM, isWithRequire, isWithBanner });
+    logger.debug({ isESM, isWithRequire, isWithBanner });
 
     // Check if the file is ESM format based on content
     if (!isESM) {
       return null;
     }
 
     // Check if the file already has the require banner
     if (isWithBanner) {
       return null;
     }
 
     // Check if the file contains require usage
     if (!isWithRequire) {
       return null;
     }
 
-    return { storybookVersion };
+    const isConfigTypescript = /\.(ts|mts|cts)$/.test(mainConfigPath);
+    return { storybookVersion, isConfigTypescript };
   },

63-70: Defensive write: skip if banner appeared between check and run.

Avoids double-prepend on concurrent edits.

     const content = await readFile(mainConfigPath, 'utf-8');
+    if (hasRequireBanner(content)) {
+      return;
+    }
     const banner = getRequireBanner();
     const comment = bannerComment;
 
     const newContent = [banner, comment, content].join('\n\n');
 
     await writeFile(mainConfigPath, newContent);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 384cbd0 and 25ab43b.

📒 Files selected for processing (3)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
🧠 Learnings (3)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing

Applied to files:

  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to **/*.{ts,tsx} : Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Applied to files:

  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
🧬 Code graph analysis (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)
scripts/utils/tools.ts (1)
  • dedent (118-118)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (5)
  • containsESMUsage (233-248)
  • containsRequireUsage (251-260)
  • hasRequireBanner (265-267)
  • getRequireBanner (270-280)
  • bannerComment (263-264)
code/lib/cli-storybook/src/automigrate/types.ts (1)
  • Fix (52-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)

269-280: LGTM: banner content is correct and minimal.

code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)

54-56: Prompt copy reads well.


14-16: No need to expose isConfigTypescript in FixFauxEsmRequireRunOptions
FixFauxEsmRequire.check/run neither reads nor acts on TS format, so adding isConfigTypescript has no effect.

Likely an incorrect or invalid review comment.

- Updated `containsRequireUsage` function to check for both `require()` calls and `require.` usage directly in the content, eliminating the need to remove comments.
- Simplified the logic for detecting require usage to improve accuracy.
- Eliminated console.log statement that logged ESM and require detection results, streamlining the function's output for cleaner execution.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (4)

1-4: Use Storybook logger for diagnostics.

We'll log read failures in check(); import the logger.

 import { readFile, writeFile } from 'node:fs/promises';
 
 import { dedent } from 'ts-dedent';
+import { logger } from 'storybook/internal/node-logger';

27-33: Harden check() against FS errors (avoid crashing the automigration).

Gracefully handle unreadable config files and emit a debug line.

-    // Read the raw file content to check for ESM syntax and require usage
-    const content = await readFile(mainConfigPath, 'utf-8');
+    // Read the raw file content to check for ESM syntax and require usage
+    let content: string;
+    try {
+      content = await readFile(mainConfigPath, 'utf-8');
+    } catch (err) {
+      logger.debug({ mainConfigPath, err }, 'fix-faux-esm-require: unable to read main config');
+      return null;
+    }

61-63: Make run() idempotent (re-check banner before writing).

Prevents duplicate headers on repeated runs/TOCTOU scenarios.

     const content = await readFile(mainConfigPath, 'utf-8');
+    if (hasRequireBanner(content)) {
+      return;
+    }
     const banner = getRequireBanner();
     const comment = bannerComment;

65-67: Preserve original EOL style when rewriting the file.

Reduces noisy diffs on Windows checkouts.

-    const newContent = [banner, comment, content].join('\n\n');
+    const eol = content.includes('\r\n') ? '\r\n' : '\n';
+    const newContent = [banner, comment, content].join(`${eol}${eol}`);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aadcab7 and b8c0048.

📒 Files selected for processing (1)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
🧠 Learnings (2)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to **/*.{ts,tsx} : Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
🧬 Code graph analysis (1)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (5)
  • containsESMUsage (233-248)
  • containsRequireUsage (251-256)
  • hasRequireBanner (261-263)
  • getRequireBanner (266-276)
  • bannerComment (259-260)
code/lib/cli-storybook/src/automigrate/types.ts (1)
  • Fix (52-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (2)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)

14-16: Include isConfigTypescript in the result and options; compute it from the path.

Tests and callers expect this flag.

 export interface FixFauxEsmRequireRunOptions {
   storybookVersion: string;
+  isConfigTypescript: boolean;
 }
-    return { storybookVersion };
+    const isConfigTypescript = /\.(ts|mts|cts)$/.test(mainConfigPath);
+    return { storybookVersion, isConfigTypescript };

Also applies to: 49-50


20-20: Docs link verified
Anchor exists and is correct; no update required.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes an issue with Storybook 10 migration when main configuration files contain require statements in faux-ESM format by adding a temporary compatibility workaround and an auto-migration fix.

  • Adds a temporary compatibility flow that retries loading main configuration files with a compatibility banner when require is not defined
  • Introduces an auto-migration (fix-faux-esm-require) that detects ESM files using require and adds a compatibility banner
  • Provides utility functions to detect ESM usage, require usage, and presence of compatibility banners

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts Adds utility functions for detecting ESM usage, require usage, and compatibility banners
code/lib/cli-storybook/src/automigrate/fixes/index.ts Registers the new fix-faux-esm-require auto-migration
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts Implements the auto-migration to add compatibility banners to faux-ESM files
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts Comprehensive test coverage for the new auto-migration
code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts Removes unused jscodeshift import
code/core/src/common/utils/load-main-config.ts Adds temporary compatibility flow to retry loading main config with require banner when needed

Comment on lines +236 to +247
const hasImportStatement =
/^\s*import\s+/m.test(content) ||
/^\s*import\s*{/m.test(content) ||
/^\s*import\s*\(/m.test(content);
const hasExportStatement =
/^\s*export\s+/m.test(content) ||
/^\s*export\s*{/m.test(content) ||
/^\s*export\s*default/m.test(content);
const hasImportMeta = /import\.meta/.test(content);

// If any ESM syntax is found, it's likely an ESM file
return hasImportStatement || hasExportStatement || hasImportMeta;
Copy link
Preview

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

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

[nitpick] The regex patterns for detecting ESM syntax could be simplified and made more robust. Consider combining them into a single regex with alternation: /^\s*(?:import(?:\s+|\s*[{(])|export(?:\s+|\s*[{]|\s*default))/m to reduce code duplication and improve maintainability.

Suggested change
const hasImportStatement =
/^\s*import\s+/m.test(content) ||
/^\s*import\s*{/m.test(content) ||
/^\s*import\s*\(/m.test(content);
const hasExportStatement =
/^\s*export\s+/m.test(content) ||
/^\s*export\s*{/m.test(content) ||
/^\s*export\s*default/m.test(content);
const hasImportMeta = /import\.meta/.test(content);
// If any ESM syntax is found, it's likely an ESM file
return hasImportStatement || hasExportStatement || hasImportMeta;
const esmRegex = /^\s*(?:import(?:\s+|\s*[{(])|export(?:\s+|\s*[{]|\s*default))/m;
const hasESMSyntax = esmRegex.test(content);
const hasImportMeta = /import\.meta/.test(content);
// If any ESM syntax is found, it's likely an ESM file
return hasESMSyntax || hasImportMeta;

Copilot uses AI. Check for mistakes.

Copy link
Contributor

@valentinpalkovic valentinpalkovic left a comment

Choose a reason for hiding this comment

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

Great job! Added some minor comments.

}
if (e.message.includes('require is not defined')) {
logger.info(
'loading main config failed, trying a temporary fix, please ensure the main config is valid ESM'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'loading main config failed, trying a temporary fix, please ensure the main config is valid ESM'
'Loading main config failed, trying a temporary fix. Please ensure the main config is valid ESM'

'loading main config failed, trying a temporary fix, please ensure the main config is valid ESM'
);
const comment =
'// end of storybook 10 migration assistant header, you can delete the above code';
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'// end of storybook 10 migration assistant header, you can delete the above code';
'// end of Storybook 10 migration assistant header, you can delete the above code';


/** Check if the file already has the require banner */
export const bannerComment =
'// end of storybook 10 migration assistant header, you can delete the above code';
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'// end of storybook 10 migration assistant header, you can delete the above code';
'// end of Storybook 10 migration assistant header. You can delete the above code';

return null;
}

return { storybookVersion };
Copy link
Contributor

Choose a reason for hiding this comment

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

Returning true is enough, since storybookVersion isn't really used in the run function.

ndelangen and others added 6 commits September 26, 2025 12:28
…ant header

- Improved the log message in `loadMainConfig` for clarity and consistency.
- Standardized the casing in the migration assistant header comment in `mainConfigFile` for better readability.
- Removed the storybookVersion parameter from the check method, returning true instead of the version.
- Updated type satisfaction to use Fix<true> for improved clarity and consistency.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
code/core/src/common/utils/load-main-config.ts (2)

32-35: Harden error check and refine log message.

Use a regex and case-insensitive match; tighten the log copy.

-    if (e.message.includes('require is not defined')) {
-      logger.info(
-        'Loading main config failed, trying a temporary fix, Please ensure the main config is valid ESM'
-      );
+    if (e.message && /\brequire is not defined\b/i.test(e.message)) {
+      logger.info('Loading main config failed. Applying a temporary compatibility banner. Ensure the main config is valid ESM.');

36-38: Align banner sentinel text with automigration helpers to avoid mismatches.

The helpers use “You can delete…”, while this uses “you can…”. Make them identical to prevent false negatives.

-      const comment =
-        '// end of Storybook 10 migration assistant header, you can delete the above code';
+      const comment =
+        '// end of Storybook 10 migration assistant header, You can delete the above code';
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (3)

232-248: Optional: simplify and strengthen ESM detection.

Consolidate regex and keep import.meta check; keeps behavior while reducing duplication.

-  const hasImportStatement =
-    /^\s*import\s+/m.test(content) ||
-    /^\s*import\s*{/m.test(content) ||
-    /^\s*import\s*\(/m.test(content);
-  const hasExportStatement =
-    /^\s*export\s+/m.test(content) ||
-    /^\s*export\s*{/m.test(content) ||
-    /^\s*export\s*default/m.test(content);
-  const hasImportMeta = /import\.meta/.test(content);
-
-  // If any ESM syntax is found, it's likely an ESM file
-  return hasImportStatement || hasExportStatement || hasImportMeta;
+  const hasESMSyntax = /^\s*(?:import(?:\s+|\s*[{(])|export(?:\s+|\s*[{]|\s*default))/m.test(
+    content
+  );
+  const hasImportMeta = /import\.meta/.test(content);
+  return hasESMSyntax || hasImportMeta;

250-256: Reduce false positives; detect require property usages.

Strip comments/strings and detect both require(…) and require.*.

-export function containsRequireUsage(content: string): boolean {
-  // Check for require() calls
-  const requireCallRegex = /\brequire\(/;
-  const requireDotRegex = /\brequire\./;
-  return requireCallRegex.test(content) || requireDotRegex.test(content);
-}
+export function containsRequireUsage(content: string): boolean {
+  const noComments = content
+    .replace(/\/\*[\s\S]*?\*\//g, '')
+    .replace(/\/\/.*$/gm, '');
+  const noStrings = noComments.replace(/(['"`])(?:\\.|(?!\1)[\s\S])*?\1/g, '');
+  return /\brequire\s*(?:\(|\.)/.test(noStrings);
+}

258-263: Make banner detection resilient to minor text variations (case/wording).

Use a case-insensitive regex to avoid mismatch with loader’s sentinel.

-export const bannerComment =
-  '// end of Storybook 10 migration assistant header, You can delete the above code';
-export function hasRequireBanner(content: string): boolean {
-  return content.includes(bannerComment);
-}
+export const bannerComment =
+  '// end of Storybook 10 migration assistant header, You can delete the above code';
+export function hasRequireBanner(content: string): boolean {
+  return /\/\/\s*end of storybook 10 migration assistant header,\s*you can delete the above code/i.test(
+    content
+  );
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8c0048 and 0c1fb28.

📒 Files selected for processing (3)
  • code/core/src/common/utils/load-main-config.ts (2 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (1 hunks)
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/core/src/common/utils/load-main-config.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/core/src/common/utils/load-main-config.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
🧠 Learnings (3)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to **/*.{ts,tsx} : Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Applied to files:

  • code/core/src/common/utils/load-main-config.ts
  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to test-storybooks/** : Maintain test configurations and assets under test-storybooks/ for Storybook testing

Applied to files:

  • code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to code/**/playwright.config.@(js|ts|mjs|cjs) : Use Playwright 1.52.0 for E2E tests and keep Playwright configuration aligned

Applied to files:

  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts
🧬 Code graph analysis (3)
code/core/src/common/utils/load-main-config.ts (2)
scripts/utils/tools.ts (1)
  • dedent (118-118)
code/core/src/shared/utils/module.ts (1)
  • importModule (54-81)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)
scripts/utils/tools.ts (1)
  • dedent (118-118)
code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.ts (2)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (5)
  • containsESMUsage (233-248)
  • containsRequireUsage (251-256)
  • hasRequireBanner (261-263)
  • getRequireBanner (266-276)
  • bannerComment (259-260)
code/lib/cli-storybook/src/automigrate/types.ts (1)
  • Fix (52-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (4)
code/lib/cli-storybook/src/automigrate/helpers/mainConfigFile.ts (1)

265-276: Ensure ts-dedent is imported as a default in this file.

getRequireBanner uses dedent; confirm the file imports the default export.

Apply at the top of this file (outside the changed hunk):

import dedent from 'ts-dedent';

Based on learnings

code/core/src/common/utils/load-main-config.ts (3)

8-8: Fix ts-dedent import (default export, not named).

Using a named import will be undefined at runtime and fail type checks in strict setups.

Apply:

-import { dedent } from 'ts-dedent';
+import dedent from 'ts-dedent';

Based on learnings


54-56: Ensure temp file is cleaned up even if import fails.

Use try/finally around import; avoid leaking temporary files.

-        const out = await importModule(modifiedMainPath);
-        await rm(modifiedMainPath);
-        return out;
+        let out;
+        try {
+          out = await importModule(modifiedMainPath);
+        } finally {
+          try {
+            await rm(modifiedMainPath);
+          } catch {}
+        }
+        return out;

51-53: Fix temp filename (extra dot before ext) and prefer uniqueness.

${ext} already includes a leading dot. Also reduce collision risk across processes.

-        const { ext, name, dir } = parse(mainPath);
-        const modifiedMainPath = join(dir, `${name}.tmp.${ext}`);
+        const { ext, name, dir } = parse(mainPath);
+        const modifiedMainPath = join(dir, `${name}.tmp.${Date.now()}.${process.pid}${ext}`);

- Removed unnecessary mock parameters from the check method tests.
- Changed assertions to return true instead of the storybookVersion for ESM with require usage detection.
- Simplified test cases for clarity and consistency.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
code/core/src/common/utils/load-main-config.ts (4)

32-36: Harden error detection for "require is not defined".

Use a regex and guard against non-string messages to avoid false negatives.

Apply:

-    if (e.message.includes('require is not defined')) {
+    if (typeof e.message === 'string' && /\brequire is not defined\b/.test(e.message)) {
       logger.info(
         'Loading main config failed, trying a temporary fix, Please ensure the main config is valid ESM'
       );

38-39: Use canonical utf8 encoding token.

Prefer 'utf8' for consistency with Node conventions.

-      const content = await readFile(mainPath, 'utf-8');
+      const content = await readFile(mainPath, 'utf8');

54-60: Don’t let cleanup override the import error; tighten types.

If rm throws in finally, it can mask the real failure. Also avoid an implicit any for out. Return directly with typed value and ignore rm errors.

As per coding guidelines

-        let out;
-        try {
-          out = await importModule(modifiedMainPath);
-        } finally {
-          await rm(modifiedMainPath);
-        }
-        return out;
+        try {
+          const out = (await importModule(modifiedMainPath)) as StorybookConfig;
+          return out;
+        } finally {
+          try {
+            await rm(modifiedMainPath);
+          } catch {
+            // ignore cleanup errors
+          }
+        }

I can also wrap the temp import in a MainFileEvaluationError for consistent UX if you want.


36-41: Idempotency check is OK, consider also detecting prior shims.

You gate on the sentinel comment only. Optionally also skip if content includes createRequire(import.meta.url) to reduce false positives.

-      if (!content.includes(comment)) {
+      if (!content.includes(comment) && !content.includes('createRequire(import.meta.url)')) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c1fb28 and f635045.

📒 Files selected for processing (2)
  • code/core/src/common/utils/load-main-config.ts (2 hunks)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/lib/cli-storybook/src/automigrate/fixes/fix-faux-esm-require.test.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Adhere to ESLint and Prettier rules across all JS/TS source files

Files:

  • code/core/src/common/utils/load-main-config.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Files:

  • code/core/src/common/utils/load-main-config.ts
🧠 Learnings (1)
📚 Learning: 2025-09-25T09:21:27.274Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-25T09:21:27.274Z
Learning: Applies to **/*.{ts,tsx} : Fix type errors and prefer precise typings instead of using any or suppressions, consistent with strict mode

Applied to files:

  • code/core/src/common/utils/load-main-config.ts
🧬 Code graph analysis (1)
code/core/src/common/utils/load-main-config.ts (1)
code/core/src/shared/utils/module.ts (1)
  • importModule (54-81)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (5)
code/core/src/common/utils/load-main-config.ts (5)

1-2: LGTM on new fs/path imports.

Usage aligns with Node ESM and project style.


4-4: LGTM on logger usage.

Good diagnostic message path.


8-8: Verify ts-dedent import style (named vs default).

ts-dedent’s export shape varies by module resolution; ensure the named import works with our bundling/ESM setup. If not, switch to default import.

Given conflicting guidance in prior comments, please confirm with a quick check in our environment. If needed, apply:

-import { dedent } from 'ts-dedent';
+import dedent from 'ts-dedent';

Based on learnings


41-49: LGTM on injected banner content.

Header provides __filename, __dirname, and require via createRequire as intended.


51-53: Fix temp filename (double dot) and add uniqueness to avoid collisions.

parse().ext includes a leading dot; current interpolation yields "main.tmp..ts". Also, make the temp name unique.

-        const { ext, name, dir } = parse(mainPath);
-        const modifiedMainPath = join(dir, `${name}.tmp.${ext}`);
+        const { ext, name, dir } = parse(mainPath);
+        const suffix = `.tmp.${Date.now()}.${process.pid}`;
+        const modifiedMainPath = join(dir, `${name}${suffix}${ext}`);

@ndelangen ndelangen merged commit e14260f into next Sep 26, 2025
57 checks passed
@ndelangen ndelangen deleted the norbert/sb10-upgrade-with-require-in-main branch September 26, 2025 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants