react-docgen
Advanced tools
Comparing version 2.20.0 to 2.20.1
@@ -50,2 +50,8 @@ 'use strict'; | ||
documentation.set('displayName', (0, _getNameOrValue2.default)(path.get('id'))); | ||
} else if (types.ArrowFunctionExpression.check(path.node) || types.FunctionExpression.check(path.node)) { | ||
if (types.VariableDeclarator.check(path.parentPath.node)) { | ||
documentation.set('displayName', (0, _getNameOrValue2.default)(path.parentPath.get('id'))); | ||
} else if (types.AssignmentExpression.check(path.parentPath.node)) { | ||
documentation.set('displayName', (0, _getNameOrValue2.default)(path.parentPath.get('left'))); | ||
} | ||
} | ||
@@ -52,0 +58,0 @@ return; |
@@ -13,2 +13,6 @@ 'use strict'; | ||
var _postProcessDocumentation = require('./utils/postProcessDocumentation'); | ||
var _postProcessDocumentation2 = _interopRequireDefault(_postProcessDocumentation); | ||
var _babylon = require('./babylon'); | ||
@@ -24,14 +28,16 @@ | ||
var ERROR_MISSING_DEFINITION = 'No suitable component definition found.'; /* | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* | ||
* | ||
*/ | ||
/* | ||
* Copyright (c) 2015, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the BSD-style license found in the | ||
* LICENSE file in the root directory of this source tree. An additional grant | ||
* of patent rights can be found in the PATENTS file in the same directory. | ||
* | ||
* | ||
* | ||
*/ | ||
var ERROR_MISSING_DEFINITION = 'No suitable component definition found.'; | ||
function executeHandlers(handlers, componentDefinitions) { | ||
@@ -43,3 +49,3 @@ return componentDefinitions.map(function (componentDefinition) { | ||
}); | ||
return documentation.toObject(); | ||
return (0, _postProcessDocumentation2.default)(documentation.toObject()); | ||
}); | ||
@@ -46,0 +52,0 @@ } |
@@ -7,2 +7,6 @@ 'use strict'; | ||
var _typeof2 = require('babel-runtime/helpers/typeof'); | ||
var _typeof3 = _interopRequireDefault(_typeof2); | ||
var _extends2 = require('babel-runtime/helpers/extends'); | ||
@@ -71,2 +75,3 @@ | ||
var namedTypes = { | ||
ArrayTypeAnnotation: handleArrayTypeAnnotation, | ||
GenericTypeAnnotation: handleGenericTypeAnnotation, | ||
@@ -83,3 +88,3 @@ ObjectTypeAnnotation: handleObjectTypeAnnotation, | ||
function getFlowTypeWithRequirements(path) { | ||
var type = getFlowType(path); | ||
var type = getFlowTypeWithResolvedTypes(path); | ||
@@ -114,2 +119,10 @@ type.required = !path.parentPath.node.optional; | ||
function handleArrayTypeAnnotation(path) { | ||
return { | ||
name: 'Array', | ||
elements: [getFlowTypeWithResolvedTypes(path.get('elementType'))], | ||
raw: (0, _printValue2.default)(path) | ||
}; | ||
} | ||
function handleGenericTypeAnnotation(path) { | ||
@@ -132,3 +145,3 @@ if (path.node.id.name === '$Keys' && path.node.typeParameters) { | ||
elements: params.map(function (param) { | ||
return getFlowType(param); | ||
return getFlowTypeWithResolvedTypes(param); | ||
}), | ||
@@ -140,3 +153,3 @@ raw: (0, _printValue2.default)(path) | ||
if (resolvedPath && resolvedPath.node.right) { | ||
type = getFlowType(resolvedPath.get('right')); | ||
type = getFlowTypeWithResolvedTypes(resolvedPath.get('right')); | ||
} | ||
@@ -157,3 +170,3 @@ } | ||
path.get('callProperties').each(function (param) { | ||
type.signature.constructor = getFlowType(param.get('value')); | ||
type.signature.constructor = getFlowTypeWithResolvedTypes(param.get('value')); | ||
}); | ||
@@ -163,3 +176,3 @@ | ||
type.signature.properties.push({ | ||
key: getFlowType(param.get('key')), | ||
key: getFlowTypeWithResolvedTypes(param.get('key')), | ||
value: getFlowTypeWithRequirements(param.get('value')) | ||
@@ -184,3 +197,3 @@ }); | ||
elements: path.get('types').map(function (subType) { | ||
return getFlowType(subType); | ||
return getFlowTypeWithResolvedTypes(subType); | ||
}) | ||
@@ -195,3 +208,3 @@ }; | ||
elements: path.get('types').map(function (subType) { | ||
return getFlowType(subType); | ||
return getFlowTypeWithResolvedTypes(subType); | ||
}) | ||
@@ -206,3 +219,3 @@ }; | ||
var type = getFlowType(typeAnnotation); | ||
var type = getFlowTypeWithResolvedTypes(typeAnnotation); | ||
type.nullable = true; | ||
@@ -220,3 +233,3 @@ | ||
arguments: [], | ||
return: getFlowType(path.get('returnType')) | ||
return: getFlowTypeWithResolvedTypes(path.get('returnType')) | ||
} | ||
@@ -231,3 +244,3 @@ }; | ||
name: (0, _getPropertyName2.default)(param.get('name')), | ||
type: getFlowType(typeAnnotation) | ||
type: getFlowTypeWithResolvedTypes(typeAnnotation) | ||
}); | ||
@@ -243,3 +256,3 @@ }); | ||
path.get('types').each(function (param) { | ||
type.elements.push(getFlowType(param)); | ||
type.elements.push(getFlowTypeWithResolvedTypes(param)); | ||
}); | ||
@@ -251,3 +264,3 @@ | ||
function handleTypeofTypeAnnotation(path) { | ||
return getFlowType(path.get('argument')); | ||
return getFlowTypeWithResolvedTypes(path.get('argument')); | ||
} | ||
@@ -261,13 +274,24 @@ | ||
/** | ||
* Tries to identify the flow type by inspecting the path for known | ||
* flow type names. This method doesn't check whether the found type is actually | ||
* existing. It simply assumes that a match is always valid. | ||
* | ||
* If there is no match, "unknown" is returned. | ||
*/ | ||
function getFlowType(path) { | ||
var visitedTypes = {}; | ||
function getFlowTypeWithResolvedTypes(path) { | ||
var node = path.node; | ||
var type = void 0; | ||
var isTypeAlias = types.TypeAlias.check(path.parentPath.node); | ||
// When we see a typealias mark it as visited so that the next | ||
// call of this function does not run into an endless loop | ||
if (isTypeAlias) { | ||
if (visitedTypes[path.parentPath.node.id.name] === true) { | ||
// if we are currently visiting this node then just return the name | ||
// as we are starting to endless loop | ||
return { name: path.parentPath.node.id.name }; | ||
} else if ((0, _typeof3.default)(visitedTypes[path.parentPath.node.id.name]) === 'object') { | ||
// if we already resolved the type simple return it | ||
return visitedTypes[path.parentPath.node.id.name]; | ||
} | ||
// mark the type as visited | ||
visitedTypes[path.parentPath.node.id.name] = true; | ||
} | ||
if (types.Type.check(node)) { | ||
@@ -283,2 +307,7 @@ if (node.type in flowTypes) { | ||
if (isTypeAlias) { | ||
// mark the type as unvisited so that further calls can resolve the type again | ||
visitedTypes[path.parentPath.node.id.name] = type; | ||
} | ||
if (!type) { | ||
@@ -289,2 +318,14 @@ type = { name: 'unknown' }; | ||
return type; | ||
} | ||
/** | ||
* Tries to identify the flow type by inspecting the path for known | ||
* flow type names. This method doesn't check whether the found type is actually | ||
* existing. It simply assumes that a match is always valid. | ||
* | ||
* If there is no match, "unknown" is returned. | ||
*/ | ||
function getFlowType(path) { | ||
visitedTypes = {}; | ||
return getFlowTypeWithResolvedTypes(path); | ||
} |
@@ -56,90 +56,107 @@ 'use strict'; | ||
var reNonLexicalBlocks = /^If|^Else|^Switch/; | ||
var validPossibleStatelessComponentTypes = ['Property', 'FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression']; | ||
function isJSXElementOrReactCreateElement(path) { | ||
function isJSXElementOrReactCall(path) { | ||
return path.node.type === 'JSXElement' || path.node.type === 'CallExpression' && (0, _isReactCreateElementCall2.default)(path) || path.node.type === 'CallExpression' && (0, _isReactCloneElementCall2.default)(path) || path.node.type === 'CallExpression' && (0, _isReactChildrenElementCall2.default)(path); | ||
} | ||
function returnsJSXElementOrReactCreateElementCall(path) { | ||
var visited = false; | ||
function resolvesToJSXElementOrReactCall(path) { | ||
// Is the path is already a JSX element or a call to one of the React.* functions | ||
if (isJSXElementOrReactCall(path)) { | ||
return true; | ||
} | ||
// early exit for ArrowFunctionExpressions | ||
if (isJSXElementOrReactCreateElement(path.get('body'))) { | ||
var resolvedPath = (0, _resolveToValue2.default)(path); | ||
// If the path points to a conditional expression, then we need to look only at | ||
// the two possible paths | ||
if (resolvedPath.node.type === 'ConditionalExpression') { | ||
return resolvesToJSXElementOrReactCall(resolvedPath.get('consequent')) || resolvesToJSXElementOrReactCall(resolvedPath.get('alternate')); | ||
} | ||
// If the path points to a logical expression (AND, OR, ...), then we need to look only at | ||
// the two possible paths | ||
if (resolvedPath.node.type === 'LogicalExpression') { | ||
return resolvesToJSXElementOrReactCall(resolvedPath.get('left')) || resolvesToJSXElementOrReactCall(resolvedPath.get('right')); | ||
} | ||
// Is the resolved path is already a JSX element or a call to one of the React.* functions | ||
// Only do this if the resolvedPath actually resolved something as otherwise we did this check already | ||
if (resolvedPath !== path && isJSXElementOrReactCall(resolvedPath)) { | ||
return true; | ||
} | ||
function isSameBlockScope(p) { | ||
var block = p; | ||
do { | ||
block = block.parent; | ||
// jump over non-lexical blocks | ||
if (reNonLexicalBlocks.test(block.parent.node.type)) { | ||
block = block.parent; | ||
} | ||
} while (!types.BlockStatement.check(block.node) && /Function|Property/.test(block.parent.parent.node.type) && !reNonLexicalBlocks.test(block.parent.node.type)); | ||
// If we have a call expression, lets try to follow it | ||
if (resolvedPath.node.type === 'CallExpression') { | ||
// special case properties | ||
if (types.Property.check(path.node)) { | ||
return block.node === path.get('value', 'body').node; | ||
var calleeValue = (0, _resolveToValue2.default)(resolvedPath.get('callee')); | ||
if (returnsJSXElementOrReactCall(calleeValue)) { | ||
return true; | ||
} | ||
return block.node === path.get('body').node; | ||
} | ||
var resolvedValue = void 0; | ||
_recast2.default.visit(path, { | ||
visitReturnStatement: function visitReturnStatement(returnPath) { | ||
var resolvedPath = (0, _resolveToValue2.default)(returnPath.get('argument')); | ||
if (isJSXElementOrReactCreateElement(resolvedPath) && isSameBlockScope(returnPath)) { | ||
visited = true; | ||
return false; | ||
var namesToResolve = [calleeValue.get('property')]; | ||
if (calleeValue.node.type === 'MemberExpression') { | ||
if (calleeValue.get('object').node.type === 'Identifier') { | ||
resolvedValue = (0, _resolveToValue2.default)(calleeValue.get('object')); | ||
} else if (types.MemberExpression.check(calleeValue.node)) { | ||
do { | ||
calleeValue = calleeValue.get('object'); | ||
namesToResolve.unshift(calleeValue.get('property')); | ||
} while (types.MemberExpression.check(calleeValue.node)); | ||
resolvedValue = (0, _resolveToValue2.default)(calleeValue.get('object')); | ||
} | ||
} | ||
if (resolvedPath.node.type === 'CallExpression') { | ||
var calleeValue = (0, _resolveToValue2.default)(resolvedPath.get('callee')); | ||
if (resolvedValue && types.ObjectExpression.check(resolvedValue.node)) { | ||
var resolvedMemberExpression = namesToResolve.reduce(function (result, path) { | ||
// eslint-disable-line no-shadow | ||
if (!path) { | ||
return result; | ||
} | ||
if (returnsJSXElementOrReactCreateElementCall(calleeValue)) { | ||
visited = true; | ||
return false; | ||
if (result) { | ||
result = (0, _getPropertyValuePath2.default)(result, path.node.name); | ||
if (result && types.Identifier.check(result.node)) { | ||
return (0, _resolveToValue2.default)(result); | ||
} | ||
} | ||
return result; | ||
}, resolvedValue); | ||
var resolvedValue = void 0; | ||
if (!resolvedMemberExpression || returnsJSXElementOrReactCall(resolvedMemberExpression)) { | ||
return true; | ||
} | ||
} | ||
} | ||
var namesToResolve = [calleeValue.get('property')]; | ||
return false; | ||
} | ||
if (calleeValue.node.type === 'MemberExpression') { | ||
if (calleeValue.get('object').node.type === 'Identifier') { | ||
resolvedValue = (0, _resolveToValue2.default)(calleeValue.get('object')); | ||
} else if (types.MemberExpression.check(calleeValue.node)) { | ||
do { | ||
calleeValue = calleeValue.get('object'); | ||
namesToResolve.unshift(calleeValue.get('property')); | ||
} while (types.MemberExpression.check(calleeValue.node)); | ||
function returnsJSXElementOrReactCall(path) { | ||
var visited = false; | ||
resolvedValue = (0, _resolveToValue2.default)(calleeValue.get('object')); | ||
} | ||
} | ||
// early exit for ArrowFunctionExpressions | ||
if (path.node.type === 'ArrowFunctionExpression' && path.get('body').node.type !== 'BlockStatement' && resolvesToJSXElementOrReactCall(path.get('body'))) { | ||
return true; | ||
} | ||
if (resolvedValue && types.ObjectExpression.check(resolvedValue.node)) { | ||
var resolvedMemberExpression = namesToResolve.reduce(function (result, path) { | ||
// eslint-disable-line no-shadow | ||
if (!path) { | ||
return result; | ||
} | ||
var scope = path.scope; | ||
// If we get a property we want the function scope it holds and not its outer scope | ||
if (path.node.type === 'Property') { | ||
scope = path.get('value').scope; | ||
} | ||
if (result) { | ||
result = (0, _getPropertyValuePath2.default)(result, path.node.name); | ||
if (result && types.Identifier.check(result.node)) { | ||
return (0, _resolveToValue2.default)(result); | ||
} | ||
} | ||
return result; | ||
}, resolvedValue); | ||
_recast2.default.visit(path, { | ||
visitReturnStatement: function visitReturnStatement(returnPath) { | ||
// Only check return statements which are part of the checked function scope | ||
if (returnPath.scope !== scope) return false; | ||
if (!resolvedMemberExpression || returnsJSXElementOrReactCreateElementCall(resolvedMemberExpression)) { | ||
visited = true; | ||
return false; | ||
} | ||
} | ||
if (resolvesToJSXElementOrReactCall(returnPath.get('argument'))) { | ||
visited = true; | ||
return false; | ||
} | ||
@@ -170,3 +187,3 @@ | ||
if (returnsJSXElementOrReactCreateElementCall(path)) { | ||
if (returnsJSXElementOrReactCall(path)) { | ||
return true; | ||
@@ -173,0 +190,0 @@ } |
{ | ||
"name": "react-docgen", | ||
"version": "2.20.0", | ||
"version": "2.20.1", | ||
"description": "A CLI and toolkit to extract information from React components for documentation generation.", | ||
@@ -22,4 +22,4 @@ "repository": { | ||
"lint": "eslint src/ bin/", | ||
"prepublish": "yarn run build", | ||
"preversion": "yarn run lint", | ||
"prepublish": "yarn build", | ||
"preversion": "yarn lint", | ||
"test": "jest", | ||
@@ -26,0 +26,0 @@ "test:ci": "yarn lint && yarn flow && yarn test --runInBand", |
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
192692
68
4511