Skip to content

OmniDoc#6552

Merged
ckifer merged 13 commits intomainfrom
omnidoc
Nov 6, 2025
Merged

OmniDoc#6552
ckifer merged 13 commits intomainfrom
omnidoc

Conversation

@PavelVanecek
Copy link
Collaborator

@PavelVanecek PavelVanecek commented Nov 3, 2025

Description

Add scripts that read three different documentations and make sure that they are all in sync.

Even the first trivial tests - all documented components must actually exist - found a problem! The website documents SankeyChart but the actual export from recharts is Sankey. I will fix that in another PR.

Related Issue

#6069

Summary by CodeRabbit

  • New Features

    • Adds automated documentation readers to compare project API, Storybook and built docs.
    • Exposes a consolidated entry of Storybook stories for easier discovery.
  • Tests

    • Adds validation suites that assert documentation and Storybook symbols match the project exports.
    • Adds a dedicated documentation test run to CI and new test projects.
  • Chores

    • Updates lint and test configurations for the new documentation checks.
  • Bug Fixes

    • Guards runtime checks to avoid errors in non-browser environments.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Walkthrough

Adds an omnidoc documentation-consistency feature: a DocReader interface plus three implementations (Project, API, Storybook) with tests; aggregates Storybook stories; updates vitest and CI to run omnidoc tests; adds ts-morph; adjusts ESLint overrides and guards window usage in storybook inspectors.

Changes

Cohort / File(s) Summary
ESLint config
eslint.config.mjs
Adds omnidocOverrides to disable several rules for omnidoc/** and spreads it into the exported config array.
DocReader interface & orchestrating test
omnidoc/DocReader.ts, omnidoc/omnidoc.spec.ts
Adds DocReader interface (getPublicSymbolNames, getPropsOf, getSVGParentOf) and a Vitest suite that compares symbols/props across Project, API, and Storybook readers.
Project doc reader & tests
omnidoc/readProject.ts, omnidoc/readProject.spec.ts
New ProjectDocReader using ts-morph to enumerate exports, extract props (recursive type traversal), and detect SVG parent types; snapshot tests added.
API doc reader & tests
omnidoc/readApiDoc.ts, omnidoc/readApiDoc.spec.ts
New ApiDocReader that reads API docs/allExamples to return public symbols and props; tests with inline snapshots.
Storybook doc reader & tests
omnidoc/readStorybookDoc.ts, omnidoc/readStorybookDoc.spec.ts
New StorybookDocReader with lazy caching that extracts prop keys from Storybook argTypes; tests and snapshots added.
Storybook stories aggregator
storybook/stories/API/allStories.ts
New module re-exporting many story defaults as named exports to provide a single entry of stories.
Vitest & build-test config
vitest.config.mts, deleted scripts/vitest-build.config.ts
Adds two Vitest project entries: omnidoc (omnidoc/**/*.spec.ts[x]) and build-output (scripts tests); removes the old scripts/vitest-build.config.ts file.
CI pipeline
.github/workflows/ci.yml
Adds a CI step "omnidoc - documentation test" to run npm run test-omnidoc in the Build/Test/Pack job.
Dependencies & scripts
package.json
Adds ts-morph dependency and a test-omnidoc script plus updated test-build-output invocation.
Storybook inspector guards
storybook/.../CartesianChartInspector.tsx, storybook/.../PolarChartInspector.tsx
Guard window access with typeof window !== 'undefined' before checking window.location.hostname to avoid SSR/runtime errors.

Sequence Diagram(s)

