Skip to content

[Omnidoc] Add a test that verifies each component and each prop has a website example#6897

Merged
ckifer merged 1 commit intomainfrom
examples
Jan 16, 2026
Merged

[Omnidoc] Add a test that verifies each component and each prop has a website example#6897
ckifer merged 1 commit intomainfrom
examples

Conversation

@PavelVanecek
Copy link
Collaborator

@PavelVanecek PavelVanecek commented Jan 16, 2026

Description

I want to use this test to verify that we have all of those props and types used at least once so that I know if we are introducing a breaking change or not. The website is the closest we have to production.

Related Issue

#6645

Summary by CodeRabbit

  • Tests

    • Added comprehensive test suite for documentation examples validation, ensuring all exports have corresponding examples.
    • Added test coverage for example retrieval functionality across multiple component scenarios.
  • Chores

    • Added internal infrastructure for scanning and mapping documentation examples to components.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

Walkthrough

Three new files are introduced: a utility class ExampleReader that parses TypeScript to build component-to-example URL mappings from source directories, and two test files validating that public exports and their component props have corresponding examples in documentation.

Changes

Cohort / File(s) Change Summary
Example Reader Utility
omnidoc/readExamples.ts
New ExampleReader class using ts-morph to parse TypeScript AST and build mappings from components to example/API URLs. Lazy initialization scans example and API directories, resolves cross-file references, and exposes getExamples(componentName, propName?) to retrieve relevant examples with optional prop filtering
Test Suite
omnidoc/readExamples.spec.ts, omnidoc/verifyExamples.spec.ts
Unit tests validating ExampleReader.getExamples() across AreaChart, YAxis, and LineChart scenarios; integration test ensuring all public exports have at least one example and component props have representative examples excluding event handlers

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly and specifically describes the main addition: a test that verifies examples exist for each component and prop.
Description check ✅ Passed The pull request description provides clear context with a problem statement and related issue link, but is missing several template sections like testing details, motivation/context expansion, and the checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

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

🤖 Fix all issues with AI agents
In `@omnidoc/readExamples.spec.ts`:
- Around line 1-3: Move the spec into the test suite and align its name:
relocate the current omnidoc/readExamples.spec.ts to the test directory (e.g.,
test/omnidoc/readExamples.spec.tsx), rename the file to use the .spec.tsx
suffix, and update the import for ExampleReader in the moved file to the correct
relative path; ensure any test runner config picks up the new location and that
the test name follows existing conventions.

In `@omnidoc/readExamples.ts`:
- Around line 96-105: When following an import specifier
(Node.isImportSpecifier) you currently call
this.processExampleMap(moduleSpecifier, examplesName) which passes the local
alias and causes aliased imports to fail; change it to resolve and pass the
original exported name by using declaration.getName() (same approach as
processApiExamplesIndex) so call this.processExampleMap(moduleSpecifier,
declaration.getName()) when handling importDecl/moduleSpecifier in
processExampleMap.
- Around line 274-306: The checkAttributes function misses JSX spread
attributes; update it to iterate node.getAttributes() and handle
Node.isJsxSpreadAttribute(attr) cases: for each spread attribute call
attr.getExpression() and if Node.isObjectLiteralExpression(expression) inspect
expression.getProperties() for a property matching propName, and if expression
is an Identifier resolve its declarations via identifier.getDefinitions() or
identifier.getSymbol()?.getDeclarations(), find VariableDeclaration(s) and
inspect their getInitializer() (treat object literal initializers like above) to
detect the prop; keep existing direct-attribute logic
(node.getAttribute(propName)) and children handling intact and return true when
any spread or direct attribute indicates usage.

In `@omnidoc/verifyExamples.spec.ts`:
- Around line 1-4: The spec file is placed outside the test suite and uses the
wrong extension; move and rename the file to the test suite (e.g.,
test/omnidoc/verifyExamples.spec.tsx) and update any module imports so they
resolve from the new location (update imports of ProjectDocReader and
ExampleReader accordingly), ensuring test runner discovers it and naming follows
the *.spec.tsx convention.
🧹 Nitpick comments (1)
omnidoc/readExamples.ts (1)

