1 /*global describe:false, it:false, beforeEach:false */
4 var expect = require('expect.js');
5 var rocambole = require('../');
8 describe('parse', function () {
10 it('should parse string and return AST', function () {
11 var ast = rocambole.parse('(function(){ return 123 })');
12 expect( ast.type ).to.equal( 'Program' );
13 expect( ast.body[0].type ).to.equal( 'ExpressionStatement' );
17 it('should include tokens before and after "program" end', function () {
18 var ast = rocambole.parse('//foo\n(function(){ return 123 })\n//bar\n');
19 expect( ast.startToken.value ).to.equal( 'foo' );
20 expect( ast.endToken.value ).to.equal( '\n' );
21 ast = rocambole.parse('\n//foo\n(function(){ return 123 })\n//dolor');
22 expect( ast.startToken.value ).to.equal( '\n' );
23 expect( ast.endToken.value ).to.equal( 'dolor' );
27 it('should work with any kind of line breaks & spaces', function () {
28 var ast = rocambole.parse('\nvar n\r\n=\n10;\r\r \t\t \n', {loc : true});
30 var br_1 = ast.startToken;
31 expect( br_1.type ).to.be( 'LineBreak' );
32 expect( br_1.value ).to.be( '\n' );
33 expect( br_1.range ).to.eql( [0, 1] );
34 expect( br_1.loc ).to.eql({
45 var ws_1 = ast.startToken.next.next;
46 expect( ws_1.type ).to.be( 'WhiteSpace' );
47 expect( ws_1.value ).to.be( ' ' );
49 var br_2 = br_1.next.next.next.next;
50 expect( br_2.type ).to.be( 'LineBreak' );
51 expect( br_2.value ).to.be( '\r\n' );
52 expect( br_2.range ).to.eql( [6, 8] );
53 expect( br_2.loc ).to.eql({
64 // it's important to notice that esprima doesn't parse "\r" as line
65 // break, so if it is not at EOF it will give conflicting "loc" info.
66 var br_6 = ast.endToken;
67 expect( br_6.type ).to.be( 'LineBreak' );
68 expect( br_6.value ).to.be( '\n' );
69 expect( br_6.range ).to.eql( [21, 22] );
70 expect( br_6.loc ).to.eql({
81 var ws_2 = ast.endToken.prev;
82 expect( ws_2.type ).to.be( 'WhiteSpace' );
83 expect( ws_2.value ).to.be( ' \t\t ' );
84 expect( ws_2.range ).to.eql( [15, 21] );
85 expect( ws_2.loc ).to.eql({
97 expect( br_5.type ).to.be( 'LineBreak' );
98 expect( br_5.value ).to.be( '\r' );
100 var br_4 = br_5.prev;
101 expect( br_4.type ).to.be( 'LineBreak' );
102 expect( br_4.value ).to.be( '\r' );
106 it('should not include any char that isn\'t a white space on a WhiteSpace token [issue #3]', function () {
107 var ast = rocambole.parse("\n/* foo */\n/* bar */\nfunction foo(){\n var bar = 'baz';\n\n //foo\n //bar\n\n var lorem = 'ipsum';\n return bar + lorem;\n}");
108 var tk = ast.startToken;
111 if (tk.type === 'WhiteSpace') {
112 expect( tk.value ).to.match( /^[\s\t]+$/ );
113 } else if (tk.type === 'LineBreak') {
114 expect( tk.value ).to.equal( '\n' );
115 } else if (tk.type === 'LineComment') {
116 expect( tk.raw ).to.match( /^\/\/\w{3}$/ );
118 } else if (tk.type === 'BlockComment') {
119 expect( tk.raw ).to.match( /^\/\* \w{3} \*\/$/ );
124 expect( nComments ).to.be( 4 );
128 it('should instrument object expression "value" node', function () {
129 // this was a bug introduced while trying to improve performance
130 var ast = rocambole.parse('amet(123, a, {flag : true});');
131 var exp = ast.body[0].expression;
132 expect( exp.startToken ).not.to.be(undefined);
133 expect( exp.callee.startToken ).not.to.be(undefined);
134 expect( exp['arguments'][0].startToken ).not.to.be(undefined);
135 expect( exp['arguments'][1].startToken ).not.to.be(undefined);
136 expect( exp['arguments'][2].startToken ).not.to.be(undefined);
137 expect( exp['arguments'][2].properties[0].startToken ).not.to.be(undefined);
138 expect( exp['arguments'][2].properties[0].key.startToken ).not.to.be(undefined);
139 expect( exp['arguments'][2].properties[0].value.startToken ).not.to.be(undefined);
144 describe('Node', function () {
146 var ast, program, expressionStatement,
147 fnExpression, block, returnStatement;
149 beforeEach(function(){
150 ast = rocambole.parse('/* block */\n(function(){\n return 123; // line\n})');
152 expressionStatement = ast.body[0];
153 fnExpression = expressionStatement.expression;
154 block = fnExpression.body;
155 returnStatement = block.body[0];
158 describe('node.parent', function () {
159 it('should add reference to parent node', function () {
160 expect( program.parent ).to.equal( undefined );
161 expect( expressionStatement.parent ).to.equal( program );
162 expect( fnExpression.parent ).to.equal( expressionStatement );
163 expect( block.parent ).to.equal( fnExpression );
168 describe('node.toString()', function(){
169 it('should return the node source', function () {
170 expect( returnStatement.type ).to.equal( 'ReturnStatement' );
171 expect( returnStatement.toString() ).to.equal( 'return 123;' );
173 it('should use raw value of comments', function () {
174 expect( block.toString() ).to.equal( '{\n return 123; // line\n}' );
176 it('should use raw value of comments', function () {
177 expect( ast.toString() ).to.equal( '/* block */\n(function(){\n return 123; // line\n})' );
182 describe('depth', function () {
183 it('should add depth property to nodes', function () {
184 expect( program.depth ).to.equal( 0 );
185 expect( expressionStatement.depth ).to.equal( 1 );
186 expect( fnExpression.depth ).to.equal( 2 );
187 expect( block.depth ).to.equal( 3 );
188 expect( returnStatement.depth ).to.equal( 4 );
193 describe('node.endToken', function () {
194 it('should return last token inside node', function () {
195 expect( program.endToken.value ).to.equal( ')' );
196 expect( expressionStatement.endToken.value ).to.equal( ')' );
197 expect( fnExpression.endToken.value ).to.equal( '}' );
198 expect( block.endToken.value ).to.equal( '}' );
199 expect( returnStatement.endToken.value ).to.equal( ';' );
202 it('should capture end token properly', function () {
203 var ast = rocambole.parse('[1,2,[3,4,[5,6,[7,8,9]]]];');
204 var exp = ast.body[0].expression;
205 expect( exp.endToken.value ).to.equal( ']' );
206 expect( exp.elements[0].value ).to.equal( 1 );
207 expect( exp.elements[0].startToken.value ).to.equal( '1' );
208 expect( exp.elements[0].endToken.value ).to.equal( '1' );
213 describe('node.startToken', function () {
214 it('should return first token inside node', function () {
215 expect( program.startToken.value ).to.equal( ' block ' );
216 expect( expressionStatement.startToken.value ).to.equal( '(' );
217 expect( fnExpression.startToken.value ).to.equal( 'function' );
218 expect( block.startToken.value ).to.equal( '{' );
219 expect( returnStatement.startToken.value ).to.equal( 'return' );
224 describe('Node.next & Node.prev', function () {
225 it('should return reference to previous and next nodes', function () {
226 var ast = rocambole.parse("\n/* foo */\n/* bar */\nfunction foo(){\n var bar = 'baz';\n var lorem = 'ipsum';\n return bar + lorem;\n}");
227 var block = ast.body[0].body.body;
228 var firstNode = block[0];
229 var secondNode = block[1];
230 var lastNode = block[2];
231 expect( firstNode.prev ).to.equal( undefined );
232 expect( firstNode.next ).to.equal( secondNode );
233 expect( secondNode.prev ).to.equal( firstNode );
234 expect( secondNode.next ).to.equal( lastNode );
235 expect( lastNode.prev ).to.equal( secondNode );
236 expect( lastNode.next ).to.equal( undefined );
243 describe('Token', function () {
245 it('should instrument tokens', function () {
246 var ast = rocambole.parse('function foo(){ return "bar"; }');
247 var tokens = ast.tokens;
249 expect( tokens[0].prev ).to.be(undefined);
250 expect( tokens[0].next ).to.be( tokens[1] );
251 expect( tokens[1].prev ).to.be( tokens[0] );
252 expect( tokens[1].next ).to.be( tokens[2] );
255 it('should add range and loc info to comment tokens', function () {
256 var ast = rocambole.parse('\n/* foo\n bar\n*/\nfunction foo(){ return "bar"; }\n// end', {loc:true});
257 var blockComment = ast.startToken.next;
258 expect( blockComment.range ).to.eql( [1, 16] );
259 expect( blockComment.loc ).to.eql({
269 var lineComment = ast.endToken;
270 expect( lineComment.range ).to.eql( [49, 55] );
271 expect( lineComment.loc ).to.eql({
283 it('should add originalIndent info to block comments', function () {
284 var ast = rocambole.parse(' /* foo */\n\t\t// bar');
285 expect( ast.startToken.next.originalIndent ).to.be(' ');
288 it('should not add originalIndent info to line comments', function () {
289 var ast = rocambole.parse(' /* foo */\n\t\t// bar');
290 expect( ast.endToken.originalIndent ).to.be(undefined);
293 it('should not add as originalIndent if prev token is not white space', function () {
294 var ast = rocambole.parse('lorem;/* foo */\n\t\t// bar');
295 expect( ast.startToken.next.next.originalIndent ).to.be(undefined);
298 it('should not add as originalIndent if prev token is not on a new line', function () {
299 var ast = rocambole.parse('lorem; /* foo */\n\t\t// bar');
300 expect( ast.startToken.next.next.next.originalIndent ).to.be(undefined);
303 it('should add as originalIndent if on a new line', function () {
304 var ast = rocambole.parse('lorem;\n /* foo */\n\t\t// bar');
305 expect( ast.startToken.next.next.next.next.originalIndent ).to.be(' ');
310 describe('export BYPASS_RECURSION', function () {
311 it('should export BYPASS_RECURSION', function () {
312 expect( rocambole.BYPASS_RECURSION.root ).to.be(true);
317 describe('empty program', function () {
318 it('should not throw if program is empty', function () {
323 it('should return augmented AST', function () {
324 var ast = rocambole.parse('');
331 // we check toString behavior later
332 toString: ast.toString,
338 it('toString should return proper value', function() {
339 var ast = rocambole.parse('');
340 expect(ast.toString()).to.be('');
345 describe('support anything that implements `toString` as input', function () {
346 it('should support arrays', function () {
347 var ast = rocambole.parse([1,2,3]);
348 expect(ast.body[0].toString()).to.eql('1,2,3');
350 it('should support functions', function () {
351 var ast = rocambole.parse(function doStuff(){
354 expect(ast.body[0].type).to.be('FunctionDeclaration');
359 describe('sparse array', function() {
360 // yes, people shold not be writting code like this, but we should not
361 // bail when that happens
362 it('should not fail on sparse arrays', function() {
363 var ast = rocambole.parse('[,3,[,4]]');
364 expect(ast.toString()).to.eql('[,3,[,4]]');
365 var elements = ast.body[0].expression.elements;
366 expect(elements[0]).to.be(null);
367 expect(elements[1].type).to.be('Literal');
368 expect(elements[1].value).to.be(3);