123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- 'use strict';
- const {GlobalReferenceTracker} = require('./utils/global-reference-tracker.js');
- const {replaceReferenceIdentifier} = require('./fix/index.js');
- const {fixSpaceAroundKeyword} = require('./fix/index.js');
- const MESSAGE_ID_ERROR = 'error';
- const MESSAGE_ID_SUGGESTION = 'suggestion';
- const messages = {
- [MESSAGE_ID_ERROR]: 'Prefer `Number.{{property}}` over `{{description}}`.',
- [MESSAGE_ID_SUGGESTION]: 'Replace `{{description}}` with `Number.{{property}}`.',
- };
- const globalObjects = {
- // Safe to replace with `Number` properties
- parseInt: true,
- parseFloat: true,
- NaN: true,
- Infinity: true,
- // Unsafe to replace with `Number` properties
- isNaN: false,
- isFinite: false,
- };
- const isNegative = node => {
- const {parent} = node;
- return parent.type === 'UnaryExpression' && parent.operator === '-' && parent.argument === node;
- };
- function checkProperty({node, path: [name]}, sourceCode) {
- const {parent} = node;
- let property = name;
- if (name === 'Infinity') {
- property = isNegative(node) ? 'NEGATIVE_INFINITY' : 'POSITIVE_INFINITY';
- }
- const problem = {
- node,
- messageId: MESSAGE_ID_ERROR,
- data: {
- description: name,
- property,
- },
- };
- if (property === 'NEGATIVE_INFINITY') {
- problem.node = parent;
- problem.data.description = '-Infinity';
- problem.fix = function * (fixer) {
- yield fixer.replaceText(parent, 'Number.NEGATIVE_INFINITY');
- yield * fixSpaceAroundKeyword(fixer, parent, sourceCode);
- };
- return problem;
- }
- const fix = fixer => replaceReferenceIdentifier(node, `Number.${property}`, fixer, sourceCode);
- const isSafeToFix = globalObjects[name];
- if (isSafeToFix) {
- problem.fix = fix;
- } else {
- problem.suggest = [
- {
- messageId: MESSAGE_ID_SUGGESTION,
- fix,
- },
- ];
- }
- return problem;
- }
- /** @param {import('eslint').Rule.RuleContext} context */
- const create = context => {
- const {
- checkInfinity,
- } = {
- checkInfinity: true,
- ...context.options[0],
- };
- const sourceCode = context.getSourceCode();
- let objects = Object.keys(globalObjects);
- if (!checkInfinity) {
- objects = objects.filter(name => name !== 'Infinity');
- }
- const tracker = new GlobalReferenceTracker({
- objects,
- handle: reference => checkProperty(reference, sourceCode),
- });
- return tracker.createListeners(context);
- };
- const schema = [
- {
- type: 'object',
- additionalProperties: false,
- properties: {
- checkInfinity: {
- type: 'boolean',
- default: true,
- },
- },
- },
- ];
- /** @type {import('eslint').Rule.RuleModule} */
- module.exports = {
- create,
- meta: {
- type: 'suggestion',
- docs: {
- description: 'Prefer `Number` static properties over global ones.',
- },
- fixable: 'code',
- hasSuggestions: true,
- schema,
- messages,
- },
- };
|