diff --git a/rules/no-array-method-this-argument.js b/rules/no-array-method-this-argument.js index 8d907edb6c..ee0be686d7 100644 --- a/rules/no-array-method-this-argument.js +++ b/rules/no-array-method-this-argument.js @@ -13,7 +13,7 @@ const SUGGESTION_BIND = 'suggestion-bind'; const SUGGESTION_REMOVE = 'suggestion-remove'; const messages = { [ERROR_PROTOTYPE_METHOD]: 'Do not use the `this` argument in `Array#{{method}}()`.', - [ERROR_STATIC_METHOD]: 'Do not use the `this` argument in `Array.from()`.', + [ERROR_STATIC_METHOD]: 'Do not use the `this` argument in `Array.{{method}}()`.', [SUGGESTION_REMOVE]: 'Remove the second argument.', [SUGGESTION_BIND]: 'Use a bound function.', }; @@ -72,30 +72,28 @@ const ignored = [ 'underscore.some', ]; -function removeThisArgument(callExpression, sourceCode) { - return fixer => removeArgument(fixer, callExpression.arguments[1], sourceCode); +function removeThisArgument(thisArgumentNode, sourceCode) { + return fixer => removeArgument(fixer, thisArgumentNode, sourceCode); } -function useBoundFunction(callExpression, sourceCode) { +function useBoundFunction(callbackNode, thisArgumentNode, sourceCode) { return function * (fixer) { - yield removeThisArgument(callExpression, sourceCode)(fixer); + yield removeThisArgument(thisArgumentNode, sourceCode)(fixer); - const [callback, thisArgument] = callExpression.arguments; - - const callbackParentheses = getParentheses(callback, sourceCode); + const callbackParentheses = getParentheses(callbackNode, sourceCode); const isParenthesized = callbackParentheses.length > 0; const callbackLastToken = isParenthesized ? callbackParentheses.at(-1) - : callback; + : callbackNode; if ( !isParenthesized - && shouldAddParenthesesToMemberExpressionObject(callback, sourceCode) + && shouldAddParenthesesToMemberExpressionObject(callbackNode, sourceCode) ) { yield fixer.insertTextBefore(callbackLastToken, '('); yield fixer.insertTextAfter(callbackLastToken, ')'); } - const thisArgumentText = getParenthesizedText(thisArgument, sourceCode); + const thisArgumentText = getParenthesizedText(thisArgumentNode, sourceCode); // `thisArgument` was a argument, no need add extra parentheses yield fixer.insertTextAfter(callbackLastToken, `.bind(${thisArgumentText})`); }; @@ -108,28 +106,26 @@ function getProblem({ thisArgumentNode, messageId, }) { - const {callee} = callExpression; - const method = callee.property.name; - const problem = { node: thisArgumentNode, messageId, - data: {method}, + data: { + method: callExpression.callee.property.name, + }, }; - const thisArgumentHasSideEffect = hasSideEffect(thisArgumentNode, sourceCode); const isArrowCallback = callbackNode.type === 'ArrowFunctionExpression'; - if (isArrowCallback) { + const thisArgumentHasSideEffect = hasSideEffect(thisArgumentNode, sourceCode); if (thisArgumentHasSideEffect) { problem.suggest = [ { messageId: SUGGESTION_REMOVE, - fix: removeThisArgument(callExpression, sourceCode), + fix: removeThisArgument(thisArgumentNode, sourceCode), }, ]; } else { - problem.fix = removeThisArgument(callExpression, sourceCode); + problem.fix = removeThisArgument(thisArgumentNode, sourceCode); } return problem; @@ -138,11 +134,11 @@ function getProblem({ problem.suggest = [ { messageId: SUGGESTION_REMOVE, - fix: removeThisArgument(callExpression, sourceCode), + fix: removeThisArgument(thisArgumentNode, sourceCode), }, { messageId: SUGGESTION_BIND, - fix: useBoundFunction(callExpression, sourceCode), + fix: useBoundFunction(callbackNode, thisArgumentNode, sourceCode), }, ]; @@ -154,7 +150,7 @@ const create = context => { const {sourceCode} = context; // Prototype methods - context.on('CallExpression', (callExpression) => { + context.on('CallExpression', callExpression => { if ( !( isMethodCall(callExpression, { @@ -201,11 +197,19 @@ const create = context => { optionalCall: false, optionalMember: false, }) - && !isNodeValueNotFunction(callExpression.arguments[0]) + && !isNodeValueNotFunction(callExpression.arguments[1]) ) ) { return; } + + return getProblem({ + sourceCode, + callExpression, + callbackNode: callExpression.arguments[1], + thisArgumentNode: callExpression.arguments[2], + messageId: ERROR_STATIC_METHOD, + }); }); }; diff --git a/test/no-array-method-this-argument.mjs b/test/no-array-method-this-argument.mjs index e5a43b9bee..6cb708b5c9 100644 --- a/test/no-array-method-this-argument.mjs +++ b/test/no-array-method-this-argument.mjs @@ -27,7 +27,7 @@ test.snapshot({ 'Array.from(iterableOrArrayLike, () => {}, ...thisArgument)', 'Array.from(iterableOrArrayLike, ...() => {}, thisArgument)', 'Array.from(...iterableOrArrayLike, () => {}, thisArgument)', - 'Array.from(iterableOrArrayLike, () => {}, thisArgument,extraArgument)', + 'Array.from(iterableOrArrayLike, () => {}, thisArgument, extraArgument)', // Ignored 'lodash.every(array, () => {})', diff --git a/test/snapshots/no-array-method-this-argument.mjs.md b/test/snapshots/no-array-method-this-argument.mjs.md index 85dacdd156..9d9e3c3993 100644 --- a/test/snapshots/no-array-method-this-argument.mjs.md +++ b/test/snapshots/no-array-method-this-argument.mjs.md @@ -193,6 +193,27 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ ` +## invalid(10): Array.from(iterableOrArrayLike, () => {}, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument)␊ + ` + +> Output + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {})␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ` + ## invalid(11): array.map(() => {}, thisArgument,) > Input @@ -235,6 +256,27 @@ Generated by [AVA](https://avajs.dev). | ^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ ` +## invalid(13): Array.from(iterableOrArrayLike, () => {}, thisArgument,) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument,)␊ + ` + +> Output + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {},)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, () => {}, thisArgument,)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ` + ## invalid(14): array.map(() => {}, thisArgumentHasSideEffect()) > Input @@ -254,6 +296,25 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(() => {})␊ ` +## invalid(15): Array.from(iterableOrArrayLike, () => {}, thisArgumentHasSideEffect()) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, () => {}, thisArgumentHasSideEffect())␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, () => {}, thisArgumentHasSideEffect())␊ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, () => {})␊ + ` + ## invalid(1): array.map(callback, thisArgument) > Input @@ -277,7 +338,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(callback.bind(thisArgument))␊ ` -## invalid(2): array.map(callback, (0, thisArgument)) +## invalid(2): Array.from(iterableOrArrayLike, callback, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, callback, thisArgument)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, callback, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, callback)␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(thisArgument))␊ + ` + +## invalid(3): array.map(callback, (0, thisArgument)) > Input @@ -300,7 +384,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(callback.bind((0, thisArgument)))␊ ` -## invalid(3): array.map(function () {}, thisArgument) +## invalid(4): Array.from(iterableOrArrayLike, callback, (0, thisArgument)) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, callback, (0, thisArgument))␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, callback, (0, thisArgument))␊ + | ^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, callback)␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind((0, thisArgument)))␊ + ` + +## invalid(5): array.map(function () {}, thisArgument) > Input @@ -323,7 +430,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(function () {}.bind(thisArgument))␊ ` -## invalid(4): array.map(function callback () {}, thisArgument) +## invalid(6): Array.from(iterableOrArrayLike, function () {}, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, function () {}, thisArgument)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, function () {}, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, function () {})␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, function () {}.bind(thisArgument))␊ + ` + +## invalid(7): array.map(function callback () {}, thisArgument) > Input @@ -346,7 +476,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map(function callback () {}.bind(thisArgument))␊ ` -## invalid(5): array.map( foo as bar, (( thisArgument )),) +## invalid(8): Array.from(iterableOrArrayLike, function callback () {}, thisArgument) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, function callback () {}, thisArgument)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, function callback () {}, thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, function callback () {})␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, function callback () {}.bind(thisArgument))␊ + ` + +## invalid(9): array.map( foo as bar, (( thisArgument )),) > Input @@ -369,7 +522,30 @@ Generated by [AVA](https://avajs.dev). 1 | array.map( (foo as bar).bind((( thisArgument ))),)␊ ` -## invalid(6): array.map( (( foo as bar )), (( thisArgument )),) +## invalid(10): Array.from(iterableOrArrayLike, foo as bar, (( thisArgument )),) + +> Input + + `␊ + 1 | Array.from(iterableOrArrayLike, foo as bar, (( thisArgument )),)␊ + ` + +> Error 1/1 + + `␊ + > 1 | Array.from(iterableOrArrayLike, foo as bar, (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, foo as bar,)␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, (foo as bar).bind((( thisArgument ))),)␊ + ` + +## invalid(11): array.map( (( foo as bar )), (( thisArgument )),) > Input @@ -392,132 +568,163 @@ Generated by [AVA](https://avajs.dev). 1 | array.map( (( foo as bar )).bind((( thisArgument ))),)␊ ` -## invalid(7): array.map( (( 0, callback )), (( thisArgument )),) +## invalid(12): Array.from(iterableOrArrayLike, (( foo as bar )), (( thisArgument )),) > Input `␊ - 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ + 1 | Array.from(iterableOrArrayLike, (( foo as bar )), (( thisArgument )),)␊ ` > Error 1/1 `␊ - > 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | Array.from(iterableOrArrayLike, (( foo as bar )), (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/2: Remove the second argument.␊ - 1 | array.map( (( 0, callback )),)␊ + 1 | Array.from(iterableOrArrayLike, (( foo as bar )),)␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 2/2: Use a bound function.␊ - 1 | array.map( (( 0, callback )).bind((( thisArgument ))),)␊ + 1 | Array.from(iterableOrArrayLike, (( foo as bar )).bind((( thisArgument ))),)␊ ` -## invalid(8): array.map((0, () => {}), thisArgument) +## invalid(13): array.map( (( 0, callback )), (( thisArgument )),) > Input `␊ - 1 | array.map((0, () => {}), thisArgument)␊ + 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ ` > Error 1/1 `␊ - > 1 | array.map((0, () => {}), thisArgument)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | array.map( (( 0, callback )), (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/2: Remove the second argument.␊ - 1 | array.map((0, () => {}))␊ + 1 | array.map( (( 0, callback )),)␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 2/2: Use a bound function.␊ - 1 | array.map((0, () => {}).bind(thisArgument))␊ + 1 | array.map( (( 0, callback )).bind((( thisArgument ))),)␊ ` -## invalid(9): array.map(callback.bind(foo), thisArgument) +## invalid(14): Array.from(iterableOrArrayLike, (( 0, callback )), (( thisArgument )),) > Input `␊ - 1 | array.map(callback.bind(foo), thisArgument)␊ + 1 | Array.from(iterableOrArrayLike, (( 0, callback )), (( thisArgument )),)␊ ` > Error 1/1 `␊ - > 1 | array.map(callback.bind(foo), thisArgument)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | Array.from(iterableOrArrayLike, (( 0, callback )), (( thisArgument )),)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/2: Remove the second argument.␊ - 1 | array.map(callback.bind(foo))␊ + 1 | Array.from(iterableOrArrayLike, (( 0, callback )),)␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 2/2: Use a bound function.␊ - 1 | array.map(callback.bind(foo).bind(thisArgument))␊ + 1 | Array.from(iterableOrArrayLike, (( 0, callback )).bind((( thisArgument ))),)␊ ` -## invalid(10): array.map(() => {}, thisArgument,) +## invalid(15): array.map((0, () => {}), thisArgument) > Input `␊ - 1 | array.map(() => {}, thisArgument,)␊ + 1 | array.map((0, () => {}), thisArgument)␊ ` -> Output +> Error 1/1 `␊ - 1 | array.map(() => {},)␊ + > 1 | array.map((0, () => {}), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | array.map((0, () => {}))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | array.map((0, () => {}).bind(thisArgument))␊ ` -> Error 1/1 +## invalid(16): Array.from(iterableOrArrayLike, (0, () => {}), thisArgument) + +> Input `␊ - > 1 | array.map(() => {}, thisArgument,)␊ - | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + 1 | Array.from(iterableOrArrayLike, (0, () => {}), thisArgument)␊ ` -## invalid(11): array.map(() => {}, (0, thisArgument),) - -> Input +> Error 1/1 `␊ - 1 | array.map(() => {}, (0, thisArgument),)␊ + > 1 | Array.from(iterableOrArrayLike, (0, () => {}), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, (0, () => {}))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, (0, () => {}).bind(thisArgument))␊ ` -> Output +## invalid(17): array.map(callback.bind(foo), thisArgument) + +> Input `␊ - 1 | array.map(() => {},)␊ + 1 | array.map(callback.bind(foo), thisArgument)␊ ` > Error 1/1 `␊ - > 1 | array.map(() => {}, (0, thisArgument),)␊ - | ^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | array.map(callback.bind(foo), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | array.map(callback.bind(foo))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | array.map(callback.bind(foo).bind(thisArgument))␊ ` -## invalid(12): array.map(() => {}, thisArgumentHasSideEffect()) +## invalid(18): Array.from(iterableOrArrayLike, callback.bind(foo), thisArgument) > Input `␊ - 1 | array.map(() => {}, thisArgumentHasSideEffect())␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(foo), thisArgument)␊ ` > Error 1/1 `␊ - > 1 | array.map(() => {}, thisArgumentHasSideEffect())␊ - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array#map()\`.␊ + > 1 | Array.from(iterableOrArrayLike, callback.bind(foo), thisArgument)␊ + | ^^^^^^^^^^^^ Do not use the \`this\` argument in \`Array.from()\`.␊ ␊ --------------------------------------------------------------------------------␊ - Suggestion 1/1: Remove the second argument.␊ - 1 | array.map(() => {})␊ + Suggestion 1/2: Remove the second argument.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(foo))␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 2/2: Use a bound function.␊ + 1 | Array.from(iterableOrArrayLike, callback.bind(foo).bind(thisArgument))␊ ` diff --git a/test/snapshots/no-array-method-this-argument.mjs.snap b/test/snapshots/no-array-method-this-argument.mjs.snap index fc008f2711..cace872995 100644 Binary files a/test/snapshots/no-array-method-this-argument.mjs.snap and b/test/snapshots/no-array-method-this-argument.mjs.snap differ