react-docgen
Version:
A CLI and toolkit to extract information from React components for documentation generation.
112 lines (93 loc) • 3.58 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = normalizeClassDefinition;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _getMemberExpressionRoot = _interopRequireDefault(require("../utils/getMemberExpressionRoot"));
var _getMembers3 = _interopRequireDefault(require("../utils/getMembers"));
var _recast = _interopRequireDefault(require("recast"));
/*
* 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.
*
*
*/
const _recast$types = _recast.default.types,
types = _recast$types.namedTypes,
builders = _recast$types.builders;
const ignore = () => false;
/**
* Given a class definition (i.e. `class` declaration or expression), this
* function "normalizes" the definition, by looking for assignments of static
* properties and converting them to ClassProperties.
*
* Example:
*
* class MyComponent extends React.Component {
* // ...
* }
* MyComponent.propTypes = { ... };
*
* is converted to
*
* class MyComponent extends React.Component {
* // ...
* static propTypes = { ... };
* }
*/
function normalizeClassDefinition(classDefinition) {
let variableName;
if (types.ClassDeclaration.check(classDefinition.node)) {
// Class declarations don't have an id, e.g.: `export default class extends React.Component {}`
if (classDefinition.node.id) {
variableName = classDefinition.node.id.name;
}
} else if (types.ClassExpression.check(classDefinition.node)) {
let parentPath = classDefinition.parentPath;
while (parentPath.node !== classDefinition.scope.node && !types.BlockStatement.check(parentPath.node)) {
if (types.VariableDeclarator.check(parentPath.node) && types.Identifier.check(parentPath.node.id)) {
variableName = parentPath.node.id.name;
break;
} else if (types.AssignmentExpression.check(parentPath.node) && types.Identifier.check(parentPath.node.left)) {
variableName = parentPath.node.left.name;
break;
}
parentPath = parentPath.parentPath;
}
}
if (!variableName) {
return;
}
const scopeRoot = classDefinition.scope;
_recast.default.visit(scopeRoot.node, {
visitFunction: ignore,
visitClassDeclaration: ignore,
visitClassExpression: ignore,
visitForInStatement: ignore,
visitForStatement: ignore,
visitAssignmentExpression: function visitAssignmentExpression(path) {
if (types.MemberExpression.check(path.node.left)) {
const first = (0, _getMemberExpressionRoot.default)(path.get('left'));
if (types.Identifier.check(first.node) && first.node.name === variableName) {
const _getMembers = (0, _getMembers3.default)(path.get('left')),
_getMembers2 = (0, _slicedToArray2.default)(_getMembers, 1),
member = _getMembers2[0];
if (member && !member.path.node.computed) {
const classProperty = builders.classProperty(member.path.node, path.node.right, null, true);
classDefinition.get('body', 'body').value.push(classProperty);
return false;
}
}
this.traverse(path);
} else {
return false;
}
}
});
}