47-71: Add explicit return types to non‑trivial ExampleReader methods.

initialize, buildUrlMap, and other helpers rely on inferred void. Please add explicit return types for these non‑trivial methods (and apply similarly to the other process* / is* methods). As per coding guidelines, please add explicit return types.

♻️ Example pattern
-  private initialize() {
+  private initialize(): void {
@@
-  private buildUrlMap() {
+  private buildUrlMap(): void {
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b132f5a and b128034.

📒 Files selected for processing (3)
  • omnidoc/readExamples.spec.ts
  • omnidoc/readExamples.ts
  • omnidoc/verifyExamples.spec.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx}: Never use any type (implicit or explicit) in TypeScript code
Prefer unknown over any and refine the type in TypeScript
Type function parameters and return values explicitly in TypeScript, do not rely on implicit any or inference; exceptions are React components and trivial functions
Do not use as type assertions in TypeScript; the only exception is as const

All imports from recharts must use the public API entry point (e.g., import { TooltipIndex } from 'recharts'). Imports from internal paths like recharts/types/* or recharts/src/* are not allowed and will fail the linter.

Files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
  • omnidoc/readExamples.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Ensure code lints by running npm run lint and follows Airbnb's Style Guide

Files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
  • omnidoc/readExamples.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When running unit tests, prefer to run a single test file using npm run test -- path/to/TestFile.spec.tsx rather than running all tests with npm test

Unit tests should be placed in the test directory, with some tests also allowed in www/test. Test files follow the naming convention *.spec.tsx.

Files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to **/*.spec.{ts,tsx} : Unit tests should be placed in the `test` directory, with some tests also allowed in `www/test`. Test files follow the naming convention `*.spec.tsx`.
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to **/*.stories.{ts,tsx} : When adding new Storybook stories, prioritize high-fidelity examples that you want published on the website and in the Storybook UI. Use low-fidelity tests in unit tests or visual regression tests instead to avoid exceeding the Chromatic open source plan limits.
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6783
File: test/util/ChartUtils.spec.tsx:15-16
Timestamp: 2025-12-16T08:12:13.355Z
Learning: In the recharts codebase, files in the `test` folder are allowed to import from internal paths (e.g., `../../src/state/cartesianAxisSlice`) and do not need to use the public API entry point (`src/index.ts`). The public API import restriction applies only to non-test code.
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Prefer to use the `createSelectorTestCase` helper function when writing or modifying tests
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to storybook/stories/**/*.stories.tsx : Update Storybook stories when APIs have been changed to ensure they work as expected
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to test/component/**/*.spec.tsx : Use React Testing Library for testing component interactions and behavior upon rendering
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to test-vr/**/*.spec.ts : Visual regression tests should follow the naming convention `*.spec.ts` and be placed in the `test-vr` directory. When updating snapshots, new files created in `test-vr/__snapshots__` should be committed to the repository.
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Use the `expectLastCalledWith` helper function instead of `expect(spy).toHaveBeenLastCalledWith(...)` for better typing and autocompletion
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from `createSelectorTestCase` to spot unnecessary re-renders and improve performance
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to storybook/stories/**/*.stories.tsx : Use Storybook for smoke tests and add play functions with assertions for actual tests
📚 Learning: 2025-12-26T15:59:11.254Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to test-vr/**/*.spec.ts : Visual regression tests should follow the naming convention `*.spec.ts` and be placed in the `test-vr` directory. When updating snapshots, new files created in `test-vr/__snapshots__` should be committed to the repository.

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-12-26T15:59:11.254Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to **/*.spec.{ts,tsx} : Unit tests should be placed in the `test` directory, with some tests also allowed in `www/test`. Test files follow the naming convention `*.spec.tsx`.

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to test/**/*.spec.{ts,tsx} : Aim for 100% unit test code coverage when writing new code

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from `createSelectorTestCase` to spot unnecessary re-renders and improve performance

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Aim for 100% unit test code coverage when writing new code

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-12-26T15:59:11.254Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-26T15:59:11.254Z
Learning: Applies to **/*.stories.{ts,tsx} : When adding new Storybook stories, prioritize high-fidelity examples that you want published on the website and in the Storybook UI. Use low-fidelity tests in unit tests or visual regression tests instead to avoid exceeding the Chromatic open source plan limits.

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Use the `expectLastCalledWith` helper function instead of `expect(spy).toHaveBeenLastCalledWith(...)` for better typing and autocompletion

Applied to files:

  • omnidoc/verifyExamples.spec.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Prefer to use the `createSelectorTestCase` helper function when writing or modifying tests

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-12-16T08:12:13.355Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6783
File: test/util/ChartUtils.spec.tsx:15-16
Timestamp: 2025-12-16T08:12:13.355Z
Learning: In the recharts codebase, files in the `test` folder are allowed to import from internal paths (e.g., `../../src/state/cartesianAxisSlice`) and do not need to use the public API entry point (`src/index.ts`). The public API import restriction applies only to non-test code.

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to storybook/stories/**/*.stories.tsx : Use Storybook for smoke tests and add play functions with assertions for actual tests

Applied to files:

  • omnidoc/verifyExamples.spec.ts
  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Mock `getBoundingClientRect` in tests using the helper function provided in `test/helper/MockGetBoundingClientRect.ts`

Applied to files:

  • omnidoc/readExamples.spec.ts
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Add tests when adding new functionality or changing existing functionality; prefer unit tests for helper functions or RTL tests for rendering

Applied to files:

  • omnidoc/readExamples.spec.ts
🧬 Code graph analysis (2)
omnidoc/verifyExamples.spec.ts (2)
omnidoc/readProject.ts (1)
  • ProjectDocReader (72-878)
omnidoc/readExamples.ts (1)
  • ExampleReader (3-317)
omnidoc/readExamples.spec.ts (1)
omnidoc/readExamples.ts (1)
  • ExampleReader (3-317)
⏰ 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)

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +1 to +3
import { describe, it, expect } from 'vitest';
import { ExampleReader } from './readExamples';

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

Move this spec into the test suite and align naming.

Specs are expected under test/ (or www/test) and follow *.spec.tsx. Keeping this under omnidoc/ with .spec.ts risks the test not running. Please move/rename (e.g., test/omnidoc/readExamples.spec.tsx) and update imports as needed. As per coding guidelines.

🤖 Prompt for AI Agents
In `@omnidoc/readExamples.spec.ts` around lines 1 - 3, Move the spec into the test
suite and align its name: relocate the current omnidoc/readExamples.spec.ts to
the test directory (e.g., test/omnidoc/readExamples.spec.tsx), rename the file
to use the .spec.tsx suffix, and update the import for ExampleReader in the
moved file to the correct relative path; ensure any test runner config picks up
the new location and that the test name follows existing conventions.

Comment on lines +96 to +105
if (declSourceFile !== sourceFile && Node.isVariableDeclaration(declaration)) {
// It is defined in another file, process it there
this.processExampleMap(declSourceFile, declaration.getName());
} else if (Node.isImportSpecifier(declaration)) {
// Sometimes it points to the import specifier
const importDecl = declaration.getImportDeclaration();
const moduleSpecifier = importDecl.getModuleSpecifierSourceFile();
if (moduleSpecifier) {
this.processExampleMap(moduleSpecifier, examplesName);
}
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

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the file structure
find . -type f -name "readExamples.ts" | head -5

Repository: recharts/recharts

Length of output: 86


🏁 Script executed:

# Find the omnidoc directory
find . -type d -name "omnidoc" | head -5

Repository: recharts/recharts

Length of output: 70


🏁 Script executed:

# Read the relevant section of the file
cat -n ./omnidoc/readExamples.ts | head -120

Repository: recharts/recharts

Length of output: 5497


🏁 Script executed:

# Also check the processExampleMap method signature
rg -A 5 "processExampleMap\(" ./omnidoc/readExamples.ts | head -30

Repository: recharts/recharts

Length of output: 956


🏁 Script executed:

# Check for aliased imports in the exampleComponents index file
rg -n "import\s+\{[^}]*\bas\b" www/src/docs/exampleComponents/index.ts

Repository: recharts/recharts

Length of output: 227


🏁 Script executed:

# Let's also check the full structure of the exampleComponents index to understand the pattern
cat www/src/docs/exampleComponents/index.ts | head -80

Repository: recharts/recharts

Length of output: 2179


🏁 Script executed:

# Let's verify what declaration.getName() returns for an ImportSpecifier
# Check the ts-morph documentation or see how ImportSpecifier works
cd ./omnidoc && cat readExamples.ts | grep -A 20 "Node.isImportSpecifier"

Repository: recharts/recharts

Length of output: 3240


🏁 Script executed:

# Let's also check if there's an imported name property we can understand
rg -n "getImportDeclaration\|getName" ./omnidoc/readExamples.ts | head -20

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Check the Legend.ts file to confirm the actual export name
cat www/src/docs/exampleComponents/Legend.ts | head -30

Repository: recharts/recharts

Length of output: 133


🏁 Script executed:

# Find the Legend file
find www/src/docs/exampleComponents -name "Legend*"

Repository: recharts/recharts

Length of output: 160


🏁 Script executed:

# Let's check what the correct pattern is by looking at line 153 more carefully
sed -n '140,160p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 879


🏁 Script executed:

# Let's check the Legend index file to see what's exported
cat www/src/docs/exampleComponents/Legend/index.ts 2>/dev/null || cat www/src/docs/exampleComponents/Legend.ts 2>/dev/null

Repository: recharts/recharts

Length of output: 394


🏁 Script executed:

# Let's find the actual Legend index
find www/src/docs/exampleComponents/Legend -name "index.ts"

Repository: recharts/recharts

Length of output: 107


🏁 Script executed:

# Let's look at the processApiExampleArray method to see how it handles imports
sed -n '150,170p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 720


🏁 Script executed:

# Let's check what declaration.getName() would return for an ImportSpecifier
# by looking at ts-morph's behavior. Let's search for how getName is used with ImportSpecifier elsewhere

rg -B 3 -A 3 "ImportSpecifier.*getName\|getName.*ImportSpecifier" .

Repository: recharts/recharts

Length of output: 43


🏁 Script executed:

# Let's verify the issue by understanding what happens:
# For: import { legendExamples as LegendExamples }
# - examplesName (getText) = "LegendExamples"
# - declaration.getName() should = "legendExamples"
# Let's check processApiExampleArray which uses declaration.getName() to confirm the pattern

sed -n '178,190p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 895


Use the imported name when resolving aliased example-map imports.

Aliased imports like import { legendExamples as LegendExamples } exist in the codebase. When following an import specifier to its module, the code at line 104 uses examplesName (the local alias), but processExampleMap needs the original exported name to find the variable in the source file. This causes aliased imports to silently fail. The pattern at line 189 in processApiExamplesIndex correctly uses declaration.getName() in the same scenario.

Fix
-                    this.processExampleMap(moduleSpecifier, examplesName);
+                    this.processExampleMap(moduleSpecifier, declaration.getName());
🤖 Prompt for AI Agents
In `@omnidoc/readExamples.ts` around lines 96 - 105, When following an import
specifier (Node.isImportSpecifier) you currently call
this.processExampleMap(moduleSpecifier, examplesName) which passes the local
alias and causes aliased imports to fail; change it to resolve and pass the
original exported name by using declaration.getName() (same approach as
processApiExamplesIndex) so call this.processExampleMap(moduleSpecifier,
declaration.getName()) when handling importDecl/moduleSpecifier in
processExampleMap.

Comment on lines +274 to +306
const jsxElements = sourceFile.getDescendantsOfKind(SyntaxKind.JsxOpeningElement);
const jsxSelfClosingElements = sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement);

const checkAttributes = (node: JsxOpeningElement | JsxSelfClosingElement) => {
if (node.getTagNameNode().getText() === localName) {
// Special handling for children
if (propName === 'children') {
// Check if it's an attribute (rare but possible)
if (node.getAttribute('children')) return true;

// If it's an opening element, check if the parent JsxElement has children
if (Node.isJsxOpeningElement(node)) {
const jsxElement = node.getParentIfKind(SyntaxKind.JsxElement);
if (jsxElement) {
const children = jsxElement.getJsxChildren();
// Filter out empty text nodes (whitespace)
const hasRealChildren = children.some(child => {
if (Node.isJsxText(child)) {
return child.getText().trim().length > 0;
}
return true;
});
if (hasRealChildren) return true;
}
}
return false;
}

const attr = node.getAttribute(propName);
return !!attr;
}
return 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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "readExamples.ts" -type f

Repository: recharts/recharts

Length of output: 86


🏁 Script executed:

find . -type d -name "www" | head -5

Repository: recharts/recharts

Length of output: 120


🏁 Script executed:

wc -l ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 90


🏁 Script executed:

sed -n '274,306p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 1398


🏁 Script executed:

rg -n "<[^>]*\{\.\.\." www/src/docs --max-count=20

Repository: recharts/recharts

Length of output: 1822


🏁 Script executed:

sed -n '1,50p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 1619


🏁 Script executed:

sed -n '150,200p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 2062


🏁 Script executed:

sed -n '250,275p' ./omnidoc/readExamples.ts

Repository: recharts/recharts

Length of output: 954


🏁 Script executed:

rg "isPropUsed" ./omnidoc/readExamples.ts -B 2 -A 2

Repository: recharts/recharts

Length of output: 569


🏁 Script executed:

grep -A 5 "ts-morph" package.json

Repository: recharts/recharts

Length of output: 243


🏁 Script executed:

rg "JsxSpreadAttribute|getAttributes" --max-count=10

Repository: recharts/recharts

Length of output: 43


🌐 Web query:

ts-morph 27.0.2 JSX spread attribute API documentation

💡 Result:

The ts-morph 27.0.2 API for JSX spread attributes is exposed as the JsxSpreadAttribute node/class. Key methods include: getStructure(), set(structure: Partial), remove(), getParent(), and getParentOrThrow(). See the API reference for full details. (jsdocs.io)

Citations:


🏁 Script executed:

npm list ts-morph | head -5

Repository: recharts/recharts

Length of output: 107


🏁 Script executed:

cat package-lock.json | grep -A 5 '"ts-morph"' | head -20

Repository: recharts/recharts

Length of output: 267


🌐 Web query:

ts-morph JsxSpreadAttribute getAttributes filter Node.isJsxSpreadAttribute

💡 Result:

Use getAttributes() then filter out spread attributes with Node.isJsxSpreadAttribute. Example:

  • import Node from ts-morph (or use the Node static on any node)
  • Filter:

const attrs = jsxElement.getAttributes().filter(a => !Node.isJsxSpreadAttribute(a));
// attrs now contains only JsxAttribute (not JsxSpreadAttribute)

Or positive test to get only spreads:

const spreads = jsxElement.getAttributes().filter(a => Node.isJsxSpreadAttribute(a));

This is supported by ts-morph’s JsxSpreadAttribute/Node helpers. [1][2]

Sources:
[1] ts-morph API docs — JsxSpreadAttribute / isJsxSpreadAttribute.
[2] ts-morph documentation — navigating AST / getAttributes usage.


isPropUsed misses JSX spread props, which can hide real usage.

The current check only inspects direct attributes, so <Comp {...props} /> or <Comp {...{ width: 10 }} /> won't count toward prop coverage. This produces false negatives for the prop‑coverage test. Spread props are actively used in the documentation (e.g., {...rest}, {...labelProps}, {...props} patterns appear in 11+ example files).

The proposed fix correctly handles this by:

  1. Filtering JSX attributes to identify spread attributes using Node.isJsxSpreadAttribute()
  2. Checking object literals within spreads for the target property
  3. Resolving identifier spreads to their variable declarations and inspecting their initializers

These ts-morph methods are available in the project's version (27.0.2) and the fix approach is sound.

🐛 Proposed fix (handle common spread cases)
     const checkAttributes = (node: JsxOpeningElement | JsxSelfClosingElement) => {
       if (node.getTagNameNode().getText() === localName) {
@@
-        const attr = node.getAttribute(propName);
+        const spreadAttrs = node.getAttributes().filter(Node.isJsxSpreadAttribute);
+        for (const spreadAttr of spreadAttrs) {
+          const expr = spreadAttr.getExpression();
+          if (Node.isObjectLiteralExpression(expr)) {
+            if (expr.getProperty(propName)) return true;
+          } else if (Node.isIdentifier(expr)) {
+            const decl = expr.getDefinitions()[0]?.getDeclarationNode();
+            if (decl && Node.isVariableDeclaration(decl)) {
+              const init = decl.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression);
+              if (init?.getProperty(propName)) return true;
+            }
+          }
+        }
+        const attr = node.getAttribute(propName);
         return !!attr;
       }
       return false;
     };
🤖 Prompt for AI Agents
In `@omnidoc/readExamples.ts` around lines 274 - 306, The checkAttributes function
misses JSX spread attributes; update it to iterate node.getAttributes() and
handle Node.isJsxSpreadAttribute(attr) cases: for each spread attribute call
attr.getExpression() and if Node.isObjectLiteralExpression(expression) inspect
expression.getProperties() for a property matching propName, and if expression
is an Identifier resolve its declarations via identifier.getDefinitions() or
identifier.getSymbol()?.getDeclarations(), find VariableDeclaration(s) and
inspect their getInitializer() (treat object literal initializers like above) to
detect the prop; keep existing direct-attribute logic
(node.getAttribute(propName)) and children handling intact and return true when
any spread or direct attribute indicates usage.

Comment on lines +1 to +4
import { describe, test, expect } from 'vitest';
import { ProjectDocReader } from './readProject';
import { ExampleReader } from './readExamples';

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

Move this spec into the test suite and align naming.

Specs are expected under test/ (or www/test) and follow *.spec.tsx. Keeping this under omnidoc/ with .spec.ts risks the test not running. Please move/rename (e.g., test/omnidoc/verifyExamples.spec.tsx) and update paths accordingly. As per coding guidelines.

🤖 Prompt for AI Agents
In `@omnidoc/verifyExamples.spec.ts` around lines 1 - 4, The spec file is placed
outside the test suite and uses the wrong extension; move and rename the file to
the test suite (e.g., test/omnidoc/verifyExamples.spec.tsx) and update any
module imports so they resolve from the new location (update imports of
ProjectDocReader and ExampleReader accordingly), ensuring test runner discovers
it and naming follows the *.spec.tsx convention.

@codecov
Copy link

codecov bot commented Jan 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.27%. Comparing base (b132f5a) to head (b128034).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6897   +/-   ##
=======================================
  Coverage   94.27%   94.27%           
=======================================
  Files         565      565           
  Lines       53858    53858           
  Branches     5178     5178           
=======================================
  Hits        50777    50777           
  Misses       3072     3072           
  Partials        9        9           

☔ 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.

@github-actions
Copy link
Contributor

Staging Deployment Details

These deployments will remain available for 30 days.

To update snapshots: Comment /update-snapshots on this PR to automatically update the baseline screenshots.

@ckifer ckifer merged commit 39fed4c into main Jan 16, 2026
45 checks passed
@ckifer ckifer deleted the examples branch January 16, 2026 15:47
@codecov
Copy link

codecov bot commented Jan 17, 2026

Bundle Report

Bundle size has no change ✅

@coderabbitai coderabbitai bot mentioned this pull request Jan 20, 2026
8 tasks
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