sequenceDiagram
    participant Test as omnidoc.spec.ts
    participant Project as ProjectDocReader
    participant API as ApiDocReader
    participant Storybook as StorybookDocReader

    Test->>Project: getPublicSymbolNames()
    Project-->>Test: projectSymbols

    Test->>API: getPublicSymbolNames()
    API-->>Test: apiSymbols

    Test->>Storybook: getPublicSymbolNames()
    Storybook-->>Test: storybookSymbols

    Note over Test: Compute diffs (apiSymbols - projectSymbols)<br/>and (storybookSymbols - projectSymbols)
    Test->>Test: expect(missingFromProject).toEqual([])<br/>expect(missingFromStorybook).toEqual([])
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing careful review:
    • omnidoc/readProject.ts: ts-morph integration, recursive type traversal, SVG extraction, handling of intersections and edge cases.
    • Tests/snapshots in omnidoc/*spec.ts: ensure snapshots reflect intended public surface and are not brittle.
    • CI and Vitest project additions: confirm test discovery and runtime config (node vs browser) are correct.
    • ESLint override and storybook window guards for SSR safety.

Suggested labels

enhancement, feature request

Suggested reviewers

  • ckifer

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'OmniDoc' is vague and generic, lacking specificity about what is being added or changed in the changeset. Use a more descriptive title like 'Add documentation sync verification scripts' to clearly convey the main change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description covers the core intent but lacks detail on testing methodology and implementation specifics required by the template.
✨ 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 omnidoc

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

@ckifer
Copy link
Member

ckifer commented Nov 3, 2025

this is craaaazzzy

@PavelVanecek
Copy link
Collaborator Author

Crazy good I hope?

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

🧹 Nitpick comments (1)
omnidoc/readStorybookDoc.ts (1)

36-62: Consider validating the Story suffix assumption.

The implementation assumes all relevant exports in allStories end with "Story" (line 46), but if an export doesn't match this pattern, it will be processed with its original name. This could lead to incorrect component name extraction if non-story exports are accidentally included in allStories.

Consider adding explicit validation:

 // Extract component name from export name (e.g., "AreaStory" -> "Area")
 const componentName = exportName.replace(/Story$/, '');

-if (!componentName || !('argTypes' in storyDefault)) {
+if (!componentName || componentName === exportName || !('argTypes' in storyDefault)) {
   continue;
 }

This ensures that only exports ending with "Story" are processed, making the assumption explicit and preventing silent failures.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a73aa5 and 2af5724.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • eslint.config.mjs (2 hunks)
  • omnidoc/DocReader.ts (1 hunks)
  • omnidoc/omnidoc.spec.ts (1 hunks)
  • omnidoc/readApiDoc.spec.ts (1 hunks)
  • omnidoc/readApiDoc.ts (1 hunks)
  • omnidoc/readProject.spec.ts (1 hunks)
  • omnidoc/readProject.ts (1 hunks)
  • omnidoc/readStorybookDoc.spec.ts (1 hunks)
  • omnidoc/readStorybookDoc.ts (1 hunks)
  • package.json (1 hunks)
  • storybook/stories/API/allStories.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
storybook/**

📄 CodeRabbit inference engine (DEVELOPING.md)

Use Storybook for high-fidelity examples intended for publication; prefer unit or VR tests for low-fidelity cases due to Chromatic limits

Files:

  • storybook/stories/API/allStories.ts
🧠 Learnings (4)
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Write unit tests using Vitest and React Testing Library

Applied to files:

  • omnidoc/readApiDoc.spec.ts
  • omnidoc/readStorybookDoc.spec.ts
📚 Learning: 2025-10-25T07:34:46.558Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-10-25T07:34:46.558Z
Learning: Applies to storybook/** : Use Storybook for high-fidelity examples intended for publication; prefer unit or VR tests for low-fidelity cases due to Chromatic limits

Applied to files:

  • omnidoc/readStorybookDoc.spec.ts
  • omnidoc/readStorybookDoc.ts
  • omnidoc/omnidoc.spec.ts
  • storybook/stories/API/allStories.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : Mock getBoundingClientRect using test/helper/MockGetBoundingClientRect.ts when rendering Recharts components (e.g., Tooltip, Legend, charts)

Applied to files:

  • omnidoc/readStorybookDoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : When testing selectors, verify render counts using the spy and rerenderSameComponent from createSelectorTestCase

Applied to files:

  • omnidoc/readStorybookDoc.spec.ts
🧬 Code graph analysis (7)
omnidoc/readApiDoc.spec.ts (1)
omnidoc/readApiDoc.ts (1)
  • ApiDocReader (7-26)
omnidoc/readApiDoc.ts (1)
omnidoc/DocReader.ts (1)
  • DocReader (1-17)
omnidoc/readStorybookDoc.spec.ts (1)
omnidoc/readStorybookDoc.ts (1)
  • StorybookDocReader (7-67)
omnidoc/readProject.ts (1)
omnidoc/DocReader.ts (1)
  • DocReader (1-17)
omnidoc/readProject.spec.ts (1)
omnidoc/readProject.ts (1)
  • ProjectDocReader (7-196)
omnidoc/readStorybookDoc.ts (1)
omnidoc/DocReader.ts (1)
  • DocReader (1-17)
omnidoc/omnidoc.spec.ts (3)
omnidoc/readProject.ts (1)
  • ProjectDocReader (7-196)
omnidoc/readApiDoc.ts (1)
  • ApiDocReader (7-26)
omnidoc/readStorybookDoc.ts (1)
  • StorybookDocReader (7-67)
⏰ 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: Build, Test, Pack
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
eslint.config.mjs (2)

341-356: LGTM! Well-structured overrides for utility scripts.

The omnidoc overrides are appropriately scoped and follow the existing patterns in the file. The disabled rules are reasonable for utility scripts that process documentation, and the inline comments clearly explain the rationale for each exception.


396-397: Correct placement in the configuration.

The omnidoc overrides are properly spread into the default export at the end of the configuration array, ensuring they take precedence over earlier rules as intended.

omnidoc/readStorybookDoc.ts (1)

1-8: LGTM: Clean implementation structure.

The lazy initialization pattern with a private cache is appropriate for this use case, and the class correctly implements the DocReader interface.

storybook/stories/API/allStories.ts (1)

1-52: LGTM: Clean aggregation of story exports.

This file serves its purpose well as a centralized entry point for all Storybook stories, enabling the documentation consistency checks implemented in this PR.

Minor observation: The naming convention differs between components (PascalCase, lines 1-33, 39-52) and hooks (camelCase, lines 34-38). This distinction is clear and likely intentional to differentiate between component stories and hook stories.

);
}

expect(missingInProject).toEqual([]);
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 3, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix failing omnidoc consistency assertion

Line 30 currently asserts missingInProject is [], but ApiDocReader still returns "SankeyChart" while the code exports "Sankey". As written, this suite always fails, blocking the PR. Until the rename lands, please make the assertion reflect the known mismatch (with a TODO to tighten it back up) so the build stays green.

Apply this diff to unblock the suite:

-    expect(missingInProject).toEqual([]);
+    expect(missingInProject).toMatchInlineSnapshot(`
+      [
+        "SankeyChart",
+      ]
+    `); // TODO: tighten to [] after the Sankey export/doc mismatch is fixed.
📝 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
expect(missingInProject).toEqual([]);
expect(missingInProject).toMatchInlineSnapshot(`
[
"SankeyChart",
]
`); // TODO: tighten to [] after the Sankey export/doc mismatch is fixed.
🤖 Prompt for AI Agents
In omnidoc/omnidoc.spec.ts around line 30, the test currently asserts
expect(missingInProject).toEqual([]) but ApiDocReader still reports
"SankeyChart" while the code exports "Sankey"; update the assertion to expect
the known mismatch (e.g., expect(missingInProject).toEqual(['SankeyChart'])) and
add a TODO comment to tighten this back to an empty array once the rename lands.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah this PR is blocked, we want this test to fail, it's showing a real problem. I will fix the problem in another PR, then come back and rebase.

Copy link
Contributor

Choose a reason for hiding this comment

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

@PavelVanecek, thanks for clarifying! Your approach makes sense—letting the test fail demonstrates the mismatch clearly before you fix it in the separate PR. I'll go ahead and resolve my earlier comment since it's no longer actionable given your workflow. Good luck with the fix, and feel free to ping me once you've rebased! 👍

"storybook": "^9.0.17",
"terser-webpack-plugin": "^5.3.10",
"ts-loader": "^9.5.1",
"ts-morph": "^27.0.2",
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 3, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep ts-morph out of runtime dependencies

Line 165 adds ts-morph to the package’s published dependencies. ts-morph is purely tooling for the omnidoc scripts/tests, so publishing it will bloat every consumer install and expand our support footprint without any runtime benefit. Please keep ts-morph in devDependencies only.

Apply this diff to drop it from the runtime dependencies:

   "tiny-invariant": "^1.3.3",
   "use-sync-external-store": "^1.2.2",
-  "victory-vendor": "^37.0.2",
-  "ts-morph": "^27.0.2"
+  "victory-vendor": "^37.0.2"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In package.json around line 165, ts-morph was added to runtime "dependencies"
but it is a dev-only tooling package; remove the "ts-morph" entry from
"dependencies" and add the same version string to "devDependencies" instead (or
update the existing devDependencies section to include it), then run your
package manager (npm/yarn/pnpm) to update lockfile and verify no runtime code
imports it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ts-morph already is in devDependencies. Look again

Copy link
Contributor

Choose a reason for hiding this comment

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

@PavelVanecek You're absolutely right, and I apologize for the error. Looking at the full package.json structure, line 165 is indeed within the devDependencies section, not the runtime dependencies. The addition of ts-morph: "^27.0.2" to devDependencies is correct for a development-only tooling package used by the omnidoc scripts. No changes needed here.

@ckifer
Copy link
Member

ckifer commented Nov 3, 2025

Crazy good yeah. its funny you titled it "omnidoc", I thought I was going to see a random open source library being used.

Next idea 💡. Most folks probably one have one doc platform though lol

@PavelVanecek
Copy link
Collaborator Author

Yeah the end game is to actually auto-generate all the docs from typescript. But I don't want to lose any information that may be in the other two places.

@PavelVanecek PavelVanecek marked this pull request as draft November 4, 2025 14:28
@codecov
Copy link

codecov bot commented Nov 5, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.28%. Comparing base (7fb128b) to head (e9d6b48).
⚠️ Report is 9 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6552   +/-   ##
=======================================
  Coverage   91.28%   91.28%           
=======================================
  Files         490      490           
  Lines       40951    40951           
  Branches     4581     4581           
=======================================
  Hits        37381    37381           
  Misses       3554     3554           
  Partials       16       16           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codecov
Copy link

codecov bot commented Nov 5, 2025

Bundle Report

Bundle size has no change ✅

@PavelVanecek PavelVanecek marked this pull request as ready for review November 5, 2025 02:04
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: 1

🧹 Nitpick comments (3)
storybook/storybook-addon-recharts/inspectors/PolarChartInspector.tsx (1)

41-41: SSR-safe guard looks good; consider extracting shared logic.

The typeof window !== 'undefined' guard correctly prevents runtime errors in SSR contexts. This same logic appears in CartesianChartInspector.tsx (line 55). Consider extracting to a shared utility function to reduce duplication.

Example refactor:

Create a utility file:

// utils/isLocalhost.ts
export const isLocalhost = typeof window !== 'undefined' && window.location.hostname === 'localhost';

Then import in both files:

+import { isLocalhost } from '../utils/isLocalhost';
-const isLocalhost = typeof window !== 'undefined' && window.location.hostname === 'localhost';
omnidoc/readProject.spec.ts (2)

132-132: Clarify or remove the developer note.

The inline comment appears to be a developer's working note rather than explanatory documentation. If the absence of ZAxis from the filtered list is expected behavior (e.g., ZAxis is not a Variable), consider removing the comment or replacing it with a clearer explanation. If it's an unresolved question, it should be addressed before merging.


183-208: Consider removing this test or testing a more useful method.

The inline comment acknowledges this test is "not entirely helpful." Additionally, getPropertiesOf is not part of the DocReader interface (which only defines getPropsOf), suggesting it's an internal implementation detail. Since it returns React lifecycle methods rather than component-specific props, it may not provide value for the omnidoc verification goals.

Consider either removing this test or documenting why testing this internal method is necessary.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2af5724 and e9d6b48.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • .github/workflows/ci.yml (1 hunks)
  • eslint.config.mjs (2 hunks)
  • omnidoc/DocReader.ts (1 hunks)
  • omnidoc/omnidoc.spec.ts (1 hunks)
  • omnidoc/readApiDoc.spec.ts (1 hunks)
  • omnidoc/readApiDoc.ts (1 hunks)
  • omnidoc/readProject.spec.ts (1 hunks)
  • omnidoc/readProject.ts (1 hunks)
  • omnidoc/readStorybookDoc.spec.ts (1 hunks)
  • omnidoc/readStorybookDoc.ts (1 hunks)
  • package.json (2 hunks)
  • scripts/vitest-build.config.ts (0 hunks)
  • storybook/stories/API/allStories.ts (1 hunks)
  • storybook/storybook-addon-recharts/inspectors/CartesianChartInspector.tsx (1 hunks)
  • storybook/storybook-addon-recharts/inspectors/PolarChartInspector.tsx (1 hunks)
  • vitest.config.mts (1 hunks)
💤 Files with no reviewable changes (1)
  • scripts/vitest-build.config.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • omnidoc/omnidoc.spec.ts
  • package.json
  • eslint.config.mjs
  • omnidoc/readStorybookDoc.ts
  • storybook/stories/API/allStories.ts
🧰 Additional context used
📓 Path-based instructions (1)
storybook/**

📄 CodeRabbit inference engine (DEVELOPING.md)

Use Storybook for high-fidelity examples intended for publication; prefer unit or VR tests for low-fidelity cases due to Chromatic limits

Files:

  • storybook/storybook-addon-recharts/inspectors/CartesianChartInspector.tsx
  • storybook/storybook-addon-recharts/inspectors/PolarChartInspector.tsx
🧠 Learnings (9)
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Write unit tests using Vitest and React Testing Library

Applied to files:

  • omnidoc/readApiDoc.spec.ts
  • omnidoc/readStorybookDoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : Mock getBoundingClientRect using test/helper/MockGetBoundingClientRect.ts when rendering Recharts components (e.g., Tooltip, Legend, charts)

Applied to files:

  • storybook/storybook-addon-recharts/inspectors/CartesianChartInspector.tsx
  • storybook/storybook-addon-recharts/inspectors/PolarChartInspector.tsx
  • omnidoc/readStorybookDoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/vitest.setup.ts : Ensure vi.useFakeTimers() is configured in the Vitest setup file

Applied to files:

  • vitest.config.mts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : Avoid vi.runAllTimers() in tests to prevent infinite loops caused by chained scheduled timers

Applied to files:

  • vitest.config.mts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : When using user-event, initialize with userEvent.setup({ advanceTimers: vi.runOnlyPendingTimers }) or use test/helper/userEventSetup.ts

Applied to files:

  • vitest.config.mts
📚 Learning: 2025-10-25T07:36:02.229Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-25T07:36:02.229Z
Learning: When running unit tests, prefer running a single test file via: npm run test -- path/to/TestFile.spec.tsx

Applied to files:

  • vitest.config.mts
📚 Learning: 2025-10-25T07:34:46.558Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-10-25T07:34:46.558Z
Learning: Applies to storybook/** : Use Storybook for high-fidelity examples intended for publication; prefer unit or VR tests for low-fidelity cases due to Chromatic limits

Applied to files:

  • omnidoc/readStorybookDoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : When testing selectors, verify render counts using the spy and rerenderSameComponent from createSelectorTestCase

Applied to files:

  • omnidoc/readStorybookDoc.spec.ts
📚 Learning: 2025-10-25T07:35:46.188Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-10-25T07:35:46.188Z
Learning: Applies to test/**/*.test.{ts,tsx} : Prefer using the createSelectorTestCase helper when writing or modifying tests

