Skip to content

Conversation

@yannbf
Copy link
Member

@yannbf yannbf commented Oct 13, 2025

Closes #32680

What I did

This PR adds an early exit condition in storyToCsfFactory to skip transformation when no stories are detected, preventing mixed CSF syntax.

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 PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

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

Summary by CodeRabbit

  • Bug Fixes

    • Prevent mixed CSF output by bailing out when no stories can be transformed, returning the original source instead.
    • Improved and clarified warning messages for unsupported or pre-transformed files.
    • Aligned logging behavior for scenarios where no logging should occur.
  • Refactor

    • Streamlined consistency checks to reduce false positives and improve reliability.
  • Tests

    • Added tests for the no-transform bail-out scenario.
    • Updated expectations and snapshots to reflect new logging and transformation behavior.

- Added early exit condition in `storyToCsfFactory` to skip transformation when no stories are detected, preventing mixed CSF syntax.
- Updated tests to verify the new behavior, ensuring proper logging when no stories are transformed.
- Mocked logger's log method for improved test coverage and validation of warning messages.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 13, 2025

📝 Walkthrough

Walkthrough

Adds an early bail-out in story-to-csf-factory to return the original source when no stories are transformed and updates tests accordingly: logger mock now includes log(), expectations adjusted, new test for bail-out behavior, and snapshots updated to include/export A and its transformation to meta.story().

Changes

Cohort / File(s) Summary
Codemod logic: early bail-out and consistency check
code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts
Adds early return when zero stories are transformed (logs warning and returns original source). Streamlines consistency check condition and updates warning message text.
Tests and snapshots for codemod behavior
code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts
Extends logger mock with log(). Adds test asserting bail-out when no stories transform. Adjusts expectations from warn to log in a no-log scenario. Updates test inputs/outputs to export A and expected transformation to meta.story().

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as Caller
  participant Factory as story-to-csf-factory
  participant Parser as Parser/Analyzer
  participant Logger as logger

  Dev->>Factory: transform(source)
  Factory->>Parser: parse + detect stories
  Parser-->>Factory: detectedStoryNames, AST

  rect rgba(200, 230, 255, 0.3)
    note over Factory: Transform pass
    Factory->>Factory: attempt to transform stories<br/>(collect transformedStoryExports)
  end

  alt No stories transformed
    Factory->>Logger: warn("No stories transformed... returning original")
    Factory-->>Dev: original source
  else Some transformed
    alt Inconsistent: transformed count != detected count
      Factory->>Logger: warn("Inconsistent transformation... returning original")
      Factory-->>Dev: original source
    else Consistent
      Factory-->>Dev: transformed source
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch yann/bail-cf-factories-codemod

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

@nx-cloud
Copy link

nx-cloud bot commented Oct 13, 2025

View your CI Pipeline Execution ↗ for commit b1b26aa

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

☁️ Nx Cloud last updated this comment at 2025-10-13 10:11:39 UTC

Copy link
Contributor

@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/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts (1)

242-248: Early bail is correct; avoid warning on already-transformed files (reduce noise).

Current behavior warns even when a file is already fully CSF-factory–converted. Consider silently returning in that case (or logging at info/debug), while keeping warnings for unsupported/partial cases.

Suggested refinement:

   // If no stories were transformed, bail early to avoid having a mixed CSF syntax and therefore a broken indexer.
   if (transformedStoryExports.size === 0) {
-    logger.warn(
-      `Skipping codemod for ${info.path}: no stories were transformed. Either there are no stories, file has been already transformed or some stories are written in an unsupported format.`
-    );
-    return info.source;
+    // Detect "already transformed": every detected story initializer is a `*.story(...)` call.
+    const alreadyTransformedCount = Object.values(csf._storyExports).reduce((acc, decl) => {
+      const init = t.isVariableDeclarator(decl as t.VariableDeclarator)
+        ? (decl as t.VariableDeclarator).init
+        : undefined;
+      return acc +
+        (t.isCallExpression(init) &&
+         t.isMemberExpression(init.callee) &&
+         t.isIdentifier(init.callee.property, { name: 'story' })
+          ? 1
+          : 0);
+    }, 0);
+
+    if (detectedStoryNames.length > 0 && alreadyTransformedCount === detectedStoryNames.length) {
+      // File appears already transformed; return source silently.
+      return info.source;
+    }
+
+    logger.warn(
+      `Skipping codemod for ${info.path}: no stories were transformed. Either there are no stories, file has been already transformed or some stories are written in an unsupported format.`
+    );
+    return info.source;
   }

If you prefer not to add the detection, alternatively lower the log level for the “already transformed” case, and keep warn for “unsupported”/partial conversions.

code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts (1)

681-698: Strengthen logger assertions and leverage global mock clearing

  • Replace vi.mocked(logger.warn).mock.calls[0][0] with expect(logger.warn).toHaveBeenLastCalledWith(...) in both tests.
  • In the “already transformed” case, add expect(logger.warn).not.toHaveBeenCalled().
  • Remove the manual beforeEach(() => vi.clearAllMocks())clearMocks: true is already enabled in your Vitest config.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9a2317 and b1b26aa.

📒 Files selected for processing (2)
  • code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts (9 hunks)
  • code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts (1 hunks)
🧰 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/codemod/helpers/story-to-csf-factory.ts
  • code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.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/codemod/helpers/story-to-csf-factory.ts
  • code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.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/codemod/helpers/story-to-csf-factory.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/codemod/helpers/story-to-csf-factory.test.ts
⏰ 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). (3)
  • GitHub Check: Danger JS
  • GitHub Check: normal
  • GitHub Check: Core Unit Tests, windows-latest
🔇 Additional comments (3)
code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.ts (1)

251-258: Consistency check looks good

The simplified condition precisely guards against mixed CSF by bailing when some detected stories couldn’t be transformed.

code/lib/cli-storybook/src/codemod/helpers/story-to-csf-factory.test.ts (2)

11-16: Logger mock extension is fine

Adding logger.log alongside warn is OK and aligns with production usage.


34-45: Snapshot churn introducing A is expected

Adding a simple story export (A) to exercise transformation paths in snapshots is reasonable and improves coverage.

Also applies to: 50-62, 66-77, 85-98, 107-120, 129-142, 151-165, 193-218, 250-275, 292-301, 368-372, 390-394, 410-412, 431-438, 457-462, 481-486, 506-511, 533-536, 558-561, 583-586, 616-623

@yannbf yannbf merged commit ee0c7a3 into next Oct 15, 2025
60 of 62 checks passed
@yannbf yannbf deleted the yann/bail-cf-factories-codemod branch October 15, 2025 09:32
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.

[Bug]: CSF-factories automigration incorrectly converts CSF1 story files

3 participants