This repository has been archived by the owner on Jan 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathindex.js
177 lines (156 loc) · 5.62 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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)
}
}