| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 | 'use strict';const {hasSideEffect} = require('@eslint-community/eslint-utils');const {methodCallSelector, notFunctionSelector} = require('./selectors/index.js');const {removeArgument} = require('./fix/index.js');const {getParentheses, getParenthesizedText} = require('./utils/parentheses.js');const shouldAddParenthesesToMemberExpressionObject = require('./utils/should-add-parentheses-to-member-expression-object.js');const {isNodeMatches} = require('./utils/is-node-matches.js');const ERROR = 'error';const SUGGESTION_BIND = 'suggestion-bind';const SUGGESTION_REMOVE = 'suggestion-remove';const messages = {	[ERROR]: 'Do not use the `this` argument in `Array#{{method}}()`.',	[SUGGESTION_REMOVE]: 'Remove the second argument.',	[SUGGESTION_BIND]: 'Use a bound function.',};const ignored = [	'lodash.every',	'_.every',	'underscore.every',	'lodash.filter',	'_.filter',	'underscore.filter',	'Vue.filter',	'R.filter',	'lodash.find',	'_.find',	'underscore.find',	'R.find',	'lodash.findLast',	'_.findLast',	'underscore.findLast',	'R.findLast',	'lodash.findIndex',	'_.findIndex',	'underscore.findIndex',	'R.findIndex',	'lodash.findLastIndex',	'_.findLastIndex',	'underscore.findLastIndex',	'R.findLastIndex',	'lodash.flatMap',	'_.flatMap',	'lodash.forEach',	'_.forEach',	'React.Children.forEach',	'Children.forEach',	'R.forEach',	'lodash.map',	'_.map',	'underscore.map',	'React.Children.map',	'Children.map',	'jQuery.map',	'$.map',	'R.map',	'lodash.some',	'_.some',	'underscore.some',];const selector = [	methodCallSelector({		methods: [			'every',			'filter',			'find',			'findLast',			'findIndex',			'findLastIndex',			'flatMap',			'forEach',			'map',			'some',		],		argumentsLength: 2,	}),	notFunctionSelector('arguments.0'),].join('');function removeThisArgument(callExpression, sourceCode) {	return fixer => removeArgument(fixer, callExpression.arguments[1], sourceCode);}function useBoundFunction(callExpression, sourceCode) {	return function * (fixer) {		yield removeThisArgument(callExpression, sourceCode)(fixer);		const [callback, thisArgument] = callExpression.arguments;		const callbackParentheses = getParentheses(callback, sourceCode);		const isParenthesized = callbackParentheses.length > 0;		const callbackLastToken = isParenthesized			? callbackParentheses[callbackParentheses.length - 1]			: callback;		if (			!isParenthesized			&& shouldAddParenthesesToMemberExpressionObject(callback, sourceCode)		) {			yield fixer.insertTextBefore(callbackLastToken, '(');			yield fixer.insertTextAfter(callbackLastToken, ')');		}		const thisArgumentText = getParenthesizedText(thisArgument, sourceCode);		// `thisArgument` was a argument, no need add extra parentheses		yield fixer.insertTextAfter(callbackLastToken, `.bind(${thisArgumentText})`);	};}/** @param {import('eslint').Rule.RuleContext} context */const create = context => {	const sourceCode = context.getSourceCode();	return {		[selector](callExpression) {			const {callee} = callExpression;			if (isNodeMatches(callee, ignored)) {				return;			}			const method = callee.property.name;			const [callback, thisArgument] = callExpression.arguments;			const problem = {				node: thisArgument,				messageId: ERROR,				data: {method},			};			const thisArgumentHasSideEffect = hasSideEffect(thisArgument, sourceCode);			const isArrowCallback = callback.type === 'ArrowFunctionExpression';			if (isArrowCallback) {				if (thisArgumentHasSideEffect) {					problem.suggest = [						{							messageId: SUGGESTION_REMOVE,							fix: removeThisArgument(callExpression, sourceCode),						},					];				} else {					problem.fix = removeThisArgument(callExpression, sourceCode);				}				return problem;			}			problem.suggest = [				{					messageId: SUGGESTION_REMOVE,					fix: removeThisArgument(callExpression, sourceCode),				},				{					messageId: SUGGESTION_BIND,					fix: useBoundFunction(callExpression, sourceCode),				},			];			return problem;		},	};};/** @type {import('eslint').Rule.RuleModule} */module.exports = {	create,	meta: {		type: 'suggestion',		docs: {			description: 'Disallow using the `this` argument in array methods.',		},		fixable: 'code',		hasSuggestions: true,		messages,	},};
 |