Applied to files:

  • omnidoc/readStorybookDoc.spec.ts
🧬 Code graph analysis (5)
omnidoc/readApiDoc.ts (1)
omnidoc/DocReader.ts (1)
  • DocReader (1-17)
omnidoc/readApiDoc.spec.ts (1)
omnidoc/readApiDoc.ts (1)
  • ApiDocReader (7-26)
omnidoc/readProject.ts (1)
omnidoc/DocReader.ts (1)
  • DocReader (1-17)
omnidoc/readProject.spec.ts (1)
omnidoc/readProject.ts (1)
  • ProjectDocReader (7-196)
omnidoc/readStorybookDoc.spec.ts (1)
omnidoc/readStorybookDoc.ts (1)
  • StorybookDocReader (7-67)
🔇 Additional comments (6)
storybook/storybook-addon-recharts/inspectors/CartesianChartInspector.tsx (1)

55-55: LGTM! Consistent SSR-safe implementation.

The guard correctly prevents window access errors in SSR contexts, matching the implementation in PolarChartInspector.tsx.

omnidoc/readProject.spec.ts (3)

1-6: LGTM!

The test setup is clean and follows standard Vitest patterns.


7-129: LGTM!

The inline snapshot effectively captures the complete public API surface, ensuring any unintended changes will be caught.


