Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support TypeScript builtin prop types (#862)
- Loading branch information
Showing
8 changed files
with
251 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
'react-docgen': minor | ||
--- | ||
|
||
Support `PropsWithoutRef`, `PropsWithRef` and `PropsWithChildren` in TypeScript. | ||
|
||
Component props are now detected correctly when these builtin types are used, | ||
but they do currently not add any props to the documentation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
...ages/react-docgen/src/utils/__tests__/__snapshots__/unwrapBuiltinTSPropTypes-test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html | ||
|
||
exports[`unwrapBuiltinTSPropTypes > React.PropsWithChildren 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "Props", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; | ||
|
||
exports[`unwrapBuiltinTSPropTypes > React.PropsWithRef 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "Props", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; | ||
|
||
exports[`unwrapBuiltinTSPropTypes > React.PropsWithoutRef 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "Props", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; | ||
|
||
exports[`unwrapBuiltinTSPropTypes > does not follow reassignment 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "bar", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; | ||
|
||
exports[`unwrapBuiltinTSPropTypes > multiple 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "Props", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; | ||
|
||
exports[`unwrapBuiltinTSPropTypes > with named import 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "Props", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; | ||
|
||
exports[`unwrapBuiltinTSPropTypes > with require 1`] = ` | ||
Node { | ||
"type": "TSTypeReference", | ||
"typeName": Node { | ||
"name": "Props", | ||
"type": "Identifier", | ||
}, | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
packages/react-docgen/src/utils/__tests__/unwrapBuiltinTSPropTypes-test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import type { TSTypeReference, VariableDeclaration } from '@babel/types'; | ||
import { parseTypescript } from '../../../tests/utils'; | ||
import unwrapBuiltinTSPropTypes from '../unwrapBuiltinTSPropTypes.js'; | ||
import { describe, expect, test } from 'vitest'; | ||
import type { NodePath } from '@babel/traverse'; | ||
|
||
describe('unwrapBuiltinTSPropTypes', () => { | ||
test('React.PropsWithChildren', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`import React from 'react'; | ||
var foo: React.PropsWithChildren<Props>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
|
||
test('React.PropsWithoutRef', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`import React from 'react'; | ||
var foo: React.PropsWithoutRef<Props>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
|
||
test('React.PropsWithRef', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`import React from 'react'; | ||
var foo: React.PropsWithRef<Props>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
|
||
test('multiple', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`import React from 'react'; | ||
var foo: React.PropsWithChildren<React.PropsWithRef<Props>>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
|
||
test('does not follow reassignment', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`import React from 'react'; | ||
type bar = React.PropsWithRef<Props> | ||
var foo: React.PropsWithChildren<bar>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
|
||
test('with require', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`const React = require('react'); | ||
var foo: React.PropsWithRef<Props>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
|
||
test('with named import', () => { | ||
const path = parseTypescript | ||
.statementLast<VariableDeclaration>( | ||
`import { PropsWithRef } from 'react'; | ||
var foo: PropsWithRef<Props>`, | ||
) | ||
.get( | ||
'declarations.0.id.typeAnnotation.typeAnnotation', | ||
) as NodePath<TSTypeReference>; | ||
|
||
expect(unwrapBuiltinTSPropTypes(path)).toMatchSnapshot(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
packages/react-docgen/src/utils/unwrapBuiltinTSPropTypes.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import type { NodePath } from '@babel/traverse'; | ||
import isReactBuiltinReference from './isReactBuiltinReference.js'; | ||
|
||
/** | ||
* Unwraps NodePaths from the builtin TS types `PropsWithoutRef`, | ||
* `PropsWithRef` and `PropsWithChildren` and returns the inner type param. | ||
* If none of the builtin types is detected the path is returned as-is | ||
*/ | ||
export default function unwrapBuiltinTSPropTypes(typePath: NodePath): NodePath { | ||
if (typePath.isTSTypeReference()) { | ||
const typeName = typePath.get('typeName'); | ||
|
||
if ( | ||
isReactBuiltinReference(typeName, 'PropsWithoutRef') || | ||
isReactBuiltinReference(typeName, 'PropsWithRef') || | ||
isReactBuiltinReference(typeName, 'PropsWithChildren') | ||
) { | ||
const typeParameters = typePath.get('typeParameters'); | ||
|
||
if (typeParameters.hasNode()) { | ||
const innerType = typeParameters.get('params')[0]; | ||
|
||
if (innerType) { | ||
return unwrapBuiltinTSPropTypes(innerType); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return typePath; | ||
} |