Skip to content

Conversation

@yannbf
Copy link
Member

@yannbf yannbf commented Sep 25, 2025

What I did

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-32565-sha-8f903c5d. 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-32565-sha-8f903c5d
Triggered by @yannbf
Repository storybookjs/storybook
Branch yann/story-inspector
Commit 8f903c5d
Datetime Fri Sep 26 13:38:41 UTC 2025 (1758893921)
Workflow run 18039447022

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=32565

Summary by CodeRabbit

  • New Features

    • Introduced “Story Inspector” addon for Storybook: toggleable toolbar tool that highlights components in the preview (green = has stories, orange = missing stories).
    • Quick actions: navigate to stories, open files in your editor, or auto-create missing stories. Badge shows component counts at a glance.
  • Documentation

    • Added comprehensive README and usage guide covering setup, workflow, detection rules, limitations, and troubleshooting.
  • Tests

    • Added extensive tests for component detection, matching, and build-time injection.
  • Chores

    • Updated configs, dependencies, versions, and build entries to enable the addon.

@yannbf yannbf self-assigned this Sep 25, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

Walkthrough

Adds a new Storybook addon “Story Inspector” with build, runtime, and documentation assets. Introduces a Vite plugin that injects component file-path metadata into JSX. Registers addon entries (manager, preview, preset), a React tool UI, and a hook to scan rendered components, match them to the story index, and emit highlights with context menus. Implements manager-side flows to navigate to stories, open in editor, and create stories programmatically. Wires addon into Storybook config (main.ts, preview.tsx), version map, build system, and package dependencies. Includes tests for the matcher utilities and Vite plugin.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Toolbar as Storybook Toolbar (Tool)
  participant Manager as Addon Manager
  participant Preview as Preview (Addon Decorator/Hook)
  participant Iframe as Preview Iframe (Canvas)
  participant Core as Storybook Core APIs

  User->>Toolbar: Toggle Story Inspector (global)
  Toolbar-->>Preview: Update globals[PARAM_KEY]
  Preview->>Iframe: Scan DOM for [data-sb-component-path]
  Preview->>Core: Request Story Index
  Core-->>Preview: Story Index
  Preview->>Preview: Match components vs. index
  Preview-->>Manager: Emit highlight configs (with/without stories)
  User->>Iframe: Click highlight menu (Navigate / Create / Open in editor)
  Iframe-->>Manager: Event (navigate/create/open)
  alt Navigate to story
    Manager->>Core: selectStory(storyId)
  else Create story
    Manager->>Core: createStory(componentPath)
    Manager->>Core: selectStory(newStoryId) (retry)
    Manager->>Core: fetch argTypes, save defaults
  else Open in editor
    Manager->>Core: openInEditor(filePath)
  end
Loading
sequenceDiagram
  autonumber
  participant Dev as Developer
  participant Vite as Vite (Build)
  participant Plugin as componentPathInjectorPlugin
  participant Bundle as Built Code
  participant Browser as Browser
  participant Iframe as Preview Iframe

  Dev->>Vite: Start Storybook (Vite)
  Vite->>Plugin: transform TSX/JSX (component files)
  Plugin->>Plugin: Inject data-sb-component-path="<relative path>"
  Plugin-->>Vite: Transformed code
  Vite-->>Bundle: Bundle output
  Browser->>Iframe: Render story
  Iframe->>Iframe: Elements carry data-sb-component-path
Loading

Possibly related PRs

Suggested labels

feature request, core

