123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- module.exports = transform;
- var pathMod = require('path')
- function transform (babel) {
- return {
- visitor: {
- ClassDeclaration: function (path, state) {
- if (classHasRenderMethod(path)) {
- setDisplayNameAfter(path, path.node.id, babel.types)
- }
- },
- FunctionDeclaration: function (path, state) {
- if (doesReturnJSX(path.node.body) || (path.node.id && path.node.id.name &&
- isKnownComponent(path.node.id.name, state.opts.knownComponents))) {
- var displayName
- if (path.parentPath.node.type === 'ExportDefaultDeclaration') {
- if (path.node.id == null) {
- // An anonymous function declaration in export default declaration.
- // Transform `export default function () { ... }`
- // to `var _uid1 = function () { .. }; export default __uid;`
- // then add displayName to _uid1
- var extension = pathMod.extname(state.file.opts.filename)
- var name = pathMod.basename(state.file.opts.filename, extension)
-
- var id = path.scope.generateUidIdentifier("uid");
- path.node.id = id
- displayName = name
- }
- setDisplayNameAfter(path, path.node.id, babel.types, displayName)
- }else if(path.parentPath.node.type === 'Program' || path.parentPath.node.type == 'ExportNamedDeclaration') {
- setDisplayNameAfter(path, path.node.id, babel.types, displayName)
- }
- }
- },
- FunctionExpression: function (path, state) {
- if(shouldSetDisplayNameForFuncExpr(path, state.opts.knownComponents)) {
- var id = findCandidateNameForExpression(path)
- if (id) {
- setDisplayNameAfter(path, id, babel.types)
- }
- }
- },
- ArrowFunctionExpression: function (path, state) {
- if(shouldSetDisplayNameForFuncExpr(path, state.opts.knownComponents)) {
- var id = findCandidateNameForExpression(path)
- if (id) {
- setDisplayNameAfter(path, id, babel.types)
- }
- }
- }
- }
- }
- }
- function isKnownComponent(name, knownComponents) {
- return (name && knownComponents && knownComponents.indexOf(name) > -1)
- }
- function componentNameFromFilename(filename) {
- var extension = pathMod.extname(filename);
- var name = pathMod.basename(filename, extension)
- return name
- }
- function shouldSetDisplayNameForFuncExpr(path, knownComponents) {
- // Parent must be either 'AssignmentExpression' or 'VariableDeclarator' or 'CallExpression' with a parent of 'VariableDeclarator'
- var id
- if (path.parentPath.node.type === 'AssignmentExpression' &&
- path.parentPath.node.left.type !== 'MemberExpression' && // skip static members
- path.parentPath.parentPath.node.type == 'ExpressionStatement' &&
- path.parentPath.parentPath.parentPath.node.type == 'Program') {
- id = path.parentPath.node.left
- }else{
- // if parent is a call expression, we have something like (function () { .. })()
- // move up, past the call expression and run the rest of the checks as usual
- if(path.parentPath.node.type === 'CallExpression') {
- path = path.parentPath
- }
- if(path.parentPath.node.type === 'VariableDeclarator') {
- if (path.parentPath.parentPath.parentPath.node.type === 'ExportNamedDeclaration' ||
- path.parentPath.parentPath.parentPath.node.type === 'Program') {
- id = path.parentPath.node.id
- }
- }
- }
- if (id) {
- if (id.name && isKnownComponent(id.name, knownComponents)) {
- return true
- }
- return doesReturnJSX(path.node.body)
- }
- return false
- }
- function classHasRenderMethod(path) {
- if(!path.node.body) {
- return false
- }
- var members = path.node.body.body
- for(var i = 0; i < members.length; i++) {
- if (members[i].type == 'ClassMethod' && members[i].key.name == 'render') {
- return true
- }
- }
- return false
- }
- // https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-react-display-name/src/index.js#L62-L77
- // crawl up the ancestry looking for possible candidates for displayName inference
- function findCandidateNameForExpression(path) {
- var id
- path.find(function (path) {
- if (path.isAssignmentExpression()) {
- id = path.node.left;
- // } else if (path.isObjectProperty()) {
- // id = path.node.key;
- } else if (path.isVariableDeclarator()) {
- id = path.node.id;
- } else if (path.isStatement()) {
- // we've hit a statement, we should stop crawling up
- return true;
- }
- // we've got an id! no need to continue
- if (id) return true;
- });
- return id
- }
- function doesReturnJSX (body) {
- if (!body) return false
- if (body.type === 'JSXElement') {
- return true
- }
- var block = body.body
- if (block && block.length) {
- var lastBlock = block.slice(0).pop()
- if (lastBlock.type === 'ReturnStatement') {
- return lastBlock.argument !== null && lastBlock.argument.type === 'JSXElement'
- }
- }
- return false
- }
- function setDisplayNameAfter(path, nameNodeId, t, displayName) {
- if (!displayName) {
- displayName = nameNodeId.name
- }
- var blockLevelStmnt
- path.find(function (path) {
- if (path.parentPath.isBlock()) {
- blockLevelStmnt = path
- return true
- }
- })
- if (blockLevelStmnt) {
- var trailingComments = blockLevelStmnt.node.trailingComments
- delete blockLevelStmnt.node.trailingComments
- var setDisplayNameStmn = t.expressionStatement(t.assignmentExpression(
- '=',
- t.memberExpression(nameNodeId, t.identifier('displayName')),
- t.stringLiteral(displayName)
- ))
- blockLevelStmnt.insertAfter(setDisplayNameStmn)
- }
- }
|