diff --git a/rules/no-for-loop.js b/rules/no-for-loop.js index 23a41ac558..3855f2705d 100644 --- a/rules/no-for-loop.js +++ b/rules/no-for-loop.js @@ -361,21 +361,37 @@ const create = context => { let declarationElement = element; let declarationType = 'const'; let removeDeclaration = true; - if ( - elementNode && - (elementNode.id.type === 'ObjectPattern' || elementNode.id.type === 'ArrayPattern') - ) { - removeDeclaration = arrayReferences.length === 1; + let typeAnnotation; + + if (elementNode) { + if (elementNode.id.type === 'ObjectPattern' || elementNode.id.type === 'ArrayPattern') { + removeDeclaration = arrayReferences.length === 1; + } if (removeDeclaration) { - declarationType = elementNode.parent.kind; - declarationElement = sourceCode.getText(elementNode.id); + declarationType = element.type === 'VariableDeclarator' ? elementNode.kind : elementNode.parent.kind; + if (elementNode.id.typeAnnotation && shouldGenerateIndex) { + declarationElement = sourceCode.text.slice(elementNode.id.range[0], elementNode.id.typeAnnotation.range[0]); + typeAnnotation = sourceCode.getText(elementNode.id.typeAnnotation, -1).trim(); + } else { + declarationElement = sourceCode.getText(elementNode.id); + } } } - const replacement = shouldGenerateIndex ? - `${declarationType} [${index}, ${declarationElement}] of ${array}.entries()` : - `${declarationType} ${declarationElement} of ${array}`; + const parts = [declarationType]; + if (shouldGenerateIndex) { + parts.push(` [${index}, ${declarationElement}]`); + if (typeAnnotation) { + parts.push(`: [number, ${typeAnnotation}]`); + } + + parts.push(` of ${array}.entries()`); + } else { + parts.push(` ${declarationElement} of ${array}`); + } + + const replacement = parts.join(''); yield fixer.replaceTextRange([ node.init.range[0], diff --git a/test/no-for-loop.js b/test/no-for-loop.js index 15c44743dd..357b10d56f 100644 --- a/test/no-for-loop.js +++ b/test/no-for-loop.js @@ -203,7 +203,7 @@ ruleTester.run('no-for-loop', rule, { console.log(i, el); } `, outdent` - for (const [i, el] of arr.entries()) { + for (let [i, el] of arr.entries()) { console.log(i, el); } `), @@ -247,7 +247,7 @@ ruleTester.run('no-for-loop', rule, { var x = xs[j];console.log(j, x); } `, outdent` - for (const [j, x] of xs.entries()) { + for (var [j, x] of xs.entries()) { console.log(j, x); } `), @@ -277,7 +277,7 @@ ruleTester.run('no-for-loop', rule, { console.log(j, x, y); } `, outdent` - for (const [j, x] of xs.entries()) { + for (var [j, x] of xs.entries()) { var y = ys[j]; console.log(j, x, y); } @@ -289,7 +289,7 @@ ruleTester.run('no-for-loop', rule, { console.log(j, x, y); } `, outdent` - for (const [j, x] of xs.entries()) { + for (var [j, x] of xs.entries()) { var y = ys[j]; console.log(j, x, y); } @@ -301,7 +301,7 @@ ruleTester.run('no-for-loop', rule, { console.log(j, x, y); } `, outdent` - for (const [j, x] of xs.entries()) { + for (var [j, x] of xs.entries()) { var y = ys[j], i = 10; console.log(j, x, y); } @@ -725,10 +725,72 @@ ruleTesterEs5.run('no-for-loop', rule, { invalid: [] }); +runTest.typescript({ + valid: [], + invalid: [ + { + // https://github.com/microsoft/vscode/blob/cf9ac85214c3f1d3d0b80cc503ff7498f2b3ea2f/src/vs/workbench/api/common/extHostLanguageFeatures.ts#L1207 + code: outdent` + for (let i = 0; i < positions.length; i++) { + let last: vscode.Position | vscode.Range = positions[i]; + let selectionRange = allProviderRanges[i]; + } + `, + output: outdent` + for (let [i, last]: [number, vscode.Position | vscode.Range] of positions.entries()) { + let selectionRange = allProviderRanges[i]; + } + `, + errors: 1 + }, + { + code: outdent` + for (let i = 0; i < positions.length; i++) { + let last: vscode.Position | vscode.Range = positions[i]; + } + `, + output: outdent` + for (let last: vscode.Position | vscode.Range of positions) { + } + `, + errors: 1 + } + ] +}); + runTest.visualize([ outdent` for (let i = 0; i < arr.length; i += 1) { console.log(arr[i]) } + `, + // #742 + outdent` + for (let i = 0; i < plugins.length; i++) { + let plugin = plugins[i]; + plugin = calculateSomeNewValue(); + // ... + } + `, + outdent` + for (let i = 0; i < array.length; i++) { + var foo = array[i]; + foo = bar(); + } + `, + outdent` + for (let i = 0; i < array.length; i++) { + let foo = array[i]; + } + `, + outdent` + for (let i = 0; i < array.length; i++) { + const foo = array[i]; + } + `, + outdent` + for (let i = 0; i < array.length; i++) { + var foo = array[i], bar = 1; + } ` ]); diff --git a/test/snapshots/no-for-loop.js.md b/test/snapshots/no-for-loop.js.md index fcbba48f5f..b10aff7088 100644 --- a/test/snapshots/no-for-loop.js.md +++ b/test/snapshots/no-for-loop.js.md @@ -27,3 +27,131 @@ Generated by [AVA](https://avajs.dev). > 3 | }␊ | ^^ Use a `for-of` loop instead of this `for` loop.␊ ` + +## no-for-loop - #2 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | for (let i = 0; i < plugins.length; i++) {␊ + 2 | let plugin = plugins[i];␊ + 3 | plugin = calculateSomeNewValue();␊ + 4 | // ...␊ + 5 | }␊ + ␊ + Output:␊ + 1 | for (let plugin of plugins) {␊ + 2 | plugin = calculateSomeNewValue();␊ + 3 | // ...␊ + 4 | }␊ + ␊ + Error 1/1:␊ + > 1 | for (let i = 0; i < plugins.length; i++) {␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | let plugin = plugins[i];␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 3 | plugin = calculateSomeNewValue();␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 4 | // ...␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 5 | }␊ + | ^^ Use a `for-of` loop instead of this `for` loop.␊ + ` + +## no-for-loop - #3 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | for (let i = 0; i < array.length; i++) {␊ + 2 | var foo = array[i];␊ + 3 | foo = bar();␊ + 4 | }␊ + ␊ + Output:␊ + 1 | for (var foo of array) {␊ + 2 | foo = bar();␊ + 3 | }␊ + ␊ + Error 1/1:␊ + > 1 | for (let i = 0; i < array.length; i++) {␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | var foo = array[i];␊ + | ^^^^^^^^^^^^^^^^^^^^␊ + > 3 | foo = bar();␊ + | ^^^^^^^^^^^^^^^^^^^^␊ + > 4 | }␊ + | ^^ Use a `for-of` loop instead of this `for` loop.␊ + ` + +## no-for-loop - #4 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | for (let i = 0; i < array.length; i++) {␊ + 2 | let foo = array[i];␊ + 3 | }␊ + ␊ + Output:␊ + 1 | for (let foo of array) {␊ + 2 | }␊ + ␊ + Error 1/1:␊ + > 1 | for (let i = 0; i < array.length; i++) {␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | let foo = array[i];␊ + | ^^^^^^^^^^^^^^^^^^^^␊ + > 3 | }␊ + | ^^ Use a `for-of` loop instead of this `for` loop.␊ + ` + +## no-for-loop - #5 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | for (let i = 0; i < array.length; i++) {␊ + 2 | const foo = array[i];␊ + 3 | }␊ + ␊ + Output:␊ + 1 | for (const foo of array) {␊ + 2 | }␊ + ␊ + Error 1/1:␊ + > 1 | for (let i = 0; i < array.length; i++) {␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | const foo = array[i];␊ + | ^^^^^^^^^^^^^^^^^^^^^^␊ + > 3 | }␊ + | ^^ Use a `for-of` loop instead of this `for` loop.␊ + ` + +## no-for-loop - #6 + +> Snapshot 1 + + `␊ + Input:␊ + 1 | for (let i = 0; i < array.length; i++) {␊ + 2 | var foo = array[i], bar = 1;␊ + 3 | }␊ + ␊ + Output:␊ + 1 | for (var foo of array) {␊ + 2 | var bar = 1;␊ + 3 | }␊ + ␊ + Error 1/1:␊ + > 1 | for (let i = 0; i < array.length; i++) {␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 2 | var foo = array[i], bar = 1;␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^␊ + > 3 | }␊ + | ^^ Use a `for-of` loop instead of this `for` loop.␊ + ` diff --git a/test/snapshots/no-for-loop.js.snap b/test/snapshots/no-for-loop.js.snap index 941ba67182..0b6be502d9 100644 Binary files a/test/snapshots/no-for-loop.js.snap and b/test/snapshots/no-for-loop.js.snap differ