]> git.proxmox.com Git - pve-eslint.git/blob - eslint/tests/lib/rules/prefer-const.js
first commit
[pve-eslint.git] / eslint / tests / lib / rules / prefer-const.js
1 /**
2 * @fileoverview Tests for prefer-const rule.
3 * @author Toru Nagashima
4 */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const rule = require("../../../lib/rules/prefer-const"),
13 fixtureParser = require("../../fixtures/fixture-parser"),
14 { RuleTester } = require("../../../lib/rule-tester");
15
16 //------------------------------------------------------------------------------
17 // Tests
18 //------------------------------------------------------------------------------
19
20 const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
21
22 ruleTester.defineRule("use-x", context => ({
23 VariableDeclaration() {
24 context.markVariableAsUsed("x");
25 }
26 }));
27
28 ruleTester.run("prefer-const", rule, {
29 valid: [
30 "var x = 0;",
31 "let x;",
32 "let x; { x = 0; } foo(x);",
33 "let x = 0; x = 1;",
34 "const x = 0;",
35 "for (let i = 0, end = 10; i < end; ++i) {}",
36 "for (let i in [1,2,3]) { i = 0; }",
37 "for (let x of [1,2,3]) { x = 0; }",
38 "(function() { var x = 0; })();",
39 "(function() { let x; })();",
40 "(function() { let x; { x = 0; } foo(x); })();",
41 "(function() { let x = 0; x = 1; })();",
42 "(function() { const x = 0; })();",
43 "(function() { for (let i = 0, end = 10; i < end; ++i) {} })();",
44 "(function() { for (let i in [1,2,3]) { i = 0; } })();",
45 "(function() { for (let x of [1,2,3]) { x = 0; } })();",
46 "(function(x = 0) { })();",
47 "let a; while (a = foo());",
48 "let a; do {} while (a = foo());",
49 "let a; for (; a = foo(); );",
50 "let a; for (;; ++a);",
51 "let a; for (const {b = ++a} in foo());",
52 "let a; for (const {b = ++a} of foo());",
53 "let a; for (const x of [1,2,3]) { if (a) {} a = foo(); }",
54 "let a; for (const x of [1,2,3]) { a = a || foo(); bar(a); }",
55 "let a; for (const x of [1,2,3]) { foo(++a); }",
56 "let a; function foo() { if (a) {} a = bar(); }",
57 "let a; function foo() { a = a || bar(); baz(a); }",
58 "let a; function foo() { bar(++a); }",
59 [
60 "let id;",
61 "function foo() {",
62 " if (typeof id !== 'undefined') {",
63 " return;",
64 " }",
65 " id = setInterval(() => {}, 250);",
66 "}",
67 "foo();"
68 ].join("\n"),
69 "/*exported a*/ let a; function init() { a = foo(); }",
70 "/*exported a*/ let a = 1",
71 "let a; if (true) a = 0; foo(a);",
72 `
73 (function (a) {
74 let b;
75 ({ a, b } = obj);
76 })();
77 `,
78 `
79 (function (a) {
80 let b;
81 ([ a, b ] = obj);
82 })();
83 `,
84 "var a; { var b; ({ a, b } = obj); }",
85 "let a; { let b; ({ a, b } = obj); }",
86 "var a; { var b; ([ a, b ] = obj); }",
87 "let a; { let b; ([ a, b ] = obj); }",
88
89 /*
90 * The assignment is located in a different scope.
91 * Those are warned by prefer-smaller-scope.
92 */
93 "let x; { x = 0; foo(x); }",
94 "(function() { let x; { x = 0; foo(x); } })();",
95 "let x; for (const a of [1,2,3]) { x = foo(); bar(x); }",
96 "(function() { let x; for (const a of [1,2,3]) { x = foo(); bar(x); } })();",
97 "let x; for (x of array) { x; }",
98
99 {
100 code: "let {a, b} = obj; b = 0;",
101 options: [{ destructuring: "all" }]
102 },
103 {
104 code: "let a, b; ({a, b} = obj); b++;",
105 options: [{ destructuring: "all" }]
106 },
107
108 // https://github.com/eslint/eslint/issues/8187
109 {
110 code: "let { name, ...otherStuff } = obj; otherStuff = {};",
111 options: [{ destructuring: "all" }],
112 parserOptions: { ecmaVersion: 2018 }
113 },
114 {
115 code: "let { name, ...otherStuff } = obj; otherStuff = {};",
116 options: [{ destructuring: "all" }],
117 parser: fixtureParser("babel-eslint5/destructuring-object-spread")
118 },
119
120 // https://github.com/eslint/eslint/issues/8308
121 {
122 code: "let predicate; [typeNode.returnType, predicate] = foo();",
123 parserOptions: { ecmaVersion: 2018 }
124 },
125 {
126 code: "let predicate; [typeNode.returnType, ...predicate] = foo();",
127 parserOptions: { ecmaVersion: 2018 }
128 },
129 {
130
131 // intentionally testing empty slot in destructuring assignment
132 code: "let predicate; [typeNode.returnType,, predicate] = foo();",
133 parserOptions: { ecmaVersion: 2018 }
134 },
135 {
136 code: "let predicate; [typeNode.returnType=5, predicate] = foo();",
137 parserOptions: { ecmaVersion: 2018 }
138 },
139 {
140 code: "let predicate; [[typeNode.returnType=5], predicate] = foo();",
141 parserOptions: { ecmaVersion: 2018 }
142 },
143 {
144 code: "let predicate; [[typeNode.returnType, predicate]] = foo();",
145 parserOptions: { ecmaVersion: 2018 }
146 },
147 {
148 code: "let predicate; [typeNode.returnType, [predicate]] = foo();",
149 parserOptions: { ecmaVersion: 2018 }
150 },
151 {
152 code: "let predicate; [, [typeNode.returnType, predicate]] = foo();",
153 parserOptions: { ecmaVersion: 2018 }
154 },
155 {
156 code: "let predicate; [, {foo:typeNode.returnType, predicate}] = foo();",
157 parserOptions: { ecmaVersion: 2018 }
158 },
159 {
160 code: "let predicate; [, {foo:typeNode.returnType, ...predicate}] = foo();",
161 parserOptions: { ecmaVersion: 2018 }
162 },
163 {
164 code: "let a; const b = {}; ({ a, c: b.c } = func());",
165 parserOptions: { ecmaVersion: 2018 }
166 },
167
168 // ignoreReadBeforeAssign
169 {
170 code: "let x; function foo() { bar(x); } x = 0;",
171 options: [{ ignoreReadBeforeAssign: true }]
172 },
173
174 // https://github.com/eslint/eslint/issues/10520
175 "const x = [1,2]; let y; [,y] = x; y = 0;",
176 "const x = [1,2,3]; let y, z; [y,,z] = x; y = 0; z = 0;"
177 ],
178 invalid: [
179 {
180 code: "let x = 1; foo(x);",
181 output: "const x = 1; foo(x);",
182 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
183 },
184 {
185 code: "for (let i in [1,2,3]) { foo(i); }",
186 output: "for (const i in [1,2,3]) { foo(i); }",
187 errors: [{ messageId: "useConst", data: { name: "i" }, type: "Identifier" }]
188 },
189 {
190 code: "for (let x of [1,2,3]) { foo(x); }",
191 output: "for (const x of [1,2,3]) { foo(x); }",
192 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
193 },
194 {
195 code: "let [x = -1, y] = [1,2]; y = 0;",
196 output: null,
197 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
198 },
199 {
200 code: "let {a: x = -1, b: y} = {a:1,b:2}; y = 0;",
201 output: null,
202 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
203 },
204 {
205 code: "(function() { let x = 1; foo(x); })();",
206 output: "(function() { const x = 1; foo(x); })();",
207 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
208 },
209 {
210 code: "(function() { for (let i in [1,2,3]) { foo(i); } })();",
211 output: "(function() { for (const i in [1,2,3]) { foo(i); } })();",
212 errors: [{ messageId: "useConst", data: { name: "i" }, type: "Identifier" }]
213 },
214 {
215 code: "(function() { for (let x of [1,2,3]) { foo(x); } })();",
216 output: "(function() { for (const x of [1,2,3]) { foo(x); } })();",
217 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
218 },
219 {
220 code: "(function() { let [x = -1, y] = [1,2]; y = 0; })();",
221 output: null,
222 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
223 },
224 {
225 code: "let f = (function() { let g = x; })(); f = 1;",
226 output: "let f = (function() { const g = x; })(); f = 1;",
227 errors: [{ messageId: "useConst", data: { name: "g" }, type: "Identifier" }]
228 },
229 {
230 code: "(function() { let {a: x = -1, b: y} = {a:1,b:2}; y = 0; })();",
231 output: null,
232 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
233 },
234 {
235 code: "let x = 0; { let x = 1; foo(x); } x = 0;",
236 output: "let x = 0; { const x = 1; foo(x); } x = 0;",
237 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
238 },
239 {
240 code: "for (let i = 0; i < 10; ++i) { let x = 1; foo(x); }",
241 output: "for (let i = 0; i < 10; ++i) { const x = 1; foo(x); }",
242 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
243 },
244 {
245 code: "for (let i in [1,2,3]) { let x = 1; foo(x); }",
246 output: "for (const i in [1,2,3]) { const x = 1; foo(x); }",
247 errors: [
248 { messageId: "useConst", data: { name: "i" }, type: "Identifier" },
249 { messageId: "useConst", data: { name: "x" }, type: "Identifier" }
250 ]
251 },
252 {
253 code: [
254 "var foo = function() {",
255 " for (const b of c) {",
256 " let a;",
257 " a = 1;",
258 " }",
259 "};"
260 ].join("\n"),
261 output: null,
262 errors: [
263 { messageId: "useConst", data: { name: "a" }, type: "Identifier" }
264 ]
265 },
266 {
267 code: [
268 "var foo = function() {",
269 " for (const b of c) {",
270 " let a;",
271 " ({a} = 1);",
272 " }",
273 "};"
274 ].join("\n"),
275 output: null,
276 errors: [
277 { messageId: "useConst", data: { name: "a" }, type: "Identifier" }
278 ]
279 },
280
281 {
282 code: "let x; x = 0;",
283 output: null,
284 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier", column: 8 }]
285 },
286 {
287 code: "switch (a) { case 0: let x; x = 0; }",
288 output: null,
289 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier", column: 29 }]
290 },
291 {
292 code: "(function() { let x; x = 1; })();",
293 output: null,
294 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier", column: 22 }]
295 },
296
297 {
298 code: "let {a = 0, b} = obj; b = 0; foo(a, b);",
299 output: null,
300 options: [{ destructuring: "any" }],
301 errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }]
302 },
303 {
304 code: "let {a: {b, c}} = {a: {b: 1, c: 2}}; b = 3;",
305 output: null,
306 options: [{ destructuring: "any" }],
307 errors: [{ messageId: "useConst", data: { name: "c" }, type: "Identifier" }]
308 },
309 {
310 code: "let {a: {b, c}} = {a: {b: 1, c: 2}}",
311 output: "const {a: {b, c}} = {a: {b: 1, c: 2}}",
312 options: [{ destructuring: "all" }],
313 errors: [
314 { messageId: "useConst", data: { name: "b" }, type: "Identifier" },
315 { messageId: "useConst", data: { name: "c" }, type: "Identifier" }
316 ]
317 },
318 {
319 code: "let a, b; ({a = 0, b} = obj); b = 0; foo(a, b);",
320 output: null,
321 options: [{ destructuring: "any" }],
322 errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }]
323 },
324 {
325 code: "let {a = 0, b} = obj; foo(a, b);",
326 output: "const {a = 0, b} = obj; foo(a, b);",
327 options: [{ destructuring: "all" }],
328 errors: [
329 { messageId: "useConst", data: { name: "a" }, type: "Identifier" },
330 { messageId: "useConst", data: { name: "b" }, type: "Identifier" }
331 ]
332 },
333 {
334 code: "let [a] = [1]",
335 output: "const [a] = [1]",
336 options: [],
337 errors: [
338 { messageId: "useConst", data: { name: "a" }, type: "Identifier" }
339 ]
340 },
341 {
342 code: "let {a} = obj",
343 output: "const {a} = obj",
344 options: [],
345 errors: [
346 { messageId: "useConst", data: { name: "a" }, type: "Identifier" }
347 ]
348 },
349 {
350 code: "let a, b; ({a = 0, b} = obj); foo(a, b);",
351 output: null,
352 options: [{ destructuring: "all" }],
353 errors: [
354 { messageId: "useConst", data: { name: "a" }, type: "Identifier" },
355 { messageId: "useConst", data: { name: "b" }, type: "Identifier" }
356 ]
357 },
358 {
359 code: "let {a = 0, b} = obj, c = a; b = a;",
360 output: null,
361 options: [{ destructuring: "any" }],
362 errors: [
363 { messageId: "useConst", data: { name: "a" }, type: "Identifier" },
364 { messageId: "useConst", data: { name: "c" }, type: "Identifier" }
365 ]
366 },
367 {
368 code: "let {a = 0, b} = obj, c = a; b = a;",
369 output: null,
370 options: [{ destructuring: "all" }],
371 errors: [{ messageId: "useConst", data: { name: "c" }, type: "Identifier" }]
372 },
373
374 // https://github.com/eslint/eslint/issues/8187
375 {
376 code: "let { name, ...otherStuff } = obj; otherStuff = {};",
377 output: null,
378 options: [{ destructuring: "any" }],
379 parserOptions: { ecmaVersion: 2018 },
380 errors: [{ messageId: "useConst", data: { name: "name" }, type: "Identifier", column: 7 }]
381 },
382 {
383 code: "let { name, ...otherStuff } = obj; otherStuff = {};",
384 output: null,
385 options: [{ destructuring: "any" }],
386 parser: fixtureParser("babel-eslint5/destructuring-object-spread"),
387 errors: [{ messageId: "useConst", data: { name: "name" }, type: "Identifier", column: 7 }]
388 },
389
390 // Warnings are located at declaration if there are reading references before assignments.
391 {
392 code: "let x; function foo() { bar(x); } x = 0;",
393 output: null,
394 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier", column: 5 }]
395 },
396
397 // https://github.com/eslint/eslint/issues/5837
398 {
399 code: "/*eslint use-x:error*/ let x = 1",
400 output: "/*eslint use-x:error*/ const x = 1",
401 parserOptions: { ecmaFeatures: { globalReturn: true } },
402 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
403 },
404 {
405 code: "/*eslint use-x:error*/ { let x = 1 }",
406 output: "/*eslint use-x:error*/ { const x = 1 }",
407 errors: [{ messageId: "useConst", data: { name: "x" }, type: "Identifier" }]
408 },
409 {
410 code: "let { foo, bar } = baz;",
411 output: "const { foo, bar } = baz;",
412 errors: [
413 { messageId: "useConst", data: { name: "foo" }, type: "Identifier" },
414 { messageId: "useConst", data: { name: "bar" }, type: "Identifier" }
415 ]
416 },
417
418 // https://github.com/eslint/eslint/issues/10520
419 {
420 code: "const x = [1,2]; let [,y] = x;",
421 output: "const x = [1,2]; const [,y] = x;",
422 errors: [{ messageId: "useConst", data: { name: "y" }, type: "Identifier" }]
423 },
424 {
425 code: "const x = [1,2,3]; let [y,,z] = x;",
426 output: "const x = [1,2,3]; const [y,,z] = x;",
427 errors: [
428 { messageId: "useConst", data: { name: "y" }, type: "Identifier" },
429 { messageId: "useConst", data: { name: "z" }, type: "Identifier" }
430 ]
431 },
432
433 // https://github.com/eslint/eslint/issues/8308
434 {
435 code: "let predicate; [, {foo:returnType, predicate}] = foo();",
436 output: null,
437 parserOptions: { ecmaVersion: 2018 },
438 errors: [
439 { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
440 ]
441 },
442 {
443 code: "let predicate; [, {foo:returnType, predicate}, ...bar ] = foo();",
444 output: null,
445 parserOptions: { ecmaVersion: 2018 },
446 errors: [
447 { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
448 ]
449 },
450 {
451 code: "let predicate; [, {foo:returnType, ...predicate} ] = foo();",
452 output: null,
453 parserOptions: { ecmaVersion: 2018 },
454 errors: [
455 { message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
456 ]
457 },
458 {
459 code: "let x = 'x', y = 'y';",
460 output: "const x = 'x', y = 'y';",
461 errors: [
462 { message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
463 { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" }
464 ]
465 },
466 {
467 code: "let x = 'x', y = 'y'; x = 1",
468 output: null,
469 errors: [
470 { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" }
471 ]
472 },
473 {
474 code: "let x = 1, y = 'y'; let z = 1;",
475 output: "const x = 1, y = 'y'; const z = 1;",
476 errors: [
477 { message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
478 { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
479 { message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
480 ]
481 },
482 {
483 code: "let { a, b, c} = obj; let { x, y, z} = anotherObj; x = 2;",
484 output: "const { a, b, c} = obj; let { x, y, z} = anotherObj; x = 2;",
485 errors: [
486 { message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
487 { message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" },
488 { message: "'c' is never reassigned. Use 'const' instead.", type: "Identifier" },
489 { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
490 { message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
491 ]
492 },
493 {
494 code: "let x = 'x', y = 'y'; function someFunc() { let a = 1, b = 2; foo(a, b) }",
495 output: "const x = 'x', y = 'y'; function someFunc() { const a = 1, b = 2; foo(a, b) }",
496 errors: [
497 { message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
498 { message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
499 { message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
500 { message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" }
501 ]
502 },
503 {
504 code: "let someFunc = () => { let a = 1, b = 2; foo(a, b) }",
505 output: "const someFunc = () => { const a = 1, b = 2; foo(a, b) }",
506 errors: [
507 { message: "'someFunc' is never reassigned. Use 'const' instead.", type: "Identifier" },
508 { message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
509 { message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" }
510 ]
511 },
512
513 // https://github.com/eslint/eslint/issues/11699
514 {
515 code: "let {a, b} = c, d;",
516 output: null,
517 errors: [
518 { messageId: "useConst", data: { name: "a" }, type: "Identifier" },
519 { messageId: "useConst", data: { name: "b" }, type: "Identifier" }
520 ]
521 },
522 {
523 code: "let {a, b, c} = {}, e, f;",
524 output: null,
525 errors: [
526 { messageId: "useConst", data: { name: "a" }, type: "Identifier" },
527 { messageId: "useConst", data: { name: "b" }, type: "Identifier" },
528 { messageId: "useConst", data: { name: "c" }, type: "Identifier" }
529 ]
530 },
531 {
532 code: [
533 "function a() {",
534 "let foo = 0,",
535 " bar = 1;",
536 "foo = 1;",
537 "}",
538 "function b() {",
539 "let foo = 0,",
540 " bar = 2;",
541 "foo = 2;",
542 "}"
543 ].join("\n"),
544 output: null,
545 errors: [
546 { message: "'bar' is never reassigned. Use 'const' instead.", type: "Identifier" },
547 { message: "'bar' is never reassigned. Use 'const' instead.", type: "Identifier" }
548 ]
549 }
550 ]
551 });