Suggested reviewers

  • kylegach
  • jonniebigodes
  • ndelangen

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The current title “WIP: Story inspector” includes a work-in-progress prefix and is too generic to clearly convey the primary addition of a new Story Inspector addon for Storybook. It does not follow the concise, descriptive style guidelines for a final PR title. Rename the pull request to a concise, descriptive title that omits “WIP:” and clearly states the main change, for example “Add Story Inspector addon to Storybook.”
✅ Passed checks (2 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch yann/story-inspector

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

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: 12

🧹 Nitpick comments (21)
code/addons/story-inspector/USAGE.md (1)

60-69: Clarify “Create story” capability and prerequisites

Spell out that automated story creation requires dev/build integration (and won’t run on hosted Storybook).

-When you click "Create story" on an orange-highlighted component:
-1. The addon automatically creates a new story file
-2. Generates basic story structure with sensible defaults
-3. Navigates you to the newly created story
-4. Shows a success notification
+When you click "Create story" on an orange-highlighted component (in local dev with the preset enabled):
+1. The addon triggers story file creation via the dev integration
+2. Generates a basic story with sensible defaults
+3. Navigates to the newly created story
+4. Shows a success notification
+
+Note: Automated file creation is not available on hosted Storybook builds without write access or the preset.
code/addons/story-inspector/package.json (1)

31-43: Export types for manager/preset entrypoints

Add type declarations for manager and preset to improve DX and TS resolution.

   "exports": {
     ".": {
       "types": "./dist/index.d.ts",
       "default": "./dist/index.js"
     },
-    "./manager": "./dist/manager.js",
+    "./manager": {
+      "types": "./dist/manager.d.ts",
+      "default": "./dist/manager.js"
+    },
     "./package.json": "./package.json",
-    "./preset": "./dist/preset.js",
+    "./preset": {
+      "types": "./dist/preset.d.ts",
+      "default": "./dist/preset.js"
+    },
     "./preview": {
       "types": "./dist/preview.d.ts",
       "default": "./dist/preview.js"
     }
   },
code/addons/story-inspector/README.md (1)

38-42: Align README claims with current behavior.

The manager flow does not yet implement an automatic navigation step after triggering story creation—the new story selection currently races and may silently fail. Until the logic reliably navigates (see manager.tsx comment), please soften the documentation so it doesn’t promise an outcome we don’t yet guarantee.

code/addons/story-inspector/src/components/StoryInspectorTool.tsx (1)

35-49: Guard against inline layout styles.

Relying on inline absolute positioning inside <IconButton> breaks if the host button isn’t position: relative (which isn’t guaranteed). This can misplace or hide the badge in themes that reset button layout.

Move these styles into a class that ensures a positioned container or wrap the badge in a relatively positioned element before applying absolute offsets.

code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts (2)

12-14: Avoid global document reassignment in tests.

Overwriting global.document for the whole module introduces hidden coupling between tests. Prefer stubbing only the members you need (e.g. vi.spyOn(document, 'getElementById')) or use vi.stubGlobal with proper teardown to keep each test isolated.


103-130: Mock DOM objects with DOM-like shape.

mockElement1/2/3 supply only getAttribute, but findComponentsInDOM later reads tagName when generating selectors. Provide a minimal DOM-like object ({ tagName: 'DIV', getAttribute: ... }) so failures surface in tests instead of at runtime.

code/addons/story-inspector/build-config.ts (2)

11-14: Confirm we really want to skip DTS for manager entry.

Turning off type generation for ./manager means downstream TypeScript consumers won’t see declarations for the public manager API. If the entry exports runtime helpers, consider leaving dts on (default) unless there’s a concrete reason to disable it.


21-25: Revisit preset DTS disablement.

The preset is a node entry that likely exports config hooks; disabling declarations makes authoring custom configs harder. Unless we hit a specific DTS bug, we should keep typings available.

code/addons/story-inspector/src/manager.tsx (3)

107-121: Required-arg defaulting is too naive.

Blindly defaulting to null/true/42 produces invalid saves for rich arg shapes (arrays, enums, functions) and often triggers validation errors. Reuse the defaults Storybook already computes (e.g. leverage argType.defaultValue or omit unsatisfied args) instead of guessing values.


149-158: Avoid hard-coded emoji spans in notifications.

Using raw emoji spans bypasses theming and accessibility hooks. Reuse Storybook’s icon components (e.g. Icons) so notifications stay consistent across themes.


170-178: Include actionable error context.

subHeadline currently prints the raw error message, which is often generic. Surface the component path and suggest manual steps (open the modal, check logs) so users aren’t left guessing.

code/addons/story-inspector/src/index.ts (1)

5-5: Rename the re-export to avoid ambiguity with the addon name

Exporting the Vite plugin as storyInspector can be confusing given the addon’s identity. Prefer a clearer name like viteStoryInspectorPlugin.

Apply:

-export { componentPathInjectorPlugin as storyInspector } from './utils/vite-plugin';
+export { componentPathInjectorPlugin as viteStoryInspectorPlugin } from './utils/vite-plugin';
code/addons/story-inspector/src/utils/vite-plugin.ts (4)

12-22: Harden ID filtering: strip Vite query suffixes; avoid Vue/Svelte unless parser supports them

Vite passes IDs with ? query. Also, babelParse here won’t handle Vue/Svelte SFCs. Limit to TSX/JSX by default and normalize ID before extension checks.

Apply:

-  const filter = (id: string) => {
-    // Include React/Vue/Svelte component files
-    const includeExtensions = ['.jsx', '.tsx', '.js', '.ts', '.vue', '.svelte'];
-    const hasIncludedExt = includeExtensions.some((ext) => id.endsWith(ext));
+  const filter = (rawId: string) => {
+    const id = rawId.split('?')[0];
+    // Include React component files by default; expand when dedicated parsers are added
+    const includeExtensions = ['.jsx', '.tsx'];
+    const hasIncludedExt = includeExtensions.some((ext) => id.endsWith(ext));
 
     // Exclude certain patterns
-    const excludePatterns = ['node_modules', '.stories.', '.spec.', '.test.', 'dist', 'build'];
+    const excludePatterns = ['node_modules', '.stories.', '.spec.', '.test.', 'dist', 'build'];
     const isExcluded = excludePatterns.some((pattern) => id.includes(pattern));
 
     return hasIncludedExt && !isExcluded;
   };

If you want .js/.ts support, keep them but rely on isComponentFile to skip non-JSX.


70-74: Normalize paths relative to the monorepo /code/ segment when present; otherwise use cwd-relative

Current logic only strips cwd. Make it robust and cross‑platform.

Apply:

-  const root = process.cwd();
-  let normalizedPath = filePath.replace(root, '');
-  normalizedPath = normalizedPath.startsWith('./') ? normalizedPath : `.${normalizedPath}`;
+  const path = require('node:path');
+  const cwd = process.cwd();
+  const idNoQuery = filePath.split('?')[0];
+  const parts = idNoQuery.split(path.sep);
+  const codeIdx = parts.lastIndexOf('code');
+  let rel =
+    codeIdx >= 0 ? parts.slice(codeIdx + 1).join(path.posix.sep) : path.relative(cwd, idNoQuery);
+  if (!rel.startsWith('.')) rel = `./${rel}`;
+  const normalizedPath = rel.replace(/\\/g, '/');

176-180: Make warnings opt‑in or silenced in tests

Unconditional console.warn can spam logs. Respect a silent option.

Apply:

-    console.warn('Story Inspector: Failed to parse code with AST, skipping transformation:', error);
+    if (!options.silent) {
+      console.warn(
+        'Story Inspector: Failed to parse code with AST, skipping transformation:',
+        error
+      );
+    }

80-164: Avoid any casts by building proper Babel JSX nodes

Use @babel/types builders to create attributes instead of casting objects to any.

Example (outside the shown range):

import * as t from '@babel/types';

// ...
node.attributes.push(
  t.jsxAttribute(t.jsxIdentifier(COMPONENT_PATH_ATTRIBUTE), t.stringLiteral(normalizedPath))
);
code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (1)

131-138: Loosen brittle formatting assertions around type annotations

Babel printing may change whitespace/punctuation across versions. Use regex or more permissive contains to avoid flaky tests.

Apply:

-    expect(result?.code).toContain('FC<React.PropsWithChildren<{layout: string;}>>');
+    expect(result?.code).toMatch(/FC<React\.PropsWithChildren<\{\s*layout:\s*string;?\s*\}>>/);
code/addons/story-inspector/src/hooks/useStoryInspector.ts (2)

97-122: Reduce repeated work when generating per-item selectors

You call generateSelectorsForComponents([component])[0] multiple times. Compute once per component inside the map for readability and perf.

Example:

menu: withStories.map<HighlightMenuItem[]>((component) => {
  const [selector] = generateSelectorsForComponents([component]);
  return [
    { /* ... */, selectors: [selector] },
    { /* ... */, selectors: [selector] },
    { /* ... */, selectors: [selector] },
  ];
}),

130-169: Same selector precompute for withoutStories menu

Mirror the selector precompute to avoid redundant calls.

code/addons/story-inspector/src/utils/story-matcher.ts (2)

60-86: Avoid O(n·m) scans by indexing entries by normalized componentPath

Current find() over Object.values for each component can be costly. Build a map once.

Apply:

-export function checkComponentsAgainstIndex(
-  components: ComponentInfo[],
-  storyIndex: StoryIndex['entries']
-): ComponentInfo[] {
-  const entries = storyIndex || {};
-
-  return components.map((component) => {
-    // Find matching story entries by comparing componentPath
-    const matchingEntry = Object.values(entries).find((entry) => {
-      // Normalize paths for comparison
-      const entryPath = (entry as any).componentPath?.replace(/\\/g, '/');
-      const componentPath = component.componentPath.replace(/\\/g, '/');
-      return entryPath === componentPath;
-    });
+export function checkComponentsAgainstIndex(
+  components: ComponentInfo[],
+  storyIndex: StoryIndex['entries']
+): ComponentInfo[] {
+  const entries = storyIndex || {};
+  const byPath = new Map<string, IndexEntry>();
+  for (const entry of Object.values(entries)) {
+    const p = (entry as any).componentPath?.replace(/\\/g, '/');
+    if (p) byPath.set(p, entry);
+  }
+
+  return components.map((component) => {
+    const componentPath = component.componentPath.replace(/\\/g, '/');
+    const matchingEntry = byPath.get(componentPath);

14-36: Optional: allow injection of a document/root for testing and flexibility

Accepting a root Document (defaulting to the preview iframe doc) would simplify testing and decouple DOM traversal.

Example signature:

export function findComponentsInDOM(rootDoc?: Document): ComponentInfo[] { /* ... */ }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0bcdc29 and ea1fb64.

⛔ Files ignored due to path filters (1)
  • code/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (27)
  • code/.storybook/main.ts (1 hunks)
  • code/.storybook/preview.tsx (2 hunks)
  • code/addons/story-inspector/README.md (1 hunks)
  • code/addons/story-inspector/USAGE.md (1 hunks)
  • code/addons/story-inspector/build-config.ts (1 hunks)
  • code/addons/story-inspector/manager.js (1 hunks)
  • code/addons/story-inspector/package.json (1 hunks)
  • code/addons/story-inspector/preset.js (1 hunks)
  • code/addons/story-inspector/preview.js (1 hunks)
  • code/addons/story-inspector/project.json (1 hunks)
  • code/addons/story-inspector/src/components/StoryInspectorTool.tsx (1 hunks)
  • code/addons/story-inspector/src/constants/index.ts (1 hunks)
  • code/addons/story-inspector/src/hooks/useStoryInspector.ts (1 hunks)
  • code/addons/story-inspector/src/index.ts (1 hunks)
  • code/addons/story-inspector/src/manager.tsx (1 hunks)
  • code/addons/story-inspector/src/preset.ts (1 hunks)
  • code/addons/story-inspector/src/preview.ts (1 hunks)
  • code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts (1 hunks)
  • code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (1 hunks)
  • code/addons/story-inspector/src/utils/story-matcher.ts (1 hunks)
  • code/addons/story-inspector/src/utils/vite-plugin.ts (1 hunks)
  • code/addons/story-inspector/tsconfig.json (1 hunks)
  • code/addons/story-inspector/vitest.config.ts (1 hunks)
  • code/core/src/common/versions.ts (1 hunks)
  • code/core/src/highlight/icons.ts (1 hunks)
  • code/package.json (1 hunks)
  • scripts/build/entry-configs.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/addons/story-inspector/preset.js
  • code/addons/story-inspector/src/constants/index.ts
  • code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
  • code/addons/story-inspector/src/index.ts
  • code/addons/story-inspector/manager.js
  • code/addons/story-inspector/src/utils/story-matcher.ts
  • code/addons/story-inspector/src/utils/vite-plugin.ts
  • code/addons/story-inspector/src/hooks/useStoryInspector.ts
  • code/addons/story-inspector/src/components/StoryInspectorTool.tsx
  • code/addons/story-inspector/build-config.ts
  • code/addons/story-inspector/vitest.config.ts
  • code/addons/story-inspector/preview.js
  • code/core/src/highlight/icons.ts
  • code/core/src/common/versions.ts
  • code/addons/story-inspector/src/preset.ts
  • code/addons/story-inspector/src/preview.ts
  • scripts/build/entry-configs.ts
  • code/addons/story-inspector/src/manager.tsx
  • code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
**/README.md

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

Update relevant README files when making significant changes

Files:

  • code/addons/story-inspector/README.md
**/*.{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/addons/story-inspector/src/constants/index.ts
  • code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
  • code/addons/story-inspector/src/index.ts
  • code/addons/story-inspector/src/utils/story-matcher.ts
  • code/addons/story-inspector/src/utils/vite-plugin.ts
  • code/addons/story-inspector/src/hooks/useStoryInspector.ts
  • code/addons/story-inspector/src/components/StoryInspectorTool.tsx
  • code/addons/story-inspector/build-config.ts
  • code/addons/story-inspector/vitest.config.ts
  • code/core/src/highlight/icons.ts
  • code/core/src/common/versions.ts
  • code/addons/story-inspector/src/preset.ts
  • code/addons/story-inspector/src/preview.ts
  • scripts/build/entry-configs.ts
  • code/addons/story-inspector/src/manager.tsx
  • code/addons/story-inspector/src/utils/__tests__/vite-plugin.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/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
  • code/addons/story-inspector/src/utils/__tests__/vite-plugin.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/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
  • code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts
code/**/tsconfig*.json

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

Keep TypeScript strict mode enabled; do not relax strict compiler options in tsconfig files

Files:

  • code/addons/story-inspector/tsconfig.json
🧠 Learnings (18)
📓 Common learnings
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
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.209Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.
📚 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/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
  • code/addons/story-inspector/project.json
  • code/package.json
  • code/addons/story-inspector/src/utils/__tests__/vite-plugin.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/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.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 only a subset of required dependencies

Applied to files:

  • code/addons/story-inspector/src/utils/__tests__/story-matcher.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/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts
📚 Learning: 2025-09-24T09:39:39.209Z
Learnt from: ndelangen
PR: storybookjs/storybook#32507
File: code/core/src/manager/globals/globals-module-info.ts:25-33
Timestamp: 2025-09-24T09:39:39.209Z
Learning: In Storybook, storybook/actions/decorator is a preview-only entrypoint and should not be included in manager globals configuration. The duplicatedKeys array in code/core/src/manager/globals/globals-module-info.ts is specifically for manager-side externalization, not preview entrypoints.

Applied to files:

  • code/addons/story-inspector/src/index.ts
  • code/addons/story-inspector/preview.js
  • code/addons/story-inspector/src/preview.ts
  • scripts/build/entry-configs.ts
  • code/addons/story-inspector/src/manager.tsx
📚 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/**/tsconfig*.json : Keep TypeScript strict mode enabled; do not relax strict compiler options in tsconfig files

Applied to files:

  • code/addons/story-inspector/tsconfig.json
📚 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,js,jsx} : Adhere to ESLint and Prettier rules across all JS/TS source files

Applied to files:

  • code/addons/story-inspector/tsconfig.json
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/**/*.{test,spec}.{ts,tsx} : Name test files as *.test.ts, *.test.tsx, *.spec.ts, or *.spec.tsx

Applied to files:

  • code/addons/story-inspector/tsconfig.json
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
PR: storybookjs/storybook#32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: In viewport tool code, when using the `useGlobals` hook from storybook/manager-api, the third returned value `storyGlobals` is guaranteed by TypeScript to be defined (not undefined/null), making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/story-inspector/src/hooks/useStoryInspector.ts
  • code/addons/story-inspector/src/components/StoryInspectorTool.tsx
  • code/addons/story-inspector/src/preview.ts
📚 Learning: 2025-09-18T20:51:06.618Z
Learnt from: Sidnioulz
PR: storybookjs/storybook#32458
File: code/core/src/viewport/components/Tool.tsx:38-39
Timestamp: 2025-09-18T20:51:06.618Z
Learning: The useGlobals hook from storybook/manager-api returns a tuple where the third element (storyGlobals) is typed as Globals, not Globals | undefined. This means TypeScript guarantees it's always defined, making the `in` operator safe to use without additional null checks.

Applied to files:

  • code/addons/story-inspector/src/hooks/useStoryInspector.ts
  • code/addons/story-inspector/src/preview.ts
📚 Learning: 2025-09-17T08:11:04.287Z
Learnt from: CR
PR: storybookjs/storybook#0
File: .cursorrules:0-0
Timestamp: 2025-09-17T08:11:04.287Z
Learning: Applies to code/vitest.workspace.ts : Keep and use the Vitest workspace configuration at code/vitest.workspace.ts

Applied to files:

  • code/addons/story-inspector/vitest.config.ts
🧬 Code graph analysis (10)
code/addons/story-inspector/src/utils/__tests__/story-matcher.test.ts (1)
code/addons/story-inspector/src/utils/story-matcher.ts (5)
  • ComponentInfo (5-11)
  • checkComponentsAgainstIndex (60-86)
  • groupComponentsByStoryStatus (89-94)
  • findComponentsInDOM (14-57)
  • generateSelectorsForComponents (97-104)
code/addons/story-inspector/src/utils/story-matcher.ts (3)
code/core/src/types/modules/indexer.ts (2)
  • IndexEntry (86-86)
  • StoryIndex (172-175)
code/addons/story-inspector/src/constants/index.ts (1)
  • COMPONENT_PATH_ATTRIBUTE (6-6)
code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts (1)
  • storyIndex (90-162)
code/addons/story-inspector/src/utils/vite-plugin.ts (2)
code/addons/story-inspector/src/index.ts (1)
  • componentPathInjectorPlugin (5-5)
code/addons/story-inspector/src/constants/index.ts (1)
  • COMPONENT_PATH_ATTRIBUTE (6-6)
code/addons/story-inspector/src/hooks/useStoryInspector.ts (3)
code/core/src/manager-api/root.tsx (3)
  • useGlobals (478-486)
  • useChannel (326-336)
  • useStorybookState (290-293)
code/addons/story-inspector/src/constants/index.ts (4)
  • PARAM_KEY (3-3)
  • EVENTS (13-16)
  • HIGHLIGHT_ID_WITH_STORIES (9-9)
  • HIGHLIGHT_ID_WITHOUT_STORIES (10-10)
code/addons/story-inspector/src/utils/story-matcher.ts (5)
  • ComponentInfo (5-11)
  • findComponentsInDOM (14-57)
  • checkComponentsAgainstIndex (60-86)
  • groupComponentsByStoryStatus (89-94)
  • generateSelectorsForComponents (97-104)
code/addons/story-inspector/src/components/StoryInspectorTool.tsx (4)
code/core/src/manager-api/root.tsx (1)
  • useGlobals (478-486)
code/addons/story-inspector/src/constants/index.ts (1)
  • PARAM_KEY (3-3)
code/addons/story-inspector/src/hooks/useStoryInspector.ts (1)
  • useStoryInspector (24-197)
code/core/src/components/index.ts (2)
  • components (93-93)
  • IconButton (54-54)
code/addons/story-inspector/build-config.ts (1)
scripts/build/utils/entry-utils.ts (1)
  • BuildEntries (18-43)
code/addons/story-inspector/src/preset.ts (2)
code/addons/story-inspector/src/index.ts (1)
  • componentPathInjectorPlugin (5-5)
code/addons/story-inspector/src/utils/vite-plugin.ts (1)
  • componentPathInjectorPlugin (10-53)
code/addons/story-inspector/src/preview.ts (1)
code/addons/story-inspector/src/constants/index.ts (1)
  • PARAM_KEY (3-3)
code/addons/story-inspector/src/manager.tsx (2)
code/addons/story-inspector/src/constants/index.ts (4)
  • ADDON_ID (1-1)
  • TOOL_ID (2-2)
  • PARAM_KEY (3-3)
  • EVENTS (13-16)
code/addons/story-inspector/src/components/StoryInspectorTool.tsx (1)
  • StoryInspectorTool (12-53)
code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (2)
code/addons/story-inspector/src/index.ts (1)
  • componentPathInjectorPlugin (5-5)
code/addons/story-inspector/src/utils/vite-plugin.ts (1)
  • componentPathInjectorPlugin (10-53)
🔇 Additional comments (17)
code/addons/story-inspector/src/constants/index.ts (1)

1-16: LGTM

Consistent IDs and const typing across addon identifiers/events.

code/.storybook/main.ts (1)

108-109: LGTM

Addon is registered in the UI config alongside other core addons.

code/package.json (1)

118-119: LGTM; build and version wiring confirmed
Entry configs (scripts/build/entry-configs.ts) and core version map (core/src/common/versions.ts) include '@storybook/addon-story-inspector'.

code/core/src/highlight/icons.ts (1)

2-5: Confirm new icon usage or remove dead entries
No references to plus or edit detected; validate they’re consumed/rendered as intended or remove them.

code/.storybook/preview.tsx (2)

15-15: Import of inspector addon is correct.

Matches the pattern used by other addons in this file.


410-411: Preview-side registration LGTM
@storybook/addon-story-inspector is present in code/.storybook/main.ts, so the preset/Vite plugin will run.

scripts/build/entry-configs.ts (2)

14-16: New import is correct path-wise.

No issues.


98-99: Naming consistency verified across build entry, versions map, and package name.

code/addons/story-inspector/project.json (1)

1-31: Approve NX target wiring: yarn prep and yarn check scripts are defined in package.json.

code/core/src/common/versions.ts (1)

9-9: Approve version map entry
Entry in versions.ts matches the package.json version (10.0.0-beta.6).

code/addons/story-inspector/preset.js (1)

1-1: Verify build output for story-inspector preset

package.json exports "./preset": "./dist/preset.js", but code/addons/story-inspector/dist/preset.js isn’t present. Ensure the build produces and includes this artifact.

code/addons/story-inspector/manager.js (1)

1-1: Approve CJS re-export wrapper
package.json exports include ./manager./dist/manager.js, consistent with other addons.

code/addons/story-inspector/src/preview.ts (1)

29-31: Initial globals should mirror a boolean toggle.

Once the parameter is a boolean, keep initialGlobals aligned—no change needed, but double-check after adjusting the parameter so both exports stay consistent.

code/addons/story-inspector/src/index.ts (2)

7-7: Double-check default export shape for preview annotations

Returning definePreviewAddon(addonAnnotations) is fine if consumers expect a function default export. Ensure this matches how other addons in this repo register preview annotations.


1-1: definePreviewAddon import is valid
definePreviewAddon is exported in code/core/src/csf/csf-factories.ts and re-exported from code/core/src/csf/index.ts, so import { definePreviewAddon } from 'storybook/internal/csf' will resolve correctly.

code/addons/story-inspector/src/utils/__tests__/vite-plugin.test.ts (2)

175-190: Verify path normalization expectation aligns with plugin behavior

After implementing code-directory-relative normalization, this should pass. If not, adjust either the plugin (preferred) or the expectation to match the agreed strategy.


6-11: LGTM: plugin meta

Name and enforce flags are correct for a pre-transform Vite plugin.

@@ -0,0 +1 @@
module.exports = require('./dist/preview');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

CJS re-export wrapper LGTM.

Preview entry correctly proxies to dist/preview.

Confirm the exports map and dist artifact exist:


🏁 Script executed:

#!/bin/bash
jq -r '.exports?"./preview"' code/addons/story-inspector/package.json
rg -n "dist/preview" -g code/addons/story-inspector -S

Length of output: 318


🏁 Script executed:

#!/bin/bash
# Verify "./preview" export entry
jq -r '.exports["./preview"]?' code/addons/story-inspector/package.json
# List any preview files in dist
ls -l code/addons/story-inspector/dist/preview*

Length of output: 159


🏁 Script executed:

#!/bin/bash
echo "Dist directory listing:"
ls -R code/addons/story-inspector/dist || echo "dist directory absent"
echo "Searching for built preview files:"
rg -nE "preview\\.(js|d\\.ts|cjs|mjs)$" -g "code/addons/story-inspector/**"

Length of output: 557


Add missing dist/preview.js (and types) before proxying
Export map defines "./preview"./dist/preview.js / preview.d.ts, but no code/addons/story-inspector/dist/preview.* files exist. Run the build and commit the generated artifacts.

🤖 Prompt for AI Agents
In code/addons/story-inspector/preview.js around line 1, the file is proxying to
./dist/preview but the built artifacts (dist/preview.js and preview.d.ts) are
missing; run the package build script (e.g., npm/yarn build or the specific
build command in the package.json) to generate dist/preview.js and
dist/preview.d.ts, add those generated files to the repository (git add/commit),
ensure .gitignore does not exclude them, and verify the package.json export map
correctly points to ./dist/preview.js and preview.d.ts so the proxy require
resolves.

Comment on lines +43 to +45
const foundComponents = findComponentsInDOM();
const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index as any);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Passing the full StoryIndex instead of entries map

checkComponentsAgainstIndex expects StoryIndex['entries'], but index is the whole object. This prevents any matches.

Apply:

-    const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index as any);
+    const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index.entries);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const foundComponents = findComponentsInDOM();
const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index as any);
const foundComponents = findComponentsInDOM();
const componentsWithStoryStatus = checkComponentsAgainstIndex(foundComponents, index.entries);
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/hooks/useStoryInspector.ts around lines 43 to
45, the call passes the entire StoryIndex object to checkComponentsAgainstIndex
which expects the entries map; change the second argument to index.entries (or
properly typed as index.entries as Record<string, StoryIndexEntry> / any) so
checkComponentsAgainstIndex receives the entries map and can match components
correctly.

Comment on lines +52 to +53
const currentStoryEntry = index[currentStoryId];

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: Accessing current story entry from index directly

index is a StoryIndex; entries are under index.entries.

Apply:

-      const currentStoryEntry = index[currentStoryId];
+      const currentStoryEntry = index.entries[currentStoryId];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const currentStoryEntry = index[currentStoryId];
const currentStoryEntry = index.entries[currentStoryId];
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/hooks/useStoryInspector.ts around lines
52-53, the code reads the current story entry from index using
index[currentStoryId] but index is a StoryIndex whose entries are under
index.entries; change the access to read from index.entries (e.g.,
index.entries[currentStoryId] or the appropriate lookup on entries) and handle
the case where index or index.entries may be undefined/null before accessing to
avoid runtime errors.

Comment on lines +20 to +22
api.on('storybook/navigate-to-story', (storyId: string) => {
api.selectStory(storyId);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use the payload object when handling navigation.

The highlight menu emits { storyId }, but this handler treats the payload as a string—selectStory ends up receiving { storyId: … }, so navigation silently fails. Destructure the payload before calling selectStory.

Apply this diff:

-  api.on('storybook/navigate-to-story', (storyId: string) => {
-    api.selectStory(storyId);
+  api.on('storybook/navigate-to-story', ({ storyId }: { storyId: string }) => {
+    api.selectStory(storyId);
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
api.on('storybook/navigate-to-story', (storyId: string) => {
api.selectStory(storyId);
});
api.on('storybook/navigate-to-story', ({ storyId }: { storyId: string }) => {
api.selectStory(storyId);
});
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/manager.tsx around lines 20 to 22, the api.on
handler treats the event payload as a string but the emitter sends an object {
storyId }, so api.selectStory receives the whole object and navigation fails;
update the handler to accept the payload object (e.g., ({ storyId }) or payload
and destructure) and pass the extracted storyId to api.selectStory.

Comment on lines +24 to +26
api.on('storybook/open-editor', (file: string) => {
api.openInEditor({ file });
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Supply file data when opening the editor.

The highlight menu never sends a payload for storybook/open-editor, so file is undefined and openInEditor becomes a no-op. Pass the component path through eventData when emitting the menu item so the handler can forward it.

🤖 Prompt for AI Agents
In code/addons/story-inspector/src/manager.tsx around lines 24 to 26, the
'storybook/open-editor' handler expects a string parameter but the highlight
menu emits no payload so file is undefined; change the handler signature to
accept the eventData object (e.g. (eventData) => ...) and call api.openInEditor
with eventData.file (or the correct property containing the component path).
Also update the menu emitter elsewhere to include the component path in
eventData when emitting 'storybook/open-editor' so the handler receives and
forwards the file path to api.openInEditor.

Comment on lines +5 to +18
export const viteFinal = async (
config: import('vite').UserConfig,
options: Options
): Promise<import('vite').UserConfig> => {
const plugins = config.plugins || [];

// Add our component path injector plugin
plugins.push(componentPathInjectorPlugin(options));

return {
...config,
plugins,
};
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Normalize Vite plugins to an array to avoid runtime errors.

config.plugins can be a single PluginOption or nested arrays; pushing to it directly risks type errors and crashes.

Apply this diff:

@@
-import type { Options } from 'storybook/internal/types';
+import type { Options } from 'storybook/internal/types';
+import type { PluginOption, UserConfig } from 'vite';
@@
-export const viteFinal = async (
-  config: import('vite').UserConfig,
-  options: Options
-): Promise<import('vite').UserConfig> => {
-  const plugins = config.plugins || [];
-
-  // Add our component path injector plugin
-  plugins.push(componentPathInjectorPlugin(options));
-
-  return {
-    ...config,
-    plugins,
-  };
-};
+export const viteFinal = async (
+  config: UserConfig,
+  options: Options
+): Promise<UserConfig> => {
+  const existing = config.plugins;
+  const normalized: PluginOption[] = Array.isArray(existing)
+    ? [...existing]
+    : existing
+      ? [existing]
+      : [];
+
+  const inspector = componentPathInjectorPlugin(options);
+  // Ensure earliest execution within 'pre' group
+  return {
+    ...config,
+    plugins: [inspector, ...normalized],
+  };
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const viteFinal = async (
config: import('vite').UserConfig,
options: Options
): Promise<import('vite').UserConfig> => {
const plugins = config.plugins || [];
// Add our component path injector plugin
plugins.push(componentPathInjectorPlugin(options));
return {
...config,
plugins,
};
};
import type { Options } from 'storybook/internal/types';
import type { PluginOption, UserConfig } from 'vite';
export const viteFinal = async (
config: UserConfig,
options: Options
): Promise<UserConfig> => {
const existing = config.plugins;
const normalized: PluginOption[] = Array.isArray(existing)
? [...existing]
: existing
? [existing]
: [];
const inspector = componentPathInjectorPlugin(options);
// Ensure earliest execution within 'pre' group
return {
...config,
plugins: [inspector, ...normalized],
};
};
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/preset.ts around lines 5 to 18,
config.plugins may be undefined, a single PluginOption, or nested arrays;
pushing directly can throw at runtime. Normalize plugins into a flat array first
(treat undefined as [] and a non-array as [value], then flatten nested arrays),
append componentPathInjectorPlugin(options) to that new array, and return the
config with the normalized plugins array (do not mutate the original
config.plugins reference).

Comment on lines +21 to +26
export const parameters = {
[PARAM_KEY]: {
// Default to disabled - users can enable via toolbar
enabled: false,
},
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Match parameters to the global shape.

useStoryInspector reads globals[PARAM_KEY] as a boolean. Setting the preview parameter to { enabled: false } populates globals.storyInspector with an object, so !!globals[PARAM_KEY] is always truthy. Initialize the parameter to false (no wrapper object) so the toggle reflects the toolbar state.

Apply this diff:

 export const parameters = {
-  [PARAM_KEY]: {
-    // Default to disabled - users can enable via toolbar
-    enabled: false,
-  },
+  // Default to disabled - users can enable via the toolbar
+  [PARAM_KEY]: false,
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const parameters = {
[PARAM_KEY]: {
// Default to disabled - users can enable via toolbar
enabled: false,
},
};
export const parameters = {
// Default to disabled - users can enable via the toolbar
[PARAM_KEY]: false,
};
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/preview.ts around lines 21 to 26, the preview
parameter sets [PARAM_KEY] to an object ({ enabled: false }) which makes
globals[PARAM_KEY] an object and always truthy; change the parameter to a
boolean by initializing [PARAM_KEY]: false (you can keep the comment) so
globals.storyInspector is a boolean and the toolbar toggle reflects the actual
state.

* This Vite plugin injects component file path metadata into JSX/TSX elements so they can be
* identified by the story inspector
*/
export function componentPathInjectorPlugin(options?: Options): any {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Type the plugin and remove unused Options; expose a minimal options shape

Return type any hampers type-safety, and Options isn’t used. Type this as a Vite Plugin and allow an optional silent flag to control logging.

Apply:

-export function componentPathInjectorPlugin(options?: Options): any {
+export function componentPathInjectorPlugin(options: { silent?: boolean } = {}): import('vite').Plugin {

Add the import (outside the shown range):

import type { Plugin } from 'vite';
🤖 Prompt for AI Agents
In code/addons/story-inspector/src/utils/vite-plugin.ts around line 10, the
function currently returns any and accepts an unused Options type; replace that
with a properly typed Vite Plugin and a minimal options shape. Add the import
"import type { Plugin } from 'vite';" at top, remove the unused Options type,
define a small local interface (e.g. { silent?: boolean }), and change the
signature to export function componentPathInjectorPlugin(options?: { silent?:
boolean }): Plugin { ... } so logging can be controlled by options.silent and
the function returns a Plugin instead of any.

Comment on lines +3 to +5
"compilerOptions": {
"strict": false
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Don’t disable TypeScript strict mode

Repo guideline: keep strict enabled. Re-enable strict here (or inherit from root).

   "compilerOptions": {
-    "strict": false
+    "strict": true
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"compilerOptions": {
"strict": false
},
"compilerOptions": {
"strict": true
},
🤖 Prompt for AI Agents
In code/addons/story-inspector/tsconfig.json lines 3-5, strict mode is disabled
("strict": false); change this to re-enable TypeScript strict checking by
setting "strict": true or remove the key so the project inherits the root
tsconfig strict setting, and ensure any resulting type errors are fixed or
narrow-scoped with proper type annotations to comply with the repo guideline.

Comment on lines +1 to +8
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
globals: true,
environment: 'node',
},
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Extend the workspace Vitest config instead of diverging per‑package settings

Keep this package aligned with code/vitest.workspace.ts and only override what’s necessary.

Apply:

-import { defineConfig } from 'vitest/config';
+import { defineConfig, mergeConfig } from 'vitest/config';
+import workspace from '../../vitest.workspace';
 
-export default defineConfig({
-  test: {
-    globals: true,
-    environment: 'node',
-  },
-});
+export default mergeConfig(
+  workspace,
+  defineConfig({
+    test: {
+      globals: true,
+      environment: 'node',
+    },
+  })
+);

If any tests touch the DOM, prefer happy-dom/jsdom or per-test overrides. Quick check:


🏁 Script executed:

#!/bin/bash
# Find DOM usage in Story Inspector tests (adjust env if matches are found)
rg -n -C1 --type=ts --type=tsx '\b(document|window|HTMLElement|DOMParser)\b' code/addons/story-inspector/src/utils/__tests__ || true

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Re-run DOM usage check without file-type filters
rg -n -C1 '\b(document|window|HTMLElement|DOMParser)\b' code/addons/story-inspector/src/utils/__tests__ || true

Length of output: 1375


🏁 Script executed:

#!/bin/bash
# Show workspace Vitest config to see default environment
sed -n '1,200p' code/vitest.workspace.ts

Length of output: 1398


Extend workspace Vitest config and override only globals

-import { defineConfig } from 'vitest/config';
+import { defineConfig, mergeConfig } from 'vitest/config';
+import workspace from '../../vitest.workspace';

-export default defineConfig({
-  test: {
-    globals: true,
-    environment: 'node',
-  },
-});
+export default mergeConfig(
+  workspace,
+  defineConfig({
+    test: {
+      globals: true,
+    },
+  })
+);

No need to override environment (defaults to 'node'). Tests mock the DOM manually; if you need a real DOM, switch to happy-dom/jsdom or use per-test overrides.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
environment: 'node',
},
});
import { defineConfig, mergeConfig } from 'vitest/config';
import workspace from '../../vitest.workspace';
export default mergeConfig(
workspace,
defineConfig({
test: {
globals: true,
},
})
);
🤖 Prompt for AI Agents
In code/addons/story-inspector/vitest.config.ts lines 1-8: remove the explicit
environment override and instead rely on the workspace Vitest config; keep only
the globals override. Concretely, delete the environment: 'node' entry so the
file only sets test.globals = true, or, if you need to explicitly inherit/extend
the workspace config, import/merge the workspace Vitest config and override only
the globals field; do not change environment here (use per-test overrides or
switch the workspace config to happy-dom/jsdom if a real DOM is required).

@yannbf yannbf marked this pull request as draft September 25, 2025 20:03
@yannbf yannbf force-pushed the yann/story-inspector branch from ea1fb64 to 968d4d5 Compare September 25, 2025 20:19
@yannbf yannbf force-pushed the yann/story-inspector branch from 43de3bb to 358a2d1 Compare September 26, 2025 11:51
@yannbf yannbf force-pushed the yann/story-inspector branch from 358a2d1 to 8f903c5 Compare September 26, 2025 13:38
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.

3 participants