From ea0b64cfa06e5f68e902307b2d5ebbef5a8d852a Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 11 Jan 2021 18:59:42 +0800 Subject: [PATCH 01/40] Add `no-array-for-each` --- docs/rules/no-array-for-each.md | 17 ++++ index.js | 1 + readme.md | 2 + rules/no-array-for-each.js | 173 ++++++++++++++++++++++++++++++++ rules/utils/method-selector.js | 8 +- test/no-array-for-each.js | 30 ++++++ 6 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 docs/rules/no-array-for-each.md create mode 100644 rules/no-array-for-each.js create mode 100644 test/no-array-for-each.js diff --git a/docs/rules/no-array-for-each.md b/docs/rules/no-array-for-each.md new file mode 100644 index 0000000000..94db7d5264 --- /dev/null +++ b/docs/rules/no-array-for-each.md @@ -0,0 +1,17 @@ +# Prefer `for…of` over `Array#forEach(…)`. + + + +This rule is partly fixable. + +## Fail + +```js +const foo = 'unicorn'; +``` + +## Pass + +```js +const foo = 'πŸ¦„'; +``` diff --git a/index.js b/index.js index 41017ea22c..e3f49943b1 100644 --- a/index.js +++ b/index.js @@ -55,6 +55,7 @@ module.exports = { 'unicorn/new-for-builtins': 'error', 'unicorn/no-abusive-eslint-disable': 'error', 'unicorn/no-array-callback-reference': 'error', + 'unicorn/no-array-for-each': 'error', 'unicorn/no-array-reduce': 'error', 'unicorn/no-console-spaces': 'error', 'unicorn/no-for-loop': 'error', diff --git a/readme.md b/readme.md index 0a57c221d7..d9e36ac4b4 100644 --- a/readme.md +++ b/readme.md @@ -49,6 +49,7 @@ Configure it in `package.json`. "unicorn/new-for-builtins": "error", "unicorn/no-abusive-eslint-disable": "error", "unicorn/no-array-callback-reference": "error", + "unicorn/no-array-for-each": "error", "unicorn/no-array-reduce": "error", "unicorn/no-console-spaces": "error", "unicorn/no-for-loop": "error", @@ -125,6 +126,7 @@ Configure it in `package.json`. - [new-for-builtins](docs/rules/new-for-builtins.md) - Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. *(partly fixable)* - [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) - Enforce specifying rules to disable in `eslint-disable` comments. - [no-array-callback-reference](docs/rules/no-array-callback-reference.md) - Prevent passing a function reference directly to iterator methods. +- [no-array-for-each](docs/rules/no-array-for-each.md) - Prefer `for…of` over `Array#forEach(…)`. *(partly fixable)* - [no-array-reduce](docs/rules/no-array-reduce.md) - Disallow `Array#reduce()` and `Array#reduceRight()`. - [no-console-spaces](docs/rules/no-console-spaces.md) - Do not use leading/trailing space between `console.log` parameters. *(fixable)* - [no-for-loop](docs/rules/no-for-loop.md) - Do not use a `for` loop that can be replaced with a `for-of` loop. *(partly fixable)* diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js new file mode 100644 index 0000000000..2937aaec8f --- /dev/null +++ b/rules/no-array-for-each.js @@ -0,0 +1,173 @@ +'use strict'; +const { hasSideEffect, isParenthesized } = require('eslint-utils'); +const getDocumentationUrl = require('./utils/get-documentation-url'); +const methodSelector = require('./utils/method-selector'); + +const MESSAGE_ID = 'no-array-for-each'; +const messages = { + [MESSAGE_ID]: 'Do not use `Array#forEach(…)`.', +}; + +const arrayForEachCallSelector = methodSelector({ + name: 'forEach', + includeOptional: true, +}); + +const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/u; +function isReturnStatementInBreakableStatements(node, callbackFunction) { + for (let parent = node; parent && parent !== callbackFunction; parent = node.parent) { + if (breakableTypePattern.test(node.type)) { + return true; + } + } + + return false; +} + +function getFix(node, getParenthesizedText, functions) { + const { + parent, + arguments: callArguments, + callee: { object: array, property: method }, + } = node; + + if ( + parent.type !== 'ExpressionStatement' || + isParenthesized(node) || + callArguments.length !== 1 || + callee.optional || + hasSideEffect(callee) + ) { + return; + } + + const [callback] = callArguments; + + if ( + // Leave non-function type to `no-array-callback-reference` rule + callback.type !== 'FunctionExpression' || + callback.type !== 'ArrowFunctionExpression' || + callback.async || + callback.generator || + !functions.get(callback) + ) { + return; + } + + const parameters = callback.params; + + if ( + parameters.length > 3 || + parameters.some( + parameter => parameters.type === 'RestElement' + ) + ) { + return; + } + + + return function(fixer) { + + + } + + // TODO: check if parameter name available + const arrayText = getParenthesizedText(array); + const fixed = []; + if (parameters.length > 1) { + fixed.push(`const [${getParenthesizedText(parameter[0])}, ${getParenthesizedText(parameter[1])}] of ${getParenthesizedText(array)}.entries()) {`) + } else { + fixed.push(`const [${getParenthesizedText(parameter[0])}] of ${getParenthesizedText(array)}) {`) + } + + const {body} = callback; + if (!Array.isArray(body)) { + fixed.push(`{${getParenthesizedText(body)}}`); + } + +} + +const create = (context) => { + const callExpressions = []; + const functionStacks = []; + const functions = new Map(); + const sourceCode = context.getSourceCode(); + + const markFunctionNotFixable = () => { + const currentFunction = functionStacks[functionStacks.length - 1]; + // Top level `return` + if (!currentFunction) { + return; + } + + const canFix = functionReturnStatements.get(currentFunction); + if (!canFix) { + return; + } + + functionReturnStatements.set(currentFunction, false); + }; + + const getParenthesizedText = node => { + const text = sourceCode.getText(node); + return isParenthesized(node, sourceCode) ? `(${text})` : text; + }; + + return { + ':function'(node) { + functionStacks.push(node); + functionReturnStatements.set(node, true); + }, + ':function:exit'(node) { + functionStacks.pop(); + }, + ReturnStatement(node) { + const currentFunction = functionStacks[functionStacks.length - 1]; + if (!currentFunction || !isReturnStatementInBreakableStatements(node, currentFunction)) { + return; + } + + markFunctionNotFixable(); + }, + ThisExpression(node) { + const currentFunction = functionStacks[functionStacks.length - 1]; + if (!currentFunction || currentFunction.type === 'FunctionExpression') { + return; + } + + markFunctionNotFixable(); + }, + 'Identifier[name="arguments"]'(node) { + const currentFunction = functionStacks[functionStacks.length - 1]; + if (!currentFunction || currentFunction.type === 'FunctionExpression') { + return; + } + + markFunctionNotFixable(); + }, + [arrayForEachCallSelector](node) { + callExpressions.push(node); + }, + 'Program:exit'() { + for (const node of callExpressions) { + context.report({ + node: node.callee.property, + messageId: MESSAGE_ID, + fix: getFix(node, getParenthesizedText, functions) + }); + } + } + }; +}; + +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + url: getDocumentationUrl(__filename), + }, + fixable: 'code', + messages, + }, +}; diff --git a/rules/utils/method-selector.js b/rules/utils/method-selector.js index de52a01483..f1cdf0ce89 100644 --- a/rules/utils/method-selector.js +++ b/rules/utils/method-selector.js @@ -8,7 +8,8 @@ module.exports = options => { object, min, max, - property = '' + property = '', + includeOptional = false } = { min: 0, max: Number.POSITIVE_INFINITY, @@ -20,10 +21,13 @@ module.exports = options => { const selector = [ `[${prefix}type="CallExpression"]`, `[${prefix}callee.type="MemberExpression"]`, - `[${prefix}callee.computed=false]`, `[${prefix}callee.property.type="Identifier"]` ]; + if (!includeOptional) { + selector.push(`[${prefix}callee.computed=false]`); + } + if (name) { selector.push(`[${prefix}callee.property.name="${name}"]`); } diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js new file mode 100644 index 0000000000..cb8253b499 --- /dev/null +++ b/test/no-array-for-each.js @@ -0,0 +1,30 @@ +import {outdent} from 'outdent'; +import {test} from './utils/test'; + +const MESSAGE_ID = 'no-array-for-each'; +const errors = [ + { + messageId: MESSAGE_ID + } +]; + +test({ + valid: [ + 'const foo = \'πŸ¦„\';' + ], + invalid: [ + { + code: outdent` + const foo = 'unicorn'; + `, + output: outdent` + const foo = 'πŸ¦„'; + `, + errors + } + ] +}); + +test.visualize([ + 'const foo = \'unicorn\';' +]); From aa5786ed2f91ebfa10eb6319c48a613bde5eb546 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 12:39:55 +0800 Subject: [PATCH 02/40] Refactor --- rules/no-array-for-each.js | 120 +++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 2937aaec8f..773a37231b 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -2,6 +2,7 @@ const { hasSideEffect, isParenthesized } = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); +const avoidCapture = require('./avoid-capture'); const MESSAGE_ID = 'no-array-for-each'; const messages = { @@ -42,6 +43,8 @@ function getFix(node, getParenthesizedText, functions) { } const [callback] = callArguments; + const returnStatements = functions.get(callback); + const parameters = callback.params; if ( // Leave non-function type to `no-array-callback-reference` rule @@ -49,64 +52,77 @@ function getFix(node, getParenthesizedText, functions) { callback.type !== 'ArrowFunctionExpression' || callback.async || callback.generator || - !functions.get(callback) + returnStatements.some(returnStatement => isReturnStatementInBreakableStatements(returnStatement, callback)) || + parameters.length > 2 || + parameters.some(parameter => parameters.type === 'RestElement') ) { return; } - const parameters = callback.params; + // TODO: check `FunctionExpression`'s `.id` `arguments` `this` - if ( - parameters.length > 3 || - parameters.some( - parameter => parameters.type === 'RestElement' - ) - ) { - return; - } + return function * (fixer) { + const scopes = []; + + let useEntries = parameters.length === 2; + const variables = ( + parameters.length === 2 ? ['index', 'element'] : ['element'] + ).map(name => avoidCapture(name, scopes, ecmaVersion)); + const forOfLoopHead = [ + 'for (const ' + ]; + if (useEntries) { + forOfLoopHead.push(`[${variables.join(', ')}]`) + } else { + forOfLoopHead.push(variables[0]) + } - return function(fixer) { + forOfLoopHead.push(' of '); + if (useEntries) { + forOfLoopHead.push(`${getParenthesizedText(array)}.entries()`); + } else { + forOfLoopHead.push(getParenthesizedText(array)); + } + forOfLoopHead.push(')'); - } + const [start] = node.range; + const [end] = callback.body.range; - // TODO: check if parameter name available - const arrayText = getParenthesizedText(array); - const fixed = []; - if (parameters.length > 1) { - fixed.push(`const [${getParenthesizedText(parameter[0])}, ${getParenthesizedText(parameter[1])}] of ${getParenthesizedText(array)}.entries()) {`) - } else { - fixed.push(`const [${getParenthesizedText(parameter[0])}] of ${getParenthesizedText(array)}) {`) - } + yield fixer.replaceTextRange([start, end], forOfLoopHead.join('')); - const {body} = callback; - if (!Array.isArray(body)) { - fixed.push(`{${getParenthesizedText(body)}}`); + // Remove call expression trailing comma + const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2); + if (isCommaTOken(penultimateToken)) { + yield fixer.remove(penultimateToken); } + yield fixer.remove(lastToken); + + for(const returnStatement of returnStatements) { + const returnToken = sourceCode.getFirstToken(returnStatement); + if (returnStatement.argument) { + // Remove `return` + yield fixer.remove(returnToken); + + // If `returnStatement` has no semi + const lastToken = sourceCode.getLastTokens(returnStatement); + yield fixer.insertTextAfter(returnStatement, + `${isSemiToken(lastToken) ? '' : ';'}break;` + ); + } else { + yield fixer.replace(returnStatement, 'break'); + } + } } const create = (context) => { - const callExpressions = []; const functionStacks = []; - const functions = new Map(); - const sourceCode = context.getSourceCode(); - - const markFunctionNotFixable = () => { - const currentFunction = functionStacks[functionStacks.length - 1]; - // Top level `return` - if (!currentFunction) { - return; - } - - const canFix = functionReturnStatements.get(currentFunction); - if (!canFix) { - return; - } + const functionReturnStatements = new Map(); + const callExpressions = []; - functionReturnStatements.set(currentFunction, false); - }; + const sourceCode = context.getSourceCode(); const getParenthesizedText = node => { const text = sourceCode.getText(node); @@ -116,34 +132,20 @@ const create = (context) => { return { ':function'(node) { functionStacks.push(node); - functionReturnStatements.set(node, true); + functionReturnStatements.set(node, []); }, ':function:exit'(node) { functionStacks.pop(); }, ReturnStatement(node) { const currentFunction = functionStacks[functionStacks.length - 1]; - if (!currentFunction || !isReturnStatementInBreakableStatements(node, currentFunction)) { - return; - } - - markFunctionNotFixable(); - }, - ThisExpression(node) { - const currentFunction = functionStacks[functionStacks.length - 1]; - if (!currentFunction || currentFunction.type === 'FunctionExpression') { - return; - } - - markFunctionNotFixable(); - }, - 'Identifier[name="arguments"]'(node) { - const currentFunction = functionStacks[functionStacks.length - 1]; - if (!currentFunction || currentFunction.type === 'FunctionExpression') { + // Global return + if (!currentFunction) { return; } - markFunctionNotFixable(); + const returnStatements = functionReturnStatements.get(currentFunction); + returnStatements.push(node); }, [arrayForEachCallSelector](node) { callExpressions.push(node); From 298e2e1fe17dda4d7e7803bf169b890f8f5db4d8 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 14:49:20 +0800 Subject: [PATCH 03/40] Tests --- rules/no-array-for-each.js | 220 +++++++++++++++++++++++++------------ test/no-array-for-each.js | 145 ++++++++++++++++++++---- 2 files changed, 274 insertions(+), 91 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 773a37231b..bea497c3cd 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -2,7 +2,8 @@ const { hasSideEffect, isParenthesized } = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); -const avoidCapture = require('./avoid-capture'); +const needsSemicolon = require('./utils/needs-semicolon'); +const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object'); const MESSAGE_ID = 'no-array-for-each'; const messages = { @@ -25,83 +26,64 @@ function isReturnStatementInBreakableStatements(node, callbackFunction) { return false; } -function getFix(node, getParenthesizedText, functions) { - const { - parent, - arguments: callArguments, - callee: { object: array, property: method }, - } = node; - - if ( - parent.type !== 'ExpressionStatement' || - isParenthesized(node) || - callArguments.length !== 1 || - callee.optional || - hasSideEffect(callee) - ) { - return; - } - - const [callback] = callArguments; - const returnStatements = functions.get(callback); - const parameters = callback.params; - - if ( - // Leave non-function type to `no-array-callback-reference` rule - callback.type !== 'FunctionExpression' || - callback.type !== 'ArrowFunctionExpression' || - callback.async || - callback.generator || - returnStatements.some(returnStatement => isReturnStatementInBreakableStatements(returnStatement, callback)) || - parameters.length > 2 || - parameters.some(parameter => parameters.type === 'RestElement') - ) { - return; - } - - // TODO: check `FunctionExpression`'s `.id` `arguments` `this` - - return function * (fixer) { - const scopes = []; +function * getFixFunction(callExpression, sourceCode) { + const [callback] = callExpression.arguments; + const {parameters} = callback; + const array = callExpression.callee.object; + const getForOfLoopHeadText = () => { + const parametersText = parameters.map(parameter => sourceCode.getText(parameter)); let useEntries = parameters.length === 2; - const variables = ( - parameters.length === 2 ? ['index', 'element'] : ['element'] - ).map(name => avoidCapture(name, scopes, ecmaVersion)); - const forOfLoopHead = [ - 'for (const ' - ]; + let text = 'for (const '; if (useEntries) { - forOfLoopHead.push(`[${variables.join(', ')}]`) + text += `[${parametersText.join(', ')}]`; } else { - forOfLoopHead.push(variables[0]) + text += parametersText[0]; + } + + text += ' of '; + + let arrayText = sourceCode.getText(array); + if ( + isParenthesized(node, sourceCode) || + (useEntries && shouldAddParenthesesToMemberExpressionObject(array, sourceCode)) + ) { + arrayText = `(${arrayText})`; } - forOfLoopHead.push(' of '); + text += arrayText; + if (useEntries) { - forOfLoopHead.push(`${getParenthesizedText(array)}.entries()`); - } else { - forOfLoopHead.push(getParenthesizedText(array)); + text += '.entries()'; } - forOfLoopHead.push(')'); + text += ') '; + return text; + }; + + const getForOfLoopHeadRange = () => { const [start] = node.range; - const [end] = callback.body.range; + let end; + if (callback.body.type === 'BlockStatement') { + end = callback.body.range[0]; + } else { + const arrowToken = sourceCode.getFirstToken(callback, (token) => '=>'); + end = arrowToken.range[1]; + } - yield fixer.replaceTextRange([start, end], forOfLoopHead.join('')); + return [start, end]; + }; - // Remove call expression trailing comma - const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2); - if (isCommaTOken(penultimateToken)) { - yield fixer.remove(penultimateToken); - } + function * replaceReturnStatement(returnStatement) { + const returnToken = sourceCode.getFirstToken(returnStatement); - yield fixer.remove(lastToken); + /* istanbul ignore next: `ReturnStatement` firstToken should be `return` */ + if (returnToken.value !== 'return') { + throw new Error(`Unexpected token ${returnToken.value}.`) + } - for(const returnStatement of returnStatements) { - const returnToken = sourceCode.getFirstToken(returnStatement); if (returnStatement.argument) { // Remove `return` yield fixer.remove(returnToken); @@ -109,12 +91,107 @@ function getFix(node, getParenthesizedText, functions) { // If `returnStatement` has no semi const lastToken = sourceCode.getLastTokens(returnStatement); yield fixer.insertTextAfter(returnStatement, - `${isSemiToken(lastToken) ? '' : ';'}break;` + `${isSemiToken(lastToken) ? '' : '; '}break;` ); } else { yield fixer.replace(returnStatement, 'break'); } } + + const shouldRemoveExpressionStatementLastToken = token => { + if (!isSemiToken(expressionStatementLastToken)) { + return false; + } + + if (callback.body.type === 'BlockStatement') { + return true; + } + + const nextToken = sourceCode.getTokenAfter(token); + if (nextToken && needsSemicolon(token, sourceCode, nextToken.value)) { + return false; + } + + return true; + }; + + + return (fixer) => { + yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); + + // Remove call expression trailing comma + const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2); + if (isCommaToken(penultimateToken)) { + yield fixer.remove(penultimateToken); + } + yield fixer.remove(lastToken); + + for(const returnStatement of returnStatements) { + yield * replaceReturnStatement(returnStatement); + } + + const expressionStatementLastToken = sourceCode.getLastToken(callExpression.parent); + if (shouldRemoveLastSemicolonToken(expressionStatementLastToken)) { + yield fixer.remove(expressionStatementLastToken); + } + }; +} + +function isFixable(callExpression, sourceCode, functionReturnStatements) { + // Check `CallExpression` + if ( + callExpression.optional || + isParenthesized(callExpression, sourceCode) || + callExpression.arguments.length !== 1 + ) { + return false; + } + + // Check `CallExpression.parent` + if (callExpression.parent.type !== 'ExpressionStatement') { + return false; + } + + // Check `CallExpression.callee` + if (callExpression.callee.optional) { + return false; + } + + // Check `CallExpression.arguments[0]`; + const [callback] = callExpression.arguments; + if ( + // Leave non-function type to `no-array-callback-reference` rule + callback.type !== 'FunctionExpression' || + callback.type !== 'ArrowFunctionExpression' || + callback.async || + callback.generator + ) { + return false; + } + + // Check `callback.parameters` + const {parameters} = callback; + if ( + !(parameters.length === 1 || parameters.length === 2) || + parameters.some(parameter => parameters.type !== 'Identifier') + ) { + return false; + } + + // TODO: check parameters conflicts + + // Check `ReturnStatement`s in `callback` + const returnStatements = functionReturnStatements.get(callback); + if (returnStatements.some(returnStatement => isReturnStatementInBreakableStatements(returnStatement, callback))) { + return false; + } + + // Check `callback` self + if (callback.type === 'FunctionExpression') { + // TODO: check `.id` `arguments` `this` of `FunctionExpression` + } + + return true; } const create = (context) => { @@ -151,12 +228,17 @@ const create = (context) => { callExpressions.push(node); }, 'Program:exit'() { - for (const node of callExpressions) { - context.report({ - node: node.callee.property, - messageId: MESSAGE_ID, - fix: getFix(node, getParenthesizedText, functions) - }); + for (const callExpression of callExpressions) { + const problem = { + node: callExpression.callee.property, + messageId: MESSAGE_ID + }; + + if (isFixable(callExpression, sourceCode, functionReturnStatements)) { + problem.fix = getFixFunction(callExpression, sourceCode); + } + + context.report(problem); } } }; diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index cb8253b499..e4a180cc05 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -1,30 +1,131 @@ import {outdent} from 'outdent'; import {test} from './utils/test'; -const MESSAGE_ID = 'no-array-for-each'; -const errors = [ - { - messageId: MESSAGE_ID - } -]; - -test({ +test.visualize([ valid: [ - 'const foo = \'πŸ¦„\';' + 'new foo.forEach(element => bar())', + 'forEach(element => bar())', + 'foo.notForEach(element => bar())' ], invalid: [ - { - code: outdent` - const foo = 'unicorn'; - `, - output: outdent` - const foo = 'πŸ¦„'; - `, - errors - } - ] -}); + // Not fixable + 'foo.forEach?.(element => bar(element))', + '(foo.forEach(element => bar(element)))', + 'foo.forEach(element => bar(element), thisArgument)', + 'foo.forEach()', + 'const baz = foo.forEach(element => bar(element))', + 'foo?.forEach(element => bar(element))', + 'foo.forEach(bar)', + 'foo.forEach(async function(element) {})', + 'foo.forEach(function * (element) {})', + 'foo.forEach(() => bar())', + 'foo.forEach((element, index, array) => bar())', + // Ideally this should be fixable, but hard to know variable conflicts + 'foo.forEach(({property}) => bar(property))', + // TODO: check parameters conflicts + // 'foo.forEach(foo => bar())', + outdent` + foo.forEach(element => { + do { + return + } while (element) + }); + `, + outdent` + foo.forEach(element => { + while (element) { + return; + } + }); + `, + outdent` + foo.forEach(element => { + for (let i = 0; i < 2; i++) { + return; + } + }); + `, + outdent` + foo.forEach(element => { + for (let i in element) { + return; + } + }); + `, + outdent` + foo.forEach(element => { + for (let i of element) { + return; + } + }); + `, + outdent` + foo.forEach(element => { + switch (element) { + default: + return; + } + }); + `, + // TODO: check parameters conflicts + // 'foo.forEach(function a(element) {bar(a)})', + // 'foo.forEach(function a(element) {bar(this)})', + // 'foo.forEach(function a(element) {bar(arguments)})', -test.visualize([ - 'const foo = \'unicorn\';' + // Auto-fix + outdent` + foo.forEach(function (element) { + bar(element); + }); + `, + outdent` + foo.forEach(function withName(element) { + bar(element); + }); + `, + outdent` + foo.forEach((element) => { + bar(element); + }); + `, + 'foo.forEach((element) => bar(element));', + outdent` + foo.forEach(function (element, index) { + bar(element, index); + }); + `, + outdent` + foo.forEach(function withName(element, index) { + bar(element, index); + }); + `, + outdent` + foo.forEach((element, index) => { + bar(element, index); + }); + `, + 'foo.forEach((element, index) => bar(element, index));', + // Trailing comma + outdent` + foo.forEach(function (element) { + bar(element); + },); + `, + outdent` + foo.forEach(function withName(element) { + bar(element); + },); + `, + outdent` + foo.forEach((element) => { + bar(element); + },); + `, + 'foo.forEach((element) => bar(element),);', + // Can't remove semi + outdent` + foo.forEach((element) => bar(element)) + ;[foo].pop(); + ` + ] ]); From 59c70a7f3c2b20b282d229840b8b371beb0997fa Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 14:55:07 +0800 Subject: [PATCH 04/40] Tests --- rules/no-array-for-each.js | 18 ++++++++++++------ test/no-array-for-each.js | 11 +++-------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index bea497c3cd..0da13d4f58 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -15,10 +15,16 @@ const arrayForEachCallSelector = methodSelector({ includeOptional: true, }); -const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/u; -function isReturnStatementInBreakableStatements(node, callbackFunction) { - for (let parent = node; parent && parent !== callbackFunction; parent = node.parent) { - if (breakableTypePattern.test(node.type)) { +const continueAbleNodeTypes = new Set([ + 'WhileStatement', + 'DoWhileStatement', + 'ForStatement', + 'ForOfStatement', + 'ForInStatement', +]); +function isReturnStatementInBreakableStatements(returnStatement, callbackFunction) { + for (let node = returnStatement; node && node !== callbackFunction; node = node.parent) { + if (continueAbleNodeTypes.has(node.type)) { return true; } } @@ -91,10 +97,10 @@ function * getFixFunction(callExpression, sourceCode) { // If `returnStatement` has no semi const lastToken = sourceCode.getLastTokens(returnStatement); yield fixer.insertTextAfter(returnStatement, - `${isSemiToken(lastToken) ? '' : '; '}break;` + `${isSemiToken(lastToken) ? '' : '; '}continue;` ); } else { - yield fixer.replace(returnStatement, 'break'); + yield fixer.replace(returnStatement, 'continue'); } } diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index e4a180cc05..849b5df748 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -24,6 +24,8 @@ test.visualize([ 'foo.forEach(({property}) => bar(property))', // TODO: check parameters conflicts // 'foo.forEach(foo => bar())', + + // Can't turn `return` to `continue` outdent` foo.forEach(element => { do { @@ -59,14 +61,7 @@ test.visualize([ } }); `, - outdent` - foo.forEach(element => { - switch (element) { - default: - return; - } - }); - `, + // TODO: check parameters conflicts // 'foo.forEach(function a(element) {bar(a)})', // 'foo.forEach(function a(element) {bar(this)})', From 5c18e074437ac2466fc86fe07ecf00a177f1fcad Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 14:57:49 +0800 Subject: [PATCH 05/40] Tests --- test/no-array-for-each.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 849b5df748..4189e584ec 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -121,6 +121,23 @@ test.visualize([ outdent` foo.forEach((element) => bar(element)) ;[foo].pop(); - ` + `, + outdent` + foo.forEach((element) => { + bar(element); + }); + function noneRelatedFunction() { + while (element) { + return; + } + } + `, + outdent` + foo.forEach((element) => { + bar(element); + }); + // GlobalReturn + return + `, ] ]); From 507863f2ee22985884f8bcc5c243ac58f584219e Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 15:10:31 +0800 Subject: [PATCH 06/40] fix --- rules/no-array-for-each.js | 12 +- test/no-array-for-each.js | 13 +- test/snapshots/no-array-for-each.js.md | 407 +++++++++++++++++++++++ test/snapshots/no-array-for-each.js.snap | Bin 0 -> 1333 bytes 4 files changed, 417 insertions(+), 15 deletions(-) create mode 100644 test/snapshots/no-array-for-each.js.md create mode 100644 test/snapshots/no-array-for-each.js.snap diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 0da13d4f58..35797b0c34 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -1,5 +1,5 @@ 'use strict'; -const { hasSideEffect, isParenthesized } = require('eslint-utils'); +const { hasSideEffect, isParenthesized, isArrowToken } = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); @@ -22,6 +22,7 @@ const continueAbleNodeTypes = new Set([ 'ForOfStatement', 'ForInStatement', ]); + function isReturnStatementInBreakableStatements(returnStatement, callbackFunction) { for (let node = returnStatement; node && node !== callbackFunction; node = node.parent) { if (continueAbleNodeTypes.has(node.type)) { @@ -32,7 +33,7 @@ function isReturnStatementInBreakableStatements(returnStatement, callbackFunctio return false; } -function * getFixFunction(callExpression, sourceCode) { +function getFixFunction(callExpression, sourceCode) { const [callback] = callExpression.arguments; const {parameters} = callback; const array = callExpression.callee.object; @@ -75,7 +76,7 @@ function * getFixFunction(callExpression, sourceCode) { if (callback.body.type === 'BlockStatement') { end = callback.body.range[0]; } else { - const arrowToken = sourceCode.getFirstToken(callback, (token) => '=>'); + const arrowToken = sourceCode.getFirstToken(callback, isArrowToken); end = arrowToken.range[1]; } @@ -122,7 +123,7 @@ function * getFixFunction(callExpression, sourceCode) { }; - return (fixer) => { + return function * (fixer) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); // Remove call expression trailing comma @@ -222,7 +223,8 @@ const create = (context) => { }, ReturnStatement(node) { const currentFunction = functionStacks[functionStacks.length - 1]; - // Global return + // `globalReturn ` + /* istanbul ignore next: ESLint deprecated `ecmaFeatures`, can't test */ if (!currentFunction) { return; } diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 4189e584ec..f21268eb79 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -1,7 +1,7 @@ import {outdent} from 'outdent'; import {test} from './utils/test'; -test.visualize([ +test.visualize({ valid: [ 'new foo.forEach(element => bar())', 'forEach(element => bar())', @@ -131,13 +131,6 @@ test.visualize([ return; } } - `, - outdent` - foo.forEach((element) => { - bar(element); - }); - // GlobalReturn - return - `, + ` ] -]); +}); diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md new file mode 100644 index 0000000000..533c26797f --- /dev/null +++ b/test/snapshots/no-array-for-each.js.md @@ -0,0 +1,407 @@ +# Snapshot report for `test/no-array-for-each.js` + +The actual snapshot is saved in `no-array-for-each.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## Invalid #1 + 1 | foo.forEach?.(element => bar(element)) + +> Error 1/1 + + `␊ + > 1 | foo.forEach?.(element => bar(element))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #2 + 1 | (foo.forEach(element => bar(element))) + +> Error 1/1 + + `␊ + > 1 | (foo.forEach(element => bar(element)))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #3 + 1 | foo.forEach(element => bar(element), thisArgument) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => bar(element), thisArgument)␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #4 + 1 | foo.forEach() + +> Error 1/1 + + `␊ + > 1 | foo.forEach()␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #5 + 1 | const baz = foo.forEach(element => bar(element)) + +> Error 1/1 + + `␊ + > 1 | const baz = foo.forEach(element => bar(element))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #6 + 1 | foo?.forEach(element => bar(element)) + +> Error 1/1 + + `␊ + > 1 | foo?.forEach(element => bar(element))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #7 + 1 | foo.forEach(bar) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(bar)␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #8 + 1 | foo.forEach(async function(element) {}) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(async function(element) {})␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #9 + 1 | foo.forEach(function * (element) {}) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function * (element) {})␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #10 + 1 | foo.forEach(() => bar()) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(() => bar())␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #11 + 1 | foo.forEach((element, index, array) => bar()) + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element, index, array) => bar())␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #12 + 1 | foo.forEach(({property}) => bar(property)) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(({property}) => bar(property))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #13 + 1 | foo.forEach(element => { + 2 | do { + 3 | return + 4 | } while (element) + 5 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | do {␊ + 3 | return␊ + 4 | } while (element)␊ + 5 | });␊ + ` + +## Invalid #14 + 1 | foo.forEach(element => { + 2 | while (element) { + 3 | return; + 4 | } + 5 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | while (element) {␊ + 3 | return;␊ + 4 | }␊ + 5 | });␊ + ` + +## Invalid #15 + 1 | foo.forEach(element => { + 2 | for (let i = 0; i < 2; i++) { + 3 | return; + 4 | } + 5 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | for (let i = 0; i < 2; i++) {␊ + 3 | return;␊ + 4 | }␊ + 5 | });␊ + ` + +## Invalid #16 + 1 | foo.forEach(element => { + 2 | for (let i in element) { + 3 | return; + 4 | } + 5 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | for (let i in element) {␊ + 3 | return;␊ + 4 | }␊ + 5 | });␊ + ` + +## Invalid #17 + 1 | foo.forEach(element => { + 2 | for (let i of element) { + 3 | return; + 4 | } + 5 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | for (let i of element) {␊ + 3 | return;␊ + 4 | }␊ + 5 | });␊ + ` + +## Invalid #18 + 1 | foo.forEach(function (element) { + 2 | bar(element); + 3 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function (element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | });␊ + ` + +## Invalid #19 + 1 | foo.forEach(function withName(element) { + 2 | bar(element); + 3 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function withName(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | });␊ + ` + +## Invalid #20 + 1 | foo.forEach((element) => { + 2 | bar(element); + 3 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | });␊ + ` + +## Invalid #21 + 1 | foo.forEach((element) => bar(element)); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => bar(element));␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #22 + 1 | foo.forEach(function (element, index) { + 2 | bar(element, index); + 3 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function (element, index) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element, index);␊ + 3 | });␊ + ` + +## Invalid #23 + 1 | foo.forEach(function withName(element, index) { + 2 | bar(element, index); + 3 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function withName(element, index) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element, index);␊ + 3 | });␊ + ` + +## Invalid #24 + 1 | foo.forEach((element, index) => { + 2 | bar(element, index); + 3 | }); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element, index) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element, index);␊ + 3 | });␊ + ` + +## Invalid #25 + 1 | foo.forEach((element, index) => bar(element, index)); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element, index) => bar(element, index));␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #26 + 1 | foo.forEach(function (element) { + 2 | bar(element); + 3 | },); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function (element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | },);␊ + ` + +## Invalid #27 + 1 | foo.forEach(function withName(element) { + 2 | bar(element); + 3 | },); + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function withName(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | },);␊ + ` + +## Invalid #28 + 1 | foo.forEach((element) => { + 2 | bar(element); + 3 | },); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | },);␊ + ` + +## Invalid #29 + 1 | foo.forEach((element) => bar(element),); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => bar(element),);␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #30 + 1 | foo.forEach((element) => bar(element)) + 2 | ;[foo].pop(); + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => bar(element))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | ;[foo].pop();␊ + ` + +## Invalid #31 + 1 | foo.forEach((element) => { + 2 | bar(element); + 3 | }); + 4 | function noneRelatedFunction() { + 5 | while (element) { + 6 | return; + 7 | } + 8 | } + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(element);␊ + 3 | });␊ + 4 | function noneRelatedFunction() {␊ + 5 | while (element) {␊ + 6 | return;␊ + 7 | }␊ + 8 | }␊ + ` diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..ecdfa95d3dd95d902bdc17963518465848eaa00d GIT binary patch literal 1333 zcmV-51^B=ardGUE;(D7WHOgVBnhg=cUfx zp4jsZtiG3ZZ}T#OMfZVZUT*xgI`(3O^Mfk^U%nRPFoH!hfUXlL5VdbU&y~`-^8UOE zwXA)NVA0n=ER?5dmUY}KC{62P-;(w@v5a8RJQfB9;eXy&OT99$7SD^F^|j?x7$aEp zB@oL69z3&6Vrl4I%c<-Pf3N*u1dE2T0{s*htG&D=;i<_JmPx!Pi&GfEqBnrpv#pIi z;Nf(mjrq#Qn%#FEVg!p;urV_C}s+R@hq7V*zs zWBBpo)SrxuV9{0}j%8kd;!@!)u4m1)YgQRpH86rj?*Vbn4aV&^-mTZd_K3V9_T)JYmZu116TLL&w#xwpHHPW61~>4drBD zm|e)OV^U~)x{T*+)ZEvs28>|Qqd+|GrI|;BfX&BePmjoz6m0*`2o{y*VqjQgqVn&! zor*vE!Hf@+d6(X11dIL$;{DrqM^^cmv#@TTnC{@XM~4wC+QQAiaOlE?#xh}R?@CwI zPw&qa?`8yx{sQ9TLT~&E=0(mAk3V^A#p;I%j9}3$9-z#8yZgEKlPW~pE>{FT*J@(~ zi}Ld_Fr2dQeQ(CGLN(PR>5-j*>vKl1=yV{yG4)DY=9=Vc-&Yw2rrwNN$_N(K<6~fW z&id`^Nkjda6HR_PiG6&%kP$387l^-Y@D<+nHg<=QNj-1>%wR7@uqZD-1H&It#^1}P z24$3%8uA%^RI+6Ri*|!#j;(nn#=q8X?$kY-4Pth!U<8ZG2rw`(Gq8j61tTkiAX75~ zmz{#4LXARNe!gB>evxZpa)w4)XP>T^z3ujVd5!@haprA2OuvQ1i zL~&6QHW$J4=_q98rKDD9D%jdl%PBA;;VwdR5MwpI5Ta+uOdu();6X*Na7x7%Z`B1w z`30#(C6%?{I0Kmn6VcQp$6+WTG8Gh z2~toPaB>!T4LJcCyITZhqX`crc4^p0ZuHtKm(X14Mq!xI|oR^=M z8kCxoSdyCJ1{KqQBr;Q6S=|gR^_jy`p9RPY)Q~HOdNDaauebylFIB+0o|s5Ojx!`c zUi4)UZt&_TB!Y~gX0AvgsYOC@rl40@l$l3KSyVMZZGH6Wu>)^Yf54jfNcEyUNqK~N rNi?yzGA|ikK2W#WRzPIW6HAa$A%kG;_|mg04rBoUGDfOSND}}6geGn# literal 0 HcmV?d00001 From 47820103929026cdc66e3e28d5994d5b8d840498 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 15:36:04 +0800 Subject: [PATCH 07/40] Update snapshot --- rules/no-array-for-each.js | 47 ++--- test/no-array-for-each.js | 34 ++++ test/snapshots/no-array-for-each.js.md | 219 +++++++++++++++++++++++ test/snapshots/no-array-for-each.js.snap | Bin 1333 -> 1756 bytes 4 files changed, 278 insertions(+), 22 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 35797b0c34..7152fd6765 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -1,5 +1,5 @@ 'use strict'; -const { hasSideEffect, isParenthesized, isArrowToken } = require('eslint-utils'); +const {hasSideEffect, isParenthesized, isArrowToken, isCommaToken, isSemicolonToken} = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); @@ -33,10 +33,11 @@ function isReturnStatementInBreakableStatements(returnStatement, callbackFunctio return false; } -function getFixFunction(callExpression, sourceCode) { +function getFixFunction(callExpression, sourceCode, functionReturnStatements) { const [callback] = callExpression.arguments; - const {parameters} = callback; + const parameters = callback.params; const array = callExpression.callee.object; + const returnStatements = functionReturnStatements.get(callback); const getForOfLoopHeadText = () => { const parametersText = parameters.map(parameter => sourceCode.getText(parameter)); @@ -53,7 +54,7 @@ function getFixFunction(callExpression, sourceCode) { let arrayText = sourceCode.getText(array); if ( - isParenthesized(node, sourceCode) || + isParenthesized(callExpression, sourceCode) || (useEntries && shouldAddParenthesesToMemberExpressionObject(array, sourceCode)) ) { arrayText = `(${arrayText})`; @@ -71,7 +72,7 @@ function getFixFunction(callExpression, sourceCode) { }; const getForOfLoopHeadRange = () => { - const [start] = node.range; + const [start] = callExpression.range; let end; if (callback.body.type === 'BlockStatement') { end = callback.body.range[0]; @@ -83,7 +84,7 @@ function getFixFunction(callExpression, sourceCode) { return [start, end]; }; - function * replaceReturnStatement(returnStatement) { + function * replaceReturnStatement(returnStatement, fixer) { const returnToken = sourceCode.getFirstToken(returnStatement); /* istanbul ignore next: `ReturnStatement` firstToken should be `return` */ @@ -95,18 +96,21 @@ function getFixFunction(callExpression, sourceCode) { // Remove `return` yield fixer.remove(returnToken); + // TODO: `.argument` might need `;` or `()` + // If `returnStatement` has no semi - const lastToken = sourceCode.getLastTokens(returnStatement); - yield fixer.insertTextAfter(returnStatement, - `${isSemiToken(lastToken) ? '' : '; '}continue;` + const lastToken = sourceCode.getLastToken(returnStatement); + yield fixer.insertTextAfter( + returnStatement, + `${isSemicolonToken(lastToken) ? '' : ';'} continue;` ); } else { - yield fixer.replace(returnStatement, 'continue'); + yield fixer.replaceText(returnToken, 'continue'); } } - const shouldRemoveExpressionStatementLastToken = token => { - if (!isSemiToken(expressionStatementLastToken)) { + const shouldRemoveExpressionStatementLastToken = (token, fixer) => { + if (!isSemicolonToken(token)) { return false; } @@ -127,19 +131,19 @@ function getFixFunction(callExpression, sourceCode) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); // Remove call expression trailing comma - const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2); + const [penultimateToken, lastToken] = sourceCode.getLastTokens(callExpression, 2); if (isCommaToken(penultimateToken)) { yield fixer.remove(penultimateToken); } yield fixer.remove(lastToken); for(const returnStatement of returnStatements) { - yield * replaceReturnStatement(returnStatement); + yield * replaceReturnStatement(returnStatement, fixer); } const expressionStatementLastToken = sourceCode.getLastToken(callExpression.parent); - if (shouldRemoveLastSemicolonToken(expressionStatementLastToken)) { - yield fixer.remove(expressionStatementLastToken); + if (shouldRemoveExpressionStatementLastToken(expressionStatementLastToken)) { + yield fixer.remove(expressionStatementLastToken, fixer); } }; } @@ -168,19 +172,18 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { const [callback] = callExpression.arguments; if ( // Leave non-function type to `no-array-callback-reference` rule - callback.type !== 'FunctionExpression' || - callback.type !== 'ArrowFunctionExpression' || + (callback.type !== 'FunctionExpression' && callback.type !== 'ArrowFunctionExpression') || callback.async || callback.generator ) { return false; } - // Check `callback.parameters` - const {parameters} = callback; + // Check `callback.params` + const parameters = callback.params; if ( !(parameters.length === 1 || parameters.length === 2) || - parameters.some(parameter => parameters.type !== 'Identifier') + parameters.some(parameter => parameter.type !== 'Identifier') ) { return false; } @@ -243,7 +246,7 @@ const create = (context) => { }; if (isFixable(callExpression, sourceCode, functionReturnStatements)) { - problem.fix = getFixFunction(callExpression, sourceCode); + problem.fix = getFixFunction(callExpression, sourceCode, functionReturnStatements); } context.report(problem); diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index f21268eb79..ec6850a044 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -131,6 +131,40 @@ test.visualize({ return; } } + `, + outdent` + foo.forEach((element) => { + if (1) { + return; + } + if (1) { + return + } + if (1) { + return!true; + } + if (1) { + return!true + } + if (1) { + return bar(); + } + if (1) { + return bar() + unreachable(); + } + if (1) { + return {}; + } + if (1) { + foo + return [] + } + if (1) { + foo + return [foo] = bar; + } + }); ` ] }); diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 533c26797f..02f5164ada 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -219,6 +219,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element); 3 | }); +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -233,6 +241,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element); 3 | }); +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -247,6 +263,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element); 3 | }); +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -259,6 +283,12 @@ Generated by [AVA](https://avajs.dev). ## Invalid #21 1 | foo.forEach((element) => bar(element)); +> Output + + `␊ + 1 | for (const element of foo) bar(element)␊ + ` + > Error 1/1 `␊ @@ -271,6 +301,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element, index); 3 | }); +> Output + + `␊ + 1 | for (const [element, index] of foo.entries()) {␊ + 2 | bar(element, index);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -285,6 +323,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element, index); 3 | }); +> Output + + `␊ + 1 | for (const [element, index] of foo.entries()) {␊ + 2 | bar(element, index);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -299,6 +345,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element, index); 3 | }); +> Output + + `␊ + 1 | for (const [element, index] of foo.entries()) {␊ + 2 | bar(element, index);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -311,6 +365,12 @@ Generated by [AVA](https://avajs.dev). ## Invalid #25 1 | foo.forEach((element, index) => bar(element, index)); +> Output + + `␊ + 1 | for (const [element, index] of foo.entries()) bar(element, index)␊ + ` + > Error 1/1 `␊ @@ -323,6 +383,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element); 3 | },); +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -337,6 +405,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element); 3 | },); +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -351,6 +427,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(element); 3 | },); +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + ` + > Error 1/1 `␊ @@ -363,6 +447,12 @@ Generated by [AVA](https://avajs.dev). ## Invalid #29 1 | foo.forEach((element) => bar(element),); +> Output + + `␊ + 1 | for (const element of foo) bar(element)␊ + ` + > Error 1/1 `␊ @@ -374,6 +464,13 @@ Generated by [AVA](https://avajs.dev). 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); +> Output + + `␊ + 1 | for (const element of foo) bar(element)␊ + 2 | [foo].pop();␊ + ` + > Error 1/1 `␊ @@ -392,6 +489,19 @@ Generated by [AVA](https://avajs.dev). 7 | } 8 | } +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(element);␊ + 3 | }␊ + 4 | function noneRelatedFunction() {␊ + 5 | while (element) {␊ + 6 | return;␊ + 7 | }␊ + 8 | }␊ + ` + > Error 1/1 `␊ @@ -405,3 +515,112 @@ Generated by [AVA](https://avajs.dev). 7 | }␊ 8 | }␊ ` + +## Invalid #32 + 1 | foo.forEach((element) => { + 2 | if (1) { + 3 | return; + 4 | } + 5 | if (1) { + 6 | return + 7 | } + 8 | if (1) { + 9 | return!true; + 10 | } + 11 | if (1) { + 12 | return!true + 13 | } + 14 | if (1) { + 15 | return bar(); + 16 | } + 17 | if (1) { + 18 | return bar() + 19 | unreachable(); + 20 | } + 21 | if (1) { + 22 | return {}; + 23 | } + 24 | if (1) { + 25 | foo + 26 | return [] + 27 | } + 28 | if (1) { + 29 | foo + 30 | return [foo] = bar; + 31 | } + 32 | }); + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | if (1) {␊ + 3 | continue;␊ + 4 | }␊ + 5 | if (1) {␊ + 6 | continue␊ + 7 | }␊ + 8 | if (1) {␊ + 9 | !true; continue;␊ + 10 | }␊ + 11 | if (1) {␊ + 12 | !true; continue;␊ + 13 | }␊ + 14 | if (1) {␊ + 15 | bar(); continue;␊ + 16 | }␊ + 17 | if (1) {␊ + 18 | bar(); continue;␊ + 19 | unreachable();␊ + 20 | }␊ + 21 | if (1) {␊ + 22 | {}; continue;␊ + 23 | }␊ + 24 | if (1) {␊ + 25 | foo␊ + 26 | []; continue;␊ + 27 | }␊ + 28 | if (1) {␊ + 29 | foo␊ + 30 | [foo] = bar; continue;␊ + 31 | }␊ + 32 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | if (1) {␊ + 3 | return;␊ + 4 | }␊ + 5 | if (1) {␊ + 6 | return␊ + 7 | }␊ + 8 | if (1) {␊ + 9 | return!true;␊ + 10 | }␊ + 11 | if (1) {␊ + 12 | return!true␊ + 13 | }␊ + 14 | if (1) {␊ + 15 | return bar();␊ + 16 | }␊ + 17 | if (1) {␊ + 18 | return bar()␊ + 19 | unreachable();␊ + 20 | }␊ + 21 | if (1) {␊ + 22 | return {};␊ + 23 | }␊ + 24 | if (1) {␊ + 25 | foo␊ + 26 | return []␊ + 27 | }␊ + 28 | if (1) {␊ + 29 | foo␊ + 30 | return [foo] = bar;␊ + 31 | }␊ + 32 | });␊ + ` diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index ecdfa95d3dd95d902bdc17963518465848eaa00d..71bc43708034c2aa47692f196c89428d6f810588 100644 GIT binary patch literal 1756 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 From b17181b4e191d98a7ddfe3004d575b6d003d74ce Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 16:08:15 +0800 Subject: [PATCH 08/40] Fix --- rules/no-array-for-each.js | 49 ++++++++--- ...eses-to-expression-statement-expression.js | 23 ++++++ test/no-array-for-each.js | 9 ++ test/snapshots/no-array-for-each.js.md | 77 ++++++++++++------ test/snapshots/no-array-for-each.js.snap | Bin 1756 -> 1821 bytes 5 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 rules/utils/should-add-parentheses-to-expression-statement-expression.js diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 7152fd6765..729d277d45 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -4,6 +4,7 @@ const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object'); +const shouldAddParenthesesToExpressionStatementExpression = require('./utils/should-add-parentheses-to-expression-statement-expression'); const MESSAGE_ID = 'no-array-for-each'; const messages = { @@ -92,21 +93,45 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { throw new Error(`Unexpected token ${returnToken.value}.`) } - if (returnStatement.argument) { - // Remove `return` - yield fixer.remove(returnToken); + if (!returnStatement.argument) { + yield fixer.replaceText(returnToken, 'continue'); + return; + } - // TODO: `.argument` might need `;` or `()` + // Remove `return` + yield fixer.remove(returnToken); + + const previousToken = sourceCode.getTokenBefore(returnToken); + const nextToken = sourceCode.getTokenAfter(returnToken); + let textBefore = ''; + let textAfter = ''; + const shouldAddParentheses = + !isParenthesized(returnStatement.argument, sourceCode) && + shouldAddParenthesesToExpressionStatementExpression(returnStatement.argument); + if (shouldAddParentheses) { + textBefore = '('; + textAfter = ')'; + } - // If `returnStatement` has no semi - const lastToken = sourceCode.getLastToken(returnStatement); - yield fixer.insertTextAfter( - returnStatement, - `${isSemicolonToken(lastToken) ? '' : ';'} continue;` - ); - } else { - yield fixer.replaceText(returnToken, 'continue'); + const shouldAddSemicolonBefore = needsSemicolon(previousToken, sourceCode, shouldAddParentheses ? '(' : nextToken.value); + if (shouldAddSemicolonBefore) { + textBefore = `;${textBefore}`; } + + if (textBefore) { + yield fixer.insertTextBefore(nextToken, textBefore); + } + + if (textAfter) { + yield fixer.insertTextAfter(returnStatement.argument, textAfter); + } + + // If `returnStatement` has no semi + const lastToken = sourceCode.getLastToken(returnStatement); + yield fixer.insertTextAfter( + returnStatement, + `${isSemicolonToken(lastToken) ? '' : ';'} continue;` + ); } const shouldRemoveExpressionStatementLastToken = (token, fixer) => { diff --git a/rules/utils/should-add-parentheses-to-expression-statement-expression.js b/rules/utils/should-add-parentheses-to-expression-statement-expression.js new file mode 100644 index 0000000000..167ecc921a --- /dev/null +++ b/rules/utils/should-add-parentheses-to-expression-statement-expression.js @@ -0,0 +1,23 @@ +'use strict'; + +const {isOpeningParenToken, isClosingParenToken} = require('eslint-utils'); + +/** +Check if parentheses should to be added to a `node` when it's used as an `expression` of `ExpressionStatement`. + +@param {Node} node - The AST node to check. +@param {SourceCode} sourceCode - The source code object. +@returns {boolean} +*/ +function shouldAddParenthesesToExpressionStatementExpression(node) { + switch (node.type) { + case 'ObjectExpression': + return true; + case 'AssignmentExpression': + return node.left.type === 'ObjectPattern' || node.left.type === 'ArrayPattern'; + default: + return false; + } +} + +module.exports = shouldAddParenthesesToExpressionStatementExpression; diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index ec6850a044..3e523542dd 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -156,6 +156,15 @@ test.visualize({ if (1) { return {}; } + if (1) { + return ({}); + } + if (1) { + return {a} = a; + } + if (1) { + return [a] = a; + } if (1) { foo return [] diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 02f5164ada..63a3c22654 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -541,14 +541,23 @@ Generated by [AVA](https://avajs.dev). 22 | return {}; 23 | } 24 | if (1) { - 25 | foo - 26 | return [] - 27 | } - 28 | if (1) { - 29 | foo - 30 | return [foo] = bar; - 31 | } - 32 | }); + 25 | return ({}); + 26 | } + 27 | if (1) { + 28 | return {a} = a; + 29 | } + 30 | if (1) { + 31 | return [a] = a; + 32 | } + 33 | if (1) { + 34 | foo + 35 | return [] + 36 | } + 37 | if (1) { + 38 | foo + 39 | return [foo] = bar; + 40 | } + 41 | }); > Output @@ -574,17 +583,26 @@ Generated by [AVA](https://avajs.dev). 19 | unreachable();␊ 20 | }␊ 21 | if (1) {␊ - 22 | {}; continue;␊ + 22 | ({}); continue;␊ 23 | }␊ 24 | if (1) {␊ - 25 | foo␊ - 26 | []; continue;␊ - 27 | }␊ - 28 | if (1) {␊ - 29 | foo␊ - 30 | [foo] = bar; continue;␊ - 31 | }␊ - 32 | }␊ + 25 | ({}); continue;␊ + 26 | }␊ + 27 | if (1) {␊ + 28 | ({a} = a); continue;␊ + 29 | }␊ + 30 | if (1) {␊ + 31 | ([a] = a); continue;␊ + 32 | }␊ + 33 | if (1) {␊ + 34 | foo␊ + 35 | ;[]; continue;␊ + 36 | }␊ + 37 | if (1) {␊ + 38 | foo␊ + 39 | ;([foo] = bar); continue;␊ + 40 | }␊ + 41 | }␊ ` > Error 1/1 @@ -615,12 +633,21 @@ Generated by [AVA](https://avajs.dev). 22 | return {};␊ 23 | }␊ 24 | if (1) {␊ - 25 | foo␊ - 26 | return []␊ - 27 | }␊ - 28 | if (1) {␊ - 29 | foo␊ - 30 | return [foo] = bar;␊ - 31 | }␊ - 32 | });␊ + 25 | return ({});␊ + 26 | }␊ + 27 | if (1) {␊ + 28 | return {a} = a;␊ + 29 | }␊ + 30 | if (1) {␊ + 31 | return [a] = a;␊ + 32 | }␊ + 33 | if (1) {␊ + 34 | foo␊ + 35 | return []␊ + 36 | }␊ + 37 | if (1) {␊ + 38 | foo␊ + 39 | return [foo] = bar;␊ + 40 | }␊ + 41 | });␊ ` diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 71bc43708034c2aa47692f196c89428d6f810588..fd18754d320ab5408b8a0ffbd93fcf30d8139099 100644 GIT binary patch literal 1821 zcmV+&2jciaRzVhe97!`DAxWB$=3~qn!x0}z)Y)_IUUx6Mu&@g@-I;Ip?sxzHzyJBq z|DXHca}Rm|0Dq2%eZ`#_bYptx^pTC2| zY%;;%0)kIlK)px5%sLhx0+KjS>PXlMI=7K+g*$7W`<;Kpxwkyuep76`r8FyNBxddh#5dw6U^d4afY5o0@K5NBtMV(JtNo7|vPsPD zVG->EKvY{`(~4z722I-|xZiZ-&NdRWg8mGK3YlOW1_tTnc&utl=M>i`b`;8?q z3kL(RYWHd}=~;BR?zx7t!p7QI60`GIoI+T?$Xg^|6#rfRfbZvSxalP(Fq;?%K*f!y zDYFB{wOqS;WCX3N`G>%)31PE*RC`^*s8sJmsz2BGS6(17J2{9!*bwAZ&4D>Z)1p1S zYRVV9kW?!oFuMcc@afab@`K{07ET&{`_@Ur0Rpq5g8`@u{C&EvV$R0b<{vv+wf#~C ziPMe0xhu6x~WJtld6ZMpox_>h*Hn+VJvM7aA!O3>av z6#D|@Z~CuXI|~(ynT>c7fVN=b;Z{?c%4n1fl(sw*Phz%=h37CNakTnc$e_;>HkfL6 ziC^DeMPhaqiz^5oz#CU8;ROa0Nq!JY;2SVUtA~Ott;Rq@DwoQmG&I!aAXY1c#YjYo zM0_)qdI5V;7>7t1B1`J+K zaq}^cIp9Ps)M#mFG*B=jNv~HHhFT0=Ub?{kUZkTdiU^%nC*T`2c2eD3s4f3{6lunT zIL9uyxuCloQSX;>Ugzm#ZA1iVmD-S`UtqM%mrJQk%kvy64!6$=9#1WeCBu) zM_wk)cW`1zj7@b86i8Ttsbi!;t2IW-e1}J+jBD9OI?6`c%tUj-F?``zEIg9dBfHT0 z4id3NNh0AXNu&;yWSo+muY~>d#R)3pX+?2b(R{5K$6Ac*Mvb0AGosAQr35(mQqFNH z-*GA9I251+wKXQ?9GCJPmqt2N;{2BK{g%d9l$0fCZC3I%V=bC8F;7z_VKvj03OkxI zDW@spYhusQLqTi)!+IT;uHYHqoR;yOmc>{bh-D23@al?OL36-!M$Uy=F6r0{TqIG= zIa74quR2F1^5{|5b%8LlPL&5E%H+FKrD3JuR8=tYY?eD!5!Mtdy4@@_Y>Zt`Y7q`WjcRxFYm=JFI(H8nd5pnxLBpmrJ!|B zX0Nv+SN5WRJQsSGe^w;6kux+3SS3cH9l& z6?gYN!bUr*J1-3)ya>7GZYFy}ffF6IO>}yAzbSSG=z8jH1}^u@OyY12y+*5{(x_Y| zO=VAJIRRrM(oxk%@e+}Hu*P)k4jMY!`{}igyidnSEM|wuOh=}&2t81o$ujFCvpRZ~ zZ>p~M*hEliHuK+E1Twp|bKvqC&{qq$TI0&X?dCV)qQ|s3`PlX*-|cj7^0DnnS~Wk3 z-C7x3d)!$EL1`$|WO1vad-rjYdo;b!P6Tc3>YV&^V8@Ufng%z21G4)eq%Xe#p|gJh LXWC(Jq8jJs-0lMG`MW^@~ z?|j%)p8NFT!z5;fUJR-b0yV{z*3PGa@}i=_hq2G0<-)<=*ivil=A`G{mZH(EiI+@2?Dcu2y%}--<(}?f!|zI zShY($ZaIP3vk2-&qPp?P$jZrnveEQQbt?$W=J*4UHSk{Y<(l(5hGo%B@~QlB1ZEo% z)_uBOOnT-Yt$n7UIIpoLmc(pG0E3kXWlMOXs3q~=X8V3Of6FZ|F@f1Ogz}rw)8+<@ zZ)v{%^>A8O{SSfJq`?4ej~dxgD;qhJcSQO72EU4nBxXBUTnz-^%j!e(@?VVc^r|jd z^jt!Xh`{WkAOMb@KD{D4C~kV*lu>tXpEMjIFnbB1Ht^ROy7GBjUtM_oSmo|3sU&8H zKE_}bLhV*rQ&v-2Zg6pZ?(7?3#RO)>!2q0?u=;kicjYK*TG~~ac*+eDv&&fULQpnJ z&lRhx(hHJ)QGQkW!~6;ovpN>M#{szEb+`4n2Y!=( z78te6Z|%l8XtJ2tW`y=&;=#_+WTnw486<6aDxSowYzTuIg!W@q%_06D$+nc%>=VCs zu#&{=z$X}NM(_YUJW~lTFqlZ-Lnwi-!%VFn3evS20}UxPl|^Z2sLe#IRtO7F6Dexq zlcvxM*oVS6L`EXAkZrWejd`?lMD+QTGO**a8YG96vR?bjlQ5G-QH$=@% z*8=8(leJKzrJ>P4!PEr3UXd4Sc64?5PGM?9x8aD;txX40I(IOIwGu&=1>KG8|8hjvIVEPx5ck*kQug## zpwnx0l%CEj#9A}?Gc!VAZvwN)NSVEim__BHwDEANDH^I^JQT;FkMU57KElJ9l$vtj z8yiImdLoa|X>|gwLt{6y+mdSY_g-b1i6E}) z5ZpYWd+br)Pvxxc?}{QYIF5H@CyA7qmjxU*_hKqx*g2I0HvU zlBPE}&?UyFDiaDMEWylUWI?MmM#}Vthf^8PWt-N~HmyxejHU5dZsS?yTC!2EY#l{P z%#I?Zoj2FXBoeVBDt2DRU1{#&-qEw-n6?h-jcLjV$RVv+88{>}radbgha_fg;gY&o zM@VDND~q*FkvlIcv#FJ|>sVQh(OW3PP$hCbKA18!f zR7{G_!A*$hYBzR$OPp>e7w8SH*QoFHPmPK;ITw;W$KDQZDI?vGUa_S@c;Y*{^*ha@a01!;z-QM;nSGDzg@u)zv$_DSJK}5 Date: Thu, 14 Jan 2021 16:11:35 +0800 Subject: [PATCH 09/40] Rename --- rules/no-array-for-each.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 729d277d45..5a497b4604 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -24,7 +24,7 @@ const continueAbleNodeTypes = new Set([ 'ForInStatement', ]); -function isReturnStatementInBreakableStatements(returnStatement, callbackFunction) { +function isReturnStatementInContinueAbleNodes(returnStatement, callbackFunction) { for (let node = returnStatement; node && node !== callbackFunction; node = node.parent) { if (continueAbleNodeTypes.has(node.type)) { return true; @@ -217,7 +217,7 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { // Check `ReturnStatement`s in `callback` const returnStatements = functionReturnStatements.get(callback); - if (returnStatements.some(returnStatement => isReturnStatementInBreakableStatements(returnStatement, callback))) { + if (returnStatements.some(returnStatement => isReturnStatementInContinueAbleNodes(returnStatement, callback))) { return false; } From b57da175a7caed1892aa8e1ce66c5e4cd8f36428 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 14 Jan 2021 16:23:08 +0800 Subject: [PATCH 10/40] Style --- rules/no-array-for-each.js | 71 ++++++++----------- ...eses-to-expression-statement-expression.js | 2 - test/no-array-for-each.js | 2 +- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 5a497b4604..97acd04664 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -1,5 +1,5 @@ 'use strict'; -const {hasSideEffect, isParenthesized, isArrowToken, isCommaToken, isSemicolonToken} = require('eslint-utils'); +const {isParenthesized, isArrowToken, isCommaToken, isSemicolonToken} = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); @@ -8,12 +8,12 @@ const shouldAddParenthesesToExpressionStatementExpression = require('./utils/sho const MESSAGE_ID = 'no-array-for-each'; const messages = { - [MESSAGE_ID]: 'Do not use `Array#forEach(…)`.', + [MESSAGE_ID]: 'Do not use `Array#forEach(…)`.' }; const arrayForEachCallSelector = methodSelector({ - name: 'forEach', - includeOptional: true, + name: 'forEach', + includeOptional: true }); const continueAbleNodeTypes = new Set([ @@ -21,7 +21,7 @@ const continueAbleNodeTypes = new Set([ 'DoWhileStatement', 'ForStatement', 'ForOfStatement', - 'ForInStatement', + 'ForInStatement' ]); function isReturnStatementInContinueAbleNodes(returnStatement, callbackFunction) { @@ -42,14 +42,10 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { const getForOfLoopHeadText = () => { const parametersText = parameters.map(parameter => sourceCode.getText(parameter)); - let useEntries = parameters.length === 2; + const useEntries = parameters.length === 2; let text = 'for (const '; - if (useEntries) { - text += `[${parametersText.join(', ')}]`; - } else { - text += parametersText[0]; - } + text += useEntries ? `[${parametersText.join(', ')}]` : parametersText[0]; text += ' of '; @@ -90,7 +86,7 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { /* istanbul ignore next: `ReturnStatement` firstToken should be `return` */ if (returnToken.value !== 'return') { - throw new Error(`Unexpected token ${returnToken.value}.`) + throw new Error(`Unexpected token ${returnToken.value}.`); } if (!returnStatement.argument) { @@ -134,7 +130,7 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { ); } - const shouldRemoveExpressionStatementLastToken = (token, fixer) => { + const shouldRemoveExpressionStatementLastToken = (token) => { if (!isSemicolonToken(token)) { return false; } @@ -151,7 +147,6 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { return true; }; - return function * (fixer) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); @@ -160,9 +155,10 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { if (isCommaToken(penultimateToken)) { yield fixer.remove(penultimateToken); } + yield fixer.remove(lastToken); - for(const returnStatement of returnStatements) { + for (const returnStatement of returnStatements) { yield * replaceReturnStatement(returnStatement, fixer); } @@ -180,17 +176,17 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { isParenthesized(callExpression, sourceCode) || callExpression.arguments.length !== 1 ) { - return false; + return false; } // Check `CallExpression.parent` if (callExpression.parent.type !== 'ExpressionStatement') { - return false; + return false; } // Check `CallExpression.callee` if (callExpression.callee.optional) { - return false; + return false; } // Check `CallExpression.arguments[0]`; @@ -201,7 +197,7 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { callback.async || callback.generator ) { - return false; + return false; } // Check `callback.params` @@ -226,27 +222,22 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { // TODO: check `.id` `arguments` `this` of `FunctionExpression` } - return true; + return true; } -const create = (context) => { +const create = context => { const functionStacks = []; const functionReturnStatements = new Map(); const callExpressions = []; const sourceCode = context.getSourceCode(); - const getParenthesizedText = node => { - const text = sourceCode.getText(node); - return isParenthesized(node, sourceCode) ? `(${text})` : text; - }; - - return { + return { ':function'(node) { functionStacks.push(node); functionReturnStatements.set(node, []); }, - ':function:exit'(node) { + ':function:exit'() { functionStacks.pop(); }, ReturnStatement(node) { @@ -260,9 +251,9 @@ const create = (context) => { const returnStatements = functionReturnStatements.get(currentFunction); returnStatements.push(node); }, - [arrayForEachCallSelector](node) { + [arrayForEachCallSelector](node) { callExpressions.push(node); - }, + }, 'Program:exit'() { for (const callExpression of callExpressions) { const problem = { @@ -277,17 +268,17 @@ const create = (context) => { context.report(problem); } } - }; + }; }; module.exports = { - create, - meta: { - type: 'suggestion', - docs: { - url: getDocumentationUrl(__filename), - }, - fixable: 'code', - messages, - }, + create, + meta: { + type: 'suggestion', + docs: { + url: getDocumentationUrl(__filename) + }, + fixable: 'code', + messages + } }; diff --git a/rules/utils/should-add-parentheses-to-expression-statement-expression.js b/rules/utils/should-add-parentheses-to-expression-statement-expression.js index 167ecc921a..3bd6122158 100644 --- a/rules/utils/should-add-parentheses-to-expression-statement-expression.js +++ b/rules/utils/should-add-parentheses-to-expression-statement-expression.js @@ -1,7 +1,5 @@ 'use strict'; -const {isOpeningParenToken, isClosingParenToken} = require('eslint-utils'); - /** Check if parentheses should to be added to a `node` when it's used as an `expression` of `ExpressionStatement`. diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 3e523542dd..597154cf2d 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -1,5 +1,5 @@ import {outdent} from 'outdent'; -import {test} from './utils/test'; +import {test} from './utils/test.js'; test.visualize({ valid: [ From f871353a27568c9e1a0fd096e541c0774f689f7a Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 10:59:55 +0800 Subject: [PATCH 11/40] Support check `this` --- rules/no-array-for-each.js | 45 ++++++++++++++----- test/no-array-for-each.js | 3 +- test/snapshots/no-array-for-each.js.md | 54 +++++++++++++++++------ test/snapshots/no-array-for-each.js.snap | Bin 1821 -> 1911 bytes 4 files changed, 76 insertions(+), 26 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 97acd04664..382b0357fd 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -34,11 +34,11 @@ function isReturnStatementInContinueAbleNodes(returnStatement, callbackFunction) return false; } -function getFixFunction(callExpression, sourceCode, functionReturnStatements) { +function getFixFunction(callExpression, sourceCode, functionInfo) { const [callback] = callExpression.arguments; const parameters = callback.params; const array = callExpression.callee.object; - const returnStatements = functionReturnStatements.get(callback); + const {returnStatements} = functionInfo.get(callback); const getForOfLoopHeadText = () => { const parametersText = parameters.map(parameter => sourceCode.getText(parameter)); @@ -169,7 +169,7 @@ function getFixFunction(callExpression, sourceCode, functionReturnStatements) { }; } -function isFixable(callExpression, sourceCode, functionReturnStatements) { +function isFixable(callExpression, sourceCode, functionInfo) { // Check `CallExpression` if ( callExpression.optional || @@ -212,8 +212,11 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { // TODO: check parameters conflicts // Check `ReturnStatement`s in `callback` - const returnStatements = functionReturnStatements.get(callback); - if (returnStatements.some(returnStatement => isReturnStatementInContinueAbleNodes(returnStatement, callback))) { + const {returnStatements, thisFound} = functionInfo.get(callback); + if ( + thisFound || + returnStatements.some(returnStatement => isReturnStatementInContinueAbleNodes(returnStatement, callback)) + ) { return false; } @@ -227,7 +230,8 @@ function isFixable(callExpression, sourceCode, functionReturnStatements) { const create = context => { const functionStacks = []; - const functionReturnStatements = new Map(); + const nonArrowFunctionStacks = []; + const functionInfo = new Map(); const callExpressions = []; const sourceCode = context.getSourceCode(); @@ -235,10 +239,29 @@ const create = context => { return { ':function'(node) { functionStacks.push(node); - functionReturnStatements.set(node, []); + functionInfo.set(node, { + returnStatements: [], + thisFound: false + }); + + if (node.type !== 'ArrowFunctionExpression') { + nonArrowFunctionStacks.push(node); + } }, - ':function:exit'() { + ':function:exit'(node) { functionStacks.pop(); + + if (node.type !== 'ArrowFunctionExpression') { + nonArrowFunctionStacks.pop(); + } + }, + ThisExpression(node) { + const currentNonArrowFunction = nonArrowFunctionStacks[functionStacks.length - 1]; + if (!currentNonArrowFunction) { + return; + } + const currentFunctionInfo = functionInfo.get(currentNonArrowFunction); + currentFunctionInfo.thisFound = true; }, ReturnStatement(node) { const currentFunction = functionStacks[functionStacks.length - 1]; @@ -248,7 +271,7 @@ const create = context => { return; } - const returnStatements = functionReturnStatements.get(currentFunction); + const {returnStatements} = functionInfo.get(currentFunction); returnStatements.push(node); }, [arrayForEachCallSelector](node) { @@ -261,8 +284,8 @@ const create = context => { messageId: MESSAGE_ID }; - if (isFixable(callExpression, sourceCode, functionReturnStatements)) { - problem.fix = getFixFunction(callExpression, sourceCode, functionReturnStatements); + if (isFixable(callExpression, sourceCode, functionInfo)) { + problem.fix = getFixFunction(callExpression, sourceCode, functionInfo); } context.report(problem); diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 597154cf2d..2a6a934f87 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -64,7 +64,8 @@ test.visualize({ // TODO: check parameters conflicts // 'foo.forEach(function a(element) {bar(a)})', - // 'foo.forEach(function a(element) {bar(this)})', + 'foo.forEach(function a(element) {bar(this)})', + 'foo.forEach((element) => {bar(this)})', // 'foo.forEach(function a(element) {bar(arguments)})', // Auto-fix diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 63a3c22654..3140092e98 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -215,6 +215,32 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #18 + 1 | foo.forEach(function a(element) {bar(this)}) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function a(element) {bar(this)})␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #19 + 1 | foo.forEach((element) => {bar(this)}) + +> Output + + `␊ + 1 | for (const element of foo) {bar(this)}␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {bar(this)})␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #20 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -236,7 +262,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #19 +## Invalid #21 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -258,7 +284,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #20 +## Invalid #22 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -280,7 +306,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #21 +## Invalid #23 1 | foo.forEach((element) => bar(element)); > Output @@ -296,7 +322,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #22 +## Invalid #24 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -318,7 +344,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #23 +## Invalid #25 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -340,7 +366,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #24 +## Invalid #26 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -362,7 +388,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #25 +## Invalid #27 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -378,7 +404,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #26 +## Invalid #28 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -400,7 +426,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #27 +## Invalid #29 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -422,7 +448,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #28 +## Invalid #30 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -444,7 +470,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #29 +## Invalid #31 1 | foo.forEach((element) => bar(element),); > Output @@ -460,7 +486,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #30 +## Invalid #32 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -479,7 +505,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #31 +## Invalid #33 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -516,7 +542,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #32 +## Invalid #34 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index fd18754d320ab5408b8a0ffbd93fcf30d8139099..256aea6bbddf458e72213c5fb45e02c5e95616bf 100644 GIT binary patch literal 1911 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 LXWC(Jq8 Date: Mon, 18 Jan 2021 11:21:38 +0800 Subject: [PATCH 12/40] Support check `function.id` and `arguments` --- rules/no-array-for-each.js | 41 +++- test/no-array-for-each.js | 77 ++++++- test/snapshots/no-array-for-each.js.md | 266 +++++++++++++++++++++-- test/snapshots/no-array-for-each.js.snap | Bin 1911 -> 2309 bytes 4 files changed, 353 insertions(+), 31 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 382b0357fd..fbf5651526 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -1,5 +1,11 @@ 'use strict'; -const {isParenthesized, isArrowToken, isCommaToken, isSemicolonToken} = require('eslint-utils'); +const { + isParenthesized, + isArrowToken, + isCommaToken, + isSemicolonToken, + findVariable +} = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); @@ -212,17 +218,35 @@ function isFixable(callExpression, sourceCode, functionInfo) { // TODO: check parameters conflicts // Check `ReturnStatement`s in `callback` - const {returnStatements, thisFound} = functionInfo.get(callback); - if ( - thisFound || - returnStatements.some(returnStatement => isReturnStatementInContinueAbleNodes(returnStatement, callback)) - ) { + const {returnStatements, thisFound, scope} = functionInfo.get(callback); + if (returnStatements.some(returnStatement => isReturnStatementInContinueAbleNodes(returnStatement, callback))) { return false; } // Check `callback` self if (callback.type === 'FunctionExpression') { - // TODO: check `.id` `arguments` `this` of `FunctionExpression` + if (thisFound) { + return false; + } + + const argumentsVariable = findVariable(scope, 'arguments'); + if ( + argumentsVariable && + argumentsVariable.references.some(reference => reference.from == scope) + ) { + return false; + } + + if (callback.id) { + const idVariable = findVariable(scope, callback.id); + + if ( + idVariable && + idVariable.references.some(reference => reference.from == scope) + ) { + return false; + } + } } return true; @@ -241,7 +265,8 @@ const create = context => { functionStacks.push(node); functionInfo.set(node, { returnStatements: [], - thisFound: false + thisFound: false, + scope: context.getScope() }); if (node.type !== 'ArrowFunctionExpression') { diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 2a6a934f87..8814f02c34 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -63,10 +63,79 @@ test.visualize({ `, // TODO: check parameters conflicts - // 'foo.forEach(function a(element) {bar(a)})', - 'foo.forEach(function a(element) {bar(this)})', - 'foo.forEach((element) => {bar(this)})', - // 'foo.forEach(function a(element) {bar(arguments)})', + + // `FunctionExpression.id` + outdent` + foo.forEach(function a(element) { + bar(a) + }) + `, + outdent` + foo.forEach(function a(element) { + function b() { + bar(a) + } + }) + `, + outdent` + foo.forEach(function a(element) { + function b(a) { + bar(a) + } + }) + `, + + // This + outdent` + foo.forEach(function(element) { + bar(this) + }) + `, + outdent` + foo.forEach(function(element) { + function b() { + bar(this) + } + }) + `, + outdent` + foo.forEach(function(element) { + const x = b => { + bar(this) + } + }) + `, + outdent` + foo.forEach((element) => { + bar(this) + }) + `, + + // `arguments` + outdent` + foo.forEach(function(element) { + bar(arguments) + }) + `, + outdent` + foo.forEach(function(element) { + function b() { + bar(arguments) + } + }) + `, + outdent` + foo.forEach(function(element) { + const b = () => { + bar(arguments) + } + }) + `, + outdent` + foo.forEach((element) => { + bar(arguments) + }) + `, // Auto-fix outdent` diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 3140092e98..cd8300a5d6 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -215,32 +215,260 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #18 - 1 | foo.forEach(function a(element) {bar(this)}) + 1 | foo.forEach(function a(element) { + 2 | bar(a) + 3 | }) > Error 1/1 `␊ - > 1 | foo.forEach(function a(element) {bar(this)})␊ + > 1 | foo.forEach(function a(element) {␊ | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(a)␊ + 3 | })␊ ` ## Invalid #19 - 1 | foo.forEach((element) => {bar(this)}) + 1 | foo.forEach(function a(element) { + 2 | function b() { + 3 | bar(a) + 4 | } + 5 | }) > Output `␊ - 1 | for (const element of foo) {bar(this)}␊ + 1 | for (const element of foo) {␊ + 2 | function b() {␊ + 3 | bar(a)␊ + 4 | }␊ + 5 | }␊ ` > Error 1/1 `␊ - > 1 | foo.forEach((element) => {bar(this)})␊ + > 1 | foo.forEach(function a(element) {␊ | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function b() {␊ + 3 | bar(a)␊ + 4 | }␊ + 5 | })␊ ` ## Invalid #20 + 1 | foo.forEach(function a(element) { + 2 | function b(a) { + 3 | bar(a) + 4 | } + 5 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | function b(a) {␊ + 3 | bar(a)␊ + 4 | }␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function a(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function b(a) {␊ + 3 | bar(a)␊ + 4 | }␊ + 5 | })␊ + ` + +## Invalid #21 + 1 | foo.forEach(function(element) { + 2 | bar(this) + 3 | }) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(this)␊ + 3 | })␊ + ` + +## Invalid #22 + 1 | foo.forEach(function(element) { + 2 | function b() { + 3 | bar(this) + 4 | } + 5 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | function b() {␊ + 3 | bar(this)␊ + 4 | }␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function b() {␊ + 3 | bar(this)␊ + 4 | }␊ + 5 | })␊ + ` + +## Invalid #23 + 1 | foo.forEach(function(element) { + 2 | const x = b => { + 3 | bar(this) + 4 | } + 5 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | const x = b => {␊ + 3 | bar(this)␊ + 4 | }␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | const x = b => {␊ + 3 | bar(this)␊ + 4 | }␊ + 5 | })␊ + ` + +## Invalid #24 + 1 | foo.forEach((element) => { + 2 | bar(this) + 3 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(this)␊ + 3 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(this)␊ + 3 | })␊ + ` + +## Invalid #25 + 1 | foo.forEach(function(element) { + 2 | bar(arguments) + 3 | }) + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(arguments)␊ + 3 | })␊ + ` + +## Invalid #26 + 1 | foo.forEach(function(element) { + 2 | function b() { + 3 | bar(arguments) + 4 | } + 5 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | function b() {␊ + 3 | bar(arguments)␊ + 4 | }␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function b() {␊ + 3 | bar(arguments)␊ + 4 | }␊ + 5 | })␊ + ` + +## Invalid #27 + 1 | foo.forEach(function(element) { + 2 | const b = () => { + 3 | bar(arguments) + 4 | } + 5 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | const b = () => {␊ + 3 | bar(arguments)␊ + 4 | }␊ + 5 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(function(element) {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | const b = () => {␊ + 3 | bar(arguments)␊ + 4 | }␊ + 5 | })␊ + ` + +## Invalid #28 + 1 | foo.forEach((element) => { + 2 | bar(arguments) + 3 | }) + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(arguments)␊ + 3 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach((element) => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | bar(arguments)␊ + 3 | })␊ + ` + +## Invalid #29 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -262,7 +490,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #21 +## Invalid #30 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -284,7 +512,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #22 +## Invalid #31 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -306,7 +534,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #23 +## Invalid #32 1 | foo.forEach((element) => bar(element)); > Output @@ -322,7 +550,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #24 +## Invalid #33 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -344,7 +572,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #25 +## Invalid #34 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -366,7 +594,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #26 +## Invalid #35 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -388,7 +616,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #27 +## Invalid #36 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -404,7 +632,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #28 +## Invalid #37 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -426,7 +654,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #29 +## Invalid #38 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -448,7 +676,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #30 +## Invalid #39 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -470,7 +698,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #31 +## Invalid #40 1 | foo.forEach((element) => bar(element),); > Output @@ -486,7 +714,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #32 +## Invalid #41 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -505,7 +733,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #33 +## Invalid #42 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -542,7 +770,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #34 +## Invalid #43 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 256aea6bbddf458e72213c5fb45e02c5e95616bf..3a309aca0dea0a10a4c1a2658c2db444fb2c1364 100644 GIT binary patch literal 2309 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 Date: Mon, 18 Jan 2021 11:29:28 +0800 Subject: [PATCH 13/40] Fix wrongly fix --- rules/no-array-for-each.js | 5 +---- test/snapshots/no-array-for-each.js.md | 10 ---------- test/snapshots/no-array-for-each.js.snap | Bin 2309 -> 2303 bytes 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index fbf5651526..c370bc382a 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -240,10 +240,7 @@ function isFixable(callExpression, sourceCode, functionInfo) { if (callback.id) { const idVariable = findVariable(scope, callback.id); - if ( - idVariable && - idVariable.references.some(reference => reference.from == scope) - ) { + if (idVariable && idVariable.references.length > 0) { return false; } } diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index cd8300a5d6..6bb1b45faa 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -235,16 +235,6 @@ Generated by [AVA](https://avajs.dev). 4 | } 5 | }) -> Output - - `␊ - 1 | for (const element of foo) {␊ - 2 | function b() {␊ - 3 | bar(a)␊ - 4 | }␊ - 5 | }␊ - ` - > Error 1/1 `␊ diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 3a309aca0dea0a10a4c1a2658c2db444fb2c1364..a05d64c42e00444db20a08d0c76b04705f3ee742 100644 GIT binary patch literal 2303 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 Zf&Ws_`Jni-Ri254{{dj2I2#}-000KOa-IMH literal 2309 zcmV+g3HtUyRzVe+Mug<+!1z)US@;vb6$00000000Bk zS`AbaR~CLVNP$?Yi1ud-I4szcD6k}<0wPfaMX*{?>!D?%BrrfKOdy#cKaJI*SUufR zw63dGQKVbfbq{)uh*sB%)ooSW7XR?HM``V<$97kix>}{JyDx7h(_}K_Kk;nN`AG83 zyZ7C9-@W(!gor=@CIC_MPq*U!`j+yu<$<%$$A1}$0nB>Z z%5n^`k+4B%)40Jy?eWv698JCbV{zVo9I@preufBtIP0PzS94LnO}Y8*%F_!m#Ma;d zMCEmLA9(uxm#(C42m(J}x{o3DI>h9@WBrR)2L~+a`nGCKWZ4`Hv84e3OslBNUc0_$ z?d~1Bx5Zzn3BeJ2fQ4ch0GS=Df1;n=7(L}rciwv}Q+XOkY!i!7aHLte_m94q-_f*f#O{K4u_qPmh~C^3)BVJl-VWt?46!qU;gfq43VKJjj@YtCIxw)|0fr&A17bdz zb13J++OpRx$nKnuJtuL*MujkFhxlz#(W0)r6KAO()G-}zpVi}teaPY+5wt9z{nK+* zUx;or829W>oU|N6>@A4$%UI{-vGQG6p^A8VLH7y_v2PCtpkny_c~_70wnbFXeaac4 zNf=`LA*c`TsBheU`EXAcR#LiJ5riXl(&G#|A*$r7lyllQwuUbHbaP}**iIa=v7ro3 zK`d>#bnw#T?K8(8IWf0bl--XbR`vvgix71mZ^{m62s+fB&=TML#ws&I7TW{Pug#P+jTHxhs?RY7q{Rq1D{A3yub*6#unF~s6w0BpN8ac2I= z$pbg8pNOI>JO7IzHXmY#q;r{}Vf2QF;^YsnO$xY)Besi0;V1xF$Ib68PR`Fbv!r_V z;B&Xram1ctQ5X(eZ2n}=r86I`S@PUY@~Q9V4d95)dy+x=GXT7Q{9IwrD(c+2y)VUf z40aoE#J74&sv* zMPEgqx@Jt{`I@|&;~O!=CKCX3j~SlPcmP|r{b0+o8z-)Rg(J3!MQAhteG&gWSKPev z9mfvHxIE@@x2>@lbvx=5UyN&EAZ# z_bT! z+mq3H;BN>Gyu?5i(Hbp9EY;9ub5s>1r^O>j2%5tmUxodNu+$Mp&}ABZhOX3rzIqx2 z*kXIG7*AL@!RUEsw4Khp=WdgOB%G^#8A({3J@5H3fHEBq%PNXkB_RR6|j-=sH??`N_ z)GPsmprq%!&foiI*9m9AgFKoq6mHzQ=Y`BkcQJmf_B7V2w2qc)U+$+CyS$jyz$HR$ zyF!>dvA2u~hK?_mF_&zVIIM|7dW6exwOA$LFPV2K zuIxeMP%ZN;DV6R`9p5j`gtFbq^ZL{|XCcr1YSu!r6Q@$Eis+{IX9{@a|7eTyj!R28 zw`cL!hQ)7wc+;*Q9@Y5qYq+T+C$gJSttlbIQkG!y21?Kx%0Qwr!zB*N9IMt7ty-Iy zWUg@vzi}#R98K$>Uc#~mX`)$3D&+}DWkU+dIiV!J5VA9b*}m|kCUR2Ae5sV7r5Mu< zl#YZGqf(cXV&r@oXSj@SxQsEJ5Z4=d%4D43GQQ!m=Z6&H?3VHEmZg}5R7SXztN4Pf{*rB@0wa0ZF-xla%u%k>zj;sx^IKtxhXY@)U4J%lSsjQ!EvvvI@lLg2c2R zftzn@T}hm)lcctJcm;=f=*-5@_2e5WMSj^`J5CVp`0Y47n5Im;JCzz10#0QG)1HlT zr!vA)!lPth71bM^O9Qq!N(QG=z^tFi1LuODm0>f$jj%T>P`V!QX3<}QUMSLid{yZ1 z^3&(XZ@d+FJR~Lwxs{jFQsg|cTt$<`GtB!;MhBWSp}Qx`Of~7{GBw4v++4JGL*pB# zNz(i~Mz|yP%K5VUC_8f=w6NFm<=z>t%<<)K9HBC)@!}Pozb+~@lqVOJxwet&#IcSLI5}DCt#tCf zT|ki+E@Eo^@;k9rffKsioaSO(vsLKl!sc*9o?XbPUHVbj^DwaZHEW7X7012qgodZm f*HT4 Date: Mon, 18 Jan 2021 12:21:54 +0800 Subject: [PATCH 14/40] More tests --- test/no-array-for-each.js | 3 + test/snapshots/no-array-for-each.js.md | 98 +++++++++++++++++------ test/snapshots/no-array-for-each.js.snap | Bin 2303 -> 2445 bytes 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 8814f02c34..bf0562e292 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -63,6 +63,9 @@ test.visualize({ `, // TODO: check parameters conflicts + 'foo.forEach(foo => bar());', + 'a[foo].forEach(foo => bar());', + 'a((foo) => foo).forEach(foo => bar());', // `FunctionExpression.id` outdent` diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 6bb1b45faa..e2b0193185 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -215,6 +215,54 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #18 + 1 | foo.forEach(foo => bar()); + +> Output + + `␊ + 1 | for (const foo of foo) bar()␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #19 + 1 | a[foo].forEach(foo => bar()); + +> Output + + `␊ + 1 | for (const foo of a[foo]) bar()␊ + ` + +> Error 1/1 + + `␊ + > 1 | a[foo].forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #20 + 1 | a((foo) => foo).forEach(foo => bar()); + +> Output + + `␊ + 1 | for (const foo of a((foo) => foo)) bar()␊ + ` + +> Error 1/1 + + `␊ + > 1 | a((foo) => foo).forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #21 1 | foo.forEach(function a(element) { 2 | bar(a) 3 | }) @@ -228,7 +276,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #19 +## Invalid #22 1 | foo.forEach(function a(element) { 2 | function b() { 3 | bar(a) @@ -246,7 +294,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #20 +## Invalid #23 1 | foo.forEach(function a(element) { 2 | function b(a) { 3 | bar(a) @@ -274,7 +322,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #21 +## Invalid #24 1 | foo.forEach(function(element) { 2 | bar(this) 3 | }) @@ -288,7 +336,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #22 +## Invalid #25 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(this) @@ -316,7 +364,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #23 +## Invalid #26 1 | foo.forEach(function(element) { 2 | const x = b => { 3 | bar(this) @@ -344,7 +392,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #24 +## Invalid #27 1 | foo.forEach((element) => { 2 | bar(this) 3 | }) @@ -366,7 +414,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #25 +## Invalid #28 1 | foo.forEach(function(element) { 2 | bar(arguments) 3 | }) @@ -380,7 +428,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #26 +## Invalid #29 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(arguments) @@ -408,7 +456,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #27 +## Invalid #30 1 | foo.forEach(function(element) { 2 | const b = () => { 3 | bar(arguments) @@ -436,7 +484,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #28 +## Invalid #31 1 | foo.forEach((element) => { 2 | bar(arguments) 3 | }) @@ -458,7 +506,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #29 +## Invalid #32 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -480,7 +528,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #30 +## Invalid #33 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -502,7 +550,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #31 +## Invalid #34 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -524,7 +572,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #32 +## Invalid #35 1 | foo.forEach((element) => bar(element)); > Output @@ -540,7 +588,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #33 +## Invalid #36 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -562,7 +610,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #34 +## Invalid #37 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -584,7 +632,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #35 +## Invalid #38 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -606,7 +654,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #36 +## Invalid #39 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -622,7 +670,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #37 +## Invalid #40 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -644,7 +692,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #38 +## Invalid #41 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -666,7 +714,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #39 +## Invalid #42 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -688,7 +736,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #40 +## Invalid #43 1 | foo.forEach((element) => bar(element),); > Output @@ -704,7 +752,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #41 +## Invalid #44 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -723,7 +771,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #42 +## Invalid #45 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -760,7 +808,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #43 +## Invalid #46 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index a05d64c42e00444db20a08d0c76b04705f3ee742..26fc91a0049a4b56e0c993357fce698c6af8d508 100644 GIT binary patch literal 2445 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 Lt@Z33bt?b>08hA* literal 2303 zcmVAqApT5pCBA_!!tG7$`}ofc#MeMX*{?>!D*&5_mu=B#^uye~i_lSY202 zowI5cMO>X@2R%nbtFvNtt%_^$AD-e$kYDci z-S2+y`@Z|#8z%SzFck=zzq=>?{oC@-*Z9xB9Q)^B3>aTJ2*JHWL%)^x=4XC+W#PXb zRF-3i4Tl4Qo2CpM>xi8_<7D#v{}ksP#t~c2;CqPB;dxi}xvHzWUGnV@)}3F9A+`nw zAR@23=g5!ty?P^gO91%(+9M3Hw;@vdPYo>J5a_p}`>U#r;bjXj#FqL2Fsq_2d(-CL zO$YWI*cE%DCJ0CD5eDg_0Lbjz@EtX2YvhdIeEY#uney{EVw)I@hbzs>eRT4b{IcOuk6)o$|J9AO}Z)H^HI~R30Vuu;LD}a{yb$oWI z>Q90@4Tkmu@zd8}h`k3yxtTGF!?L+m@F0jL=LXwl6ReQjYCRKI+V zU^<4_0SNVn-zx9if9-g0H&#-*Aw2*`?DR1-x*)1#>*WhNwzdW@`)qr7PRL#yvC+Xa z&Oxkfxpwqg>h8HQC(bM^7Gw|Lh?PD~<0?emC)=|98Ul`W#I?jWzqwwCBQ|s_jdc)f zs=I?H{BCbn(B_!x%uHbpj@SVP?~MasM^%70p(^b{^_Yu4-TAeDJcd|21b|)lrp?VC zmpXXo_L&H(vg^MXV)G&Ph`Ltm8zyWS7AAglYr5ZE9I@RD3daM`I%RQRabkYPg%#EF zhn~Nmh9mYIgThcaV*97<*Did#amDj{$!EV=G>9WM?-?3t&jGOS^rgby_3BIS9eg#q zbErp;Blc|uV}A_5hqqt98*x4>cih0x&VM#^s&K@fV$e1TfCIAz&-I0uK2BdWBnw;K z9f%`#LKuw`5FPPtJF#e`-~BMn_ly3(9s5_1!HfAyapSGm; zSM)1uCN^HK$-5iVh#~fKh@Od~Ga8Rzt9Ku5S$*fs?Jse}zCh5}2hkt)_e;gi>pr=8 zeddOcrP62&vEoPo{;JKymeken^*ebpZnt(l%t<4=ior0%-!g_}H=>S*$Tl9#2uX~j zaKxtmgho5WUH^v<&PiU})|~Ko)-!`&@4*l|DGGpx2j_<#`G@@I_=Goto3<^^#Sr^* zh{x}jb}oG@|D)FIWo03+k2;GXc1$z?ejotVKg=J5V5A_OkPxeg5{)LVM5CRpC@K>Q z>npXIN>WSJ8bm}|I-yi(g(gNM5)kmU%J_p=M!$$G4WZUhgkDDyg&A6{qBhE;>eiZH ziwffe=2PN30MDFcIaxufDdTkYuFOCXQYaDxSwdJ&QiO^~BjQuwuT(+`e@&e#LV9J! zK|xxQ(reWz@O^^uy#fC568ys;O0lpM%YYxyhC;1H8nuohOm=EYjONoy(ac6CF&~Oj zn3)Wg3xAVu;U#)?5v9_oiIpm#MN+Ak1}$393w`%g~nU(OY+e z09$U$6)}XF6AbQ8M%kFmbM7`eNW{9@n~{Xo+47zb11Qt}vMi#AQCaAF&zgft%}qMMf_RI40meB=E}P3ep}{vxg%+K(jAFa zm72$65R`Pk>-?2(x=#2M+{mNFeBs9KdmhM~G$-T7qNlM`rLnhFd$XTf?(}9>1GfmJ z^$ua0#MU;(8#>;iQEeU&K4xmRd*` zIn#rRQ7v;XDdny`I<8+F31yoP&*P8IF$+2FS27j~9XOR*R74lOKbOZN|3@v#yH0K4 zY|rAWhQ()oc*~|Ap49sBTexu|2eO-1ttuge5{97j21-yWwVp&}hD{ulIToX*S&TL^ ziR|Dc?%-rJIFiyry@dG;l6aGlM8Xl0NJkWsu|f%4A!KI|-M(<7rm<3qT&bjyrD)Uj zYAp#Lj6zvX3X$`rtl?6w;ZoXgLRfF$D3h{=OSy(iUm8(}wOh)yTbg7NQW)S?uHZ^0 znl(yn(|!bfhtKKKVvUksrEi`w7AxzwM_7J(P}jhf>2#z@e<5$1_px zP)3+bxRnfyqI!d4X}}Ce$>2~5nDoF?p^F_LsuL|v6 zetP}*jkf}~mqaHayYs3wYH|@-uAs=`Ii^07)`1=x-`$gWrW*CKnVMu>Zm!z8q4AE> zL@B;qBkYJhaz1eQ+IHI$JtR1MXY1+oyc#P_{}~(T04KTUdb59T)QjkV6k-M zoMvXP`OCGlRhj)uSuvq7s`22}nXfJoRcd!G5Ob|l!hz!!!E>Uq)LZG`Jvfgd4_uJc z`sDjti^9Wq={U>DdSk87#|6jkirl*>Q#$o!t@~kM_AS#4rz(zX)A21&p{rFF5j?Ty Zf&Ws_`Jni-Ri254{{dj2I2#}-000KOa-IMH From a747d9332cc363106026d283c8365bb97bfe252f Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 12:57:13 +0800 Subject: [PATCH 15/40] Fix logic --- rules/no-array-for-each.js | 44 +++++++++++++++-------- test/snapshots/no-array-for-each.js.md | 20 +++++------ test/snapshots/no-array-for-each.js.snap | Bin 2445 -> 2427 bytes 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 8f1d704341..dabec37855 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -175,29 +175,41 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { }; } -function isParameterSafeToFix(parameter, {scope, array}) { +const isChildScope = (child, parent) => { + for (let scope = child; scope; scope = scope.upper) { + if (scope === parent) { + return true; + } + } + return false; +}; + +function isParameterSafeToFix(parameter, {scope, array, identifiers}) { const {type, name} = parameter; if (type !== 'Identifier') { return false; } - const variable = findVariable(scope, name); - if (!variable) { - return true; - } + const [arrayStart, arrayEnd] = array.range; + const identifiersInArray = identifiers.filter( + ({name, range: [start, end]}) => name === parameter.name && start >= arrayStart && end <= arrayEnd + ); - const [arrayStart, arrayEnd] = array; - for (const {identifier} of variable.references) { - const [start, end] = identifier; - if (start >= arrayStart && end <= arrayEnd) { + for (const identifier of identifiersInArray) { + const variable = findVariable(scope, identifier); + if (!variable) { + return false; + } + + if (!isChildScope(variable.scope, scope)) { return false; } } - return false; + return true; } -function isFixable({callExpression, scope}, sourceCode, functionInfo) { +function isFixable({callExpression, scope, identifiers}, sourceCode, functionInfo) { // Check `CallExpression` if ( callExpression.optional || @@ -232,7 +244,7 @@ function isFixable({callExpression, scope}, sourceCode, functionInfo) { const parameters = callback.params; if ( !(parameters.length === 1 || parameters.length === 2) || - parameters.some(parameter => !isParameterSafeToFix(parameter, {scope, array: callExpression})) + parameters.some(parameter => !isParameterSafeToFix(parameter, {scope, array: callExpression, identifiers})) ) { return false; } @@ -272,8 +284,9 @@ function isFixable({callExpression, scope}, sourceCode, functionInfo) { const create = context => { const functionStacks = []; const nonArrowFunctionStacks = []; - const functionInfo = new Map(); const callExpressions = []; + const identifiers = []; + const functionInfo = new Map(); const sourceCode = context.getSourceCode(); @@ -305,6 +318,9 @@ const create = context => { const currentFunctionInfo = functionInfo.get(currentNonArrowFunction); currentFunctionInfo.thisFound = true; }, + Identifier(node) { + identifiers.push(node); + }, ReturnStatement(node) { const currentFunction = functionStacks[functionStacks.length - 1]; // `globalReturn ` @@ -329,7 +345,7 @@ const create = context => { messageId: MESSAGE_ID }; - if (isFixable({callExpression, scope}, sourceCode, functionInfo)) { + if (isFixable({callExpression, scope, identifiers}, sourceCode, functionInfo)) { problem.fix = getFixFunction(callExpression, sourceCode, functionInfo); } diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index e2b0193185..b4e4d3c836 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -217,12 +217,6 @@ Generated by [AVA](https://avajs.dev). ## Invalid #18 1 | foo.forEach(foo => bar()); -> Output - - `␊ - 1 | for (const foo of foo) bar()␊ - ` - > Error 1/1 `␊ @@ -233,12 +227,6 @@ Generated by [AVA](https://avajs.dev). ## Invalid #19 1 | a[foo].forEach(foo => bar()); -> Output - - `␊ - 1 | for (const foo of a[foo]) bar()␊ - ` - > Error 1/1 `␊ @@ -419,6 +407,14 @@ Generated by [AVA](https://avajs.dev). 2 | bar(arguments) 3 | }) +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | bar(arguments)␊ + 3 | }␊ + ` + > Error 1/1 `␊ diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 26fc91a0049a4b56e0c993357fce698c6af8d508..79a9eaa93f2ec4cc6a0eb49ae4c73de0d933fe8d 100644 GIT binary patch literal 2427 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 literal 2445 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 Lt@Z33bt?b>08hA* From 4f374e55744e7de0ba184dc671d06f4b02d07393 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 13:02:29 +0800 Subject: [PATCH 16/40] Style --- test/snapshots/no-array-for-each.js.md | 90 ++++++++++++++++------- test/snapshots/no-array-for-each.js.snap | Bin 2427 -> 2568 bytes 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index b4e4d3c836..aba945cf6d 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -225,6 +225,16 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #19 + 1 | index.forEach((a, index) => bar()); + +> Error 1/1 + + `␊ + > 1 | index.forEach((a, index) => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #20 1 | a[foo].forEach(foo => bar()); > Error 1/1 @@ -234,7 +244,17 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #20 +## Invalid #21 + 1 | a[index].forEach((b, index) => bar()); + +> Error 1/1 + + `␊ + > 1 | a[index].forEach((b, index) => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #22 1 | a((foo) => foo).forEach(foo => bar()); > Output @@ -250,7 +270,23 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #21 +## Invalid #23 + 1 | a((foo, index) => foo + index).forEach((foo, index) => bar()); + +> Output + + `␊ + 1 | for (const [foo, index] of a((foo, index) => foo + index).entries()) bar()␊ + ` + +> Error 1/1 + + `␊ + > 1 | a((foo, index) => foo + index).forEach((foo, index) => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #24 1 | foo.forEach(function a(element) { 2 | bar(a) 3 | }) @@ -264,7 +300,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #22 +## Invalid #25 1 | foo.forEach(function a(element) { 2 | function b() { 3 | bar(a) @@ -282,7 +318,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #23 +## Invalid #26 1 | foo.forEach(function a(element) { 2 | function b(a) { 3 | bar(a) @@ -310,7 +346,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #24 +## Invalid #27 1 | foo.forEach(function(element) { 2 | bar(this) 3 | }) @@ -324,7 +360,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #25 +## Invalid #28 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(this) @@ -352,7 +388,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #26 +## Invalid #29 1 | foo.forEach(function(element) { 2 | const x = b => { 3 | bar(this) @@ -380,7 +416,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #27 +## Invalid #30 1 | foo.forEach((element) => { 2 | bar(this) 3 | }) @@ -402,7 +438,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #28 +## Invalid #31 1 | foo.forEach(function(element) { 2 | bar(arguments) 3 | }) @@ -424,7 +460,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #29 +## Invalid #32 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(arguments) @@ -452,7 +488,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #30 +## Invalid #33 1 | foo.forEach(function(element) { 2 | const b = () => { 3 | bar(arguments) @@ -480,7 +516,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #31 +## Invalid #34 1 | foo.forEach((element) => { 2 | bar(arguments) 3 | }) @@ -502,7 +538,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #32 +## Invalid #35 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -524,7 +560,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #33 +## Invalid #36 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -546,7 +582,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #34 +## Invalid #37 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -568,7 +604,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #35 +## Invalid #38 1 | foo.forEach((element) => bar(element)); > Output @@ -584,7 +620,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #36 +## Invalid #39 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -606,7 +642,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #37 +## Invalid #40 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -628,7 +664,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #38 +## Invalid #41 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -650,7 +686,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #39 +## Invalid #42 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -666,7 +702,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #40 +## Invalid #43 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -688,7 +724,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #41 +## Invalid #44 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -710,7 +746,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #42 +## Invalid #45 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -732,7 +768,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #43 +## Invalid #46 1 | foo.forEach((element) => bar(element),); > Output @@ -748,7 +784,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #44 +## Invalid #47 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -767,7 +803,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #45 +## Invalid #48 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -804,7 +840,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #46 +## Invalid #49 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 79a9eaa93f2ec4cc6a0eb49ae4c73de0d933fe8d..fdf836ecc591dff61d31aa98696bbfdc1e3fdb19 100644 GIT binary patch literal 2568 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 From dcafc690236ee98b0a2733162d2e30b84f451a80 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 13:50:20 +0800 Subject: [PATCH 17/40] Style --- rules/no-array-for-each.js | 12 +++++++----- test/no-array-for-each.js | 4 +++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index dabec37855..32c81ce098 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -136,7 +136,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { ); } - const shouldRemoveExpressionStatementLastToken = (token) => { + const shouldRemoveExpressionStatementLastToken = token => { if (!isSemicolonToken(token)) { return false; } @@ -181,18 +181,19 @@ const isChildScope = (child, parent) => { return true; } } + return false; }; function isParameterSafeToFix(parameter, {scope, array, identifiers}) { - const {type, name} = parameter; + const {type, name: parameterName} = parameter; if (type !== 'Identifier') { return false; } const [arrayStart, arrayEnd] = array.range; const identifiersInArray = identifiers.filter( - ({name, range: [start, end]}) => name === parameter.name && start >= arrayStart && end <= arrayEnd + ({name, range: [start, end]}) => name === parameterName && start >= arrayStart && end <= arrayEnd ); for (const identifier of identifiersInArray) { @@ -264,7 +265,7 @@ function isFixable({callExpression, scope, identifiers}, sourceCode, functionInf const argumentsVariable = findVariable(callbackScope, 'arguments'); if ( argumentsVariable && - argumentsVariable.references.some(reference => reference.from == scope) + argumentsVariable.references.some(reference => reference.from === scope) ) { return false; } @@ -310,11 +311,12 @@ const create = context => { nonArrowFunctionStacks.pop(); } }, - ThisExpression(node) { + ThisExpression() { const currentNonArrowFunction = nonArrowFunctionStacks[functionStacks.length - 1]; if (!currentNonArrowFunction) { return; } + const currentFunctionInfo = functionInfo.get(currentNonArrowFunction); currentFunctionInfo.thisFound = true; }, diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index bf0562e292..6ce4324228 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -62,10 +62,12 @@ test.visualize({ }); `, - // TODO: check parameters conflicts 'foo.forEach(foo => bar());', + 'index.forEach((a, index) => bar());', 'a[foo].forEach(foo => bar());', + 'a[index].forEach((b, index) => bar());', 'a((foo) => foo).forEach(foo => bar());', + 'a((foo, index) => foo + index).forEach((foo, index) => bar());', // `FunctionExpression.id` outdent` From 1a7e6d4fef431c310496787c70a0877ae50dce13 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 14:05:16 +0800 Subject: [PATCH 18/40] More tests --- test/no-array-for-each.js | 20 +++- test/snapshots/no-array-for-each.js.md | 139 ++++++++++++++++++----- test/snapshots/no-array-for-each.js.snap | Bin 2568 -> 2805 bytes 3 files changed, 127 insertions(+), 32 deletions(-) diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 6ce4324228..51597c14f5 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -22,8 +22,6 @@ test.visualize({ 'foo.forEach((element, index, array) => bar())', // Ideally this should be fixable, but hard to know variable conflicts 'foo.forEach(({property}) => bar(property))', - // TODO: check parameters conflicts - // 'foo.forEach(foo => bar())', // Can't turn `return` to `continue` outdent` @@ -62,12 +60,30 @@ test.visualize({ }); `, + // `parameters` 'foo.forEach(foo => bar());', + outdent` + const foo = []; + foo.forEach(foo => bar()); + `, 'index.forEach((a, index) => bar());', + outdent` + const index = []; + index.forEach((a, index) => bar()); + `, 'a[foo].forEach(foo => bar());', + outdent` + const foo = 1; + a[foo].forEach(foo => bar()); + `, 'a[index].forEach((b, index) => bar());', 'a((foo) => foo).forEach(foo => bar());', 'a((foo, index) => foo + index).forEach((foo, index) => bar());', + outdent` + const foo = []; + const index = 1; + a.forEach((foo, index) => foo[index]); + `, // `FunctionExpression.id` outdent` diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index aba945cf6d..d3f8d3b9b8 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -225,6 +225,25 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #19 + 1 | const foo = []; + 2 | foo.forEach(foo => bar()); + +> Output + + `␊ + 1 | const foo = [];␊ + 2 | for (const foo of foo) bar()␊ + ` + +> Error 1/1 + + `␊ + 1 | const foo = [];␊ + > 2 | foo.forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #20 1 | index.forEach((a, index) => bar()); > Error 1/1 @@ -234,7 +253,26 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #20 +## Invalid #21 + 1 | const index = []; + 2 | index.forEach((a, index) => bar()); + +> Output + + `␊ + 1 | const index = [];␊ + 2 | for (const [a, index] of index.entries()) bar()␊ + ` + +> Error 1/1 + + `␊ + 1 | const index = [];␊ + > 2 | index.forEach((a, index) => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #22 1 | a[foo].forEach(foo => bar()); > Error 1/1 @@ -244,7 +282,26 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #21 +## Invalid #23 + 1 | const foo = 1; + 2 | a[foo].forEach(foo => bar()); + +> Output + + `␊ + 1 | const foo = 1;␊ + 2 | for (const foo of a[foo]) bar()␊ + ` + +> Error 1/1 + + `␊ + 1 | const foo = 1;␊ + > 2 | a[foo].forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #24 1 | a[index].forEach((b, index) => bar()); > Error 1/1 @@ -254,7 +311,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #22 +## Invalid #25 1 | a((foo) => foo).forEach(foo => bar()); > Output @@ -270,7 +327,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #23 +## Invalid #26 1 | a((foo, index) => foo + index).forEach((foo, index) => bar()); > Output @@ -286,7 +343,29 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #24 +## Invalid #27 + 1 | const foo = []; + 2 | const index = 1; + 3 | a.forEach((foo, index) => foo[index]); + +> Output + + `␊ + 1 | const foo = [];␊ + 2 | const index = 1;␊ + 3 | for (const [foo, index] of a.entries()) foo[index]␊ + ` + +> Error 1/1 + + `␊ + 1 | const foo = [];␊ + 2 | const index = 1;␊ + > 3 | a.forEach((foo, index) => foo[index]);␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #28 1 | foo.forEach(function a(element) { 2 | bar(a) 3 | }) @@ -300,7 +379,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #25 +## Invalid #29 1 | foo.forEach(function a(element) { 2 | function b() { 3 | bar(a) @@ -318,7 +397,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #26 +## Invalid #30 1 | foo.forEach(function a(element) { 2 | function b(a) { 3 | bar(a) @@ -346,7 +425,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #27 +## Invalid #31 1 | foo.forEach(function(element) { 2 | bar(this) 3 | }) @@ -360,7 +439,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #28 +## Invalid #32 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(this) @@ -388,7 +467,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #29 +## Invalid #33 1 | foo.forEach(function(element) { 2 | const x = b => { 3 | bar(this) @@ -416,7 +495,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #30 +## Invalid #34 1 | foo.forEach((element) => { 2 | bar(this) 3 | }) @@ -438,7 +517,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #31 +## Invalid #35 1 | foo.forEach(function(element) { 2 | bar(arguments) 3 | }) @@ -460,7 +539,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #32 +## Invalid #36 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(arguments) @@ -488,7 +567,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #33 +## Invalid #37 1 | foo.forEach(function(element) { 2 | const b = () => { 3 | bar(arguments) @@ -516,7 +595,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #34 +## Invalid #38 1 | foo.forEach((element) => { 2 | bar(arguments) 3 | }) @@ -538,7 +617,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #35 +## Invalid #39 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -560,7 +639,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #36 +## Invalid #40 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -582,7 +661,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #37 +## Invalid #41 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -604,7 +683,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #38 +## Invalid #42 1 | foo.forEach((element) => bar(element)); > Output @@ -620,7 +699,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #39 +## Invalid #43 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -642,7 +721,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #40 +## Invalid #44 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -664,7 +743,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #41 +## Invalid #45 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -686,7 +765,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #42 +## Invalid #46 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -702,7 +781,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #43 +## Invalid #47 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -724,7 +803,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #44 +## Invalid #48 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -746,7 +825,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #45 +## Invalid #49 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -768,7 +847,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #46 +## Invalid #50 1 | foo.forEach((element) => bar(element),); > Output @@ -784,7 +863,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #47 +## Invalid #51 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -803,7 +882,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #48 +## Invalid #52 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -840,7 +919,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #49 +## Invalid #53 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index fdf836ecc591dff61d31aa98696bbfdc1e3fdb19..7b307f4a0e56e215d30a8b7a70a162519e0d25b7 100644 GIT binary patch literal 2805 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 Date: Mon, 18 Jan 2021 14:14:43 +0800 Subject: [PATCH 19/40] Clean --- rules/no-array-for-each.js | 47 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 32c81ce098..1cea6d3edc 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -185,18 +185,23 @@ const isChildScope = (child, parent) => { return false; }; -function isParameterSafeToFix(parameter, {scope, array, identifiers}) { +function isParameterSafeToFix(parameter, {scope, array, allIdentifiers}) { const {type, name: parameterName} = parameter; if (type !== 'Identifier') { return false; } const [arrayStart, arrayEnd] = array.range; - const identifiersInArray = identifiers.filter( - ({name, range: [start, end]}) => name === parameterName && start >= arrayStart && end <= arrayEnd - ); + for (const identifier of allIdentifiers) { + const {name, range: [start, end]} = identifier; + if ( + name !== parameterName || + start < arrayStart || + end > arrayEnd + ) { + continue; + } - for (const identifier of identifiersInArray) { const variable = findVariable(scope, identifier); if (!variable) { return false; @@ -210,7 +215,7 @@ function isParameterSafeToFix(parameter, {scope, array, identifiers}) { return true; } -function isFixable({callExpression, scope, identifiers}, sourceCode, functionInfo) { +function isFixable(callExpression, sourceCode, {scope, functionInfo, allIdentifiers}) { // Check `CallExpression` if ( callExpression.optional || @@ -245,7 +250,7 @@ function isFixable({callExpression, scope, identifiers}, sourceCode, functionInf const parameters = callback.params; if ( !(parameters.length === 1 || parameters.length === 2) || - parameters.some(parameter => !isParameterSafeToFix(parameter, {scope, array: callExpression, identifiers})) + parameters.some(parameter => !isParameterSafeToFix(parameter, {scope, array: callExpression, allIdentifiers})) ) { return false; } @@ -283,17 +288,17 @@ function isFixable({callExpression, scope, identifiers}, sourceCode, functionInf } const create = context => { - const functionStacks = []; - const nonArrowFunctionStacks = []; + const functionStack = []; + const nonArrowFunctionStack = []; const callExpressions = []; - const identifiers = []; + const allIdentifiers = []; const functionInfo = new Map(); const sourceCode = context.getSourceCode(); return { ':function'(node) { - functionStacks.push(node); + functionStack.push(node); functionInfo.set(node, { returnStatements: [], thisFound: false, @@ -301,18 +306,18 @@ const create = context => { }); if (node.type !== 'ArrowFunctionExpression') { - nonArrowFunctionStacks.push(node); + nonArrowFunctionStack.push(node); } }, ':function:exit'(node) { - functionStacks.pop(); + functionStack.pop(); if (node.type !== 'ArrowFunctionExpression') { - nonArrowFunctionStacks.pop(); + nonArrowFunctionStack.pop(); } }, ThisExpression() { - const currentNonArrowFunction = nonArrowFunctionStacks[functionStacks.length - 1]; + const currentNonArrowFunction = nonArrowFunctionStack[functionStack.length - 1]; if (!currentNonArrowFunction) { return; } @@ -321,10 +326,10 @@ const create = context => { currentFunctionInfo.thisFound = true; }, Identifier(node) { - identifiers.push(node); + allIdentifiers.push(node); }, ReturnStatement(node) { - const currentFunction = functionStacks[functionStacks.length - 1]; + const currentFunction = functionStack[functionStack.length - 1]; // `globalReturn ` /* istanbul ignore next: ESLint deprecated `ecmaFeatures`, can't test */ if (!currentFunction) { @@ -341,14 +346,14 @@ const create = context => { }); }, 'Program:exit'() { - for (const {node: callExpression, scope} of callExpressions) { + for (const {node, scope} of callExpressions) { const problem = { - node: callExpression.callee.property, + node: node.callee.property, messageId: MESSAGE_ID }; - if (isFixable({callExpression, scope, identifiers}, sourceCode, functionInfo)) { - problem.fix = getFixFunction(callExpression, sourceCode, functionInfo); + if (isFixable(node, sourceCode, {scope, allIdentifiers, functionInfo})) { + problem.fix = getFixFunction(node, sourceCode, functionInfo); } context.report(problem); From bfa8ea0f5cacf005f89f59f56fb7d2875d5eb7de Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 14:25:46 +0800 Subject: [PATCH 20/40] Simplify array parentheses check --- rules/no-array-for-each.js | 6 +--- test/no-array-for-each.js | 3 ++ test/snapshots/no-array-for-each.js.md | 44 +++++++++++++++++++---- test/snapshots/no-array-for-each.js.snap | Bin 2805 -> 2894 bytes 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 1cea6d3edc..92946da4f8 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -9,7 +9,6 @@ const { const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); -const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object'); const shouldAddParenthesesToExpressionStatementExpression = require('./utils/should-add-parentheses-to-expression-statement-expression'); const MESSAGE_ID = 'no-array-for-each'; @@ -56,10 +55,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { text += ' of '; let arrayText = sourceCode.getText(array); - if ( - isParenthesized(callExpression, sourceCode) || - (useEntries && shouldAddParenthesesToMemberExpressionObject(array, sourceCode)) - ) { + if (isParenthesized(array, sourceCode)) { arrayText = `(${arrayText})`; } diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 51597c14f5..b62e854ccd 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -191,6 +191,9 @@ test.visualize({ }); `, 'foo.forEach((element, index) => bar(element, index));', + // Array is parenthesized + '(foo).forEach((element, index) => bar(element, index))', + '(0, foo).forEach((element, index) => bar(element, index))', // Trailing comma outdent` foo.forEach(function (element) { diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index d3f8d3b9b8..72abaf002b 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -782,6 +782,38 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #47 + 1 | (foo).forEach((element, index) => bar(element, index)) + +> Output + + `␊ + 1 | for (const [element, index] of (foo).entries()) bar(element, index)␊ + ` + +> Error 1/1 + + `␊ + > 1 | (foo).forEach((element, index) => bar(element, index))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #48 + 1 | (0, foo).forEach((element, index) => bar(element, index)) + +> Output + + `␊ + 1 | for (const [element, index] of (0, foo).entries()) bar(element, index)␊ + ` + +> Error 1/1 + + `␊ + > 1 | (0, foo).forEach((element, index) => bar(element, index))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #49 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -803,7 +835,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #48 +## Invalid #50 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -825,7 +857,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #49 +## Invalid #51 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -847,7 +879,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #50 +## Invalid #52 1 | foo.forEach((element) => bar(element),); > Output @@ -863,7 +895,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #51 +## Invalid #53 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -882,7 +914,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #52 +## Invalid #54 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -919,7 +951,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #53 +## Invalid #55 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 7b307f4a0e56e215d30a8b7a70a162519e0d25b7..27148329a0524047d4b0e466933d73d0102c8eef 100644 GIT binary patch literal 2894 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 Date: Mon, 18 Jan 2021 14:37:34 +0800 Subject: [PATCH 21/40] Fix ASI problem --- rules/no-array-for-each.js | 10 ++++++++-- test/no-array-for-each.js | 2 +- test/snapshots/no-array-for-each.js.md | 2 +- test/snapshots/no-array-for-each.js.snap | Bin 2894 -> 2893 bytes 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 92946da4f8..e6760803e1 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -142,7 +142,9 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { } const nextToken = sourceCode.getTokenAfter(token); - if (nextToken && needsSemicolon(token, sourceCode, nextToken.value)) { + const lastTokenInCallback = sourceCode.getLastToken(callback); + + if (nextToken && needsSemicolon(lastTokenInCallback, sourceCode, nextToken.value)) { return false; } @@ -153,7 +155,11 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); // Remove call expression trailing comma - const [penultimateToken, lastToken] = sourceCode.getLastTokens(callExpression, 2); + const [ + penultimateToken, + lastToken + ] = sourceCode.getLastTokens(callExpression, 2); + if (isCommaToken(penultimateToken)) { yield fixer.remove(penultimateToken); } diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index b62e854ccd..4430493ecf 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -211,7 +211,7 @@ test.visualize({ },); `, 'foo.forEach((element) => bar(element),);', - // Can't remove semi + // Last semi token outdent` foo.forEach((element) => bar(element)) ;[foo].pop(); diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 72abaf002b..408bdc4b65 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -903,7 +903,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | for (const element of foo) bar(element)␊ - 2 | [foo].pop();␊ + 2 | ;[foo].pop();␊ ` > Error 1/1 diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 27148329a0524047d4b0e466933d73d0102c8eef..ad1f57e03cfc56b7b89138b2d14c342ef652db8a 100644 GIT binary patch literal 2893 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 literal 2894 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 Date: Mon, 18 Jan 2021 14:46:18 +0800 Subject: [PATCH 22/40] Fix parameter check --- rules/no-array-for-each.js | 6 +- test/snapshots/no-array-for-each.js.md | 123 ++++++++++++++--------- test/snapshots/no-array-for-each.js.snap | Bin 2893 -> 2979 bytes 3 files changed, 76 insertions(+), 53 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index e6760803e1..0b554dc33b 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -205,11 +205,7 @@ function isParameterSafeToFix(parameter, {scope, array, allIdentifiers}) { } const variable = findVariable(scope, identifier); - if (!variable) { - return false; - } - - if (!isChildScope(variable.scope, scope)) { + if (!variable || variable.scope === scope || isChildScope(scope, variable.scope)) { return false; } } diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 408bdc4b65..cc50972580 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -228,22 +228,31 @@ Generated by [AVA](https://avajs.dev). 1 | const foo = []; 2 | foo.forEach(foo => bar()); -> Output +> Error 1/1 `␊ 1 | const foo = [];␊ - 2 | for (const foo of foo) bar()␊ + > 2 | foo.forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` +## Invalid #20 + 1 | const foo = []; + 2 | function unicorn() { + 3 | foo.forEach(foo => bar()); + 4 | } + > Error 1/1 `␊ 1 | const foo = [];␊ - > 2 | foo.forEach(foo => bar());␊ - | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function unicorn() {␊ + > 3 | foo.forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 4 | }␊ ` -## Invalid #20 +## Invalid #21 1 | index.forEach((a, index) => bar()); > Error 1/1 @@ -253,26 +262,35 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #21 +## Invalid #22 1 | const index = []; 2 | index.forEach((a, index) => bar()); -> Output +> Error 1/1 `␊ 1 | const index = [];␊ - 2 | for (const [a, index] of index.entries()) bar()␊ + > 2 | index.forEach((a, index) => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` +## Invalid #23 + 1 | const index = []; + 2 | function unicorn() { + 3 | index.forEach((a, index) => bar()); + 4 | } + > Error 1/1 `␊ 1 | const index = [];␊ - > 2 | index.forEach((a, index) => bar());␊ - | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function unicorn() {␊ + > 3 | index.forEach((a, index) => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 4 | }␊ ` -## Invalid #22 +## Invalid #24 1 | a[foo].forEach(foo => bar()); > Error 1/1 @@ -282,26 +300,35 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #23 +## Invalid #25 1 | const foo = 1; 2 | a[foo].forEach(foo => bar()); -> Output +> Error 1/1 `␊ 1 | const foo = 1;␊ - 2 | for (const foo of a[foo]) bar()␊ + > 2 | a[foo].forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` +## Invalid #26 + 1 | const foo = 1; + 2 | function unicorn() { + 3 | a[foo].forEach(foo => bar()); + 4 | } + > Error 1/1 `␊ 1 | const foo = 1;␊ - > 2 | a[foo].forEach(foo => bar());␊ - | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | function unicorn() {␊ + > 3 | a[foo].forEach(foo => bar());␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 4 | }␊ ` -## Invalid #24 +## Invalid #27 1 | a[index].forEach((b, index) => bar()); > Error 1/1 @@ -311,7 +338,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #25 +## Invalid #28 1 | a((foo) => foo).forEach(foo => bar()); > Output @@ -327,7 +354,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #26 +## Invalid #29 1 | a((foo, index) => foo + index).forEach((foo, index) => bar()); > Output @@ -343,7 +370,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #27 +## Invalid #30 1 | const foo = []; 2 | const index = 1; 3 | a.forEach((foo, index) => foo[index]); @@ -365,7 +392,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #28 +## Invalid #31 1 | foo.forEach(function a(element) { 2 | bar(a) 3 | }) @@ -379,7 +406,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #29 +## Invalid #32 1 | foo.forEach(function a(element) { 2 | function b() { 3 | bar(a) @@ -397,7 +424,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #30 +## Invalid #33 1 | foo.forEach(function a(element) { 2 | function b(a) { 3 | bar(a) @@ -425,7 +452,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #31 +## Invalid #34 1 | foo.forEach(function(element) { 2 | bar(this) 3 | }) @@ -439,7 +466,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #32 +## Invalid #35 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(this) @@ -467,7 +494,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #33 +## Invalid #36 1 | foo.forEach(function(element) { 2 | const x = b => { 3 | bar(this) @@ -495,7 +522,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #34 +## Invalid #37 1 | foo.forEach((element) => { 2 | bar(this) 3 | }) @@ -517,7 +544,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #35 +## Invalid #38 1 | foo.forEach(function(element) { 2 | bar(arguments) 3 | }) @@ -539,7 +566,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #36 +## Invalid #39 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(arguments) @@ -567,7 +594,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #37 +## Invalid #40 1 | foo.forEach(function(element) { 2 | const b = () => { 3 | bar(arguments) @@ -595,7 +622,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #38 +## Invalid #41 1 | foo.forEach((element) => { 2 | bar(arguments) 3 | }) @@ -617,7 +644,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #39 +## Invalid #42 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -639,7 +666,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #40 +## Invalid #43 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -661,7 +688,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #41 +## Invalid #44 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -683,7 +710,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #42 +## Invalid #45 1 | foo.forEach((element) => bar(element)); > Output @@ -699,7 +726,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #43 +## Invalid #46 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -721,7 +748,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #44 +## Invalid #47 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -743,7 +770,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #45 +## Invalid #48 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -765,7 +792,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #46 +## Invalid #49 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -781,7 +808,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #47 +## Invalid #50 1 | (foo).forEach((element, index) => bar(element, index)) > Output @@ -797,7 +824,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #48 +## Invalid #51 1 | (0, foo).forEach((element, index) => bar(element, index)) > Output @@ -813,7 +840,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #49 +## Invalid #52 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -835,7 +862,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #50 +## Invalid #53 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -857,7 +884,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #51 +## Invalid #54 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -879,7 +906,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #52 +## Invalid #55 1 | foo.forEach((element) => bar(element),); > Output @@ -895,7 +922,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #53 +## Invalid #56 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -914,7 +941,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #54 +## Invalid #57 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -951,7 +978,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #55 +## Invalid #58 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index ad1f57e03cfc56b7b89138b2d14c342ef652db8a..384d0e6575e2e1ac8d3c5c3209ea1ff95cad0aad 100644 GIT binary patch literal 2979 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 From 2bcc256f9059c836226a2c4dc1a94064ad1102b1 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 14:52:38 +0800 Subject: [PATCH 23/40] Add `return` in `switch` --- test/no-array-for-each.js | 29 ++++++ test/snapshots/no-array-for-each.js.md | 117 +++++++++++++++-------- test/snapshots/no-array-for-each.js.snap | Bin 2979 -> 3061 bytes 3 files changed, 106 insertions(+), 40 deletions(-) diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 4430493ecf..a62c56e0ca 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -59,6 +59,17 @@ test.visualize({ } }); `, + // `ReturnStatement` in `switch` is fixable + outdent` + foo.forEach(element => { + switch (element) { + case 1: + break; + case 2: + return; + } + }); + `, // `parameters` 'foo.forEach(foo => bar());', @@ -66,16 +77,34 @@ test.visualize({ const foo = []; foo.forEach(foo => bar()); `, + outdent` + const foo = []; + function unicorn() { + foo.forEach(foo => bar()); + } + `, 'index.forEach((a, index) => bar());', outdent` const index = []; index.forEach((a, index) => bar()); `, + outdent` + const index = []; + function unicorn() { + index.forEach((a, index) => bar()); + } + `, 'a[foo].forEach(foo => bar());', outdent` const foo = 1; a[foo].forEach(foo => bar()); `, + outdent` + const foo = 1; + function unicorn() { + a[foo].forEach(foo => bar()); + } + `, 'a[index].forEach((b, index) => bar());', 'a((foo) => foo).forEach(foo => bar());', 'a((foo, index) => foo + index).forEach((foo, index) => bar());', diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index cc50972580..c392b3002c 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -215,6 +215,43 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #18 + 1 | foo.forEach(element => { + 2 | switch (element) { + 3 | case 1: + 4 | break; + 5 | case 2: + 6 | return; + 7 | } + 8 | }); + +> Output + + `␊ + 1 | for (const element of foo) {␊ + 2 | switch (element) {␊ + 3 | case 1:␊ + 4 | break;␊ + 5 | case 2:␊ + 6 | continue;␊ + 7 | }␊ + 8 | }␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => {␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + 2 | switch (element) {␊ + 3 | case 1:␊ + 4 | break;␊ + 5 | case 2:␊ + 6 | return;␊ + 7 | }␊ + 8 | });␊ + ` + +## Invalid #19 1 | foo.forEach(foo => bar()); > Error 1/1 @@ -224,7 +261,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #19 +## Invalid #20 1 | const foo = []; 2 | foo.forEach(foo => bar()); @@ -236,7 +273,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #20 +## Invalid #21 1 | const foo = []; 2 | function unicorn() { 3 | foo.forEach(foo => bar()); @@ -252,7 +289,7 @@ Generated by [AVA](https://avajs.dev). 4 | }␊ ` -## Invalid #21 +## Invalid #22 1 | index.forEach((a, index) => bar()); > Error 1/1 @@ -262,7 +299,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #22 +## Invalid #23 1 | const index = []; 2 | index.forEach((a, index) => bar()); @@ -274,7 +311,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #23 +## Invalid #24 1 | const index = []; 2 | function unicorn() { 3 | index.forEach((a, index) => bar()); @@ -290,7 +327,7 @@ Generated by [AVA](https://avajs.dev). 4 | }␊ ` -## Invalid #24 +## Invalid #25 1 | a[foo].forEach(foo => bar()); > Error 1/1 @@ -300,7 +337,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #25 +## Invalid #26 1 | const foo = 1; 2 | a[foo].forEach(foo => bar()); @@ -312,7 +349,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #26 +## Invalid #27 1 | const foo = 1; 2 | function unicorn() { 3 | a[foo].forEach(foo => bar()); @@ -328,7 +365,7 @@ Generated by [AVA](https://avajs.dev). 4 | }␊ ` -## Invalid #27 +## Invalid #28 1 | a[index].forEach((b, index) => bar()); > Error 1/1 @@ -338,7 +375,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #28 +## Invalid #29 1 | a((foo) => foo).forEach(foo => bar()); > Output @@ -354,7 +391,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #29 +## Invalid #30 1 | a((foo, index) => foo + index).forEach((foo, index) => bar()); > Output @@ -370,7 +407,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #30 +## Invalid #31 1 | const foo = []; 2 | const index = 1; 3 | a.forEach((foo, index) => foo[index]); @@ -392,7 +429,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #31 +## Invalid #32 1 | foo.forEach(function a(element) { 2 | bar(a) 3 | }) @@ -406,7 +443,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #32 +## Invalid #33 1 | foo.forEach(function a(element) { 2 | function b() { 3 | bar(a) @@ -424,7 +461,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #33 +## Invalid #34 1 | foo.forEach(function a(element) { 2 | function b(a) { 3 | bar(a) @@ -452,7 +489,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #34 +## Invalid #35 1 | foo.forEach(function(element) { 2 | bar(this) 3 | }) @@ -466,7 +503,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #35 +## Invalid #36 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(this) @@ -494,7 +531,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #36 +## Invalid #37 1 | foo.forEach(function(element) { 2 | const x = b => { 3 | bar(this) @@ -522,7 +559,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #37 +## Invalid #38 1 | foo.forEach((element) => { 2 | bar(this) 3 | }) @@ -544,7 +581,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #38 +## Invalid #39 1 | foo.forEach(function(element) { 2 | bar(arguments) 3 | }) @@ -566,7 +603,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #39 +## Invalid #40 1 | foo.forEach(function(element) { 2 | function b() { 3 | bar(arguments) @@ -594,7 +631,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #40 +## Invalid #41 1 | foo.forEach(function(element) { 2 | const b = () => { 3 | bar(arguments) @@ -622,7 +659,7 @@ Generated by [AVA](https://avajs.dev). 5 | })␊ ` -## Invalid #41 +## Invalid #42 1 | foo.forEach((element) => { 2 | bar(arguments) 3 | }) @@ -644,7 +681,7 @@ Generated by [AVA](https://avajs.dev). 3 | })␊ ` -## Invalid #42 +## Invalid #43 1 | foo.forEach(function (element) { 2 | bar(element); 3 | }); @@ -666,7 +703,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #43 +## Invalid #44 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | }); @@ -688,7 +725,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #44 +## Invalid #45 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -710,7 +747,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #45 +## Invalid #46 1 | foo.forEach((element) => bar(element)); > Output @@ -726,7 +763,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #46 +## Invalid #47 1 | foo.forEach(function (element, index) { 2 | bar(element, index); 3 | }); @@ -748,7 +785,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #47 +## Invalid #48 1 | foo.forEach(function withName(element, index) { 2 | bar(element, index); 3 | }); @@ -770,7 +807,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #48 +## Invalid #49 1 | foo.forEach((element, index) => { 2 | bar(element, index); 3 | }); @@ -792,7 +829,7 @@ Generated by [AVA](https://avajs.dev). 3 | });␊ ` -## Invalid #49 +## Invalid #50 1 | foo.forEach((element, index) => bar(element, index)); > Output @@ -808,7 +845,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #50 +## Invalid #51 1 | (foo).forEach((element, index) => bar(element, index)) > Output @@ -824,7 +861,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #51 +## Invalid #52 1 | (0, foo).forEach((element, index) => bar(element, index)) > Output @@ -840,7 +877,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #52 +## Invalid #53 1 | foo.forEach(function (element) { 2 | bar(element); 3 | },); @@ -862,7 +899,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #53 +## Invalid #54 1 | foo.forEach(function withName(element) { 2 | bar(element); 3 | },); @@ -884,7 +921,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #54 +## Invalid #55 1 | foo.forEach((element) => { 2 | bar(element); 3 | },); @@ -906,7 +943,7 @@ Generated by [AVA](https://avajs.dev). 3 | },);␊ ` -## Invalid #55 +## Invalid #56 1 | foo.forEach((element) => bar(element),); > Output @@ -922,7 +959,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #56 +## Invalid #57 1 | foo.forEach((element) => bar(element)) 2 | ;[foo].pop(); @@ -941,7 +978,7 @@ Generated by [AVA](https://avajs.dev). 2 | ;[foo].pop();␊ ` -## Invalid #57 +## Invalid #58 1 | foo.forEach((element) => { 2 | bar(element); 3 | }); @@ -978,7 +1015,7 @@ Generated by [AVA](https://avajs.dev). 8 | }␊ ` -## Invalid #58 +## Invalid #59 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 384d0e6575e2e1ac8d3c5c3209ea1ff95cad0aad..f3f24c0d84f891c7cf1676296231ece868a7f3cf 100644 GIT binary patch literal 3061 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 Dy@ma; literal 2979 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 Date: Mon, 18 Jan 2021 15:13:33 +0800 Subject: [PATCH 24/40] Fix parenthesized callback --- rules/no-array-for-each.js | 20 ++++++++++++++++++++ test/no-array-for-each.js | 2 ++ test/snapshots/no-array-for-each.js.md | 16 ++++++++++++++++ test/snapshots/no-array-for-each.js.snap | Bin 3061 -> 3107 bytes 4 files changed, 38 insertions(+) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 0b554dc33b..73826e8aca 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -4,12 +4,14 @@ const { isArrowToken, isCommaToken, isSemicolonToken, + isClosingParenToken, findVariable } = require('eslint-utils'); const getDocumentationUrl = require('./utils/get-documentation-url'); const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); const shouldAddParenthesesToExpressionStatementExpression = require('./utils/should-add-parentheses-to-expression-statement-expression'); +const getParenthesizedTimes = require('./utils/get-parenthesized-times'); const MESSAGE_ID = 'no-array-for-each'; const messages = { @@ -151,9 +153,27 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { return true; }; + function * removeCallbackParenthesis(fixer) { + const parenthesizedTimes = getParenthesizedTimes(callback, sourceCode); + if (parenthesizedTimes > 0) { + // Opening parenthesis tokens already included in `getForOfLoopHeadRange` + + const closingParenthesisTokens = sourceCode.getTokensAfter( + callback, + {count: parenthesizedTimes, filter: isClosingParenToken} + ); + + for (const closingParenthesisToken of closingParenthesisTokens) { + yield fixer.remove(closingParenthesisToken); + } + } + }; + return function * (fixer) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); + yield * removeCallbackParenthesis(fixer); + // Remove call expression trailing comma const [ penultimateToken, diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index a62c56e0ca..1f93be3a56 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -255,6 +255,8 @@ test.visualize({ } } `, + // `callback` is parenthesized + `foo.forEach((((((element => bar(element)))))));`, outdent` foo.forEach((element) => { if (1) { diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index c392b3002c..1ee297b234 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -1016,6 +1016,22 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #59 + 1 | foo.forEach((((((element => bar(element))))))); + +> Output + + `␊ + 1 | for (const element of foo) bar(element)␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach((((((element => bar(element)))))));␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #60 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index f3f24c0d84f891c7cf1676296231ece868a7f3cf..34840743d924c96222f8bfac31dd949f7d4e0ba9 100644 GIT binary patch literal 3107 zcmV+;4BYcURzVTaosO`fXZ%O8sf00000000Bc zS_xQFM;@Q|lu|&!qavO>K{0_KB%pvnM7$AC)KxL+1A>V_f=Q4|6sodyYu8(g_ff67 z`l+l|JiGPttSHv|!n0m=1+m5IYIWz$dkM+Q3*-XL_x;8EX8tq(bLKxYadiYB95^q0 z_f&9ro}@I-Vem!&n~gC*ebkVgpYHzOza+nm>3#Rous^EOQZR(JgB=>(T;*~xF~>Xd zw+4Gaspn`6p(`OZe?RDQdbIqqdW~d7)$E^P3x&GlkV1D2+;^{hXGS;^afF^@D61g= zorN7{e%{|Z#BtB_s?Zb{5=ZDhhIkGD1Uy}~Xzt~gL;hYF>lNMo+e#dvnGAh^6k6=N z_K9lD_LJm{0z#VdC;{{;_irj?i~bG(BkqKu^D- zS+a_6!Xj@uri?9b<%uISs4-2uAoWZ?@Zr{_Y1>B$xF3$t-x<2v6o7#R1&+h+Ef?)pdY_opfB#Vo zp&88ph~D$0?4HAkzM) zttvc*y6xYMA+$pa03;1|p1LsghV!FYx!bn|cF)5QnoYI*c`e$b>&Y7xq3+uQ24bJU9%&tnT4AILAifFpDr zLtY*LB>TMmJveG)Mr>)1HIfZKzQ+)H3{uK9Y~MA{pe=nGNBC<-mgHjymA3*Q)#dew z+lQ`x*EUsiN7B!^JBHAoA*li%WkpAA^6Uy6%I^9;9E2mZRco5ILDDQLi%?-Xe>MEF zbiwnGs@FI|pD;A34UF0b#r->vDRnyY-s`h+kt`cW=uU=0+QJ^QPP@8CF57fcedcg- zH`f^$LJvdAZl}&1=5kNyF$_F#JaBg%j!?IDG%bRZqlsK{XnKdiGH2KLvf09I7(!jz z1CYO?Ps>XInH!599!vW*SvVd?XeLALJONlxAn`6a<*|2?r+3SOi>C-2p(zZNLs}O2 zU`uOW!=j^U8n4A|e{;eS>QB(L1=7l?j)LH+JMn;eQr*=f%Ez z+|>(5=xT=AbOPXr>l5kG@Y`)R+!<``^W2O0DUY@` zz!6%=P;h4ee%yC(Y<5gYLx+6}Cr9==B)|~5AJWnD=kupE7Z1wn+v#P+IrTvdp#eMq zPOgo(lX@pUvqizh%;ArH3owLUf>h$YS9~Slbf@uGe46&=@6EyxI)D$?&-F_tu3z;= zzWmRwDfz8kVVqIua)$W60F-VSwP(fUrmW?q&U6F<-!XL zp_{0dqdr>%C&BR>n#D0UD-$blg!c2N$-N5zFP4^18L`*(lBmLSlhu{dE$xxF3 z0IDu_e0%D;&*?V#JMhb@oWmGG4?%jhYjE=)o=b|G1>34B2WzfgcBn8$Ip+C#tou6IjN+Ybd^F3zXwy_bK!rw!vEy*#RigMX|RD3 zG(o9QYbbHyph7W}o|=n{gMdV*0BWUe#pjFlRIt`gSZd8?qGn>g@&$xOCRg`TO-@H& zZFLdWi%}ezlh$54voeVih_)s&xxO4?#>BaX!{u;jl9aAU(8!evLdR^A<2j`eupK(F zCP94lMai|@h*ArTNH@pB_~P-kIY7rMr5MRLR?RmGS;N#?#g$rG1?^*Kt0mllQ%A$J1TvZd3HogD`GXq_{oEX)W4LvW--R-HSFTMCvP<1A21mniW(lF#;gZIQX8 zrpP2n`>1T8god`j@8i_eW>|xsOrAvWgbYAW135HuMYZaogVRMC==AuPUSE!`W zRb+gMl!p>gq!V1k7FdLG31flzyl^%3gI^NAn4Lt_4vV!isHoQd)T^b8_dnxq!s{siNzb$G{; zs5H7t(ZvYC65QFu&5F7nP6N8CpKBeRUxxJrP&6V^_DjmOrj)?L)* z!mCyhl1&`&X~Wjx!Fr+vp-MMXK94tk1TyDf%eiLP#Y>e%GV<#*dFy;HuQhFj#tKnE zq$|v{r4)DlrF)TPbvEk_+{U^}d&uCK@fvQBm{!g=fWud|@6j!AxBoG{D1nYj#{C^;EKIu9)003QM^+*5! literal 3061 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 Dy@ma; From 2599ae53d98840e9f1a1a699f2efc525c1288205 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 15:16:22 +0800 Subject: [PATCH 25/40] Keep `semi` for arrow functions --- rules/no-array-for-each.js | 9 +-------- test/snapshots/no-array-for-each.js.md | 14 +++++++------- test/snapshots/no-array-for-each.js.snap | Bin 3107 -> 3110 bytes 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 73826e8aca..22dfe42321 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -139,14 +139,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { return false; } - if (callback.body.type === 'BlockStatement') { - return true; - } - - const nextToken = sourceCode.getTokenAfter(token); - const lastTokenInCallback = sourceCode.getLastToken(callback); - - if (nextToken && needsSemicolon(lastTokenInCallback, sourceCode, nextToken.value)) { + if (callback.body.type !== 'BlockStatement') { return false; } diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 1ee297b234..8d22a2c42b 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -381,7 +381,7 @@ Generated by [AVA](https://avajs.dev). > Output `␊ - 1 | for (const foo of a((foo) => foo)) bar()␊ + 1 | for (const foo of a((foo) => foo)) bar();␊ ` > Error 1/1 @@ -397,7 +397,7 @@ Generated by [AVA](https://avajs.dev). > Output `␊ - 1 | for (const [foo, index] of a((foo, index) => foo + index).entries()) bar()␊ + 1 | for (const [foo, index] of a((foo, index) => foo + index).entries()) bar();␊ ` > Error 1/1 @@ -417,7 +417,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | const foo = [];␊ 2 | const index = 1;␊ - 3 | for (const [foo, index] of a.entries()) foo[index]␊ + 3 | for (const [foo, index] of a.entries()) foo[index];␊ ` > Error 1/1 @@ -753,7 +753,7 @@ Generated by [AVA](https://avajs.dev). > Output `␊ - 1 | for (const element of foo) bar(element)␊ + 1 | for (const element of foo) bar(element);␊ ` > Error 1/1 @@ -835,7 +835,7 @@ Generated by [AVA](https://avajs.dev). > Output `␊ - 1 | for (const [element, index] of foo.entries()) bar(element, index)␊ + 1 | for (const [element, index] of foo.entries()) bar(element, index);␊ ` > Error 1/1 @@ -949,7 +949,7 @@ Generated by [AVA](https://avajs.dev). > Output `␊ - 1 | for (const element of foo) bar(element)␊ + 1 | for (const element of foo) bar(element);␊ ` > Error 1/1 @@ -1021,7 +1021,7 @@ Generated by [AVA](https://avajs.dev). > Output `␊ - 1 | for (const element of foo) bar(element)␊ + 1 | for (const element of foo) bar(element);␊ ` > Error 1/1 diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 34840743d924c96222f8bfac31dd949f7d4e0ba9..93f32dce0acc33e9403a0ccd01aa74152602c724 100644 GIT binary patch literal 3110 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 Awg3PC literal 3107 zcmV+;4BYcURzVTaosO`fXZ%O8sf00000000Bc zS_xQFM;@Q|lu|&!qavO>K{0_KB%pvnM7$AC)KxL+1A>V_f=Q4|6sodyYu8(g_ff67 z`l+l|JiGPttSHv|!n0m=1+m5IYIWz$dkM+Q3*-XL_x;8EX8tq(bLKxYadiYB95^q0 z_f&9ro}@I-Vem!&n~gC*ebkVgpYHzOza+nm>3#Rous^EOQZR(JgB=>(T;*~xF~>Xd zw+4Gaspn`6p(`OZe?RDQdbIqqdW~d7)$E^P3x&GlkV1D2+;^{hXGS;^afF^@D61g= zorN7{e%{|Z#BtB_s?Zb{5=ZDhhIkGD1Uy}~Xzt~gL;hYF>lNMo+e#dvnGAh^6k6=N z_K9lD_LJm{0z#VdC;{{;_irj?i~bG(BkqKu^D- zS+a_6!Xj@uri?9b<%uISs4-2uAoWZ?@Zr{_Y1>B$xF3$t-x<2v6o7#R1&+h+Ef?)pdY_opfB#Vo zp&88ph~D$0?4HAkzM) zttvc*y6xYMA+$pa03;1|p1LsghV!FYx!bn|cF)5QnoYI*c`e$b>&Y7xq3+uQ24bJU9%&tnT4AILAifFpDr zLtY*LB>TMmJveG)Mr>)1HIfZKzQ+)H3{uK9Y~MA{pe=nGNBC<-mgHjymA3*Q)#dew z+lQ`x*EUsiN7B!^JBHAoA*li%WkpAA^6Uy6%I^9;9E2mZRco5ILDDQLi%?-Xe>MEF zbiwnGs@FI|pD;A34UF0b#r->vDRnyY-s`h+kt`cW=uU=0+QJ^QPP@8CF57fcedcg- zH`f^$LJvdAZl}&1=5kNyF$_F#JaBg%j!?IDG%bRZqlsK{XnKdiGH2KLvf09I7(!jz z1CYO?Ps>XInH!599!vW*SvVd?XeLALJONlxAn`6a<*|2?r+3SOi>C-2p(zZNLs}O2 zU`uOW!=j^U8n4A|e{;eS>QB(L1=7l?j)LH+JMn;eQr*=f%Ez z+|>(5=xT=AbOPXr>l5kG@Y`)R+!<``^W2O0DUY@` zz!6%=P;h4ee%yC(Y<5gYLx+6}Cr9==B)|~5AJWnD=kupE7Z1wn+v#P+IrTvdp#eMq zPOgo(lX@pUvqizh%;ArH3owLUf>h$YS9~Slbf@uGe46&=@6EyxI)D$?&-F_tu3z;= zzWmRwDfz8kVVqIua)$W60F-VSwP(fUrmW?q&U6F<-!XL zp_{0dqdr>%C&BR>n#D0UD-$blg!c2N$-N5zFP4^18L`*(lBmLSlhu{dE$xxF3 z0IDu_e0%D;&*?V#JMhb@oWmGG4?%jhYjE=)o=b|G1>34B2WzfgcBn8$Ip+C#tou6IjN+Ybd^F3zXwy_bK!rw!vEy*#RigMX|RD3 zG(o9QYbbHyph7W}o|=n{gMdV*0BWUe#pjFlRIt`gSZd8?qGn>g@&$xOCRg`TO-@H& zZFLdWi%}ezlh$54voeVih_)s&xxO4?#>BaX!{u;jl9aAU(8!evLdR^A<2j`eupK(F zCP94lMai|@h*ArTNH@pB_~P-kIY7rMr5MRLR?RmGS;N#?#g$rG1?^*Kt0mllQ%A$J1TvZd3HogD`GXq_{oEX)W4LvW--R-HSFTMCvP<1A21mniW(lF#;gZIQX8 zrpP2n`>1T8god`j@8i_eW>|xsOrAvWgbYAW135HuMYZaogVRMC==AuPUSE!`W zRb+gMl!p>gq!V1k7FdLG31flzyl^%3gI^NAn4Lt_4vV!isHoQd)T^b8_dnxq!s{siNzb$G{; zs5H7t(ZvYC65QFu&5F7nP6N8CpKBeRUxxJrP&6V^_DjmOrj)?L)* z!mCyhl1&`&X~Wjx!Fr+vp-MMXK94tk1TyDf%eiLP#Y>e%GV<#*dFy;HuQhFj#tKnE zq$|v{r4)DlrF)TPbvEk_+{U^}d&uCK@fvQBm{!g=fWud|@6j!AxBoG{D1nYj#{C^;EKIu9)003QM^+*5! From edd49ba6c58a6b9431be5db7ee83eb58c264e8e3 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 15:27:38 +0800 Subject: [PATCH 26/40] Ignore unreachable --- rules/no-array-for-each.js | 1 + 1 file changed, 1 insertion(+) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 22dfe42321..16c1f9bd1e 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -242,6 +242,7 @@ function isFixable(callExpression, sourceCode, {scope, functionInfo, allIdentifi } // Check `CallExpression.callee` + /* istanbul ignore next: Because of `ChainExpression` wrapper, `foo?.forEach()` is already failed on previous check, keep this just for safety */ if (callExpression.callee.optional) { return false; } From 80cde6429889b81c8871b3481a557d33fdae49ea Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 15:32:53 +0800 Subject: [PATCH 27/40] Fix style --- rules/no-array-for-each.js | 2 +- test/no-array-for-each.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 16c1f9bd1e..ba6ef57b9d 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -160,7 +160,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { yield fixer.remove(closingParenthesisToken); } } - }; + } return function * (fixer) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 1f93be3a56..f252ea7e50 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -256,7 +256,7 @@ test.visualize({ } `, // `callback` is parenthesized - `foo.forEach((((((element => bar(element)))))));`, + 'foo.forEach((((((element => bar(element)))))));', outdent` foo.forEach((element) => { if (1) { From 0917e76dee22dd08758a19b5c371ca8d84811c79 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 15:46:37 +0800 Subject: [PATCH 28/40] Fix `arguments` check --- rules/no-array-for-each.js | 2 +- test/snapshots/no-array-for-each.js.md | 8 -------- test/snapshots/no-array-for-each.js.snap | Bin 3110 -> 3105 bytes 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index ba6ef57b9d..570aec257d 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -282,7 +282,7 @@ function isFixable(callExpression, sourceCode, {scope, functionInfo, allIdentifi const argumentsVariable = findVariable(callbackScope, 'arguments'); if ( argumentsVariable && - argumentsVariable.references.some(reference => reference.from === scope) + argumentsVariable.references.some(reference => reference.from === callbackScope) ) { return false; } diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index 8d22a2c42b..e844f58970 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -586,14 +586,6 @@ Generated by [AVA](https://avajs.dev). 2 | bar(arguments) 3 | }) -> Output - - `␊ - 1 | for (const element of foo) {␊ - 2 | bar(arguments)␊ - 3 | }␊ - ` - > Error 1/1 `␊ diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 93f32dce0acc33e9403a0ccd01aa74152602c724..6be9890751a4fe0085b0ba7229c97be5d0681f52 100644 GIT binary patch literal 3105 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 literal 3110 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 Awg3PC From c33b4260863898e7ab7fd172c76787b484bba169 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 15:53:10 +0800 Subject: [PATCH 29/40] Test possible conflicts --- .../conflicts-no-array-for-each-and-prevent-abbreviations.js | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 test/integration/unicorn/conflicts-no-array-for-each-and-prevent-abbreviations.js diff --git a/test/integration/unicorn/conflicts-no-array-for-each-and-prevent-abbreviations.js b/test/integration/unicorn/conflicts-no-array-for-each-and-prevent-abbreviations.js new file mode 100644 index 0000000000..0383a2dd38 --- /dev/null +++ b/test/integration/unicorn/conflicts-no-array-for-each-and-prevent-abbreviations.js @@ -0,0 +1,2 @@ +const btn = bar; +foo.forEach(btn => click(btn)) From 078e93bb9f51382b7e615b790f78aee69b07cf84 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 15:55:39 +0800 Subject: [PATCH 30/40] Extend fix range --- rules/no-array-for-each.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 570aec257d..b159c4aba8 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -12,6 +12,7 @@ const methodSelector = require('./utils/method-selector'); const needsSemicolon = require('./utils/needs-semicolon'); const shouldAddParenthesesToExpressionStatementExpression = require('./utils/should-add-parentheses-to-expression-statement-expression'); const getParenthesizedTimes = require('./utils/get-parenthesized-times'); +const extendFixRange = require('./utils/extend-fix-range'); const MESSAGE_ID = 'no-array-for-each'; const messages = { @@ -187,6 +188,9 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { if (shouldRemoveExpressionStatementLastToken(expressionStatementLastToken)) { yield fixer.remove(expressionStatementLastToken, fixer); } + + // Prevent possible conflicts + yield * extendFixRange(fixer, callExpression.parent.range); }; } From f035acaff0f25aa1c61364fb505e859532fd5f5b Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 16:19:26 +0800 Subject: [PATCH 31/40] Add docs --- docs/rules/no-array-for-each.md | 36 +++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/docs/rules/no-array-for-each.md b/docs/rules/no-array-for-each.md index 94db7d5264..d7ee3df469 100644 --- a/docs/rules/no-array-for-each.md +++ b/docs/rules/no-array-for-each.md @@ -1,17 +1,45 @@ -# Prefer `for…of` over `Array#forEach(…)`. +# Prefer `for…of` over `Array#forEach(…)` - +[`for…of` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) is more readable than [`Array#forEach(…)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). This rule is partly fixable. ## Fail ```js -const foo = 'unicorn'; +array.forEach(element => { + bar(element); +}); +``` + +```js +array.forEach((element, index) => { + bar(element, index); +}); +``` + +```js +array.forEach((element, index, array) => { + bar(element, index, array); +}); ``` ## Pass ```js -const foo = 'πŸ¦„'; +for (const element of array) { + bar(element); +} +``` + +```js +for (const [index, element] of array.entries()) { + bar(element, index); +} +``` + +```js +for (const [index, element] of array.entries) { + bar(element, index, array); +} ``` From 4941a08691d7971e3223eba2926d2c068d282e22 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 16:24:56 +0800 Subject: [PATCH 32/40] Fix `lint` --- rules/no-unused-properties.js | 16 ++++++++++------ rules/prevent-abbreviations.js | 8 ++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/rules/no-unused-properties.js b/rules/no-unused-properties.js index aa22ed79a3..3eea993f64 100644 --- a/rules/no-unused-properties.js +++ b/rules/no-unused-properties.js @@ -118,15 +118,15 @@ const create = context => { }; const checkProperties = (objectExpression, references, path = []) => { - objectExpression.properties.forEach(property => { + for (const property of objectExpression.properties) { const {key} = property; if (!key) { - return; + continue; } if (propertyKeysEqual(key, specialProtoPropertyKey)) { - return; + continue; } const nextPath = path.concat(key); @@ -187,7 +187,7 @@ const create = context => { .filter(Boolean); checkProperty(property, nextReferences, nextPath); - }); + } }; const checkObject = (declaratorOrProperty, references, path) => { @@ -215,11 +215,15 @@ const create = context => { }; const checkVariables = scope => { - scope.variables.forEach(variable => checkVariable(variable)); + for (const variable of scope.variables) { + checkVariable(variable); + } }; const checkChildScopes = scope => { - scope.childScopes.forEach(scope => checkScope(scope)); + for (const childScope of scope.childScopes) { + checkScope(childScope); + } }; const checkScope = scope => { diff --git a/rules/prevent-abbreviations.js b/rules/prevent-abbreviations.js index 1af88d2f3e..041bd6ebcb 100644 --- a/rules/prevent-abbreviations.js +++ b/rules/prevent-abbreviations.js @@ -673,11 +673,15 @@ const create = context => { }; const checkVariables = scope => { - scope.variables.forEach(variable => checkPossiblyWeirdClassVariable(variable)); + for (const variable of scope.variables) { + checkPossiblyWeirdClassVariable(variable); + } }; const checkChildScopes = scope => { - scope.childScopes.forEach(scope => checkScope(scope)); + for (const childScope of scope.childScopes) { + checkScope(childScope); + } }; const checkScope = scope => { From e32cb9ffdd94b22a698b27f6bc899fa37759dd65 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 16:33:40 +0800 Subject: [PATCH 33/40] Rename a function --- rules/no-array-for-each.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index b159c4aba8..c55e4f176e 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -147,7 +147,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { return true; }; - function * removeCallbackParenthesis(fixer) { + function * removeCallbackParentheses(fixer) { const parenthesizedTimes = getParenthesizedTimes(callback, sourceCode); if (parenthesizedTimes > 0) { // Opening parenthesis tokens already included in `getForOfLoopHeadRange` @@ -166,7 +166,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { return function * (fixer) { yield fixer.replaceTextRange(getForOfLoopHeadRange(), getForOfLoopHeadText()); - yield * removeCallbackParenthesis(fixer); + yield * removeCallbackParentheses(fixer); // Remove call expression trailing comma const [ From 34e5a58c5d0bc97c100b3cb570a279a3f16f376b Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 22:42:07 +0800 Subject: [PATCH 34/40] Improve `=>` token search, fix crash on `typescript` parser --- rules/no-array-for-each.js | 6 +++- test/no-array-for-each.js | 66 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index c55e4f176e..ebe6c257fa 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -79,7 +79,7 @@ function getFixFunction(callExpression, sourceCode, functionInfo) { if (callback.body.type === 'BlockStatement') { end = callback.body.range[0]; } else { - const arrowToken = sourceCode.getFirstToken(callback, isArrowToken); + const arrowToken = sourceCode.getTokenBefore(callback.body, isArrowToken); end = arrowToken.range[1]; } @@ -270,6 +270,10 @@ function isFixable(callExpression, sourceCode, {scope, functionInfo, allIdentifi ) { return false; } + // `foo.forEach((element: Type, index: number) => foo())`, should fix to `const [index, element]: [number, Type] of`, not handled + if (parameters.length === 2 && parameters.some(node => node.typeAnnotation)) { + return false; + } // Check `ReturnStatement`s in `callback` const {returnStatements, thisFound, scope: callbackScope} = functionInfo.get(callback); diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index f252ea7e50..cfb2964ec2 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -302,3 +302,69 @@ test.visualize({ ` ] }); + +test.typescript({ + valid: [], + invalid: [ + // https://github.com/vercel/next.js/blob/699a7aeaaa48a6c3611ede7a35af2d9676421de0/packages/next/build/index.ts#L1358 + { + code: outdent` + staticPages.forEach((pg) => allStaticPages.add(pg)) + pageInfos.forEach((info: PageInfo, key: string) => { + allPageInfos.set(key, info) + }) + `, + output: outdent` + for (const pg of staticPages) allStaticPages.add(pg) + pageInfos.forEach((info: PageInfo, key: string) => { + allPageInfos.set(key, info) + }) + `, + errors: 2 + }, + // https://github.com/gatsbyjs/gatsby/blob/3163ca67d44b79c727dd3e331fb56b21707877a5/packages/gatsby/src/bootstrap/remove-stale-jobs.ts#L14 + { + code: outdent` + const actions: Array = [] + + state.jobsV2.complete.forEach( + (job: IGatsbyCompleteJobV2, contentDigest: string): void => { + if (isJobStale(job)) { + actions.push(internalActions.removeStaleJob(contentDigest)) + } + } + ) + `, + output: outdent` + const actions: Array = [] + + state.jobsV2.complete.forEach( + (job: IGatsbyCompleteJobV2, contentDigest: string): void => { + if (isJobStale(job)) { + actions.push(internalActions.removeStaleJob(contentDigest)) + } + } + ) + `, + errors: 1 + }, + // https://github.com/microsoft/fluentui/blob/20f3d664a36c93174dc32786a9d465dd343dabe5/apps/todo-app/src/DataProvider.ts#L157 + { + code: 'this._listeners.forEach((listener: () => void) => listener());', + output: 'for (const listener: () => void of this._listeners) listener();', + errors: 1 + }, + // https://github.com/angular/angular/blob/4e8198d60f421ce120e3a6b57afe60a9332d2692/packages/animations/browser/src/render/transition_animation_engine.ts#L1636 + { + code: outdent` + const cloakVals: string[] = []; + elements.forEach(element => cloakVals.push(cloakElement(element))); + `, + output: outdent` + const cloakVals: string[] = []; + for (const element of elements) cloakVals.push(cloakElement(element)); + `, + errors: 1 + } + ] +}) From 6a91f93e438fb6839f3122bc0cb5218b71359eec Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 23:03:07 +0800 Subject: [PATCH 35/40] Fix code style --- rules/no-array-for-each.js | 3 ++- test/no-array-for-each.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index ebe6c257fa..17587a80f2 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -270,7 +270,8 @@ function isFixable(callExpression, sourceCode, {scope, functionInfo, allIdentifi ) { return false; } - // `foo.forEach((element: Type, index: number) => foo())`, should fix to `const [index, element]: [number, Type] of`, not handled + + // `foo.forEach((element: Type, index: number) => bar())`, should fix to `for (const [index, element]: [number, Type] of …`, not handled if (parameters.length === 2 && parameters.some(node => node.typeAnnotation)) { return false; } diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index cfb2964ec2..b6b2761179 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -367,4 +367,4 @@ test.typescript({ errors: 1 } ] -}) +}); From bc475384271c701f0a5b472dda832ad13cafb5d6 Mon Sep 17 00:00:00 2001 From: fisker Date: Mon, 18 Jan 2021 23:45:11 +0800 Subject: [PATCH 36/40] One more test --- test/no-array-for-each.js | 2 ++ test/snapshots/no-array-for-each.js.md | 18 +++++++++++++++++- test/snapshots/no-array-for-each.js.snap | Bin 3105 -> 3140 bytes 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index b6b2761179..19f4095b77 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -255,6 +255,8 @@ test.visualize({ } } `, + // A test to make sure function head part range correctly calculated + 'foo.forEach(element => ({}))', // `callback` is parenthesized 'foo.forEach((((((element => bar(element)))))));', outdent` diff --git a/test/snapshots/no-array-for-each.js.md b/test/snapshots/no-array-for-each.js.md index e844f58970..7eb9b1d409 100644 --- a/test/snapshots/no-array-for-each.js.md +++ b/test/snapshots/no-array-for-each.js.md @@ -1008,6 +1008,22 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #59 + 1 | foo.forEach(element => ({})) + +> Output + + `␊ + 1 | for (const element of foo) ({})␊ + ` + +> Error 1/1 + + `␊ + > 1 | foo.forEach(element => ({}))␊ + | ^^^^^^^ Do not use `Array#forEach(…)`.␊ + ` + +## Invalid #60 1 | foo.forEach((((((element => bar(element))))))); > Output @@ -1023,7 +1039,7 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^ Do not use `Array#forEach(…)`.␊ ` -## Invalid #60 +## Invalid #61 1 | foo.forEach((element) => { 2 | if (1) { 3 | return; diff --git a/test/snapshots/no-array-for-each.js.snap b/test/snapshots/no-array-for-each.js.snap index 6be9890751a4fe0085b0ba7229c97be5d0681f52..f7483072a376bfbf28885eed1f8cdaec551718d3 100644 GIT binary patch literal 3140 zcmV-K47>9|RzVlq&jEjC#RfA|at!l%-IpO7-ZgD=KIg zZMD{?$K_~2t@hPpMJtLM?$)YRYki9N>h^5)&7FI5Np5b)3O48b2lCDQGygjC&rAgF z0K@`Zc=@%ilf3jx`%l^C8((phWp6HA8mImDm0=I_|2wa?-<2emFwcGUV$6d+7JQ zzItxlIn{Et^_nrtn9m>lINzh-y(gP6gm!KPKwM=)*i8B8X$kjt zJ#9NDK!7219i;d<1F+38d#`)wCtnD7b^AV!Q1{j}ZGkj&KKYyPeaVDNfu#q7zD^v9 zBQ&KAO#|D)9)CR!EW9=AV01*cMO6Y3v8| z34n~im;a57Po6WbI`%W^hVNft2t5W#c@ZnW=ohhhNXr4ebjejk7(!K@0m$@vKKAGD zE_~HBQ+HiD)U!W^&}vAU@H;sP@f-d60Jm$u1m7NsBeYu=nzlpAZdNfYXkxX;@mD=s zJQT}wafH5NsJJWaG545HhqzT6E49ZDWc2kZz!2*F4)okR+Uz8+8zSE%aLaw)FJIsY zoyyP+NO`)rmEV2PJyGuIlX`8QXbXnW$=v`b+BT%)xv=ancildm^=pP`3Xaf9hLnB) zEG?G$R~_};Gu_X>WAWLe1dh=C48;;KkHc?m?ks4&>rj@i$BM4Md*BGoXXrVkweP!! zM!p|=e75(A$)DbL3&#*D?+(Cc_xcW>*gB@}&h5k9bXn!EF@zq3^u@0aZs&BWzPqr? zsHxcNUU4`=eS6SU3TgAOR$uPEH#6qysR{8NzntG6N9a?A^8Ep*Se5s7L0N9!;M$2d z6a6bU;0S%dP)PvPVaoj1nXO9yz0|*O+@E**^uQ7NkRfGHD2vZ;vO_UHciC`#M8%Qi zS&=wGYZ%f6!XAqb?_Vdc3b}IfQR=Ka-!#J!dY_@#5o8i_d1icQ?2gLujB7fGYnz zlJjB5dQLeX*k-VBPY#CAGDs)aubj4i-3!I)XML1Koqe9;2))NpUNDTt&Et0$j3#5e zgw5TfAAggGA=EDffS*?{POrKXmVxj6amV`PP-smGUBHlEC;)feo<2Dy3M*X}`69kU z-Tn0#LO+4@pIuXr7e87sE5%!NY@^qiM;Jn%Q7wl8H-}b&A1~`xjJi@cqZUW#nqD-? zdjs&Og1u3>GT>EWxPo0dp`W95Bw*e z>y#|Ur?fkvxNuOB1WHfMMW#SN$|`_bX2P^GnxyMhX*z{kMX=0HIi6RFP>w_Kn>aOv4Vuw|D$)sohym!x zfgC!8N-skWW`hSsk4f*oCcP=7AKN*K+c_F_?yl3oaS7uYMBxS|k%+@25?f@7V3{Jh zOh`@-I!HNOeOa!4T&^g~T(szVl|}|#LZ&KZ0%UzLE4Y{|xR@545ai`^1{1S_i@Ab} z`&eXRqe0Qd3_TsU;~= z&H${?5nQ1oqKpTKW(E+TwFZg;eZUbWk~MXt$Sm{lYdB0j^97zwId-|VKkY1~Nd4k! zJwfQcHl+vMm5z6tQp1SBrmUd*Gf{3+Mi_HAl?=>4dHJ@b0n;5NgH0)57@y7q+k&6r zVKTshur~}KwLjnuto1?97wO#HdRjxfOtA4jlkfZvDYIjTq?=QrCIU9&=v<*fhh%nb ztWB$!*fFVs&y?#Q4POyZ49?%zENjI3ni*=dYZ*3t364!Y zE!@&*n_w?v_bk38en}%5h%c_}yTl^Rg&Wx0;CAiz)eKp7 z{fuNNjR-B>={YvrNFME|BfZmVxcI_O-{cD}_o@y{HrI$c4>Ep{QfiR`K|O-RqAHgV z=6i2AzD6O_Le~+7Q$7DyZDkzR0Gv*|SG|@#j=447PPdw$FszqiF7>OmBM!cziBBGO zA3X3?P4hef{pZA@K90|kMp5}UTTt+i8g%;{g-$-2%#=0aQvlb1E?zKm-_Q#OSFLQ5 z!zNm*nByk>Xw@{^+z>l!07gX#{i2qo&f>1s);A=lix{gSWLP-I(}r!t^Yb)2LX~c& ze4c84e`m}2m3Q@Pj7vtlWE3`P@;3UeXfg`XZt(MNZWi*X<^0fX1|QFykuH)x$`?B z&pU|?YVmCe_3H7KtxN4HTUo_jv|pGB$Mu53LPnAdb4aXv54&yK8A(PC764{o3ieEBG{<%Q9f-!OXEYkb~!#wJ^`7c}Ue zH?~w8-NFyFYc+Cohcx6_k^)FTOln evE1=JW0Be%RT{x_N^tDwX#WQc?CvV2Hvj;7qX$L+ literal 3105 zcmV++4BqoWRzV|t9{;Dk6OiQ zwa^rc6$E}U-WL%v0)w0u z0Q44j|M0C5KA|rAp45k>xsy0zix~)=0q}pkX2s%)=P`e;i|rBJ|I<1QvAZF{iu5L*o~I4cs{5pk%>HFL_fp0BEFaKw&p zP2&Z`@P*_fuNvw5H+JC<#T5Kh(jka#0uI0 z5WVkF6=I8JFDxiM>hFDPtSn~7rXs_Uso3&vbclnRXt;7+V$KVx2 zV&CZ-$*VDK*S`#iIU_B^aKz5&NW-ZU0JG%6qHiWX8{>Uyd8@qBGvcz z7eRyLvSP~yY?2k7c!eQ0%L{)65T-hn%YwuRYyPQJ~qY8Gof;U_$v&tCm`m1J+#vm z|Lm=Mt50S8kSd;vBUbb-jY|;A3S~Z}XTA2%@b>9cSbmnk5leW}D1ulMaDPV^L5sa7 zGqgQccKgv4N9;WYG6Jq4vt2|%vj?1?K;^|dRLoq z@HK{5pY8x`{^3b=PUo_Ri@T1QhQ00^g(Ehf!7GRzBU*3W_jqQ+?ThaZ?zDAbe;l## zJ!ss6C|;BI_T2TkA$@8m-5cvuQiLORf)9<~AdXC3_&UAyx_>Y8DTw{!VQ>!|v9UdA zT!J|6`AB{;;`^>eRilc}tjGw$5!=5PjT;chKR$J2V@j#ttqac*W&K(ol!ujCxnNfp|iZH}x^akMM#f$Uiw3m*~8P@B0?FG#d46zR&N0h;hfxSo?Eu+Pp5F z(9b9~Mo8lhMA?ps`{u@w5$?hkF5%C2j>QnWpbr4wuU(Q{`oKRGKXiKcmN*gACdEEs zu)q(1ht4nS&x!rlEf4y2aL2luEf`{7K>Tm-wDX0}7R`$HP@dc7e)$=O*r_5|a?*E) zs05t8sa-kdR$Wppj@UmLeAgF%XRDviny}yVilo*%?s>}_p*Uhg`q3zXs4wsN``H`5 z=eo}O8n0029m5c-@dx1L?y>C;JdqW*3;M9t(si-X7-H{3H~|;5<6+LAEhcx1B*erA zM6ycNFIlA?Mkb~R1bG>1Rfb%x&B+%M10sn8QZ3LiLZKT0KOa#45Yy-nF;qn;Razob zBPV7IQme@vA6-}X3bqSp^mEf665jxL#+0YY)8$GnHC&!8BM^iHHgSb4AxM*J2?a5L z2#~@*5rhQ(@$(a+egmmWu4=h9Q>~Q3??Ke}eE6SW_@8{C)Id@!0~Sz%CaRPgEhR4O zR4j$kQ)7|wkdUzxK&7;MA#7rEi zlb*e9WK}XH5Uow5a(y|ZjEeIOyUXL5Nphw#QL9iX3AV9ahUb++#5L&j#sul3FG{}s zN|alnM7lTu`j3htn#AZ57IG6=u2>EqbO>Er+He6Vl`Y6gU!Aa0yp% z2`xAwfD5K!XA)L$30H7Qu*pWO+!C(bk}zE(G9NBJB)4U_u4P~Vr)8j+X&Fz-cv=QZ z*p`9ZmPm4#RH&#gjMUP28K(nQ=s>Q}fnoX`gfkroQ04$dfi~a>6U3@INNgOFl{k#a z#+N-h8m$jUQz6ojDwz)ux~@gxL06^y-J;OYYhY1S(DfNFwp*6`!|R$hI6a@Ib2s<_R;Hj-0?cljhFz)54nBjOm+yGtYNfzI#=4ovx67M4%Gj1U zX`3Z;YQzSZ%(kS7n~~^-usLmVc+zBK(q^9H@+Q0#Nm3czeXu@4a0GWV zaTTIzhSLC>_4BQxOPf$Ze8#ixrie5aZeTxCw>9=(E!cT@PO#?i?0_9$1~Z;QnIz9{ z7?BjwjL_7@nQfzu=9wLpY1=&w2j7ZiHv6h(bRQOHJR>SiW9%ZMrbP+_4Ga>CN)P;) z@BLu^YK2?_O-JaGZT|hxOh2pwIF)$sQ%!wrGwWb0&1!r{V?N(;s9nun65%VG`R>O0 ztD7~=^9BIzXUC!*%V$VEul$QGDELQ>nmtRQO^G4XW*Zzt(GtrXMd=5v=GmQxTImza6s7cQTZSrwyTzE_NA1qN%!-g| z;*3u#wh7PH)2(n-x|p(gg7L$RC1+dSMY}0pm#mUe*rdVRU3&-k_fZ3vPt|3P(MB{+m95b8qpdO}v}!f7b%)f&S=0W26<=Y^L!$;pM`8-^BTOO* z#}oJ0Eg&$_QOn6xDYK3+a&n From de64278fbd93ce96655a5dcb22c76fa6250c522e Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 19 Jan 2021 13:23:32 +0800 Subject: [PATCH 37/40] Update no-array-for-each.js --- test/no-array-for-each.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/no-array-for-each.js b/test/no-array-for-each.js index 19f4095b77..7cca704672 100644 --- a/test/no-array-for-each.js +++ b/test/no-array-for-each.js @@ -1,7 +1,7 @@ import {outdent} from 'outdent'; import {test} from './utils/test.js'; -test.visualize({ +test.snapshot({ valid: [ 'new foo.forEach(element => bar())', 'forEach(element => bar())', From 1f1dbb81a620c0397c420be43907a9efbbed6148 Mon Sep 17 00:00:00 2001 From: fisker Date: Tue, 19 Jan 2021 13:27:08 +0800 Subject: [PATCH 38/40] Rename file --- .../conflicts-no-array-for-each-and-prevent-abbreviations.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/integration/{unicorn => fixtures-local}/conflicts-no-array-for-each-and-prevent-abbreviations.js (100%) diff --git a/test/integration/unicorn/conflicts-no-array-for-each-and-prevent-abbreviations.js b/test/integration/fixtures-local/conflicts-no-array-for-each-and-prevent-abbreviations.js similarity index 100% rename from test/integration/unicorn/conflicts-no-array-for-each-and-prevent-abbreviations.js rename to test/integration/fixtures-local/conflicts-no-array-for-each-and-prevent-abbreviations.js From 6982ad4ca382ca87f3201524820211e6d99f32d8 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 19 Jan 2021 14:55:41 +0700 Subject: [PATCH 39/40] Update no-array-for-each.md --- docs/rules/no-array-for-each.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/no-array-for-each.md b/docs/rules/no-array-for-each.md index d7ee3df469..c0dd2986d2 100644 --- a/docs/rules/no-array-for-each.md +++ b/docs/rules/no-array-for-each.md @@ -1,6 +1,6 @@ # Prefer `for…of` over `Array#forEach(…)` -[`for…of` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) is more readable than [`Array#forEach(…)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). +A [`for…of` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) is more readable than [`Array#forEach(…)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). This rule is partly fixable. @@ -39,7 +39,7 @@ for (const [index, element] of array.entries()) { ``` ```js -for (const [index, element] of array.entries) { +for (const [index, element] of array.entries()) { bar(element, index, array); } ``` From c767fe046a88d26a220e6dd9f3777002f95d6558 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 19 Jan 2021 15:06:01 +0700 Subject: [PATCH 40/40] Update no-array-for-each.js --- rules/no-array-for-each.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js index 17587a80f2..cdd5afae54 100644 --- a/rules/no-array-for-each.js +++ b/rules/no-array-for-each.js @@ -256,8 +256,8 @@ function isFixable(callExpression, sourceCode, {scope, functionInfo, allIdentifi if ( // Leave non-function type to `no-array-callback-reference` rule (callback.type !== 'FunctionExpression' && callback.type !== 'ArrowFunctionExpression') || - callback.async || - callback.generator + callback.async || + callback.generator ) { return false; }