securityos/node_modules/eslint-plugin-unicorn/rules/prefer-date-now.js

116 lines
3.0 KiB
JavaScript

'use strict';
const {
matches,
methodCallSelector,
newExpressionSelector,
callExpressionSelector,
} = require('./selectors/index.js');
const {fixSpaceAroundKeyword} = require('./fix/index.js');
const MESSAGE_ID_DEFAULT = 'prefer-date';
const MESSAGE_ID_METHOD = 'prefer-date-now-over-methods';
const MESSAGE_ID_NUMBER = 'prefer-date-now-over-number-data-object';
const messages = {
[MESSAGE_ID_DEFAULT]: 'Prefer `Date.now()` over `new Date()`.',
[MESSAGE_ID_METHOD]: 'Prefer `Date.now()` over `Date#{{method}}()`.',
[MESSAGE_ID_NUMBER]: 'Prefer `Date.now()` over `Number(new Date())`.',
};
const createNewDateSelector = path => newExpressionSelector({path, name: 'Date', argumentsLength: 0});
const operatorsSelector = (...operators) => matches(operators.map(operator => `[operator="${operator}"]`));
// `new Date()`
const newDateSelector = createNewDateSelector();
// `new Date().{getTime,valueOf}()`
const methodsSelector = [
methodCallSelector({
methods: ['getTime', 'valueOf'],
argumentsLength: 0,
}),
createNewDateSelector('callee.object'),
].join('');
// `{Number,BigInt}(new Date())`
const builtinObjectSelector = [
callExpressionSelector({names: ['Number', 'BigInt'], argumentsLength: 1}),
createNewDateSelector('arguments.0'),
].join('');
// https://github.com/estree/estree/blob/master/es5.md#unaryoperator
const unaryExpressionsSelector = [
'UnaryExpression',
operatorsSelector('+', '-'),
createNewDateSelector('argument'),
].join('');
const assignmentExpressionSelector = [
'AssignmentExpression',
operatorsSelector('-=', '*=', '/=', '%=', '**='),
'>',
`${newDateSelector}.right`,
].join('');
const binaryExpressionSelector = [
'BinaryExpression',
operatorsSelector('-', '*', '/', '%', '**'),
// Both `left` and `right` properties
'>',
newDateSelector,
].join('');
const getProblem = (node, problem, sourceCode) => ({
node,
messageId: MESSAGE_ID_DEFAULT,
* fix(fixer) {
yield fixer.replaceText(node, 'Date.now()');
if (node.type === 'UnaryExpression') {
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
}
},
...problem,
});
/** @param {import('eslint').Rule.RuleContext} context */
const create = context => ({
[methodsSelector](node) {
const method = node.callee.property;
return getProblem(node, {
node: method,
messageId: MESSAGE_ID_METHOD,
data: {method: method.name},
});
},
[builtinObjectSelector](node) {
const {name} = node.callee;
if (name === 'Number') {
return getProblem(node, {
messageId: MESSAGE_ID_NUMBER,
});
}
return getProblem(node.arguments[0]);
},
[unaryExpressionsSelector](node) {
return getProblem(
node.operator === '-' ? node.argument : node,
{},
context.getSourceCode(),
);
},
[assignmentExpressionSelector](node) {
return getProblem(node);
},
[binaryExpressionSelector](node) {
return getProblem(node);
},
});
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
create,
meta: {
type: 'suggestion',
docs: {
description: 'Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch.',
},
fixable: 'code',
messages,
},
};