/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at . */ import * as t from "@babel/types"; // the function class is inferred from a call like // createClass or extend function fromCallExpression(callExpression) { const allowlist = ["extend", "createClass"]; const { callee } = callExpression.node; if (!callee) { return null; } const name = t.isMemberExpression(callee) ? callee.property.name : callee.name; if (!allowlist.includes(name)) { return null; } const variable = callExpression.findParent(p => t.isVariableDeclarator(p.node) ); if (variable) { return variable.node.id.name; } const assignment = callExpression.findParent(p => t.isAssignmentExpression(p.node) ); if (!assignment) { return null; } const { left } = assignment.node; if (left.name) { return name; } if (t.isMemberExpression(left)) { return left.property.name; } return null; } // the function class is inferred from a prototype assignment // e.g. TodoClass.prototype.render = function() {} function fromPrototype(assignment) { const { left } = assignment.node; if (!left) { return null; } if ( t.isMemberExpression(left) && left.object && t.isMemberExpression(left.object) && left.object.property.identifier === "prototype" ) { return left.object.object.name; } return null; } // infer class finds an appropriate class for functions // that are defined inside of a class like thing. // e.g. `class Foo`, `TodoClass.prototype.foo`, // `Todo = createClass({ foo: () => {}})` export function inferClassName(path) { const classDeclaration = path.findParent(p => t.isClassDeclaration(p.node)); if (classDeclaration) { return classDeclaration.node.id.name; } const callExpression = path.findParent(p => t.isCallExpression(p.node)); if (callExpression) { return fromCallExpression(callExpression); } const assignment = path.findParent(p => t.isAssignmentExpression(p.node)); if (assignment) { return fromPrototype(assignment); } return null; }