forked from mmckegg/hoister
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
106 lines (88 loc) · 2.2 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
module.exports = hoist
function hoist(ast){
var parentStack = []
var variables = []
var functions = []
if (Array.isArray(ast)){
walkAll(ast)
prependScope(ast, variables, functions)
} else {
walk(ast)
}
return ast
// walk through each node of a program of block statement
function walkAll(nodes){
var result = null
for (var i=0;i<nodes.length;i++){
var childNode = nodes[i]
if (childNode === null) continue
if (childNode.type === 'EmptyStatement') continue
var result = walk(childNode)
if (result === 'remove'){
nodes.splice(i--, 1)
}
}
}
function walk(node){
var parent = parentStack[parentStack.length-1]
var remove = false
parentStack.push(node)
var excludeBody = false
if (shouldScope(node, parent)){
hoist(node.body)
excludeBody = true
}
if (node.type === 'VariableDeclarator'){
variables.push(node)
}
if (node.type === 'FunctionDeclaration'){
functions.push(node)
remove = true
}
for (var key in node){
if (key === 'type' || (excludeBody && key === 'body')) continue
if (key in node && node[key] && typeof node[key] == 'object'){
if (node[key].type){
walk(node[key])
} else if (Array.isArray(node[key])){
walkAll(node[key])
}
}
}
parentStack.pop()
if (remove){
return 'remove'
}
}
}
function shouldScope(node, parent){
if (node.type === 'Program'){
return true
} else if (node.type === 'BlockStatement'){
if (parent && (parent.type === 'FunctionExpression' || parent.type === 'FunctionDeclaration')){
return true
}
}
}
function prependScope(nodes, variables, functions){
if (variables && variables.length){
var declarations = []
for (var i=0;i<variables.length;i++){
declarations.push({
type: 'VariableDeclarator',
id: variables[i].id,
init: null
})
}
nodes.unshift({
type: 'VariableDeclaration',
kind: 'var',
declarations: declarations
})
}
if (functions && functions.length){
for (var i=0;i<functions.length;i++){
nodes.unshift(functions[i])
}
}
}