Skip to content

Commit 8d8411b

Browse files
fiskersindresorhus
andauthored
prefer-node-protocol: Add checkRequire option (#1206)
Co-authored-by: Sindre Sorhus <[email protected]>
1 parent f1f30c3 commit 8d8411b

File tree

5 files changed

+126
-2
lines changed

5 files changed

+126
-2
lines changed

docs/rules/prefer-node-protocol.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,21 @@ import _ from 'lodash';
4545
```js
4646
import fs from './fs.js';
4747
```
48+
49+
## Options
50+
51+
Type: `object`
52+
53+
### `checkRequire`
54+
55+
Type: `boolean`\
56+
Default: `false`
57+
58+
Currently, `require(…)` with the `node:` protocol is only available on Node.js 16. If you don't care about old versions, you can set this to `true`.
59+
60+
We'll remove this option and check `require(…)` by default once this feature get backported to v12.
61+
62+
```js
63+
// eslint unicorn/prefer-node-protocol: ["error", {"checkRequire": true}]
64+
const fs = require('fs'); // Fails
65+
```

rules/prefer-node-protocol.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,32 @@ const messages = {
77
[MESSAGE_ID]: 'Prefer `node:{{moduleName}}` over `{{moduleName}}`.'
88
};
99

10-
const selector = [
10+
const importExportSelector = [
1111
':matches(ImportDeclaration, ExportNamedDeclaration, ImportExpression)',
1212
' > ',
1313
'Literal.source'
1414
].join('');
1515

16+
const requireSelector = [
17+
'CallExpression',
18+
'[optional!=true]',
19+
'[callee.type="Identifier"]',
20+
'[callee.name="require"]',
21+
'[arguments.length=1]',
22+
' > ',
23+
'Literal.arguments'
24+
].join('');
25+
1626
/** @param {import('eslint').Rule.RuleContext} context */
1727
const create = context => {
28+
const {checkRequire} = {
29+
checkRequire: false,
30+
...context.options[0]
31+
};
32+
const selector = checkRequire ?
33+
`:matches(${importExportSelector}, ${requireSelector})` :
34+
importExportSelector;
35+
1836
return {
1937
[selector](node) {
2038
const {value} = node;
@@ -38,6 +56,19 @@ const create = context => {
3856
};
3957
};
4058

59+
const schema = [
60+
{
61+
type: 'object',
62+
properties: {
63+
checkRequire: {
64+
type: 'boolean',
65+
default: false
66+
}
67+
},
68+
additionalProperties: false
69+
}
70+
];
71+
4172
module.exports = {
4273
create,
4374
meta: {
@@ -47,7 +78,7 @@ module.exports = {
4778
url: getDocumentationUrl(__filename)
4879
},
4980
fixable: 'code',
50-
schema: [],
81+
schema,
5182
messages
5283
}
5384
};

test/prefer-node-protocol.mjs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@ test.snapshot({
6060
]
6161
});
6262

63+
// `options`
64+
const checkRequireOptions = [{checkRequire: true}];
65+
test.snapshot({
66+
valid: [
67+
'const fs = require("node:fs");',
68+
'const fs = require("node:fs/promises");',
69+
'const fs = require(fs);',
70+
'const fs = notRequire("fs");',
71+
'const fs = foo.require("fs");',
72+
'const fs = require.resolve("fs");',
73+
'const fs = require(`fs`);',
74+
'const fs = require?.("fs");',
75+
'const fs = require("fs", extra);',
76+
'const fs = require();',
77+
'const fs = require(...["fs"]);',
78+
'const fs = require("unicorn");'
79+
].map(code => ({code, options: checkRequireOptions})),
80+
invalid: [
81+
'const {promises} = require("fs")',
82+
'const fs = require(\'fs/promises\')'
83+
].map(code => ({code, options: checkRequireOptions}))
84+
});
85+
6386
test.babel({
6487
valid: [
6588
'export fs from "node:fs";'

test/snapshots/prefer-node-protocol.mjs.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,55 @@ Generated by [AVA](https://avajs.dev).
251251
> 1 | import "timers/promises";␊
252252
| ^^^^^^^^^^^^^^^^^ Prefer \`node:timers/promises\` over \`timers/promises\`.␊
253253
`
254+
255+
## Invalid #1
256+
1 | const {promises} = require("fs")
257+
258+
> Options
259+
260+
`␊
261+
[␊
262+
{␊
263+
"checkRequire": true␊
264+
}␊
265+
]␊
266+
`
267+
268+
> Output
269+
270+
`␊
271+
1 | const {promises} = require("node:fs")␊
272+
`
273+
274+
> Error 1/1
275+
276+
`␊
277+
> 1 | const {promises} = require("fs")␊
278+
| ^^^^ Prefer \`node:fs\` over \`fs\`.␊
279+
`
280+
281+
## Invalid #2
282+
1 | const fs = require('fs/promises')
283+
284+
> Options
285+
286+
`␊
287+
[␊
288+
{␊
289+
"checkRequire": true␊
290+
}␊
291+
]␊
292+
`
293+
294+
> Output
295+
296+
`␊
297+
1 | const fs = require('node:fs/promises')␊
298+
`
299+
300+
> Error 1/1
301+
302+
`␊
303+
> 1 | const fs = require('fs/promises')␊
304+
| ^^^^^^^^^^^^^ Prefer \`node:fs/promises\` over \`fs/promises\`.␊
305+
`
146 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)