-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
React: Improve error messages in component manifest #32954
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,7 @@ import { dirname, sep } from 'node:path'; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { babelParse, types as t } from 'storybook/internal/babel'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getProjectRoot, supportedExtensions } from 'storybook/internal/common'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { logger } from 'storybook/internal/node-logger'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as find from 'empathic/find'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,6 +13,7 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| makeFsImporter, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parse, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from 'react-docgen'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { dedent } from 'ts-dedent'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as TsconfigPaths from 'tsconfig-paths'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { type ComponentRef } from './getComponentImports'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -33,6 +35,9 @@ const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver(); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handlers = [...defaultHandlers, actualNameHandler, exportNameHandler]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function getMatchingDocgen(docgens: DocObj[], component: ComponentRef) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (docgens.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (docgens.length === 1) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return docgens[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -91,75 +96,141 @@ export const parseWithReactDocgen = cached( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const getExportPaths = cached( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (code: string, filePath: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ast = (() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return babelParse(code); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (_) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| })(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!ast) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return [] as string[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let ast; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ast = babelParse(code); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (_) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const basedir = dirname(filePath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const body = ast.program.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return body | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .flatMap((n) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.isExportAllDeclaration(n) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? [n.source.value] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : t.isExportNamedDeclaration(n) && !!n.source && !n.declaration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? [n.source.value] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .flatMap((statement) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| t.isExportAllDeclaration(statement) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? [statement.source.value] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : t.isExportNamedDeclaration(statement) && !!statement.source && !statement.declaration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? [statement.source.value] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map((s) => matchPath(s, basedir)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map((s) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map((id) => matchPath(id, basedir)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .flatMap((id) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return cachedResolveImport(s, { basedir }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return [cachedResolveImport(id, { basedir })]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter((p): p is string => !!p && !p.includes('node_modules')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { name: 'getExportPaths' } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const gatherDocgensForPath = cached( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| filePath: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| depth: number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): { docgens: DocObj[]; analyzed: { path: string; code: string }[] } => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (depth > 5 || filePath.includes('node_modules')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { docgens: [], analyzed: [] }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens: DocObj[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errors: { path: string; code: string; name: string; message: string }[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (path.includes('node_modules')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errors: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: '/* File in node_modules */', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'Component file in node_modules', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: dedent` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Component files in node_modules are not supported. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The distributed files in node_modules usually don't contain the necessary comments or types needed to analyze component information. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Configure TypeScript path aliases to map your package name to the source file instead. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Example (tsconfig.json): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "compilerOptions": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "baseUrl": ".", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "paths": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@design-system/button": ["src/components/Button.tsx"], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "@design-system/*": ["src/components/*"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Then import using: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Button } from '@design-system/button' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Storybook resolves tsconfig paths automatically. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let code: string | undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let code; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code = cachedReadFileSync(filePath, 'utf-8') as string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code = cachedReadFileSync(path, 'utf-8') as string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errors: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code: '/* File not found or unreadable */', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'Component file could not be read', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: `Could not read the component file located at "${path}".\nPrefer relative imports if possible.`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!code) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { docgens: [], analyzed: [{ path: filePath, code: '/* File not found */' }] }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (depth > 5) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errors: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'Max re-export depth exceeded', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: dedent` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Traversal stopped after 5 steps while following re-exports starting from this file. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This usually indicates a deep or circular re-export chain. Try one of the following: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Import the component file directly (e.g., src/components/Button.tsx), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Reduce the number of re-export hops. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+188
to
205
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid including full source in error objects. Line 194 includes the full source code in the error object's Apply this diff: if (depth > 5) {
return {
docgens: [],
errors: [
{
path,
- code,
+ code: '/* Max re-export depth exceeded */',
name: 'Max re-export depth exceeded',
message: dedent`🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const reexportResults = getExportPaths(code, filePath).map((p) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gatherDocgensForPath(p, depth + 1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const fromReexports = reexportResults.flatMap((r) => r.docgens); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const analyzedChildren = reexportResults.flatMap((r) => r.analyzed); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const exportPaths = getExportPaths(code, path).map((p) => gatherDocgensForPath(p, depth + 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const docgens = exportPaths.flatMap((r) => r.docgens); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const errors = exportPaths.flatMap((r) => r.errors); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let locals: DocObj[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| locals = parseWithReactDocgen(code as string, filePath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| locals = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens: [...parseWithReactDocgen(code, path), ...docgens], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const message = e instanceof Error ? e.message : String(e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| errors: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| code, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'No component definition found', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: dedent` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ${message} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You can debug your component file in this playground: https://react-docgen.dev/playground | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+216
to
233
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid including full source in error objects. Line 223 includes the full source code in the error object. This creates the same manifest bloat issue as line 194. Use a placeholder comment instead. Apply this diff: } catch (e) {
const message = e instanceof Error ? e.message : String(e);
return {
docgens,
errors: [
{
path,
- code,
+ code: '/* Component parse failed */',
name: 'No component definition found',
message: dedent`🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgens: [...locals, ...fromReexports], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| analyzed: [{ path: filePath, code }, ...analyzedChildren], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { name: 'gatherDocgensWithTrace', key: (filePath) => filePath } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -171,39 +242,25 @@ export const getReactDocgen = cached( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | { type: 'success'; data: DocObj } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | { type: 'error'; error: { name: string; message: string } } => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (path.includes('node_modules')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: 'error', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'Component file in node_modules', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: `Component files in node_modules are not supported. Please import your component file directly.`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const docgenWithInfo = gatherDocgensForPath(path, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const docgens = docgenWithInfo.docgens; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const noCompDefError = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: 'error' as const, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'No component definition found', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Could not find a component definition.\n` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Prefer relative imports if possible.\n` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `Avoid pointing to transpiled files.\n` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `You can debug your component file in this playground: https://react-docgen.dev/playground\n\n` + | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| docgenWithInfo.analyzed.map(({ path, code }) => `File: ${path}\n${code}`).join('\n'), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!docgens || docgens.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return noCompDefError; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { docgens, errors } = gatherDocgensForPath(path, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const docgen = getMatchingDocgen(docgens, component); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!docgen) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return noCompDefError; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const error = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: errors.at(-1)?.name ?? 'No component definition found', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: errors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (e) => dedent` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| File: ${e.path} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Error: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ${e.message} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Code: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ${e.code}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .join('\n\n'), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+251
to
+262
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep docgen errors concise and non-empty Line [249]: when - const error = {
- name: errors.at(-1)?.name ?? 'No component definition found',
- message: errors
- .map(
- (e) => dedent`
- File: ${e.path}
- Error:
- ${e.message}
- Code:
- ${e.code}`
- )
- .join('\n\n'),
- };
+ const formattedMessage =
+ errors.length > 0
+ ? errors
+ .map(
+ (e) => dedent`
+ File: ${e.path}
+ Error:
+ ${e.message}`
+ )
+ .join('\n\n')
+ : dedent`
+ No component definition found.
+ We attempted to parse "${path}" but react-docgen did not return any components.`;
+ const error = {
+ name: errors.at(-1)?.name ?? 'No component definition found',
+ message: formattedMessage,
+ };📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { type: 'error', error }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { type: 'success', data: docgen }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid embedding the full story source in manifest errors
Line [151]: appending
${storyFile}injects the entire story file into the manifest error payload. For sizable stories this can add hundreds of kilobytes per entry and leaks every line of the source to downstream consumers. The code-frame fallback already gives localized context; we should keep that and drop the raw file dump.📝 Committable suggestion
🤖 Prompt for AI Agents