115 lines
2.4 KiB
JavaScript
115 lines
2.4 KiB
JavaScript
'use strict';
|
|
const getDocumentationUrl = require('./utils/get-documentation-url');
|
|
const isShadowed = require('./utils/is-shadowed');
|
|
const renameIdentifier = require('./utils/rename-identifier');
|
|
|
|
const METHOD_ERROR_MESSAGE_ID = 'method-error';
|
|
const METHOD_SUGGESTION_MESSAGE_ID = 'method-suggestion';
|
|
const PROPERTY_ERROR_MESSAGE_ID = 'property-error';
|
|
|
|
const methods = {
|
|
// Safe
|
|
parseInt: true,
|
|
parseFloat: true,
|
|
// Unsafe
|
|
isNaN: false,
|
|
isFinite: false
|
|
};
|
|
|
|
const methodsSelector = [
|
|
'CallExpression',
|
|
'>',
|
|
'Identifier.callee',
|
|
`:matches(${Object.keys(methods).map(name => `[name="${name}"]`).join(', ')})`
|
|
].join('');
|
|
|
|
const propertiesSelector = [
|
|
'Identifier',
|
|
'[name="NaN"]',
|
|
`:not(${
|
|
[
|
|
'MemberExpression[computed=false] > Identifier.property',
|
|
'FunctionDeclaration > Identifier.id',
|
|
'ClassDeclaration > Identifier.id',
|
|
'MethodDefinition > Identifier.key',
|
|
'VariableDeclarator > Identifier.id',
|
|
'Property[shorthand=false] > Identifier.key',
|
|
'TSDeclareFunction > Identifier.id',
|
|
'TSEnumMember > Identifier.id',
|
|
'TSPropertySignature > Identifier.key'
|
|
].join(', ')
|
|
})`
|
|
].join('');
|
|
|
|
const create = context => {
|
|
const sourceCode = context.getSourceCode();
|
|
|
|
return {
|
|
[methodsSelector]: node => {
|
|
if (isShadowed(context.getScope(), node)) {
|
|
return;
|
|
}
|
|
|
|
const {name} = node;
|
|
const isSafe = methods[name];
|
|
|
|
const problem = {
|
|
node,
|
|
messageId: METHOD_ERROR_MESSAGE_ID,
|
|
data: {
|
|
name
|
|
}
|
|
};
|
|
|
|
const fix = fixer => renameIdentifier(node, `Number.${name}`, fixer, sourceCode);
|
|
|
|
if (isSafe) {
|
|
problem.fix = fix;
|
|
} else {
|
|
problem.suggest = [
|
|
{
|
|
messageId: METHOD_SUGGESTION_MESSAGE_ID,
|
|
data: {
|
|
name
|
|
},
|
|
fix
|
|
}
|
|
];
|
|
}
|
|
|
|
context.report(problem);
|
|
},
|
|
[propertiesSelector]: node => {
|
|
if (isShadowed(context.getScope(), node)) {
|
|
return;
|
|
}
|
|
|
|
const {name} = node;
|
|
context.report({
|
|
node,
|
|
messageId: PROPERTY_ERROR_MESSAGE_ID,
|
|
data: {
|
|
name
|
|
},
|
|
fix: fixer => renameIdentifier(node, `Number.${name}`, fixer, sourceCode)
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
create,
|
|
meta: {
|
|
type: 'suggestion',
|
|
docs: {
|
|
url: getDocumentationUrl(__filename)
|
|
},
|
|
fixable: 'code',
|
|
messages: {
|
|
[METHOD_ERROR_MESSAGE_ID]: 'Prefer `Number.{{name}}()` over `{{name}}()`.',
|
|
[METHOD_SUGGESTION_MESSAGE_ID]: 'Replace `{{name}}()` with `Number.{{name}}()`.',
|
|
[PROPERTY_ERROR_MESSAGE_ID]: 'Prefer `Number.{{name}}` over `{{name}}`.'
|
|
}
|
|
}
|
|
};
|