-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathindex.js
118 lines (106 loc) · 2.82 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
import syntaxJsx from '@babel/plugin-syntax-jsx'
/**
* Check if first parameter is `h`
* @param t
* @param path ObjectMethod | ClassMethod
* @returns boolean
*/
const firstParamIsH = (t, path) => {
const params = path.get('params')
return params.length && t.isIdentifier(params[0]) && params[0].node.name === 'h'
}
/**
* Check if body contains JSX
* @param t
* @param path ObjectMethod | ClassMethod
* @returns boolean
*/
const hasJSX = (t, path) => {
const JSXChecker = {
hasJSX: false,
}
path.traverse(
{
JSXElement() {
this.hasJSX = true
},
},
JSXChecker,
)
return JSXChecker.hasJSX
}
/**
* Check if is inside a JSX expression
* @param t
* @param path ObjectMethod | ClassMethod
* @returns boolean
*/
const isInsideJSXExpression = (t, path) => {
if (!path.parentPath) {
return false
}
if (t.isJSXExpressionContainer(path.parentPath)) {
return true
}
return isInsideJSXExpression(t, path.parentPath)
}
/**
* check if has Defined H Variable And assigned $createElement in method or arguments[0] in render
* @param t
* @param path ObjectMethod | ClassMethod
* @returns boolean
*/
const hasDefinedHVariable = (t, path) => {
let result = {
hasDefined: false
}
const inRender = path.node.key.name === 'render'
path.traverse(
{
VariableDeclarator(path, state) {
if (state.hasDefined || path.node.id.name !== 'h') {
return
}
const { init } = path.node
state.hasDefined = t.isMemberExpression(init) &&
(inRender ?
t.isIdentifier(init.object) && init.object.name === 'arguments' && t.isNumericLiteral(init.property) && init.property.value === 0 :
t.isThisExpression(init.object) && t.isIdentifier(init.property) && init.property.name === '$createElement'
)
}
},
result
)
return result.hasDefined
}
export default babel => {
const t = babel.types
return {
inherits: syntaxJsx,
visitor: {
Program(path1) {
path1.traverse({
'ObjectMethod|ClassMethod'(path) {
if (firstParamIsH(t, path) || !hasJSX(t, path) || isInsideJSXExpression(t, path) || hasDefinedHVariable(t, path)) {
return
}
const isRender = path.node.key.name === 'render'
path
.get('body')
.unshiftContainer(
'body',
t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier('h'),
isRender
? t.memberExpression(t.identifier('arguments'), t.numericLiteral(0), true)
: t.memberExpression(t.thisExpression(), t.identifier('$createElement')),
),
]),
)
}
})
}
},
}
}