/** * Try to find the part of JavaScript a comment is referring to, by * looking at the syntax tree closest to that comment. * * @param {Object} path abstract syntax tree path * @returns {?Object} ast path, if one is found. * @private */ function findTarget(path: ?Object) { if (!path) { return path; } if ( t.isExportDefaultDeclaration(path) || (t.isExportNamedDeclaration(path) && path.has('declaration')) ) { path = path.get('declaration'); } if (t.isVariableDeclaration(path)) { // var x = init; path = path.get('declarations')[0]; } else if (t.isExpressionStatement(path)) { // foo.x = TARGET path = path.get('expression').get('right'); } else if (t.isObjectProperty(path)) { // var foo = { x: TARGET }; object property path = path.get('value'); } else if (t.isClassProperty(path) && path.get('value').node) { // var foo = { x = TARGET }; class property path = path.get('value'); } return path.node && path; }
export function push(mutatorMap: Object, node: Object, kind: string, file, scope?): Object { let alias = t.toKeyAlias(node); // let map = {}; if (has(mutatorMap, alias)) map = mutatorMap[alias]; mutatorMap[alias] = map; // map._inherits = map._inherits || []; map._inherits.push(node); map._key = node.key; if (node.computed) { map._computed = true; } if (node.decorators) { let decorators = map.decorators = map.decorators || t.arrayExpression([]); decorators.elements = decorators.elements.concat(node.decorators.map(dec => dec.expression).reverse()); } if (map.value || map.initializer) { throw file.buildCodeFrameError(node, "Key conflict with sibling node"); } let key, value; // save the key so we can possibly do function name inferences if (t.isObjectProperty(node) || t.isObjectMethod(node) || t.isClassMethod(node)) { key = t.toComputedKey(node, node.key); } if (t.isObjectProperty(node) || t.isClassProperty(node)) { value = node.value; } else if (t.isObjectMethod(node) || t.isClassMethod(node)) { value = t.functionExpression(null, node.params, node.body, node.generator, node.async); } let inheritedKind = toKind(node); if (!kind || inheritedKind !== "value") { kind = inheritedKind; } // infer function name if (scope && t.isStringLiteral(key) && (kind === "value" || kind === "initializer") && t.isFunctionExpression(value)) { value = nameFunction({ id: key, node: value, scope }); } if (value) { t.inheritsComments(value, node); map[kind] = value; } return map; }
function parseSourceFile(source, fileName) { let proptypesHtml = ''; const ast = babylon.parse(source, { sourceType: 'module', plugins: ['jsx' , 'classProperties', 'objectRestSpread'] }); let propTypes = []; let componentName = fileName; traverse(ast, { enter(path) { // Update the component name with the variable name used in its class definition if (t.isClassDeclaration(path.node)) { componentName = path.node.id.name; } // iterate over each prop and populate an array containing the name of // the prop and its value if (t.isClassProperty(path.node) && t.isIdentifier(path.node.key, { name: 'propTypes' } )) { path.node.value.properties.forEach(prop => { let propValue = generate(prop.value, {}, source).code; const propName = prop.key.name; let link; // look up the variable name and see if it's being required from a // local file. If it is, convert the text to a hyperlink so we can // jump to the proptype definition on the page. let variableName = prop.value.object ? prop.value.object.name : null; if (!variableName && prop.value.object) { variableName = prop.value.object.object ? prop.value.object.object.name : null; } const binding = variableName && path.scope.getBinding(variableName); if (binding && isLocalPropTypeRequire(binding.path.node)) { link = variableName; // propValue = propValue.replace(variableName, '<a href="#' + variableName + '">' + variableName + '</a>'); } propTypes.push({ name: propName, value: propValue, link: link }); }); } } }); if (propTypes.length) { proptypesHtml += createPropTypesSection(componentName, '<code><' + componentName + '/></code>', propTypes, false); } return proptypesHtml; }
each(map, function (node, key) { if (key[0] === "_") return; let inheritNode = node; if (t.isClassMethod(node) || t.isClassProperty(node)) node = node.value; let prop = t.objectProperty(t.identifier(key), node); t.inheritsComments(prop, inheritNode); t.removeComments(inheritNode); mapNode.properties.push(prop); });
function handleThirdPartyComponent(expr) { if (t.isClassProperty(expr) && expr.key.name === 'config' && t.isObjectExpression(expr.value)) { const properties = expr.value.properties; for (const prop of properties) { if (t.isObjectProperty(prop) && (t.isIdentifier(prop.key, { name: 'usingComponents' }) || t.isStringLiteral(prop.key, { value: 'usingComponents' })) && t.isObjectExpression(prop.value)) { for (const value of prop.value.properties) { if (t.isObjectProperty(value)) { if (t.isStringLiteral(value.key)) { constant_1.THIRD_PARTY_COMPONENTS.add(value.key.value); } if (t.isIdentifier(value.key)) { constant_1.THIRD_PARTY_COMPONENTS.add(value.key.name); } } } } } } }
isPure(node, constantsOnly?: boolean) { if (t.isIdentifier(node)) { let binding = this.getBinding(node.name); if (!binding) return false; if (constantsOnly) return binding.constant; return true; } else if (t.isClass(node)) { if (node.superClass && !this.isPure(node.superClass, constantsOnly)) return false; return this.isPure(node.body, constantsOnly); } else if (t.isClassBody(node)) { for (let method of node.body) { if (!this.isPure(method, constantsOnly)) return false; } return true; } else if (t.isBinary(node)) { return this.isPure(node.left, constantsOnly) && this.isPure(node.right, constantsOnly); } else if (t.isArrayExpression(node)) { for (let elem of (node.elements: Array<Object>)) { if (!this.isPure(elem, constantsOnly)) return false; } return true; } else if (t.isObjectExpression(node)) { for (let prop of (node.properties: Array<Object>)) { if (!this.isPure(prop, constantsOnly)) return false; } return true; } else if (t.isClassMethod(node)) { if (node.computed && !this.isPure(node.key, constantsOnly)) return false; if (node.kind === "get" || node.kind === "set") return false; return true; } else if (t.isClassProperty(node) || t.isObjectProperty(node)) { if (node.computed && !this.isPure(node.key, constantsOnly)) return false; return this.isPure(node.value, constantsOnly); } else if (t.isUnaryExpression(node)) { return this.isPure(node.argument, constantsOnly); } else { return t.isPureish(node); } }
function findKind(path) { if (!path) { return comment; } else if (t.isClassDeclaration(path)) { comment.kind = 'class'; } else if (t.isFunction(path)) { if (path.node && (path.node.kind === 'get' || path.node.kind === 'set')) { comment.kind = 'member'; } else if (path.node && path.node.id && path.node.id.name && !!/^[A-Z]/.exec(path.node.id.name)) { comment.kind = 'class'; } else { comment.kind = 'function'; } } else if (t.isTypeAlias(path)) { comment.kind = 'typedef'; } else if (t.isVariableDeclaration(path)) { if (path.node.kind === 'const') { comment.kind = 'constant'; } else { // This behavior is in need of fixing https://github.com/documentationjs/documentation/issues/351 findKind(path.node.declarations[0].init); } } else if (t.isExportNamedDeclaration(path) && path.node.declaration) { // && makes sure that // export { foo } from bar; // doesn't check for a non-existent declaration type if (path.node.declaration.kind === 'const') { comment.kind = 'constant'; } } else if (t.isExpressionStatement(path)) { // module.exports = function() {} findKind(path.node.expression.right); } else if (t.isClassProperty(path)) { comment.kind = 'member'; } else if (t.isProperty(path)) { // { foo: function() {} } findKind(path.node.value); } }
export default function getFunctionName(path: NodePath): string { if (path.node.id) { return path.node.id.name; } if (path.type === "MethodDefinition") { return path.node.key.name; } const parent = path.parent; if (parent.type == "ObjectProperty") { return parent.key.name; } if (parent.type == "ObjectExpression" || path.node.type == "ClassMethod") { return path.node.key.name; } if (parent.type == "VariableDeclarator") { return parent.id.name; } if (parent.type == "AssignmentExpression") { if (parent.left.type == "MemberExpression") { return parent.left.property.name; } return parent.left.name; } if (t.isClassProperty(parent) && t.isArrowFunctionExpression(path)) { return parent.key.name; } return "anonymous"; }
return shouldSkipInference(function inferMembership(comment) { if (comment.kind === 'module') { currentModule = comment; } if (comment.lends) { return; } if (comment.memberof) { return normalizeMemberof(comment); } if (!comment.context.ast) { return comment; } var path = comment.context.ast; var identifiers; // Deal with an oddity of espree: the jsdoc comment is attached to a different // node in the two expressions `a.b = c` vs `a.b = function () {}`. if (n.isExpressionStatement(path.node) && n.isAssignmentExpression(path.node.expression) && n.isMemberExpression(path.node.expression.left)) { path = path.get('expression').get('left'); } // Same as above but for `b: c` vs `b: function () {}`. if (n.isObjectProperty(path.node) && n.isIdentifier(path.node.key)) { path = path.get('key'); } // Foo.bar = ...; // Foo.prototype.bar = ...; // Foo.bar.baz = ...; if (n.isMemberExpression(path.node)) { identifiers = [].concat( extractThis(path), extractIdentifiers(path) ); if (identifiers.length >= 2) { inferMembershipFromIdentifiers(comment, identifiers.slice(0, -1)); } } // /** @lends Foo */{ bar: ... } if (n.isIdentifier(path.node) && n.isObjectProperty(path.parentPath) && n.isObjectExpression(path.parentPath.parentPath)) { // The @lends comment is sometimes attached to the first property rather than // the object expression itself. identifiers = findLendsIdentifiers(path.parentPath.parentPath.node) || findLendsIdentifiers(path.parentPath.parentPath.node.properties[0]); if (identifiers) { inferMembershipFromIdentifiers(comment, identifiers); } } // Foo = { bar: ... }; // Foo.prototype = { bar: ... }; // Foo.bar = { baz: ... }; if (n.isIdentifier(path.node) && n.isObjectProperty(path.parentPath) && n.isObjectExpression(path.parentPath.parentPath) && n.isAssignmentExpression(path.parentPath.parentPath.parentPath)) { identifiers = extractIdentifiers(path.parentPath.parentPath.parentPath.get('left')); if (identifiers.length >= 1) { inferMembershipFromIdentifiers(comment, identifiers); } } // var Foo = { bar: ... } if (n.isIdentifier(path) && n.isObjectProperty(path.parentPath) && n.isObjectExpression(path.parentPath.parentPath) && n.isVariableDeclarator(path.parentPath.parentPath.parentPath)) { identifiers = [path.parentPath.parentPath.parentPath.node.id.name]; inferMembershipFromIdentifiers(comment, identifiers); } // class Foo { bar() { } } // var Foo = class { bar() { } } // class Foo { prop: T } // var Foo = class { prop: T } if ((n.isClassMethod(path) || n.isClassProperty(path)) && n.isClassBody(path.parentPath) && n.isClass(path.parentPath.parentPath)) { if (n.isExpression(path.parentPath.parentPath)) { identifiers = extractIdentifiers(path.parentPath.parentPath.parentPath.get('left')); } else { var declarationNode = path.parentPath.parentPath.node; if (!declarationNode.id) { // export default function () {} // export default class {} // Use module name instead. identifiers = [pathParse(comment.context.file).name]; } else { identifiers = [declarationNode.id.name]; } } var scope = 'instance'; if (path.node.static == true) { scope = 'static'; } inferMembershipFromIdentifiers(comment, identifiers, scope); } // var function Foo() { // function bar() {} // return { bar: bar }; // } /* if (n.isFunctionDeclaration(path) && n.isBlockStatement(path.parentPath) && n.isFunction(path.parentPath.parentPath)) { inferMembershipFromIdentifiers(comment, [path.parentPath.parentPath.node.id.name]); } */ return comment; });
var type = find(classBody, node => t.isClassProperty(node) && node.key.name === 'defaultProps' && node.static);
var type = find(classBody, node => t.isClassProperty(node) && node.key.name === 'propTypes' && node.static);