| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 | 'use strict';const {methodCallSelector, matches, memberExpressionSelector} = require('./selectors/index.js');const {checkVueTemplate} = require('./utils/rule.js');const {isBooleanNode} = require('./utils/boolean.js');const {getParenthesizedRange} = require('./utils/parentheses.js');const {removeMemberExpressionProperty} = require('./fix/index.js');const {isLiteral, isUndefined} = require('./ast/index.js');const ERROR_ID_ARRAY_SOME = 'some';const SUGGESTION_ID_ARRAY_SOME = 'some-suggestion';const ERROR_ID_ARRAY_FILTER = 'filter';const messages = {	[ERROR_ID_ARRAY_SOME]: 'Prefer `.some(…)` over `.{{method}}(…)`.',	[SUGGESTION_ID_ARRAY_SOME]: 'Replace `.{{method}}(…)` with `.some(…)`.',	[ERROR_ID_ARRAY_FILTER]: 'Prefer `.some(…)` over non-zero length check from `.filter(…)`.',};const arrayFindOrFindLastCallSelector = methodCallSelector({	methods: ['find', 'findLast'],	minimumArguments: 1,	maximumArguments: 2,});const isCheckingUndefined = node =>	node.parent.type === 'BinaryExpression'	// Not checking yoda expression `null != foo.find()` and `undefined !== foo.find()	&& node.parent.left === node	&& (		(			(				node.parent.operator === '!='				|| node.parent.operator === '=='				|| node.parent.operator === '==='				|| node.parent.operator === '!=='			)			&& isUndefined(node.parent.right)		)		|| (			(				node.parent.operator === '!='				|| node.parent.operator === '=='			)			// eslint-disable-next-line unicorn/no-null			&& isLiteral(node.parent.right, null)		)	);const arrayFilterCallSelector = [	'BinaryExpression',	'[right.type="Literal"]',	'[right.raw="0"]',	// We assume the user already follows `unicorn/explicit-length-check`. These are allowed in that rule.	matches(['[operator=">"]', '[operator="!=="]']),	' > ',	`${memberExpressionSelector('length')}.left`,	' > ',	`${methodCallSelector('filter')}.object`,].join('');/** @param {import('eslint').Rule.RuleContext} context */const create = context => ({	[arrayFindOrFindLastCallSelector](callExpression) {		const isCompare = isCheckingUndefined(callExpression);		if (!isCompare && !isBooleanNode(callExpression)) {			return;		}		const methodNode = callExpression.callee.property;		return {			node: methodNode,			messageId: ERROR_ID_ARRAY_SOME,			data: {method: methodNode.name},			suggest: [				{					messageId: SUGGESTION_ID_ARRAY_SOME,					* fix(fixer) {						yield fixer.replaceText(methodNode, 'some');						if (!isCompare) {							return;						}						const parenthesizedRange = getParenthesizedRange(callExpression, context.getSourceCode());						yield fixer.replaceTextRange([parenthesizedRange[1], callExpression.parent.range[1]], '');						if (callExpression.parent.operator === '!=' || callExpression.parent.operator === '!==') {							return;						}						yield fixer.insertTextBeforeRange(parenthesizedRange, '!');					},				},			],		};	},	[arrayFilterCallSelector](filterCall) {		const filterProperty = filterCall.callee.property;		return {			node: filterProperty,			messageId: ERROR_ID_ARRAY_FILTER,			* fix(fixer) {				// `.filter` to `.some`				yield fixer.replaceText(filterProperty, 'some');				const sourceCode = context.getSourceCode();				const lengthNode = filterCall.parent;				/*					Remove `.length`					`(( (( array.filter() )).length )) > (( 0 ))`					------------------------^^^^^^^				*/				yield removeMemberExpressionProperty(fixer, lengthNode, sourceCode);				const compareNode = lengthNode.parent;				/*					Remove `> 0`					`(( (( array.filter() )).length )) > (( 0 ))`					----------------------------------^^^^^^^^^^				*/				yield fixer.removeRange([					getParenthesizedRange(lengthNode, sourceCode)[1],					compareNode.range[1],				]);				// The `BinaryExpression` always ends with a number or `)`, no need check for ASI			},		};	},});/** @type {import('eslint').Rule.RuleModule} */module.exports = {	create: checkVueTemplate(create),	meta: {		type: 'suggestion',		docs: {			description: 'Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`.',		},		fixable: 'code',		messages,		hasSuggestions: true,	},};
 |