]> git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/rules/utils/ast-utils.js
update to 7.1.0 sources
[pve-eslint.git] / eslint / tests / lib / rules / utils / ast-utils.js
1 /**
2 * @fileoverview Tests for ast utils.
3 * @author Gyandeep Singh
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const assert = require("chai").assert,
13 espree = require("espree"),
14 astUtils = require("../../../../lib/rules/utils/ast-utils"),
15 { Linter } = require("../../../../lib/linter"),
16 { SourceCode } = require("../../../../lib/source-code");
17
18 //------------------------------------------------------------------------------
19 // Tests
20 //------------------------------------------------------------------------------
21
22 const ESPREE_CONFIG = {
23 ecmaVersion: 6,
24 comment: true,
25 tokens: true,
26 range: true,
27 loc: true
28 };
29 const linter = new Linter();
30
31 describe("ast-utils", () => {
32 let callCounts;
33
34 beforeEach(() => {
35 callCounts = new Map();
36 });
37
38 /**
39 * Asserts that a given function is called at least once during a test
40 * @param {Function} func The function that must be called at least once
41 * @returns {Function} A wrapper around the same function
42 */
43 function mustCall(func) {
44 callCounts.set(func, 0);
45 return function Wrapper(...args) {
46 callCounts.set(func, callCounts.get(func) + 1);
47
48 return func.call(this, ...args);
49 };
50 }
51
52 afterEach(() => {
53 callCounts.forEach((callCount, func) => {
54 assert(
55 callCount > 0,
56 `Expected ${func.toString()} to be called at least once but it was not called`
57 );
58 });
59 });
60
61 describe("isTokenOnSameLine", () => {
62 it("should return false if the tokens are not on the same line", () => {
63 linter.defineRule("checker", mustCall(context => ({
64 BlockStatement: mustCall(node => {
65 assert.isFalse(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node));
66 })
67 })));
68
69 linter.verify("if(a)\n{}", { rules: { checker: "error" } });
70 });
71
72 it("should return true if the tokens are on the same line", () => {
73
74 linter.defineRule("checker", mustCall(context => ({
75 BlockStatement: mustCall(node => {
76 assert.isTrue(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node));
77 })
78 })));
79
80 linter.verify("if(a){}", { rules: { checker: "error" } });
81 });
82 });
83
84 describe("isNullOrUndefined", () => {
85 it("should return true if the argument is null", () => {
86 assert.isTrue(astUtils.isNullOrUndefined(espree.parse("null").body[0].expression));
87 });
88
89 it("should return true if the argument is undefined", () => {
90 assert.isTrue(astUtils.isNullOrUndefined(espree.parse("undefined").body[0].expression));
91 });
92
93 it("should return false if the argument is a number", () => {
94 assert.isFalse(astUtils.isNullOrUndefined(espree.parse("1").body[0].expression));
95 });
96
97 it("should return false if the argument is a string", () => {
98 assert.isFalse(astUtils.isNullOrUndefined(espree.parse("'test'").body[0].expression));
99 });
100
101 it("should return false if the argument is a boolean", () => {
102 assert.isFalse(astUtils.isNullOrUndefined(espree.parse("true").body[0].expression));
103 });
104
105 it("should return false if the argument is an object", () => {
106 assert.isFalse(astUtils.isNullOrUndefined(espree.parse("({})").body[0].expression));
107 });
108
109 it("should return false if the argument is a unicode regex", () => {
110 assert.isFalse(astUtils.isNullOrUndefined(espree.parse("/abc/u", { ecmaVersion: 6 }).body[0].expression));
111 });
112 });
113
114 describe("checkReference", () => {
115
116 // catch
117 it("should return true if reference is assigned for catch", () => {
118 linter.defineRule("checker", mustCall(context => ({
119 CatchClause: mustCall(node => {
120 const variables = context.getDeclaredVariables(node);
121
122 assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
123 })
124 })));
125
126 linter.verify("try { } catch (e) { e = 10; }", { rules: { checker: "error" } });
127 });
128
129 // const
130 it("should return true if reference is assigned for const", () => {
131 linter.defineRule("checker", mustCall(context => ({
132 VariableDeclaration: mustCall(node => {
133 const variables = context.getDeclaredVariables(node);
134
135 assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
136 })
137 })));
138
139 linter.verify("const a = 1; a = 2;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
140 });
141
142 it("should return false if reference is not assigned for const", () => {
143 linter.defineRule("checker", mustCall(context => ({
144 VariableDeclaration: mustCall(node => {
145 const variables = context.getDeclaredVariables(node);
146
147 assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0);
148 })
149 })));
150
151 linter.verify("const a = 1; c = 2;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
152 });
153
154 // class
155 it("should return true if reference is assigned for class", () => {
156 linter.defineRule("checker", mustCall(context => ({
157 ClassDeclaration: mustCall(node => {
158 const variables = context.getDeclaredVariables(node);
159
160 assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
161 assert.lengthOf(astUtils.getModifyingReferences(variables[1].references), 0);
162 })
163 })));
164
165 linter.verify("class A { }\n A = 1;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
166 });
167
168 it("should return false if reference is not assigned for class", () => {
169 linter.defineRule("checker", mustCall(context => ({
170 ClassDeclaration: mustCall(node => {
171 const variables = context.getDeclaredVariables(node);
172
173 assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0);
174 })
175 })));
176
177 linter.verify("class A { } foo(A);", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
178 });
179 });
180
181 describe("isDirectiveComment", () => {
182
183 /**
184 * Asserts the node is NOT a directive comment
185 * @param {ASTNode} node node to assert
186 * @returns {void}
187 *
188 */
189 function assertFalse(node) {
190 assert.isFalse(astUtils.isDirectiveComment(node));
191 }
192
193 /**
194 * Asserts the node is a directive comment
195 * @param {ASTNode} node node to assert
196 * @returns {void}
197 *
198 */
199 function assertTrue(node) {
200 assert.isTrue(astUtils.isDirectiveComment(node));
201 }
202
203 it("should return false if it is not a directive line comment", () => {
204 const code = [
205 "// lalala I'm a normal comment",
206 "// trying to confuse eslint ",
207 "//trying to confuse eslint-directive-detection",
208 "//eslint is awesome"
209 ].join("\n");
210 const ast = espree.parse(code, ESPREE_CONFIG);
211 const sourceCode = new SourceCode(code, ast);
212 const comments = sourceCode.getAllComments();
213
214 comments.forEach(assertFalse);
215 });
216
217 it("should return false if it is not a directive block comment", () => {
218 const code = [
219 "/* lalala I'm a normal comment */",
220 "/* trying to confuse eslint */",
221 "/* trying to confuse eslint-directive-detection */",
222 "/*eSlInT is awesome*/"
223 ].join("\n");
224 const ast = espree.parse(code, ESPREE_CONFIG);
225 const sourceCode = new SourceCode(code, ast);
226 const comments = sourceCode.getAllComments();
227
228 comments.forEach(assertFalse);
229 });
230
231 it("should return true if it is a directive line comment", () => {
232 const code = [
233 "// eslint-disable-line no-undef",
234 "// eslint-secret-directive 4 8 15 16 23 42 ",
235 "// eslint-directive-without-argument",
236 "//eslint-directive-without-padding"
237 ].join("\n");
238 const ast = espree.parse(code, ESPREE_CONFIG);
239 const sourceCode = new SourceCode(code, ast);
240 const comments = sourceCode.getAllComments();
241
242 comments.forEach(assertTrue);
243 });
244
245 it("should return true if it is a directive block comment", () => {
246 const code = [
247 "/* eslint-disable no-undef */",
248 "/*eslint-enable no-undef*/",
249 "/* eslint-env {\"es6\": true} */",
250 "/* eslint foo */",
251 "/*eslint bar*/"
252 ].join("\n");
253 const ast = espree.parse(code, ESPREE_CONFIG);
254 const sourceCode = new SourceCode(code, ast);
255 const comments = sourceCode.getAllComments();
256
257 comments.forEach(assertTrue);
258 });
259 });
260
261 describe("isParenthesised", () => {
262 it("should return false for not parenthesised nodes", () => {
263 const code = "condition ? 1 : 2";
264 const ast = espree.parse(code, ESPREE_CONFIG);
265 const sourceCode = new SourceCode(code, ast);
266
267 assert.isFalse(astUtils.isParenthesised(sourceCode, ast.body[0].expression));
268 });
269
270 it("should return true for not parenthesised nodes", () => {
271 const code = "(condition ? 1 : 2)";
272 const ast = espree.parse(code, ESPREE_CONFIG);
273 const sourceCode = new SourceCode(code, ast);
274
275 assert.isTrue(astUtils.isParenthesised(sourceCode, ast.body[0].expression));
276 });
277 });
278
279 describe("isFunction", () => {
280 it("should return true for FunctionDeclaration", () => {
281 const ast = espree.parse("function a() {}");
282 const node = ast.body[0];
283
284 assert(astUtils.isFunction(node));
285 });
286
287 it("should return true for FunctionExpression", () => {
288 const ast = espree.parse("(function a() {})");
289 const node = ast.body[0].expression;
290
291 assert(astUtils.isFunction(node));
292 });
293
294 it("should return true for AllowFunctionExpression", () => {
295 const ast = espree.parse("(() => {})", { ecmaVersion: 6 });
296 const node = ast.body[0].expression;
297
298 assert(astUtils.isFunction(node));
299 });
300
301 it("should return false for Program, VariableDeclaration, BlockStatement", () => {
302 const ast = espree.parse("var a; { }");
303
304 assert(!astUtils.isFunction(ast));
305 assert(!astUtils.isFunction(ast.body[0]));
306 assert(!astUtils.isFunction(ast.body[1]));
307 });
308 });
309
310 describe("isLoop", () => {
311 it("should return true for DoWhileStatement", () => {
312 const ast = espree.parse("do {} while (a)");
313 const node = ast.body[0];
314
315 assert(astUtils.isLoop(node));
316 });
317
318 it("should return true for ForInStatement", () => {
319 const ast = espree.parse("for (var k in obj) {}");
320 const node = ast.body[0];
321
322 assert(astUtils.isLoop(node));
323 });
324
325 it("should return true for ForOfStatement", () => {
326 const ast = espree.parse("for (var x of list) {}", { ecmaVersion: 6 });
327 const node = ast.body[0];
328
329 assert(astUtils.isLoop(node));
330 });
331
332 it("should return true for ForStatement", () => {
333 const ast = espree.parse("for (var i = 0; i < 10; ++i) {}");
334 const node = ast.body[0];
335
336 assert(astUtils.isLoop(node));
337 });
338
339 it("should return true for WhileStatement", () => {
340 const ast = espree.parse("while (a) {}");
341 const node = ast.body[0];
342
343 assert(astUtils.isLoop(node));
344 });
345
346 it("should return false for Program, VariableDeclaration, BlockStatement", () => {
347 const ast = espree.parse("var a; { }");
348
349 assert(!astUtils.isLoop(ast));
350 assert(!astUtils.isLoop(ast.body[0]));
351 assert(!astUtils.isLoop(ast.body[1]));
352 });
353 });
354
355 describe("isInLoop", () => {
356
357 /**
358 * Asserts that the unique node of the given type in the code is either
359 * in a loop or not in a loop.
360 * @param {string} code the code to check.
361 * @param {string} nodeType the type of the node to consider. The code
362 * must have exactly one node of ths type.
363 * @param {boolean} expectedInLoop the expected result for whether the
364 * node is in a loop.
365 * @returns {void}
366 */
367 function assertNodeTypeInLoop(code, nodeType, expectedInLoop) {
368 const results = [];
369
370 linter.defineRule("checker", mustCall(() => ({
371 [nodeType]: mustCall(node => {
372 results.push(astUtils.isInLoop(node));
373 })
374 })));
375 linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
376
377 assert.lengthOf(results, 1);
378 assert.strictEqual(results[0], expectedInLoop);
379 }
380
381 it("should return true for a loop itself", () => {
382 assertNodeTypeInLoop("while (a) {}", "WhileStatement", true);
383 });
384
385 it("should return true for a loop condition", () => {
386 assertNodeTypeInLoop("while (a) {}", "Identifier", true);
387 });
388
389 it("should return true for a loop assignee", () => {
390 assertNodeTypeInLoop("for (var a in b) {}", "VariableDeclaration", true);
391 });
392
393 it("should return true for a node within a loop body", () => {
394 assertNodeTypeInLoop("for (var a of b) { console.log('Hello'); }", "Literal", true);
395 });
396
397 it("should return false for a node outside a loop body", () => {
398 assertNodeTypeInLoop("while (true) {} a(b);", "CallExpression", false);
399 });
400
401 it("should return false when the loop is not in the current function", () => {
402 assertNodeTypeInLoop("while (true) { funcs.push(() => { var a; }); }", "VariableDeclaration", false);
403 });
404 });
405
406 describe("getStaticStringValue", () => {
407
408 /* eslint-disable quote-props */
409 const expectedResults = {
410
411 // string literals
412 "''": "",
413 "'foo'": "foo",
414
415 // boolean literals
416 "false": "false",
417 "true": "true",
418
419 // null literal
420 "null": "null",
421
422 // number literals
423 "0": "0",
424 "0.": "0",
425 ".0": "0",
426 "1": "1",
427 "1.": "1",
428 ".1": "0.1",
429 "12": "12",
430 ".12": "0.12",
431 "0.12": "0.12",
432 "12.34": "12.34",
433 "12e3": "12000",
434 "12e-3": "0.012",
435 "12.34e5": "1234000",
436 "12.34e-5": "0.0001234",
437 "011": "9",
438 "081": "81",
439 "0b11": "3",
440 "0b011": "3",
441 "0o11": "9",
442 "0o011": "9",
443 "0x11": "17",
444 "0x011": "17",
445
446 // regexp literals
447 "/a/": "/a/",
448 "/a/i": "/a/i",
449 "/[0-9]/": "/[0-9]/",
450 "/(?<zero>0)/": "/(?<zero>0)/",
451 "/(?<zero>0)/s": "/(?<zero>0)/s",
452 "/(?<=a)b/s": "/(?<=a)b/s",
453
454 // simple template literals
455 "``": "",
456 "`foo`": "foo",
457
458 // unsupported
459 "`${''}`": null,
460 "`${0}`": null,
461 "tag``": null,
462 "-0": null,
463 "-1": null,
464 "1 + 2": null,
465 "[]": null,
466 "({})": null,
467 "foo": null,
468 "undefined": null,
469 "this": null,
470 "(function () {})": null
471 };
472 /* eslint-enable quote-props */
473
474 Object.keys(expectedResults).forEach(key => {
475 it(`should return ${expectedResults[key]} for ${key}`, () => {
476 const ast = espree.parse(key, { ecmaVersion: 2018 });
477
478 assert.strictEqual(astUtils.getStaticStringValue(ast.body[0].expression), expectedResults[key]);
479 });
480 });
481 });
482
483 describe("getStaticPropertyName", () => {
484 it("should return 'b' for `a.b`", () => {
485 const ast = espree.parse("a.b");
486 const node = ast.body[0].expression;
487
488 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
489 });
490
491 it("should return 'b' for `a['b']`", () => {
492 const ast = espree.parse("a['b']");
493 const node = ast.body[0].expression;
494
495 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
496 });
497
498 it("should return 'b' for `a[`b`]`", () => {
499 const ast = espree.parse("a[`b`]", { ecmaVersion: 6 });
500 const node = ast.body[0].expression;
501
502 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
503 });
504
505 it("should return '100' for `a[100]`", () => {
506 const ast = espree.parse("a[100]");
507 const node = ast.body[0].expression;
508
509 assert.strictEqual(astUtils.getStaticPropertyName(node), "100");
510 });
511
512 it("should return null for `a[b]`", () => {
513 const ast = espree.parse("a[b]");
514 const node = ast.body[0].expression;
515
516 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
517 });
518
519 it("should return null for `a['a' + 'b']`", () => {
520 const ast = espree.parse("a['a' + 'b']");
521 const node = ast.body[0].expression;
522
523 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
524 });
525
526 it("should return null for `a[tag`b`]`", () => {
527 const ast = espree.parse("a[tag`b`]", { ecmaVersion: 6 });
528 const node = ast.body[0].expression;
529
530 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
531 });
532
533 it("should return null for `a[`${b}`]`", () => {
534 const ast = espree.parse("a[`${b}`]", { ecmaVersion: 6 });
535 const node = ast.body[0].expression;
536
537 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
538 });
539
540 it("should return 'b' for `b: 1`", () => {
541 const ast = espree.parse("({b: 1})");
542 const node = ast.body[0].expression.properties[0];
543
544 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
545 });
546
547 it("should return 'b' for `b() {}`", () => {
548 const ast = espree.parse("({b() {}})", { ecmaVersion: 6 });
549 const node = ast.body[0].expression.properties[0];
550
551 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
552 });
553
554 it("should return 'b' for `get b() {}`", () => {
555 const ast = espree.parse("({get b() {}})", { ecmaVersion: 6 });
556 const node = ast.body[0].expression.properties[0];
557
558 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
559 });
560
561 it("should return 'b' for `['b']: 1`", () => {
562 const ast = espree.parse("({['b']: 1})", { ecmaVersion: 6 });
563 const node = ast.body[0].expression.properties[0];
564
565 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
566 });
567
568 it("should return 'b' for `['b']() {}`", () => {
569 const ast = espree.parse("({['b']() {}})", { ecmaVersion: 6 });
570 const node = ast.body[0].expression.properties[0];
571
572 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
573 });
574
575 it("should return 'b' for `[`b`]: 1`", () => {
576 const ast = espree.parse("({[`b`]: 1})", { ecmaVersion: 6 });
577 const node = ast.body[0].expression.properties[0];
578
579 assert.strictEqual(astUtils.getStaticPropertyName(node), "b");
580 });
581
582 it("should return '100' for` [100]: 1`", () => {
583 const ast = espree.parse("({[100]: 1})", { ecmaVersion: 6 });
584 const node = ast.body[0].expression.properties[0];
585
586 assert.strictEqual(astUtils.getStaticPropertyName(node), "100");
587 });
588
589 it("should return '/(?<zero>0)/' for `[/(?<zero>0)/]: 1`", () => {
590 const ast = espree.parse("({[/(?<zero>0)/]: 1})", { ecmaVersion: 2018 });
591 const node = ast.body[0].expression.properties[0];
592
593 assert.strictEqual(astUtils.getStaticPropertyName(node), "/(?<zero>0)/");
594 });
595
596 it("should return null for `[b]: 1`", () => {
597 const ast = espree.parse("({[b]: 1})", { ecmaVersion: 6 });
598 const node = ast.body[0].expression.properties[0];
599
600 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
601 });
602
603 it("should return null for `['a' + 'b']: 1`", () => {
604 const ast = espree.parse("({['a' + 'b']: 1})", { ecmaVersion: 6 });
605 const node = ast.body[0].expression.properties[0];
606
607 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
608 });
609
610 it("should return null for `[tag`b`]: 1`", () => {
611 const ast = espree.parse("({[tag`b`]: 1})", { ecmaVersion: 6 });
612 const node = ast.body[0].expression.properties[0];
613
614 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
615 });
616
617 it("should return null for `[`${b}`]: 1`", () => {
618 const ast = espree.parse("({[`${b}`]: 1})", { ecmaVersion: 6 });
619 const node = ast.body[0].expression.properties[0];
620
621 assert.strictEqual(astUtils.getStaticPropertyName(node), null);
622 });
623
624 it("should return null for non member expressions", () => {
625 const ast = espree.parse("foo()");
626
627 assert.strictEqual(astUtils.getStaticPropertyName(ast.body[0].expression), null);
628 assert.strictEqual(astUtils.getStaticPropertyName(ast.body[0]), null);
629 assert.strictEqual(astUtils.getStaticPropertyName(ast.body), null);
630 assert.strictEqual(astUtils.getStaticPropertyName(ast), null);
631 assert.strictEqual(astUtils.getStaticPropertyName(null), null);
632 });
633 });
634
635 describe("getDirectivePrologue", () => {
636 it("should return empty array if node is not a Program, FunctionDeclaration, FunctionExpression, or ArrowFunctionExpression", () => {
637 const ast = espree.parse("if (a) { b(); }");
638 const node = ast.body[0];
639
640 assert.deepStrictEqual(astUtils.getDirectivePrologue(node), []);
641 });
642
643 it("should return empty array if node is a braceless ArrowFunctionExpression node", () => {
644 const ast = espree.parse("var foo = () => 'use strict';", { ecmaVersion: 6 });
645 const node = ast.body[0].declarations[0].init;
646
647 assert.deepStrictEqual(astUtils.getDirectivePrologue(node), []);
648 });
649
650 it("should return empty array if there are no directives in Program body", () => {
651 const ast = espree.parse("var foo;");
652 const node = ast;
653
654 assert.deepStrictEqual(astUtils.getDirectivePrologue(node), []);
655 });
656
657 it("should return empty array if there are no directives in FunctionDeclaration body", () => {
658 const ast = espree.parse("function foo() { return bar; }");
659 const node = ast.body[0];
660
661 assert.deepStrictEqual(astUtils.getDirectivePrologue(node), []);
662 });
663
664 it("should return empty array if there are no directives in FunctionExpression body", () => {
665 const ast = espree.parse("var foo = function() { return bar; }");
666 const node = ast.body[0].declarations[0].init;
667
668 assert.deepStrictEqual(astUtils.getDirectivePrologue(node), []);
669 });
670
671 it("should return empty array if there are no directives in ArrowFunctionExpression body", () => {
672 const ast = espree.parse("var foo = () => { return bar; };", { ecmaVersion: 6 });
673 const node = ast.body[0].declarations[0].init;
674
675 assert.deepStrictEqual(astUtils.getDirectivePrologue(node), []);
676 });
677
678 it("should return directives in Program body", () => {
679 const ast = espree.parse("'use strict'; 'use asm'; var foo;");
680 const result = astUtils.getDirectivePrologue(ast);
681
682 assert.strictEqual(result.length, 2);
683 assert.strictEqual(result[0].expression.value, "use strict");
684 assert.strictEqual(result[1].expression.value, "use asm");
685 });
686
687 it("should return directives in FunctionDeclaration body", () => {
688 const ast = espree.parse("function foo() { 'use strict'; 'use asm'; return bar; }");
689 const result = astUtils.getDirectivePrologue(ast.body[0]);
690
691 assert.strictEqual(result.length, 2);
692 assert.strictEqual(result[0].expression.value, "use strict");
693 assert.strictEqual(result[1].expression.value, "use asm");
694 });
695
696 it("should return directives in FunctionExpression body", () => {
697 const ast = espree.parse("var foo = function() { 'use strict'; 'use asm'; return bar; }");
698 const result = astUtils.getDirectivePrologue(ast.body[0].declarations[0].init);
699
700 assert.strictEqual(result.length, 2);
701 assert.strictEqual(result[0].expression.value, "use strict");
702 assert.strictEqual(result[1].expression.value, "use asm");
703 });
704
705 it("should return directives in ArrowFunctionExpression body", () => {
706 const ast = espree.parse("var foo = () => { 'use strict'; 'use asm'; return bar; };", { ecmaVersion: 6 });
707 const result = astUtils.getDirectivePrologue(ast.body[0].declarations[0].init);
708
709 assert.strictEqual(result.length, 2);
710 assert.strictEqual(result[0].expression.value, "use strict");
711 assert.strictEqual(result[1].expression.value, "use asm");
712 });
713 });
714
715 {
716 const expectedResults = {
717 5: true,
718 0: true,
719 "5.": false,
720 "5.0": false,
721 "05": false,
722 "0x5": false,
723 "5e0": false,
724 "5e-0": false,
725 "'5'": false
726 };
727
728 describe("isDecimalInteger", () => {
729 Object.keys(expectedResults).forEach(key => {
730 it(`should return ${expectedResults[key]} for ${key}`, () => {
731 assert.strictEqual(astUtils.isDecimalInteger(espree.parse(key).body[0].expression), expectedResults[key]);
732 });
733 });
734 });
735
736 describe("isDecimalIntegerNumericToken", () => {
737 Object.keys(expectedResults).forEach(key => {
738 it(`should return ${expectedResults[key]} for ${key}`, () => {
739 assert.strictEqual(astUtils.isDecimalIntegerNumericToken(espree.tokenize(key)[0]), expectedResults[key]);
740 });
741 });
742 });
743 }
744
745 describe("getFunctionNameWithKind", () => {
746 const expectedResults = {
747 "function foo() {}": "function 'foo'",
748 "(function foo() {})": "function 'foo'",
749 "(function() {})": "function",
750 "function* foo() {}": "generator function 'foo'",
751 "(function* foo() {})": "generator function 'foo'",
752 "(function*() {})": "generator function",
753 "() => {}": "arrow function",
754 "async () => {}": "async arrow function",
755 "({ foo: function foo() {} })": "method 'foo'",
756 "({ foo: function() {} })": "method 'foo'",
757 "({ '': function() {} })": "method ''",
758 "({ ['foo']: function() {} })": "method 'foo'",
759 "({ ['']: function() {} })": "method ''",
760 "({ [foo]: function() {} })": "method",
761 "({ foo() {} })": "method 'foo'",
762 "({ foo: function* foo() {} })": "generator method 'foo'",
763 "({ foo: function*() {} })": "generator method 'foo'",
764 "({ ['foo']: function*() {} })": "generator method 'foo'",
765 "({ [foo]: function*() {} })": "generator method",
766 "({ *foo() {} })": "generator method 'foo'",
767 "({ foo: async function foo() {} })": "async method 'foo'",
768 "({ foo: async function() {} })": "async method 'foo'",
769 "({ ['foo']: async function() {} })": "async method 'foo'",
770 "({ [foo]: async function() {} })": "async method",
771 "({ async foo() {} })": "async method 'foo'",
772 "({ get foo() {} })": "getter 'foo'",
773 "({ set foo(a) {} })": "setter 'foo'",
774 "class A { constructor() {} }": "constructor",
775 "class A { foo() {} }": "method 'foo'",
776 "class A { *foo() {} }": "generator method 'foo'",
777 "class A { async foo() {} }": "async method 'foo'",
778 "class A { ['foo']() {} }": "method 'foo'",
779 "class A { *['foo']() {} }": "generator method 'foo'",
780 "class A { async ['foo']() {} }": "async method 'foo'",
781 "class A { [foo]() {} }": "method",
782 "class A { *[foo]() {} }": "generator method",
783 "class A { async [foo]() {} }": "async method",
784 "class A { get foo() {} }": "getter 'foo'",
785 "class A { set foo(a) {} }": "setter 'foo'",
786 "class A { static foo() {} }": "static method 'foo'",
787 "class A { static *foo() {} }": "static generator method 'foo'",
788 "class A { static async foo() {} }": "static async method 'foo'",
789 "class A { static get foo() {} }": "static getter 'foo'",
790 "class A { static set foo(a) {} }": "static setter 'foo'"
791 };
792
793 Object.keys(expectedResults).forEach(key => {
794 it(`should return "${expectedResults[key]}" for "${key}".`, () => {
795 linter.defineRule("checker", mustCall(() => ({
796 ":function": mustCall(node => {
797 assert.strictEqual(
798 astUtils.getFunctionNameWithKind(node),
799 expectedResults[key]
800 );
801 })
802 })));
803
804 linter.verify(key, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 8 } });
805 });
806 });
807 });
808
809 describe("getFunctionHeadLoc", () => {
810 const expectedResults = {
811 "function foo() {}": [0, 12],
812 "(function foo() {})": [1, 13],
813 "(function() {})": [1, 9],
814 "function* foo() {}": [0, 13],
815 "(function* foo() {})": [1, 14],
816 "(function*() {})": [1, 10],
817 "() => {}": [3, 5],
818 "async () => {}": [9, 11],
819 "({ foo: function foo() {} })": [3, 20],
820 "({ foo: function() {} })": [3, 16],
821 "({ ['foo']: function() {} })": [3, 20],
822 "({ [foo]: function() {} })": [3, 18],
823 "({ foo() {} })": [3, 6],
824 "({ foo: function* foo() {} })": [3, 21],
825 "({ foo: function*() {} })": [3, 17],
826 "({ ['foo']: function*() {} })": [3, 21],
827 "({ [foo]: function*() {} })": [3, 19],
828 "({ *foo() {} })": [3, 7],
829 "({ foo: async function foo() {} })": [3, 26],
830 "({ foo: async function() {} })": [3, 22],
831 "({ ['foo']: async function() {} })": [3, 26],
832 "({ [foo]: async function() {} })": [3, 24],
833 "({ async foo() {} })": [3, 12],
834 "({ get foo() {} })": [3, 10],
835 "({ set foo(a) {} })": [3, 10],
836 "class A { constructor() {} }": [10, 21],
837 "class A { foo() {} }": [10, 13],
838 "class A { *foo() {} }": [10, 14],
839 "class A { async foo() {} }": [10, 19],
840 "class A { ['foo']() {} }": [10, 17],
841 "class A { *['foo']() {} }": [10, 18],
842 "class A { async ['foo']() {} }": [10, 23],
843 "class A { [foo]() {} }": [10, 15],
844 "class A { *[foo]() {} }": [10, 16],
845 "class A { async [foo]() {} }": [10, 21],
846 "class A { get foo() {} }": [10, 17],
847 "class A { set foo(a) {} }": [10, 17],
848 "class A { static foo() {} }": [10, 20],
849 "class A { static *foo() {} }": [10, 21],
850 "class A { static async foo() {} }": [10, 26],
851 "class A { static get foo() {} }": [10, 24],
852 "class A { static set foo(a) {} }": [10, 24]
853 };
854
855 Object.keys(expectedResults).forEach(key => {
856 const expectedLoc = {
857 start: {
858 line: 1,
859 column: expectedResults[key][0]
860 },
861 end: {
862 line: 1,
863 column: expectedResults[key][1]
864 }
865 };
866
867 it(`should return "${JSON.stringify(expectedLoc)}" for "${key}".`, () => {
868 linter.defineRule("checker", mustCall(() => ({
869 ":function": mustCall(node => {
870 assert.deepStrictEqual(
871 astUtils.getFunctionHeadLoc(node, linter.getSourceCode()),
872 expectedLoc
873 );
874 })
875 })));
876
877 linter.verify(key, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 8 } }, "test.js", true);
878 });
879 });
880 });
881
882 describe("isEmptyBlock", () => {
883 const expectedResults = {
884 "{}": true,
885 "{ a }": false,
886 a: false
887 };
888
889 Object.keys(expectedResults).forEach(key => {
890 it(`should return ${expectedResults[key]} for ${key}`, () => {
891 const ast = espree.parse(key);
892
893 assert.strictEqual(astUtils.isEmptyBlock(ast.body[0]), expectedResults[key]);
894 });
895 });
896 });
897
898 describe("isEmptyFunction", () => {
899 const expectedResults = {
900 "(function foo() {})": true,
901 "(function foo() { a })": false,
902 "(a) => {}": true,
903 "(a) => { a }": false,
904 "(a) => a": false
905 };
906
907 Object.keys(expectedResults).forEach(key => {
908 it(`should return ${expectedResults[key]} for ${key}`, () => {
909 const ast = espree.parse(key, { ecmaVersion: 6 });
910
911 assert.strictEqual(astUtils.isEmptyFunction(ast.body[0].expression), expectedResults[key]);
912 });
913 });
914 });
915
916 describe("getNextLocation", () => {
917
918 /* eslint-disable quote-props */
919 const expectedResults = {
920 "": [[1, 0], null],
921 "\n": [[1, 0], [2, 0], null],
922 "\r\n": [[1, 0], [2, 0], null],
923 "foo": [[1, 0], [1, 1], [1, 2], [1, 3], null],
924 "foo\n": [[1, 0], [1, 1], [1, 2], [1, 3], [2, 0], null],
925 "foo\r\n": [[1, 0], [1, 1], [1, 2], [1, 3], [2, 0], null],
926 "foo;\n": [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [2, 0], null],
927 "a\nb": [[1, 0], [1, 1], [2, 0], [2, 1], null],
928 "a\nb\n": [[1, 0], [1, 1], [2, 0], [2, 1], [3, 0], null],
929 "a\r\nb\r\n": [[1, 0], [1, 1], [2, 0], [2, 1], [3, 0], null],
930 "a\nb\r\n": [[1, 0], [1, 1], [2, 0], [2, 1], [3, 0], null],
931 "a\n\n": [[1, 0], [1, 1], [2, 0], [3, 0], null],
932 "a\r\n\r\n": [[1, 0], [1, 1], [2, 0], [3, 0], null],
933 "\n\r\n\n\r\n": [[1, 0], [2, 0], [3, 0], [4, 0], [5, 0], null],
934 "ab\u2029c": [[1, 0], [1, 1], [1, 2], [2, 0], [2, 1], null],
935 "ab\ncde\n": [[1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2], [2, 3], [3, 0], null],
936 "a ": [[1, 0], [1, 1], [1, 2], null],
937 "a\t": [[1, 0], [1, 1], [1, 2], null],
938 "a \n": [[1, 0], [1, 1], [1, 2], [2, 0], null]
939 };
940 /* eslint-enable quote-props */
941
942 Object.keys(expectedResults).forEach(code => {
943 it(`should return expected locations for "${code}".`, () => {
944 const ast = espree.parse(code, ESPREE_CONFIG);
945 const sourceCode = new SourceCode(code, ast);
946 const locations = expectedResults[code];
947
948 for (let i = 0; i < locations.length - 1; i++) {
949 const location = { line: locations[i][0], column: locations[i][1] };
950 const expectedNextLocation = locations[i + 1]
951 ? { line: locations[i + 1][0], column: locations[i + 1][1] }
952 : null;
953
954 assert.deepStrictEqual(
955 astUtils.getNextLocation(sourceCode, location),
956 expectedNextLocation
957 );
958 }
959 });
960 });
961 });
962
963 describe("getParenthesisedText", () => {
964 const expectedResults = {
965 "(((foo))); bar;": "(((foo)))",
966 "(/* comment */(((foo.bar())))); baz();": "(/* comment */(((foo.bar()))))",
967 "(foo, bar)": "(foo, bar)"
968 };
969
970 Object.keys(expectedResults).forEach(key => {
971 it(`should return ${expectedResults[key]} for ${key}`, () => {
972 const ast = espree.parse(key, { tokens: true, comment: true, range: true, loc: true });
973 const sourceCode = new SourceCode(key, ast);
974
975 assert.strictEqual(astUtils.getParenthesisedText(sourceCode, ast.body[0].expression), expectedResults[key]);
976 });
977 });
978 });
979
980 describe("couldBeError", () => {
981 const EXPECTED_RESULTS = {
982 5: false,
983 null: false,
984 true: false,
985 "'foo'": false,
986 "`foo`": false,
987 foo: true,
988 "new Foo": true,
989 "Foo()": true,
990 "foo`bar`": true,
991 "foo.bar": true,
992 "(foo = bar)": true,
993 "(foo = 1)": false,
994 "(1, 2, 3)": false,
995 "(foo, 2, 3)": false,
996 "(1, 2, foo)": true,
997 "1 && 2": false,
998 "1 && foo": true,
999 "foo && 2": true,
1000 "foo ? 1 : 2": false,
1001 "foo ? bar : 2": true,
1002 "foo ? 1 : bar": true,
1003 "[1, 2, 3]": false,
1004 "({ foo: 1 })": false
1005 };
1006
1007 Object.keys(EXPECTED_RESULTS).forEach(key => {
1008 it(`returns ${EXPECTED_RESULTS[key]} for ${key}`, () => {
1009 const ast = espree.parse(key, { ecmaVersion: 6 });
1010
1011 assert.strictEqual(astUtils.couldBeError(ast.body[0].expression), EXPECTED_RESULTS[key]);
1012 });
1013 });
1014 });
1015
1016 describe("isArrowToken", () => {
1017 const code = "() => 5";
1018 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1019 const expected = [false, false, true, false];
1020
1021 tokens.forEach((token, index) => {
1022 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1023 assert.strictEqual(astUtils.isArrowToken(token), expected[index]);
1024 });
1025 });
1026 });
1027
1028 {
1029 const code = "if (obj && foo) { obj[foo](); }";
1030 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1031 const expected = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true];
1032
1033 describe("isClosingBraceToken", () => {
1034 tokens.forEach((token, index) => {
1035 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1036 assert.strictEqual(astUtils.isClosingBraceToken(token), expected[index]);
1037 });
1038 });
1039 });
1040
1041 describe("isNotClosingBraceToken", () => {
1042 tokens.forEach((token, index) => {
1043 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1044 assert.strictEqual(astUtils.isNotClosingBraceToken(token), !expected[index]);
1045 });
1046 });
1047 });
1048 }
1049
1050 {
1051 const code = "if (obj && foo) { obj[foo](); }";
1052 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1053 const expected = [false, false, false, false, false, false, false, false, false, false, true, false, false, false, false];
1054
1055 describe("isClosingBracketToken", () => {
1056 tokens.forEach((token, index) => {
1057 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1058 assert.strictEqual(astUtils.isClosingBracketToken(token), expected[index]);
1059 });
1060 });
1061 });
1062
1063 describe("isNotClosingBracketToken", () => {
1064 tokens.forEach((token, index) => {
1065 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1066 assert.strictEqual(astUtils.isNotClosingBracketToken(token), !expected[index]);
1067 });
1068 });
1069 });
1070 }
1071
1072 {
1073 const code = "if (obj && foo) { obj[foo](); }";
1074 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1075 const expected = [false, false, false, false, false, true, false, false, false, false, false, false, true, false, false];
1076
1077 describe("isClosingParenToken", () => {
1078 tokens.forEach((token, index) => {
1079 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1080 assert.strictEqual(astUtils.isClosingParenToken(token), expected[index]);
1081 });
1082 });
1083 });
1084
1085 describe("isNotClosingParenToken", () => {
1086 tokens.forEach((token, index) => {
1087 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1088 assert.strictEqual(astUtils.isNotClosingParenToken(token), !expected[index]);
1089 });
1090 });
1091 });
1092 }
1093
1094 {
1095 const code = "const obj = {foo: 1, bar: 2};";
1096 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1097 const expected = [false, false, false, false, false, true, false, false, false, true, false, false, false];
1098
1099 describe("isColonToken", () => {
1100 tokens.forEach((token, index) => {
1101 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1102 assert.strictEqual(astUtils.isColonToken(token), expected[index]);
1103 });
1104 });
1105 });
1106
1107 describe("isNotColonToken", () => {
1108 tokens.forEach((token, index) => {
1109 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1110 assert.strictEqual(astUtils.isNotColonToken(token), !expected[index]);
1111 });
1112 });
1113 });
1114 }
1115
1116 {
1117 const code = "const obj = {foo: 1, bar: 2};";
1118 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1119 const expected = [false, false, false, false, false, false, false, true, false, false, false, false, false];
1120
1121 describe("isCommaToken", () => {
1122 tokens.forEach((token, index) => {
1123 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1124 assert.strictEqual(astUtils.isCommaToken(token), expected[index]);
1125 });
1126 });
1127 });
1128
1129 describe("isNotCommaToken", () => {
1130 tokens.forEach((token, index) => {
1131 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1132 assert.strictEqual(astUtils.isNotCommaToken(token), !expected[index]);
1133 });
1134 });
1135 });
1136 }
1137
1138 {
1139 const code = "const obj = {foo: 1.5, bar: a.b};";
1140 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1141 const expected = [false, false, false, false, false, false, false, false, false, false, false, true, false, false, false];
1142
1143 describe("isDotToken", () => {
1144 tokens.forEach((token, index) => {
1145 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1146 assert.strictEqual(astUtils.isDotToken(token), expected[index]);
1147 });
1148 });
1149 });
1150
1151 describe("isNotDotToken", () => {
1152 tokens.forEach((token, index) => {
1153 it(`should return ${!expected[index]} for '${token.value}'.`, () => {
1154 assert.strictEqual(astUtils.isNotDotToken(token), !expected[index]);
1155 });
1156 });
1157 });
1158 }
1159
1160 describe("isCommentToken", () => {
1161 const code = "const obj = /*block*/ {foo: 1, bar: 2}; //line";
1162 const ast = espree.parse(code, { ecmaVersion: 6, tokens: true, comment: true });
1163
1164 ast.tokens.forEach(token => {
1165 it(`should return false for '${token.value}'.`, () => {
1166 assert.strictEqual(astUtils.isCommentToken(token), false);
1167 });
1168 });
1169 ast.comments.forEach(comment => {
1170 it(`should return true for '${comment.value}'.`, () => {
1171 assert.strictEqual(astUtils.isCommentToken(comment), true);
1172 });
1173 });
1174 });
1175
1176 describe("isKeywordToken", () => {
1177 const code = "const obj = {foo: 1, bar: 2};";
1178 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1179 const expected = [true, false, false, false, false, false, false, false, false, false, false, false, false];
1180
1181 tokens.forEach((token, index) => {
1182 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1183 assert.strictEqual(astUtils.isKeywordToken(token), expected[index]);
1184 });
1185 });
1186 });
1187
1188 {
1189 const code = "if (obj && foo) { obj[foo](); }";
1190 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1191 const expected = [false, false, false, false, false, false, true, false, false, false, false, false, false, false, false];
1192
1193 describe("isOpeningBraceToken", () => {
1194 tokens.forEach((token, index) => {
1195 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1196 assert.strictEqual(astUtils.isOpeningBraceToken(token), expected[index]);
1197 });
1198 });
1199 });
1200
1201 describe("isNotOpeningBraceToken", () => {
1202 tokens.forEach((token, index) => {
1203 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1204 assert.strictEqual(astUtils.isNotOpeningBraceToken(token), !expected[index]);
1205 });
1206 });
1207 });
1208 }
1209
1210 {
1211 const code = "if (obj && foo) { obj[foo](); }";
1212 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1213 const expected = [false, false, false, false, false, false, false, false, true, false, false, false, false, false, false];
1214
1215 describe("isOpeningBracketToken", () => {
1216 tokens.forEach((token, index) => {
1217 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1218 assert.strictEqual(astUtils.isOpeningBracketToken(token), expected[index]);
1219 });
1220 });
1221 });
1222
1223 describe("isNotOpeningBracketToken", () => {
1224 tokens.forEach((token, index) => {
1225 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1226 assert.strictEqual(astUtils.isNotOpeningBracketToken(token), !expected[index]);
1227 });
1228 });
1229 });
1230 }
1231
1232 {
1233 const code = "if (obj && foo) { obj[foo](); }";
1234 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1235 const expected = [false, true, false, false, false, false, false, false, false, false, false, true, false, false, false];
1236
1237 describe("isOpeningParenToken", () => {
1238 tokens.forEach((token, index) => {
1239 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1240 assert.strictEqual(astUtils.isOpeningParenToken(token), expected[index]);
1241 });
1242 });
1243 });
1244
1245 describe("isNotOpeningParenToken", () => {
1246 tokens.forEach((token, index) => {
1247 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1248 assert.strictEqual(astUtils.isNotOpeningParenToken(token), !expected[index]);
1249 });
1250 });
1251 });
1252 }
1253
1254 {
1255 const code = "if (obj && foo) { obj[foo](); }";
1256 const tokens = espree.parse(code, { ecmaVersion: 6, tokens: true }).tokens;
1257 const expected = [false, false, false, false, false, false, false, false, false, false, false, false, false, true, false];
1258
1259 describe("isSemicolonToken", () => {
1260 tokens.forEach((token, index) => {
1261 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1262 assert.strictEqual(astUtils.isSemicolonToken(token), expected[index]);
1263 });
1264 });
1265 });
1266
1267 describe("isNotSemicolonToken", () => {
1268 tokens.forEach((token, index) => {
1269 it(`should return ${expected[index]} for '${token.value}'.`, () => {
1270 assert.strictEqual(astUtils.isNotSemicolonToken(token), !expected[index]);
1271 });
1272 });
1273 });
1274 }
1275
1276 describe("isNullLiteral", () => {
1277 const EXPECTED_RESULTS = {
1278 null: true,
1279 "/abc/u": false,
1280 5: false,
1281 true: false,
1282 "'null'": false,
1283 foo: false
1284 };
1285
1286 Object.keys(EXPECTED_RESULTS).forEach(key => {
1287 it(`returns ${EXPECTED_RESULTS[key]} for ${key}`, () => {
1288 const ast = espree.parse(key, { ecmaVersion: 6 });
1289
1290 assert.strictEqual(astUtils.isNullLiteral(ast.body[0].expression), EXPECTED_RESULTS[key]);
1291 });
1292 });
1293 });
1294
1295 describe("createGlobalLinebreakMatcher", () => {
1296 it("returns a regular expression with the g flag", () => {
1297 assert.instanceOf(astUtils.createGlobalLinebreakMatcher(), RegExp);
1298 assert(astUtils.createGlobalLinebreakMatcher().toString().endsWith("/gu"));
1299 });
1300 it("returns unique objects on each call", () => {
1301 const firstObject = astUtils.createGlobalLinebreakMatcher();
1302 const secondObject = astUtils.createGlobalLinebreakMatcher();
1303
1304 assert.notStrictEqual(firstObject, secondObject);
1305 });
1306 describe("correctly matches linebreaks", () => {
1307 const LINE_COUNTS = {
1308 foo: 1,
1309 "foo\rbar": 2,
1310 "foo\n": 2,
1311 "foo\nbar": 2,
1312 "foo\r\nbar": 2,
1313 "foo\r\u2028bar": 3,
1314 "foo\u2029bar": 2
1315 };
1316
1317 Object.keys(LINE_COUNTS).forEach(text => {
1318 it(text, () => {
1319 assert.strictEqual(text.split(astUtils.createGlobalLinebreakMatcher()).length, LINE_COUNTS[text]);
1320 });
1321 });
1322 });
1323 });
1324
1325 describe("canTokensBeAdjacent", () => {
1326 const CASES = new Map([
1327 [["foo", "bar"], false],
1328 [[";foo", "bar"], false],
1329 [[";", "bar"], true],
1330 [[")", "bar"], true],
1331 [["foo0", "bar"], false],
1332 [["foo;", "bar"], true],
1333 [["foo", "0"], false],
1334 [["of", ".2"], true],
1335 [["2", ".2"], false],
1336 [["of", "'foo'"], true],
1337 [["foo", "`bar`"], true],
1338 [["`foo`", "in"], true],
1339 [["of", "0.2"], false],
1340 [["of", "0."], false],
1341 [[".2", "foo"], false],
1342 [["2.", "foo"], false],
1343 [["+", "-"], true],
1344 [["++", "-"], true],
1345 [["+", "--"], true],
1346 [["++", "--"], true],
1347 [["-", "+"], true],
1348 [["--", "+"], true],
1349 [["-", "++"], true],
1350 [["--", "++"], true],
1351 [["+", "+"], false],
1352 [["-", "-"], false],
1353 [["++", "+"], false],
1354 [["--", "-"], false],
1355 [["+", "++"], false],
1356 [["-", "--"], false],
1357 [["a/", "b"], true],
1358 [["a/", "+b"], true],
1359 [["a+", "/^regex$/"], true],
1360 [["a/", "/^regex$/"], false],
1361 [["a+", "/**/b"], true],
1362 [["a/", "/**/b"], false],
1363 [["a+", "//\nb"], true],
1364 [["a/", "//\nb"], false],
1365 [["a/**/", "b"], true],
1366 [["/**/a", "b"], false],
1367 [["a", "/**/b"], true],
1368 [["a", "b/**/"], false],
1369 [["a", "//\nb"], true],
1370 [["a", "b//"], false],
1371 [["#!/usr/bin/env node", "("], false],
1372 [["123invalidtoken", "("], false],
1373 [["(", "123invalidtoken"], false],
1374 [["(", "1n"], true],
1375 [["1n", "+"], true],
1376 [["1n", "in"], false]
1377 ]);
1378
1379 CASES.forEach((expectedResult, tokenStrings) => {
1380 it(tokenStrings.join(", "), () => {
1381 assert.strictEqual(astUtils.canTokensBeAdjacent(tokenStrings[0], tokenStrings[1]), expectedResult);
1382 });
1383 });
1384
1385 it("#!/usr/bin/env node, (", () => {
1386 assert.strictEqual(
1387 astUtils.canTokensBeAdjacent(
1388 { type: "Shebang", value: "#!/usr/bin/env node" },
1389 { type: "Punctuator", value: "(" }
1390 ),
1391 false
1392 );
1393 });
1394 });
1395
1396 describe("equalTokens", () => {
1397 it("should return true if tokens are equal", () => {
1398 const code = "a=0;a=0;";
1399 const ast = espree.parse(code, ESPREE_CONFIG);
1400 const sourceCode = new SourceCode(code, ast);
1401
1402 assert.strictEqual(astUtils.equalTokens(ast.body[0], ast.body[1], sourceCode), true);
1403 });
1404
1405 it("should return false if tokens are not equal", () => {
1406 const code = "a=0;a=1;";
1407 const ast = espree.parse(code, ESPREE_CONFIG);
1408 const sourceCode = new SourceCode(code, ast);
1409
1410 assert.strictEqual(astUtils.equalTokens(ast.body[0], ast.body[1], sourceCode), false);
1411 });
1412 });
1413
1414 describe("hasOctalEscapeSequence", () => {
1415
1416 /* eslint-disable quote-props */
1417 const expectedResults = {
1418 "\\1": true,
1419 "\\2": true,
1420 "\\7": true,
1421 "\\00": true,
1422 "\\01": true,
1423 "\\02": true,
1424 "\\07": true,
1425 "\\08": true,
1426 "\\09": true,
1427 "\\10": true,
1428 "\\12": true,
1429 " \\1": true,
1430 "\\1 ": true,
1431 "a\\1": true,
1432 "\\1a": true,
1433 "a\\1a": true,
1434 " \\01": true,
1435 "\\01 ": true,
1436 "a\\01": true,
1437 "\\01a": true,
1438 "a\\01a": true,
1439 "a\\08a": true,
1440 "\\0\\1": true,
1441 "\\0\\01": true,
1442 "\\0\\08": true,
1443 "\\n\\1": true,
1444 "\\n\\01": true,
1445 "\\n\\08": true,
1446 "\\\\\\1": true,
1447 "\\\\\\01": true,
1448 "\\\\\\08": true,
1449
1450 "\\0": false,
1451 "\\8": false,
1452 "\\9": false,
1453 " \\0": false,
1454 "\\0 ": false,
1455 "a\\0": false,
1456 "\\0a": false,
1457 "a\\8a": false,
1458 "\\0\\8": false,
1459 "\\8\\0": false,
1460 "\\80": false,
1461 "\\81": false,
1462 "\\\\": false,
1463 "\\\\0": false,
1464 "\\\\01": false,
1465 "\\\\08": false,
1466 "\\\\1": false,
1467 "\\\\12": false,
1468 "\\\\\\0": false,
1469 "\\\\\\8": false,
1470 "\\0\\\\": false,
1471 "0": false,
1472 "1": false,
1473 "8": false,
1474 "01": false,
1475 "08": false,
1476 "80": false,
1477 "12": false,
1478 "\\a": false,
1479 "\\n": false
1480 };
1481 /* eslint-enable quote-props */
1482
1483 Object.keys(expectedResults).forEach(key => {
1484 it(`should return ${expectedResults[key]} for ${key}`, () => {
1485 const ast = espree.parse(`"${key}"`);
1486
1487 assert.strictEqual(astUtils.hasOctalEscapeSequence(ast.body[0].expression.raw), expectedResults[key]);
1488 });
1489 });
1490 });
1491 });