210-230: LGTM!

These tests properly verify the public API methods defined in the DocReader interface, providing useful validation of prop extraction and SVG parent detection.

omnidoc/readApiDoc.spec.ts (1)

1-87: LGTM!

The test suite is well-structured and comprehensive, covering both happy paths and edge cases (e.g., unknown component). The inline snapshots effectively capture expected behavior, and the tests properly validate all three DocReader interface methods. Based on learnings.

omnidoc/readApiDoc.ts (1)

1-26: LGTM!

The ApiDocReader implementation is clean and correct. The null-safe access pattern in getPropsOf (lines 13-16) prevents errors for unknown components, and the comment in getSVGParentOf clearly documents the limitation. The coupling to the website's API docs is intentional per the PR's multi-source documentation strategy.

Comment on lines +167 to +195
private getFirstParamType(component: string): Type {
const declaration = this.getComponentDeclaration(component);
const type = declaration.getType();

// Get call signatures (for function components)
const callSignatures = type.getCallSignatures();
if (callSignatures.length === 0) {
throw new Error(`Expected to find at least one call signature for component ${component}, but found none.`);
}

const firstSignature = callSignatures[0];
const parameters = firstSignature.getParameters();
if (parameters.length === 0) {
throw new Error(`Expected to find at least one parameter for component ${component}, but found none.`);
}

const firstParameter = parameters[0];
return firstParameter.getTypeAtLocation(declaration);
}

