| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 | 
							- 'use strict';
 
- const {getStaticValue} = require('@eslint-community/eslint-utils');
 
- const {isNumberLiteral} = require('../ast/index.js');
 
- const isStaticProperties = (node, object, properties) =>
 
- 	node.type === 'MemberExpression'
 
- 	&& !node.computed
 
- 	&& !node.optional
 
- 	&& node.object.type === 'Identifier'
 
- 	&& node.object.name === object
 
- 	&& node.property.type === 'Identifier'
 
- 	&& properties.has(node.property.name);
 
- const isFunctionCall = (node, functionName) => node.type === 'CallExpression'
 
- 	&& !node.optional
 
- 	&& node.callee.type === 'Identifier'
 
- 	&& node.callee.name === functionName;
 
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math#static_properties
 
- const mathProperties = new Set([
 
- 	'E',
 
- 	'LN2',
 
- 	'LN10',
 
- 	'LOG2E',
 
- 	'LOG10E',
 
- 	'PI',
 
- 	'SQRT1_2',
 
- 	'SQRT2',
 
- ]);
 
- // `Math.{E,LN2,LN10,LOG2E,LOG10E,PI,SQRT1_2,SQRT2}`
 
- const isMathProperty = node => isStaticProperties(node, 'Math', mathProperties);
 
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math#static_methods
 
- const mathMethods = new Set([
 
- 	'abs',
 
- 	'acos',
 
- 	'acosh',
 
- 	'asin',
 
- 	'asinh',
 
- 	'atan',
 
- 	'atanh',
 
- 	'atan2',
 
- 	'cbrt',
 
- 	'ceil',
 
- 	'clz32',
 
- 	'cos',
 
- 	'cosh',
 
- 	'exp',
 
- 	'expm1',
 
- 	'floor',
 
- 	'fround',
 
- 	'hypot',
 
- 	'imul',
 
- 	'log',
 
- 	'log1p',
 
- 	'log10',
 
- 	'log2',
 
- 	'max',
 
- 	'min',
 
- 	'pow',
 
- 	'random',
 
- 	'round',
 
- 	'sign',
 
- 	'sin',
 
- 	'sinh',
 
- 	'sqrt',
 
- 	'tan',
 
- 	'tanh',
 
- 	'trunc',
 
- ]);
 
- // `Math.{abs, …, trunc}(…)`
 
- const isMathMethodCall = node =>
 
- 	node.type === 'CallExpression'
 
- 	&& !node.optional
 
- 	&& isStaticProperties(node.callee, 'Math', mathMethods);
 
- // `Number(…)`
 
- const isNumberCall = node => isFunctionCall(node, 'Number');
 
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#static_properties
 
- const numberProperties = new Set([
 
- 	'EPSILON',
 
- 	'MAX_SAFE_INTEGER',
 
- 	'MAX_VALUE',
 
- 	'MIN_SAFE_INTEGER',
 
- 	'MIN_VALUE',
 
- 	'NaN',
 
- 	'NEGATIVE_INFINITY',
 
- 	'POSITIVE_INFINITY',
 
- ]);
 
- const isNumberProperty = node => isStaticProperties(node, 'Number', numberProperties);
 
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#static_methods
 
- const numberMethods = new Set([
 
- 	'parseFloat',
 
- 	'parseInt',
 
- ]);
 
- const isNumberMethodCall = node =>
 
- 	node.type === 'CallExpression'
 
- 	&& !node.optional
 
- 	&& isStaticProperties(node.callee, 'Number', numberMethods);
 
- const isGlobalParseToNumberFunctionCall = node => isFunctionCall(node, 'parseInt') || isFunctionCall(node, 'parseFloat');
 
- const isStaticNumber = (node, scope) =>
 
- 	typeof getStaticValue(node, scope)?.value === 'number';
 
- const isLengthProperty = node =>
 
- 	node.type === 'MemberExpression'
 
- 	&& !node.computed
 
- 	&& !node.optional
 
- 	&& node.property.type === 'Identifier'
 
- 	&& node.property.name === 'length';
 
- // `+` and `>>>` operators are handled separately
 
- const mathOperators = new Set(['-', '*', '/', '%', '**', '<<', '>>', '|', '^', '&']);
 
- function isNumber(node, scope) {
 
- 	if (
 
- 		isNumberLiteral(node)
 
- 		|| isMathProperty(node)
 
- 		|| isMathMethodCall(node)
 
- 		|| isNumberCall(node)
 
- 		|| isNumberProperty(node)
 
- 		|| isNumberMethodCall(node)
 
- 		|| isGlobalParseToNumberFunctionCall(node)
 
- 		|| isLengthProperty(node)
 
- 	) {
 
- 		return true;
 
- 	}
 
- 	switch (node.type) {
 
- 		case 'AssignmentExpression': {
 
- 			const {operator} = node;
 
- 			if (operator === '=' && isNumber(node.right, scope)) {
 
- 				return true;
 
- 			}
 
- 			// Fall through
 
- 		}
 
- 		case 'BinaryExpression': {
 
- 			let {operator} = node;
 
- 			if (node.type === 'AssignmentExpression') {
 
- 				operator = operator.slice(0, -1);
 
- 			}
 
- 			if (operator === '+' && isNumber(node.left, scope) && isNumber(node.right, scope)) {
 
- 				return true;
 
- 			}
 
- 			// `>>>` (zero-fill right shift) can't use on `BigInt`
 
- 			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#operators
 
- 			if (operator === '>>>') {
 
- 				return true;
 
- 			}
 
- 			// `a * b` can be `BigInt`, we need make sure at least one side is number
 
- 			if (mathOperators.has(operator) && (isNumber(node.left, scope) || isNumber(node.right, scope))) {
 
- 				return true;
 
- 			}
 
- 			break;
 
- 		}
 
- 		case 'UnaryExpression': {
 
- 			const {operator} = node;
 
- 			// `+` can't use on `BigInt`
 
- 			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#operators
 
- 			if (operator === '+') {
 
- 				return true;
 
- 			}
 
- 			if ((operator === '-' || operator === '~') && isNumber(node.argument, scope)) {
 
- 				return true;
 
- 			}
 
- 			break;
 
- 		}
 
- 		case 'UpdateExpression': {
 
- 			if (isNumber(node.argument, scope)) {
 
- 				return true;
 
- 			}
 
- 			break;
 
- 		}
 
- 		case 'ConditionalExpression': {
 
- 			const isConsequentNumber = isNumber(node.consequent, scope);
 
- 			const isAlternateNumber = isNumber(node.alternate, scope);
 
- 			if (isConsequentNumber && isAlternateNumber) {
 
- 				return true;
 
- 			}
 
- 			const testStaticValueResult = getStaticValue(node.test, scope);
 
- 			if (
 
- 				testStaticValueResult !== null
 
- 				&& (
 
- 					(testStaticValueResult.value && isConsequentNumber)
 
- 					|| (!testStaticValueResult.value && isAlternateNumber)
 
- 				)
 
- 			) {
 
- 				return true;
 
- 			}
 
- 			break;
 
- 		}
 
- 		case 'SequenceExpression': {
 
- 			if (isNumber(node.expressions[node.expressions.length - 1], scope)) {
 
- 				return true;
 
- 			}
 
- 			break;
 
- 		}
 
- 		// No default
 
- 	}
 
- 	return isStaticNumber(node, scope);
 
- }
 
- module.exports = isNumber;
 
 
  |