-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathindex.js
105 lines (90 loc) · 2.47 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
import syntaxJsx from '@babel/plugin-syntax-jsx'
/**
* Check path has JSX
* @param t
* @param path
* @returns boolean
*/
const hasJSX = (t, path) => {
let hasJSX = false
let parentScope
path.traverse({
JSXElement(elPath) {
if (parentScope === elPath.scope) {
hasJSX = true
}
},
ArrowFunctionExpression(blockPath) {
const isParent = blockPath.parentPath === path
if (!isParent) {
return
}
parentScope = blockPath.scope
},
})
return hasJSX
}
/**
* Check if it's a functional componet declarator
* @param t
* @param path
* @returns boolean
*/
const isFunctionalComponentDeclarator = (t, path) => {
const firstCharacter = path.get('id.name').node[0]
if (firstCharacter < 'A' || firstCharacter > 'Z') {
return false
}
return hasJSX(t, path)
}
/**
* Convert arrow function to functional component
* @param t
* @param path
* @param name
*/
const convertFunctionalComponent = (t, path, name = null) => {
const params = [t.identifier('h'), ...path.node.params]
const body = path.node.body
const props = [
t.objectProperty(t.identifier('functional'), t.booleanLiteral(true)),
t.objectProperty(t.identifier('render'), t.arrowFunctionExpression(params, body)),
]
if (process.env.NODE_ENV === 'development' && name) {
props.unshift(t.objectProperty(t.identifier('name'), t.stringLiteral(name)))
}
path.replaceWith(t.objectExpression(props))
}
export default babel => {
const t = babel.types
return {
inherits: syntaxJsx,
visitor: {
Program(path) {
path.traverse({
ExportDefaultDeclaration(path) {
if (!t.isArrowFunctionExpression(path.node.declaration) || !hasJSX(t, path)) {
return
}
convertFunctionalComponent(t, path.get('declaration'))
},
VariableDeclaration(path) {
if (
path.node.declarations.length !== 1 ||
!t.isVariableDeclarator(path.node.declarations[0]) ||
!t.isArrowFunctionExpression(path.node.declarations[0].init)
) {
return
}
const declarator = path.get('declarations')[0]
if (!isFunctionalComponentDeclarator(t, declarator)) {
return
}
const name = path.node.declarations[0].id.name
convertFunctionalComponent(t, path.get('declarations')[0].get('init'), name)
},
})
},
},
}
}