Skip to content

Commit 2ea0f22

Browse files
authored
feat: add prefer-global/crypto rule (#514)
1 parent 9c5e437 commit 2ea0f22

File tree

5 files changed

+177
-0
lines changed

5 files changed

+177
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ For [Shareable Configs](https://eslint.org/docs/latest/developer-guide/shareable
165165
| [no-unsupported-features/node-builtins](docs/rules/no-unsupported-features/node-builtins.md) | disallow unsupported Node.js built-in APIs on the specified version | 🟢 ✅ | | |
166166
| [prefer-global/buffer](docs/rules/prefer-global/buffer.md) | enforce either `Buffer` or `require("buffer").Buffer` | | | |
167167
| [prefer-global/console](docs/rules/prefer-global/console.md) | enforce either `console` or `require("console")` | | | |
168+
| [prefer-global/crypto](docs/rules/prefer-global/crypto.md) | enforce either `crypto` or `require("crypto").webcrypto` | | | |
168169
| [prefer-global/process](docs/rules/prefer-global/process.md) | enforce either `process` or `require("process")` | | | |
169170
| [prefer-global/text-decoder](docs/rules/prefer-global/text-decoder.md) | enforce either `TextDecoder` or `require("util").TextDecoder` | | | |
170171
| [prefer-global/text-encoder](docs/rules/prefer-global/text-encoder.md) | enforce either `TextEncoder` or `require("util").TextEncoder` | | | |

docs/rules/prefer-global/crypto.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Enforce either `crypto` or `require("crypto").webcrypto` (`n/prefer-global/crypto`)
2+
3+
<!-- end auto-generated rule header -->
4+
5+
An implementation of the Web Crypto API is defined as a global variable.
6+
7+
```js
8+
console.log(crypto === require("node:crypto").webcrypto) //→ true
9+
```
10+
11+
It will be readable if we use `crypto` consistently.
12+
13+
## 📖 Rule Details
14+
15+
This rule enforces whether to use the global `crypto` variable or the `webcrypto` property from the `crypto` module.
16+
17+
### Options
18+
19+
This rule has a string option.
20+
21+
```json
22+
{
23+
"n/prefer-global/crypto": ["error", "always" | "never"]
24+
}
25+
```
26+
27+
- `"always"` (default) ... enforces to use the global variable `crypto` rather than `require("crypto").webcrypto`.
28+
- `"never"` ... enforces to use `require("crypto").webcrypto` rather than the global variable `crypto`.
29+
30+
#### always
31+
32+
Examples of 👎 **incorrect** code for this rule:
33+
34+
```js
35+
/*eslint n/prefer-global/crypto: [error]*/
36+
37+
const { webcrypto } = require("crypto")
38+
webcrypto.randomUUID()
39+
```
40+
41+
Examples of 👍 **correct** code for this rule:
42+
43+
```js
44+
/*eslint n/prefer-global/crypto: [error]*/
45+
46+
crypto.randomUUID()
47+
```
48+
49+
#### never
50+
51+
Examples of 👎 **incorrect** code for the `"never"` option:
52+
53+
```js
54+
/*eslint n/prefer-global/crypto: [error, never]*/
55+
56+
crypto.randomUUID()
57+
```
58+
59+
Examples of 👍 **correct** code for the `"never"` option:
60+
61+
```js
62+
/*eslint n/prefer-global/crypto: [error, never]*/
63+
64+
const { webcrypto } = require("crypto")
65+
webcrypto.randomUUID()
66+
```
67+
68+
## 🔎 Implementation
69+
70+
- [Rule source](../../../lib/rules/prefer-global/crypto.js)
71+
- [Test source](../../../tests/lib/rules/prefer-global/crypto.js)

lib/all-rules.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module.exports = {
3838
"no-unsupported-features/node-builtins": require("./rules/no-unsupported-features/node-builtins"),
3939
"prefer-global/buffer": require("./rules/prefer-global/buffer"),
4040
"prefer-global/console": require("./rules/prefer-global/console"),
41+
"prefer-global/crypto": require("./rules/prefer-global/crypto"),
4142
"prefer-global/process": require("./rules/prefer-global/process"),
4243
"prefer-global/text-decoder": require("./rules/prefer-global/text-decoder"),
4344
"prefer-global/text-encoder": require("./rules/prefer-global/text-encoder"),

lib/rules/prefer-global/crypto.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* @author Pixel998
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
"use strict"
6+
7+
const { READ } = require("@eslint-community/eslint-utils")
8+
const checkForPreferGlobal = require("../../util/check-prefer-global")
9+
10+
const traceMap = {
11+
globals: {
12+
crypto: { [READ]: true },
13+
},
14+
modules: {
15+
crypto: { webcrypto: { [READ]: true } },
16+
"node:crypto": { webcrypto: { [READ]: true } },
17+
},
18+
}
19+
20+
/** @type {import('../rule-module').RuleModule} */
21+
module.exports = {
22+
meta: {
23+
docs: {
24+
description:
25+
'enforce either `crypto` or `require("crypto").webcrypto`',
26+
recommended: false,
27+
url: "https://github.com/eslint-community/eslint-plugin-n/blob/HEAD/docs/rules/prefer-global/crypto.md",
28+
},
29+
type: "suggestion",
30+
fixable: null,
31+
schema: [{ enum: ["always", "never"] }],
32+
messages: {
33+
preferGlobal:
34+
"Unexpected use of 'require(\"crypto\").webcrypto'. Use the global variable 'crypto' instead.",
35+
preferModule:
36+
"Unexpected use of the global variable 'crypto'. Use 'require(\"crypto\").webcrypto' instead.",
37+
},
38+
},
39+
40+
create(context) {
41+
return {
42+
"Program:exit"() {
43+
checkForPreferGlobal(context, traceMap)
44+
},
45+
}
46+
},
47+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @author Pixel998
3+
* See LICENSE file in root directory for full license.
4+
*/
5+
"use strict"
6+
7+
const RuleTester = require("#test-helpers").RuleTester
8+
const rule = require("../../../../lib/rules/prefer-global/crypto")
9+
10+
const provideModuleMethods = ["require", "process.getBuiltinModule"]
11+
12+
new RuleTester().run("prefer-global/crypto", rule, {
13+
valid: [
14+
"crypto.randomUUID()",
15+
{
16+
code: "crypto.randomUUID()",
17+
options: ["always"],
18+
},
19+
...provideModuleMethods.flatMap(method => [
20+
{
21+
code: `const { webcrypto } = ${method}('crypto'); webcrypto.randomUUID()`,
22+
options: ["never"],
23+
},
24+
{
25+
code: `const { webcrypto } = ${method}('node:crypto'); webcrypto.randomUUID()`,
26+
options: ["never"],
27+
},
28+
]),
29+
],
30+
invalid: [
31+
...provideModuleMethods.flatMap(method => [
32+
{
33+
code: `const { webcrypto } = ${method}('crypto'); webcrypto.randomUUID()`,
34+
errors: [{ messageId: "preferGlobal" }],
35+
},
36+
{
37+
code: `const { webcrypto } = ${method}('node:crypto'); webcrypto.randomUUID()`,
38+
errors: [{ messageId: "preferGlobal" }],
39+
},
40+
{
41+
code: `const { webcrypto } = ${method}('crypto'); webcrypto.randomUUID()`,
42+
options: ["always"],
43+
errors: [{ messageId: "preferGlobal" }],
44+
},
45+
{
46+
code: `const { webcrypto } = ${method}('node:crypto'); webcrypto.randomUUID()`,
47+
options: ["always"],
48+
errors: [{ messageId: "preferGlobal" }],
49+
},
50+
]),
51+
{
52+
code: "crypto.randomUUID()",
53+
options: ["never"],
54+
errors: [{ messageId: "preferModule" }],
55+
},
56+
],
57+
})

0 commit comments

Comments
 (0)