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 | 1
1
1
82124
82123
64
106
64
82059
82059
82056
82056
82056
83291
83291
77220
79214
79214
79204
79200
79186
79001
79001
78990
77220
23915
25909
23904
25933
53305
53291
1
1
1
1
4380
1
1
2
2
2
2
2
2
15
1
1
2
| var VISITOR_KEYS = require("./visitor-keys");
var _ = require("lodash");
var traverse = module.exports = function (parent, callbacks, blacklistTypes) {
// falsy node
if (!parent) return;
// array of nodes
if (_.isArray(parent)) {
_.each(parent, function (node) {
traverse(node, callbacks, blacklistTypes);
});
return;
}
// unknown node type to traverse
var keys = VISITOR_KEYS[parent.type];
if (!keys) return;
// blacklist these node types from being traversed
blacklistTypes = blacklistTypes || [];
// normalise callbacks
if (_.isFunction(callbacks)) callbacks = { enter: callbacks };
_.each(keys, function (key) {
var nodes = parent[key];
if (!nodes) return;
var handle = function (obj, key) {
var node = obj[key];
if (!node) return;
// type is blacklisted
if (_.contains(blacklistTypes, node.type)) return;
// enter
var result = callbacks.enter(node, parent, obj, key);
// stop iteration
if (result === false) return;
// replace node
if (result != null) node = obj[key] = result;
// traverse node
traverse(node, callbacks, blacklistTypes);
// exit
if (callbacks.exit) callbacks.exit(node, parent, obj, key);
};
if (_.isArray(nodes)) {
_.each(nodes, function (node, i) {
handle(nodes, i);
});
// remove deleted nodes
parent[key] = _.flatten(parent[key]).filter(function (node) {
return node !== traverse.Delete;
});
} else {
handle(parent, key);
if (parent[key] === traverse.Delete) {
throw new Error("trying to delete property " + key + " from " +
parent.type + " but can't because it's required");
}
}
});
};
traverse.FUNCTION_TYPES = ["ArrowFunctionExpression", "FunctionDeclaration", "FunctionExpression"];
traverse.aliases = {
ArrowFunctionExpression: ["Function"],
FunctionDeclaration: ["Function"],
FunctionExpression: ["Function"]
};
traverse.isFunction = function (node) {
return _.contains(traverse.FUNCTION_TYPES, node.type);
};
traverse.Delete = {};
traverse.hasType = function (tree, type, blacklistTypes) {
blacklistTypes = [].concat(blacklistTypes || []);
var has = false;
Iif (_.isArray(tree)) {
// array of nodes, find the first
return !!_.find(tree, function (node) {
return traverse.hasType(node, type, blacklistTypes);
});
} else {
// the node we're searching in is blacklisted
Iif (_.contains(blacklistTypes, tree.type)) return false;
// the type we're looking for is the same as the passed node
Iif (tree.type === type) return true;
traverse(tree, function (node) {
if (node.type === type) {
has = true;
return false;
}
}, blacklistTypes);
}
return has;
};
|