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