Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
618 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch | ||
|
||
[`Date.now()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now) is shorter and nicer than [`new Date().getTime()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime). | ||
|
||
This rule is fixable. | ||
|
||
## Fail | ||
|
||
```js | ||
const foo = new Date().getTime(); | ||
``` | ||
|
||
```js | ||
const foo = new Date().valueOf(); | ||
``` | ||
|
||
```js | ||
const foo = +new Date; | ||
``` | ||
|
||
```js | ||
const foo = Number(new Date()); | ||
``` | ||
|
||
```js | ||
const foo = new Date() * 2; | ||
``` | ||
|
||
## Pass | ||
|
||
```js | ||
const foo = Date.now(); | ||
``` | ||
|
||
```js | ||
const foo = Date.now() * 2; | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
'use strict'; | ||
const getDocumentationUrl = require('./utils/get-documentation-url'); | ||
const methodSelector = require('./utils/method-selector'); | ||
|
||
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 => { | ||
const prefix = path ? `${path}.` : ''; | ||
return [ | ||
`[${prefix}type="NewExpression"]`, | ||
`[${prefix}callee.type="Identifier"]`, | ||
`[${prefix}callee.name="Date"]`, | ||
`[${prefix}arguments.length=0]` | ||
].join(''); | ||
}; | ||
|
||
const operatorsSelector = (...operators) => `:matches(${ | ||
operators.map(operator => `[operator="${operator}"]`).join(', ') | ||
})`; | ||
const newDateSelector = createNewDateSelector(); | ||
const methodsSelector = [ | ||
methodSelector({ | ||
names: ['getTime', 'valueOf'], | ||
length: 0 | ||
}), | ||
createNewDateSelector('callee.object') | ||
].join(''); | ||
const builtinObjectSelector = [ | ||
'CallExpression', | ||
'[callee.type="Identifier"]', | ||
':matches([callee.name="Number"], [callee.name="BigInt"])', | ||
'[arguments.length=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 create = context => { | ||
const report = (node, problem) => context.report({ | ||
node, | ||
messageId: MESSAGE_ID_DEFAULT, | ||
fix: fixer => fixer.replaceText(node, 'Date.now()'), | ||
...problem | ||
}); | ||
|
||
return { | ||
[methodsSelector](node) { | ||
const method = node.callee.property; | ||
report(node, { | ||
node: method, | ||
messageId: MESSAGE_ID_METHOD, | ||
data: {method: method.name} | ||
}); | ||
}, | ||
[builtinObjectSelector](node) { | ||
const {name} = node.callee; | ||
if (name === 'Number') { | ||
report(node, { | ||
messageId: MESSAGE_ID_NUMBER | ||
}); | ||
} else { | ||
report(node.arguments[0]); | ||
} | ||
}, | ||
[unaryExpressionsSelector](node) { | ||
report(node.operator === '-' ? node.argument : node); | ||
}, | ||
[assignmentExpressionSelector](node) { | ||
report(node); | ||
}, | ||
[binaryExpressionSelector](node) { | ||
report(node); | ||
} | ||
}; | ||
}; | ||
|
||
const schema = []; | ||
|
||
module.exports = { | ||
create, | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
url: getDocumentationUrl(__filename) | ||
}, | ||
fixable: 'code', | ||
schema, | ||
messages | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import {test} from './utils/test'; | ||
|
||
test({ | ||
valid: [ | ||
'const ts = Date.now()', | ||
|
||
// Test `new Date()` | ||
// Not `NewExpression` | ||
'+Date()', | ||
'+ Date', | ||
// Not `Identifier` | ||
'+ new window.Date()', | ||
// Not `Date` | ||
'+ new Moments()', | ||
// More arguments | ||
'+ new Date(0)', | ||
'+ new Date(...[])', | ||
|
||
// Test `new Date().getTime()` and `new Date().valueOf()` | ||
// Not `CallExpression` | ||
'new Date.getTime()', | ||
// Not `MemberExpression` | ||
'valueOf()', | ||
// `computed` | ||
'new Date()[getTime]()', | ||
// Not `Identifier` | ||
'new Date()["valueOf"]()', | ||
// Not listed names | ||
'new Date().notListed(0)', | ||
// More arguments | ||
'new Date().getTime(0)', | ||
'new Date().valueOf(...[])', | ||
|
||
// Test `Number(new Date())` and `BigInt(new Date())` | ||
// Not `CallExpression` | ||
'new Number(new Date())', | ||
// Not `Identifier` | ||
'window.BigInt(new Date())', | ||
// Not listed names | ||
'toNumber(new Date())', | ||
// More/less arguments | ||
'BigInt()', | ||
'Number(new Date(), extraArgument)', | ||
'BigInt([...new Date()])', | ||
|
||
// Test `+ new Date()` / `- new Date()` | ||
// Not `UnaryExpression` | ||
'throw new Date()', | ||
// Not `+/-` | ||
'typeof new Date()', | ||
|
||
// Test `AssignmentExpression` | ||
// Not `AssignmentExpression` | ||
'const foo = () => {return new Date()}', | ||
// `operator` not listed | ||
'foo += new Date()', | ||
|
||
// Test `BinaryExpression` | ||
// Not `BinaryExpression` | ||
'function * foo() {yield new Date()}', | ||
// `operator` not listed | ||
'new Date() + new Date()', | ||
|
||
// We are not checking these cases | ||
'foo = new Date() | 0', | ||
'foo &= new Date()', | ||
'foo = new Date() >> 0' | ||
], | ||
invalid: [] | ||
}); | ||
|
||
test.visualize([ | ||
// `Date` methods | ||
'const ts = new Date().getTime();', | ||
'const ts = (new Date).getTime();', | ||
'const ts = (new Date()).getTime();', | ||
'const ts = new Date().valueOf();', | ||
'const ts = (new Date).valueOf();', | ||
'const ts = (new Date()).valueOf();', | ||
|
||
// `Number()` and `BigInt()` | ||
'const ts = /* 1 */ Number(/* 2 */ new /* 3 */ Date( /* 4 */ ) /* 5 */) /* 6 */', | ||
'const tsBigInt = /* 1 */ BigInt(/* 2 */ new /* 3 */ Date( /* 4 */ ) /* 5 */) /* 6 */', | ||
|
||
// `UnaryExpression` | ||
'const ts = + /* 1 */ new Date;', | ||
'const ts = - /* 1 */ new Date();', | ||
|
||
// `BinaryExpression` | ||
'const ts = new Date() - 0', | ||
'const foo = bar - new Date', | ||
'const foo = new Date() * bar', | ||
'const ts = new Date() / 1', | ||
'const ts = new Date() % Infinity', | ||
'const ts = new Date() ** 1', | ||
'const zero = (new Date(/* 1 */) /* 2 */) /* 3 */ - /* 4 */new Date', | ||
|
||
// `AssignmentExpression` | ||
'foo -= new Date()', | ||
'foo *= new Date()', | ||
'foo /= new Date', | ||
'foo %= new Date()', | ||
'foo **= new Date()' | ||
]); |
Oops, something went wrong.