forked from danielstjules/jsinspect
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nodeUtilsSpec.js
261 lines (232 loc) · 8.2 KB
/
nodeUtilsSpec.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
var expect = require('expect.js');
var fixtures = require('./fixtures');
var helpers = require('./helpers');
var NodeUtils = require('../lib/nodeUtils');
describe('NodeUtils', function() {
describe('walkSubtrees', function() {
it('walks each child node using DFS', function() {
var res = [];
var root = helpers.parse(fixtures.simple)[0];
NodeUtils.walkSubtrees(root, node => res.push(node.type));
expect(res).to.eql([
'ExpressionStatement',
'UpdateExpression',
'Identifier',
'ExpressionStatement',
'CallExpression',
'Identifier'
]);
});
});
describe('getDFSTraversal', function() {
it('returns the DFS traversal of the AST', function() {
var res = [];
var ast = helpers.parse(fixtures.simple)[0];
var res = NodeUtils.getDFSTraversal(ast).map(node => node.type);
expect(res).to.eql([
'BlockStatement',
'ExpressionStatement',
'UpdateExpression',
'Identifier',
'ExpressionStatement',
'CallExpression',
'Identifier'
]);
});
});
describe('getBFSTraversal', function() {
it('returns the BFS traversal of the AST', function() {
var res = [];
var ast = helpers.parse(fixtures.simple)[0];
var res = NodeUtils.getBFSTraversal(ast).map(node => node.type);
expect(res).to.eql([
'BlockStatement',
'ExpressionStatement',
'ExpressionStatement',
'UpdateExpression',
'CallExpression',
'Identifier',
'Identifier'
]);
});
});
describe('getChildren', function() {
it('returns the children of a Node', function() {
var parent = helpers.parse(fixtures.intersection)[0];
var res = NodeUtils.getChildren(parent);
// Children should be the three identifiers intersectionA,
// array1, and array2, followed by a block statement
expect(res.map(node => node.type)).to.eql([
'Identifier',
'Identifier',
'Identifier',
'BlockStatement'
])
});
it('ignores null children', function() {
var parent = helpers.parse(fixtures.nullChildren)[1].expression.left;
// parent.elements is an array with a leading null that should be ignored,
// followed by an identifier
var res = NodeUtils.getChildren(parent);
expect(res).to.have.length(1);
expect(res[0].type).to.be('Identifier');
});
it('ignores empty JSXText nodes', function() {
var parent = helpers.parse(fixtures.jsxNesting)[0].expression;
var res = NodeUtils.getChildren(parent);
res.forEach(node => expect(node.type).not.to.be('JSXText'));
});
});
describe('isBefore', function() {
describe('given nodes with different line numbers', function() {
it('returns true if the first node has a lower line number', function() {
var res = NodeUtils.isBefore(
{loc: {start: {line: 0, column: 0}}},
{loc: {start: {line: 1, column: 0}}}
);
expect(res).to.be(true);
});
it('returns false if the first node has a higher numbered line', function() {
var res = NodeUtils.isBefore(
{loc: {start: {line: 1, column: 0}}},
{loc: {start: {line: 0, column: 0}}}
);
expect(res).to.be(false);
});
});
describe('given nodes with the same line number', function() {
it('returns true if the first node has a lower column number', function() {
var res = NodeUtils.isBefore(
{loc: {start: {line: 0, column: 0}}},
{loc: {start: {line: 0, column: 1}}}
);
expect(res).to.be(true);
});
it('returns false if the first node has a higher column number', function() {
var res = NodeUtils.isBefore(
{loc: {start: {line: 0, column: 1}}},
{loc: {start: {line: 0, column: 0}}}
);
expect(res).to.be(false);
});
});
});
describe('isES6ModuleImport', function() {
it('returns true for an import declaration', function() {
// ImportDeclaration
var nodes = [helpers.parse(fixtures.es6Module)[0]];
expect(NodeUtils.isES6ModuleImport(nodes)).to.be(true);
});
it('returns false for export declaration', function() {
// ExportNamedDeclaration
var nodes = [helpers.parse(fixtures.es6Module)[1]];
expect(NodeUtils.isES6ModuleImport(nodes)).to.be(false);
});
it('returns false otherwise', function() {
var nodes = helpers.parse(fixtures.commonjs);
expect(NodeUtils.isES6ModuleImport(nodes)).to.be(false);
});
});
describe('isAMD', function() {
it('returns true for an expression containing a define', function() {
// First expression is define
var nodes = [helpers.parse(fixtures.amd)[0]];
expect(NodeUtils.isAMD(nodes)).to.be(true);
});
it('returns true for an expression containing a define', function() {
// Third expression is require
var nodes = [helpers.parse(fixtures.amd)[2]];
expect(NodeUtils.isAMD(nodes)).to.be(true);
});
it('returns true even if the function is a property', function() {
var nodes = [helpers.parse(fixtures.amd)[4]];
expect(NodeUtils.isAMD(nodes)).to.be(true);
});
it('returns true even if a nested property', function() {
var nodes = [helpers.parse(fixtures.amd)[6]];
expect(NodeUtils.isAMD(nodes)).to.be(true);
});
it('returns false otherwise', function() {
var nodes = helpers.parse(fixtures.commonjs);
expect(NodeUtils.isAMD(nodes)).to.be(false);
});
});
describe('isCommonJS', function() {
it('returns true for an expression containing a require', function() {
// First node is an ExpressionStatement
var nodes = [helpers.parse(fixtures.commonjs)[0]];
expect(NodeUtils.isCommonJS(nodes)).to.be(true);
});
it('returns true for a declaration containing a require', function() {
// Second node is a VariableDeclaration
var nodes = [helpers.parse(fixtures.commonjs)[1]];
expect(NodeUtils.isCommonJS(nodes)).to.be(true);
});
it('returns false otherwise', function() {
var nodes = helpers.parse(fixtures.amd);
expect(NodeUtils.isCommonJS(nodes)).to.be(false);
});
});
describe('typesMatch', function() {
it('returns true if all node types match', function() {
var res = NodeUtils.typesMatch([
{type: 'a'}, {type: 'a'}, {type: 'a'}
]);
expect(res).to.be(true);
});
it('returns false if not all node types match', function() {
var res = NodeUtils.typesMatch([
{type: 'a'}, {type: 'a'}, {type: 'b'}
]);
expect(res).to.be(false);
});
});
describe('identifiersMatch', function() {
it('returns true if all node are matching identifiers', function() {
var res = NodeUtils.identifiersMatch([
{name: 'a'}, {name: 'a'}, {name: 'a'}
]);
expect(res).to.be(true);
});
it('returns false if not all node names match', function() {
var res = NodeUtils.identifiersMatch([
{name: 'a'}, {name: 'a'}, {name: 'b'}
]);
expect(res).to.be(false);
});
});
describe('literalsMatch', function() {
it('returns true if all literals have the same value', function() {
var res = NodeUtils.literalsMatch([
{type: 'Literal', value: 'a'},
{type: 'Literal', value: 'a'},
{type: 'Literal', value: 'a'}
]);
expect(res).to.be(true);
});
it('returns false if not all literals have the same value', function() {
var res = NodeUtils.literalsMatch([
{type: 'Literal', value: 'a'},
{type: 'Literal', value: 'a'},
{type: 'Literal', value: 'b'}
]);
expect(res).to.be(false);
});
it('treats JSXText as a literal', function() {
var res = NodeUtils.literalsMatch([
{type: 'JSXText', value: 'a'},
{type: 'JSXText', value: 'a'},
{type: 'JSXText', value: 'b'}
]);
expect(res).to.be(false);
});
it('ignores the values of nodes which are not literals', function() {
var res = NodeUtils.literalsMatch([
{type: 'Foo', value: 'a'},
{type: 'Foo', value: 'a'},
{type: 'Foo', value: 'b'}
]);
expect(res).to.be(true);
});
});
});