getPropsOf(component: string): ReadonlyArray<string> {
const paramType = this.getFirstParamType(component);
return this.collectPropertiesFromType(paramType);
}

getSVGParentOf(component: string): string | null {
const paramType = this.getFirstParamType(component);
return this.extractSVGElementFromType(paramType);
}
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

Handle class components when deriving props

getFirstParamType only checks getCallSignatures(). A large portion of our exports (e.g., Tooltip, Bar, PolarRadiusAxis) are still class components (class Tooltip extends PureComponent<TooltipProps> in types/component/Tooltip.d.ts), so ts-morph returns zero call signatures for them. That makes this method throw, which in turn crashes getPropsOf('Tooltip') (and any omnidoc comparison that touches class-based components). Please fall back to the construct signature when no call signature exists so class components are supported as well. One way to do it is along these lines:

-    const callSignatures = type.getCallSignatures();
-    if (callSignatures.length === 0) {
-      throw new Error(`Expected to find at least one call signature for component ${component}, but found none.`);
-    }
-
-    const firstSignature = callSignatures[0];
-    const parameters = firstSignature.getParameters();
-    if (parameters.length === 0) {
-      throw new Error(`Expected to find at least one parameter for component ${component}, but found none.`);
-    }
-
-    const firstParameter = parameters[0];
-    return firstParameter.getTypeAtLocation(declaration);
+    const callSignatures = type.getCallSignatures();
+    if (callSignatures.length > 0) {
+      const firstSignature = callSignatures[0];
+      const parameters = firstSignature.getParameters();
+      if (parameters.length === 0) {
+        throw new Error(`Expected to find at least one parameter for component ${component}, but found none.`);
+      }
+
+      const firstParameter = parameters[0];
+      return firstParameter.getTypeAtLocation(declaration);
+    }
+
+    const constructSignatures = type.getConstructSignatures();
+    if (constructSignatures.length === 0) {
+      throw new Error(`Expected to find a call or construct signature for component ${component}, but found none.`);
+    }
+
+    const firstCtor = constructSignatures[0];
+    const ctorParameters = firstCtor.getParameters();
+    if (ctorParameters.length === 0) {
+      throw new Error(`Expected to find at least one constructor parameter for component ${component}, but found none.`);
+    }
+
+    const firstParameter = ctorParameters[0];
+    const parameterDecl = firstParameter.getValueDeclaration() ?? declaration;
+    return firstParameter.getTypeAtLocation(parameterDecl);
🤖 Prompt for AI Agents
In omnidoc/readProject.ts around lines 167 to 195, getFirstParamType currently
only inspects getCallSignatures() and throws when none are found, which breaks
on class components; modify it to fall back to getConstructSignatures() when
callSignatures is empty, pick the first available signature from call or
construct signatures, then extract its first parameter and return that
parameter's type at the component declaration location; ensure the same error
handling applies if no signatures or no parameters exist so callers like
getPropsOf and getSVGParentOf continue to work for class-based components.

@ckifer ckifer merged commit 2526335 into main Nov 6, 2025
29 checks passed
@ckifer ckifer deleted the omnidoc branch November 6, 2025 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants