| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 | 'use strict';const {hasSideEffect} = require('@eslint-community/eslint-utils');const {fixSpaceAroundKeyword} = require('./fix/index.js');const ERROR_BITWISE = 'error-bitwise';const ERROR_BITWISE_NOT = 'error-bitwise-not';const SUGGESTION_BITWISE = 'suggestion-bitwise';const messages = {	[ERROR_BITWISE]: 'Use `Math.trunc` instead of `{{operator}} {{value}}`.',	[ERROR_BITWISE_NOT]: 'Use `Math.trunc` instead of `~~`.',	[SUGGESTION_BITWISE]: 'Replace `{{operator}} {{value}}` with `Math.trunc`.',};const createBitwiseNotSelector = (level, isNegative) => {	const prefix = 'argument.'.repeat(level);	const selector = [		`[${prefix}type="UnaryExpression"]`,		`[${prefix}operator="~"]`,	].join('');	return isNegative ? `:not(${selector})` : selector;};// Bitwise operatorsconst bitwiseOperators = new Set(['|', '>>', '<<', '^']);// Unary Expression Selector: Inner-most 2 bitwise NOTconst bitwiseNotUnaryExpressionSelector = [	createBitwiseNotSelector(0),	createBitwiseNotSelector(1),	createBitwiseNotSelector(2, true),].join('');/** @param {import('eslint').Rule.RuleContext} context */const create = context => {	const sourceCode = context.getSourceCode();	const mathTruncFunctionCall = node => {		const text = sourceCode.getText(node);		const parenthesized = node.type === 'SequenceExpression' ? `(${text})` : text;		return `Math.trunc(${parenthesized})`;	};	return {		':matches(BinaryExpression, AssignmentExpression)[right.type="Literal"]'(node) {			const {type, operator, right, left} = node;			const isAssignment = type === 'AssignmentExpression';			if (				right.value !== 0				|| !bitwiseOperators.has(isAssignment ? operator.slice(0, -1) : operator)			) {				return;			}			const problem = {				node,				messageId: ERROR_BITWISE,				data: {					operator,					value: right.raw,				},			};			if (!isAssignment || !hasSideEffect(left, sourceCode)) {				const fix = function * (fixer) {					const fixed = mathTruncFunctionCall(left);					if (isAssignment) {						const operatorToken = sourceCode.getTokenAfter(left, token => token.type === 'Punctuator' && token.value === operator);						yield fixer.replaceText(operatorToken, '=');						yield fixer.replaceText(right, fixed);					} else {						yield * fixSpaceAroundKeyword(fixer, node, sourceCode);						yield fixer.replaceText(node, fixed);					}				};				if (operator === '|') {					problem.suggest = [						{							messageId: SUGGESTION_BITWISE,							fix,						},					];				} else {					problem.fix = fix;				}			}			return problem;		},		[bitwiseNotUnaryExpressionSelector]: node => ({			node,			messageId: ERROR_BITWISE_NOT,			* fix(fixer) {				yield fixer.replaceText(node, mathTruncFunctionCall(node.argument.argument));				yield * fixSpaceAroundKeyword(fixer, node, sourceCode);			},		}),	};};/** @type {import('eslint').Rule.RuleModule} */module.exports = {	create,	meta: {		type: 'suggestion',		docs: {			description: 'Enforce the use of `Math.trunc` instead of bitwise operators.',		},		fixable: 'code',		hasSuggestions: true,		messages,	},};
 |