react-docgen
Advanced tools
Comparing version 6.0.4 to 7.0.0
import type { Handler } from './index.js'; | ||
/** | ||
* This handler tries to find flow Type annotated react components and extract | ||
* This handler tries to find flow and TS Type annotated react components and extract | ||
* its types to the documentation. It also extracts docblock comments which are | ||
@@ -5,0 +5,0 @@ * inlined in the type definition. |
@@ -64,3 +64,3 @@ import { unwrapUtilityType } from '../utils/flowUtilityTypes.js'; | ||
/** | ||
* This handler tries to find flow Type annotated react components and extract | ||
* This handler tries to find flow and TS Type annotated react components and extract | ||
* its types to the documentation. It also extracts docblock comments which are | ||
@@ -70,10 +70,12 @@ * inlined in the type definition. | ||
const codeTypeHandler = function (documentation, componentDefinition) { | ||
const typesPath = getTypeFromReactComponent(componentDefinition); | ||
if (!typesPath) { | ||
const typePaths = getTypeFromReactComponent(componentDefinition); | ||
if (typePaths.length === 0) { | ||
return; | ||
} | ||
applyToTypeProperties(documentation, typesPath, (propertyPath, typeParams) => { | ||
setPropDescriptor(documentation, propertyPath, typeParams); | ||
}, null); | ||
for (const typePath of typePaths) { | ||
applyToTypeProperties(documentation, typePath, (propertyPath, typeParams) => { | ||
setPropDescriptor(documentation, propertyPath, typeParams); | ||
}, null); | ||
} | ||
}; | ||
export default codeTypeHandler; |
@@ -28,3 +28,3 @@ import getPropertyName from '../utils/getPropertyName.js'; | ||
} | ||
if (resolvedPath.isImportDeclaration() && path.isIdentifier()) { | ||
if (resolvedPath.parentPath?.isImportDeclaration() && path.isIdentifier()) { | ||
defaultValue = path.node.name; | ||
@@ -31,0 +31,0 @@ } |
@@ -31,3 +31,3 @@ import { getDocblock } from '../utils/docblock.js'; | ||
return values.push({ | ||
value: printValue(value.isImportDeclaration() ? elementPath : value), | ||
value: printValue(value.parentPath?.isImportDeclaration() ? elementPath : value), | ||
computed: !value.isLiteral(), | ||
@@ -34,0 +34,0 @@ }); |
@@ -5,8 +5,9 @@ import type { NodePath } from '@babel/traverse'; | ||
/** | ||
* Given an React component (stateless or class) tries to find the | ||
* flow type for the props. If not found or not one of the supported | ||
* component types returns null. | ||
* Given an React component (stateless or class) tries to find | ||
* flow or TS types for the props. It may find multiple types. | ||
* If not found or it is not one of the supported component types, | ||
* this function returns an empty array. | ||
*/ | ||
declare const _default: (path: NodePath) => NodePath | null; | ||
declare const _default: (componentDefinition: NodePath) => NodePath[]; | ||
export default _default; | ||
export declare function applyToTypeProperties(documentation: Documentation, path: NodePath, callback: (propertyPath: NodePath, params: TypeParameters | null) => void, typeParams: TypeParameters | null): void; |
@@ -9,5 +9,7 @@ import getMemberValuePath from './getMemberValuePath.js'; | ||
import getTypeIdentifier from './getTypeIdentifier.js'; | ||
import isReactBuiltinReference from './isReactBuiltinReference.js'; | ||
import unwrapBuiltinTSPropTypes from './unwrapBuiltinTSPropTypes.js'; | ||
// TODO TESTME | ||
function getStatelessPropsPath(componentDefinition) { | ||
let value = resolveToValue(componentDefinition); | ||
let value = componentDefinition; | ||
if (isReactForwardRefCall(value)) { | ||
@@ -20,31 +22,64 @@ value = resolveToValue(value.get('arguments')[0]); | ||
} | ||
function findAssignedVariableType(componentDefinition) { | ||
const variableDeclarator = componentDefinition.findParent((path) => path.isVariableDeclarator()); | ||
if (!variableDeclarator) | ||
return null; | ||
const typeAnnotation = getTypeAnnotation(variableDeclarator.get('id')); | ||
if (!typeAnnotation) | ||
return null; | ||
if (typeAnnotation.isTSTypeReference()) { | ||
const typeName = typeAnnotation.get('typeName'); | ||
if (isReactBuiltinReference(typeName, 'FunctionComponent') || | ||
isReactBuiltinReference(typeName, 'FC') || | ||
isReactBuiltinReference(typeName, 'VoidFunctionComponent') || | ||
isReactBuiltinReference(typeName, 'VFC')) { | ||
const typeParameters = typeAnnotation.get('typeParameters'); | ||
if (typeParameters.hasNode()) { | ||
return typeParameters.get('params')[0] ?? null; | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
/** | ||
* Given an React component (stateless or class) tries to find the | ||
* flow type for the props. If not found or not one of the supported | ||
* component types returns null. | ||
* Given an React component (stateless or class) tries to find | ||
* flow or TS types for the props. It may find multiple types. | ||
* If not found or it is not one of the supported component types, | ||
* this function returns an empty array. | ||
*/ | ||
export default (path) => { | ||
let typePath = null; | ||
if (isReactComponentClass(path)) { | ||
const superTypes = path.get('superTypeParameters'); | ||
export default (componentDefinition) => { | ||
const typePaths = []; | ||
if (isReactComponentClass(componentDefinition)) { | ||
const superTypes = componentDefinition.get('superTypeParameters'); | ||
if (superTypes.hasNode()) { | ||
const params = superTypes.get('params'); | ||
if (params.length >= 1) { | ||
typePath = params[params.length === 3 ? 1 : 0]; | ||
typePaths.push(params[params.length === 3 ? 1 : 0]); | ||
} | ||
} | ||
else { | ||
const propsMemberPath = getMemberValuePath(path, 'props'); | ||
const propsMemberPath = getMemberValuePath(componentDefinition, 'props'); | ||
if (!propsMemberPath) { | ||
return null; | ||
return []; | ||
} | ||
typePath = getTypeAnnotation(propsMemberPath.parentPath); | ||
const typeAnnotation = getTypeAnnotation(propsMemberPath.parentPath); | ||
if (typeAnnotation) { | ||
typePaths.push(typeAnnotation); | ||
} | ||
} | ||
return typePath; | ||
} | ||
const propsParam = getStatelessPropsPath(path); | ||
if (propsParam) { | ||
typePath = getTypeAnnotation(propsParam); | ||
else { | ||
const propsParam = getStatelessPropsPath(componentDefinition); | ||
if (propsParam) { | ||
const typeAnnotation = getTypeAnnotation(propsParam); | ||
if (typeAnnotation) { | ||
typePaths.push(typeAnnotation); | ||
} | ||
} | ||
const assignedVariableType = findAssignedVariableType(componentDefinition); | ||
if (assignedVariableType) { | ||
typePaths.push(assignedVariableType); | ||
} | ||
} | ||
return typePath; | ||
return typePaths.map((typePath) => unwrapBuiltinTSPropTypes(typePath)); | ||
}; | ||
@@ -51,0 +86,0 @@ export function applyToTypeProperties(documentation, path, callback, typeParams) { |
@@ -28,3 +28,5 @@ import * as docblock from './docblock.js'; | ||
export { default as isExportsOrModuleAssignment } from './isExportsOrModuleAssignment.js'; | ||
export { default as isImportSpecifier } from './isImportSpecifier.js'; | ||
export { default as isReactBuiltinCall } from './isReactBuiltinCall.js'; | ||
export { default as isReactBuiltinReference } from './isReactBuiltinReference.js'; | ||
export { default as isReactChildrenElementCall } from './isReactChildrenElementCall.js'; | ||
@@ -31,0 +33,0 @@ export { default as isReactCloneElementCall } from './isReactCloneElementCall.js'; |
@@ -26,3 +26,5 @@ import * as docblock from './docblock.js'; | ||
export { default as isExportsOrModuleAssignment } from './isExportsOrModuleAssignment.js'; | ||
export { default as isImportSpecifier } from './isImportSpecifier.js'; | ||
export { default as isReactBuiltinCall } from './isReactBuiltinCall.js'; | ||
export { default as isReactBuiltinReference } from './isReactBuiltinReference.js'; | ||
export { default as isReactChildrenElementCall } from './isReactChildrenElementCall.js'; | ||
@@ -29,0 +31,0 @@ export { default as isReactCloneElementCall } from './isReactCloneElementCall.js'; |
@@ -1,27 +0,2 @@ | ||
import isReactModuleName from './isReactModuleName.js'; | ||
import resolveToModule from './resolveToModule.js'; | ||
import resolveToValue from './resolveToValue.js'; | ||
import isDestructuringAssignment from './isDestructuringAssignment.js'; | ||
function isNamedMemberExpression(value, name) { | ||
if (!value.isMemberExpression()) { | ||
return false; | ||
} | ||
const property = value.get('property'); | ||
return property.isIdentifier() && property.node.name === name; | ||
} | ||
function isNamedImportDeclaration(value, callee, name) { | ||
if (!value.isImportDeclaration() || !callee.isIdentifier()) { | ||
return false; | ||
} | ||
return value.get('specifiers').some((specifier) => { | ||
if (!specifier.isImportSpecifier()) { | ||
return false; | ||
} | ||
const imported = specifier.get('imported'); | ||
const local = specifier.get('local'); | ||
return ((imported.isIdentifier({ name }) || | ||
imported.isStringLiteral({ value: name })) && | ||
local.node.name === callee.node.name); | ||
}); | ||
} | ||
import isReactBuiltinReference from './isReactBuiltinReference.js'; | ||
/** | ||
@@ -32,25 +7,7 @@ * Returns true if the expression is a function call of the form | ||
export default function isReactBuiltinCall(path, name) { | ||
if (path.isCallExpression()) { | ||
const callee = path.get('callee'); | ||
if (callee.isMemberExpression() && | ||
callee.get('property').isIdentifier({ name })) { | ||
const module = resolveToModule(callee.get('object')); | ||
return Boolean(module && isReactModuleName(module)); | ||
} | ||
const value = resolveToValue(callee); | ||
if (value === callee) { | ||
return false; | ||
} | ||
if ( | ||
// const { x } = require('react') | ||
isDestructuringAssignment(value, name) || | ||
// `require('react').createElement` | ||
isNamedMemberExpression(value, name) || | ||
// `import { createElement } from 'react'` | ||
isNamedImportDeclaration(value, callee, name)) { | ||
const module = resolveToModule(value); | ||
return Boolean(module && isReactModuleName(module)); | ||
} | ||
if (!path.isCallExpression()) { | ||
return false; | ||
} | ||
return false; | ||
const callee = path.get('callee'); | ||
return isReactBuiltinReference(callee, name); | ||
} |
@@ -1,3 +0,2 @@ | ||
import isReactModuleName from './isReactModuleName.js'; | ||
import resolveToModule from './resolveToModule.js'; | ||
import isReactBuiltinReference from './isReactBuiltinReference.js'; | ||
/** | ||
@@ -12,14 +11,10 @@ * Returns true if the expression is a function call of the form | ||
const callee = path.get('callee'); | ||
if (!callee.isMemberExpression() || | ||
(!callee.get('property').isIdentifier({ name: 'only' }) && | ||
!callee.get('property').isIdentifier({ name: 'map' }))) { | ||
return false; | ||
if (callee.isMemberExpression()) { | ||
const calleeProperty = callee.get('property'); | ||
if (calleeProperty.isIdentifier({ name: 'only' }) || | ||
calleeProperty.isIdentifier({ name: 'map' })) { | ||
return isReactBuiltinReference(callee.get('object'), 'Children'); | ||
} | ||
} | ||
const calleeObj = callee.get('object'); | ||
if (!calleeObj.isMemberExpression() || | ||
!calleeObj.get('property').isIdentifier({ name: 'Children' })) { | ||
return false; | ||
} | ||
const module = resolveToModule(calleeObj); | ||
return Boolean(module && isReactModuleName(module)); | ||
return false; | ||
} |
@@ -5,2 +5,3 @@ import isReactModuleName from './isReactModuleName.js'; | ||
import isDestructuringAssignment from './isDestructuringAssignment.js'; | ||
import isImportSpecifier from './isImportSpecifier.js'; | ||
function isRenderMethod(path) { | ||
@@ -23,12 +24,16 @@ if ((!path.isClassMethod() || path.node.kind !== 'method') && | ||
const property = path.get('property'); | ||
if (!property.isIdentifier({ name: 'Component' }) && | ||
!property.isIdentifier({ name: 'PureComponent' })) { | ||
return false; | ||
if (property.isIdentifier({ name: 'Component' }) || | ||
property.isIdentifier({ name: 'PureComponent' })) { | ||
return true; | ||
} | ||
} | ||
else if (!isDestructuringAssignment(path, 'Component') && | ||
!isDestructuringAssignment(path, 'PureComponent')) { | ||
return false; | ||
else if (isImportSpecifier(path, 'Component') || | ||
isImportSpecifier(path, 'PureComponent')) { | ||
return true; | ||
} | ||
return true; | ||
else if (isDestructuringAssignment(path, 'Component') || | ||
isDestructuringAssignment(path, 'PureComponent')) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
@@ -43,6 +48,2 @@ /** | ||
} | ||
// extends something | ||
if (!path.node.superClass) { | ||
return false; | ||
} | ||
// React.Component or React.PureComponent | ||
@@ -59,2 +60,6 @@ const superClass = path.get('superClass'); | ||
} | ||
else { | ||
// does not extend anything | ||
return false; | ||
} | ||
// render method | ||
@@ -61,0 +66,0 @@ if (path.get('body').get('body').some(isRenderMethod)) { |
import type { NodePath } from '@babel/traverse'; | ||
/** | ||
* Returns true of the path is an unreachable TypePath | ||
* This evaluates the NodePaths returned from resolveToValue | ||
*/ | ||
declare const _default: (path: NodePath) => boolean; | ||
export default _default; |
/** | ||
* Returns true of the path is an unreachable TypePath | ||
* This evaluates the NodePaths returned from resolveToValue | ||
*/ | ||
export default (path) => { | ||
return (path.isIdentifier() || path.isImportDeclaration() || path.isCallExpression()); | ||
return (path.isIdentifier() || | ||
path.parentPath?.isImportDeclaration() || | ||
path.isCallExpression()); | ||
}; |
@@ -33,4 +33,4 @@ import getMemberExpressionRoot from './getMemberExpressionRoot.js'; | ||
} | ||
else if (path.isImportDeclaration()) { | ||
return path.node.source.value; | ||
else if (path.parentPath?.isImportDeclaration()) { | ||
return path.parentPath.node.source.value; | ||
} | ||
@@ -37,0 +37,0 @@ else if (path.isMemberExpression()) { |
@@ -140,7 +140,10 @@ import { Scope, visitors } from '@babel/traverse'; | ||
} | ||
else if (resolved.isImportDeclaration() && resolved.node.specifiers) { | ||
else if (resolved.isImportSpecifier() || | ||
resolved.isImportDefaultSpecifier() || | ||
resolved.isImportNamespaceSpecifier()) { | ||
const declaration = resolved.parentPath; | ||
// Handle references to namespace imports, e.g. import * as foo from 'bar'. | ||
// Try to find a specifier that matches the root of the member expression, and | ||
// find the export that matches the property name. | ||
for (const specifier of resolved.get('specifiers')) { | ||
for (const specifier of declaration.get('specifiers')) { | ||
const property = path.get('property'); | ||
@@ -155,3 +158,3 @@ let propertyName; | ||
specifier.node.local.name === root.node.name) { | ||
const resolvedPath = path.hub.import(resolved, propertyName); | ||
const resolvedPath = path.hub.import(declaration, propertyName); | ||
if (resolvedPath) { | ||
@@ -164,8 +167,2 @@ return resolveToValue(resolvedPath); | ||
} | ||
else if (path.isImportDefaultSpecifier() || | ||
path.isImportNamespaceSpecifier() || | ||
path.isImportSpecifier()) { | ||
// go up to the import declaration | ||
return path.parentPath; | ||
} | ||
else if (path.isTypeCastExpression() || | ||
@@ -172,0 +169,0 @@ path.isTSAsExpression() || |
{ | ||
"name": "react-docgen", | ||
"version": "6.0.4", | ||
"version": "7.0.0", | ||
"description": "A library to extract information from React components for documentation generation.", | ||
@@ -21,3 +21,3 @@ "repository": { | ||
"engines": { | ||
"node": ">=14.18.0" | ||
"node": ">=16.14.0" | ||
}, | ||
@@ -44,3 +44,3 @@ "main": "dist/main.js", | ||
"@types/babel__traverse": "^7.18.0", | ||
"@types/doctrine": "^0.0.6", | ||
"@types/doctrine": "^0.0.8", | ||
"@types/resolve": "^1.20.2", | ||
@@ -47,0 +47,0 @@ "doctrine": "^3.0.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
229724
170
5768
+ Added@types/doctrine@0.0.8(transitive)
- Removed@types/doctrine@0.0.6(transitive)
Updated@types/doctrine@^0.0.8