Skip to content

Commit e5e17f8

Browse files
authored
new-for-builtins: Correct fix for Date() (#2543)
1 parent 35fdb1c commit e5e17f8

6 files changed

+212
-53
lines changed

docs/rules/new-for-builtins.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs-eslintconfigjs).
44

5-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
5+
🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
66

77
<!-- end auto-generated rule header -->
88
<!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` -->

readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export default [
7171
| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. || 🔧 | 💡 |
7272
| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. || | |
7373
| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. || | |
74-
| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. || 🔧 | |
74+
| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. || 🔧 | 💡 |
7575
| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. || | |
7676
| [no-accessor-recursion](docs/rules/no-accessor-recursion.md) | Disallow recursive access to `this` within getters and setters. || | |
7777
| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. || | 💡 |

rules/new-for-builtins.js

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import {GlobalReferenceTracker} from './utils/global-reference-tracker.js';
22
import * as builtins from './utils/builtins.js';
3-
import {switchCallExpressionToNewExpression, switchNewExpressionToCallExpression} from './fix/index.js';
3+
import {
4+
switchCallExpressionToNewExpression,
5+
switchNewExpressionToCallExpression,
6+
fixSpaceAroundKeyword,
7+
} from './fix/index.js';
8+
9+
const MESSAGE_ID_ERROR_DATE = 'error-date';
10+
const MESSAGE_ID_SUGGESTION_DATE = 'suggestion-date';
411

512
const messages = {
613
enforce: 'Use `new {{name}}()` instead of `{{name}}()`.',
714
disallow: 'Use `{{name}}()` instead of `new {{name}}()`.',
15+
[MESSAGE_ID_ERROR_DATE]: 'Use `String(new Date())` instead of `Date()`.',
16+
[MESSAGE_ID_SUGGESTION_DATE]: 'Switch to `String(new Date())`.',
817
};
918

1019
function enforceNewExpression({node, path: [name]}, sourceCode) {
@@ -19,6 +28,33 @@ function enforceNewExpression({node, path: [name]}, sourceCode) {
1928
}
2029
}
2130

31+
// `Date()` returns a string representation of the current date and time, exactly as `new Date().toString()` does.
32+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#return_value
33+
if (name === 'Date') {
34+
function * fix(fixer) {
35+
yield fixer.replaceText(node, 'String(new Date())');
36+
yield * fixSpaceAroundKeyword(fixer, node, sourceCode);
37+
}
38+
39+
const problem = {
40+
node,
41+
messageId: MESSAGE_ID_ERROR_DATE,
42+
};
43+
44+
if (sourceCode.getCommentsInside(node).length === 0 && node.arguments.length === 0) {
45+
problem.fix = fix;
46+
} else {
47+
problem.suggest = [
48+
{
49+
messageId: MESSAGE_ID_SUGGESTION_DATE,
50+
fix,
51+
},
52+
];
53+
}
54+
55+
return problem;
56+
}
57+
2258
return {
2359
node,
2460
messageId: 'enforce',
@@ -77,6 +113,7 @@ const config = {
77113
recommended: true,
78114
},
79115
fixable: 'code',
116+
hasSuggestions: true,
80117
messages,
81118
},
82119
};

test/new-for-builtins.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ test.snapshot({
1313
'const foo = new BigInt64Array()',
1414
'const foo = new BigUint64Array()',
1515
'const foo = new DataView()',
16-
'const foo = new Date()',
1716
'const foo = new Error()',
1817
'const foo = new Float32Array()',
1918
'const foo = new Float64Array()',
@@ -205,7 +204,6 @@ test.snapshot({
205204
'const foo = BigInt64Array()',
206205
'const foo = BigUint64Array()',
207206
'const foo = DataView()',
208-
'const foo = Date()',
209207
'const foo = Error()',
210208
'const foo = Error(\'Foo bar\')',
211209
'const foo = Float32Array()',
@@ -259,3 +257,22 @@ test.snapshot({
259257
`,
260258
],
261259
});
260+
261+
// `Date`
262+
test.snapshot({
263+
valid: [
264+
'const foo = new Date();',
265+
],
266+
invalid: [
267+
'const foo = Date();',
268+
'const foo = globalThis.Date();',
269+
outdent`
270+
function foo() {
271+
return(globalThis).Date();
272+
}
273+
`,
274+
'const foo = Date(/*comment*/);',
275+
'const foo = globalThis/*comment*/.Date();',
276+
'const foo = Date(bar);',
277+
],
278+
});

0 commit comments

Comments
 (0)