Skip to content

Commit c8fbf00

Browse files
aladdin-addscagood
andauthored
feat(no-sync): Add ignores option (#386)
Co-authored-by: scagood <[email protected]>
1 parent 2f60954 commit c8fbf00

File tree

3 files changed

+61
-23
lines changed

3 files changed

+61
-23
lines changed

docs/rules/no-sync.md

+22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ This rule is aimed at preventing synchronous methods from being called in Node.j
1010

1111
### Options
1212

13+
#### allowAtRootLevel
14+
1315
This rule has an optional object option `{ allowAtRootLevel: <boolean> }`, which determines whether synchronous methods should be allowed at the top level of a file, outside of any functions. This option defaults to `false`.
1416

1517
Examples of **incorrect** code for this rule with the default `{ allowAtRootLevel: false }` option:
@@ -56,6 +58,26 @@ Examples of **correct** code for this rule with the `{ allowAtRootLevel: true }`
5658
fs.readFileSync(somePath).toString();
5759
```
5860

61+
#### ignores
62+
63+
You can `ignore` specific function names using this option.
64+
65+
Examples of **incorrect** code for this rule with the `{ ignores: ['readFileSync'] }` option:
66+
67+
```js
68+
/*eslint n/no-sync: ["error", { ignores: ['readFileSync'] }] */
69+
70+
fs.readdirSync(somePath);
71+
```
72+
73+
Examples of **correct** code for this rule with the `{ ignores: ['readFileSync'] }` option:
74+
75+
```js
76+
/*eslint n/no-sync: ["error", { ignores: ['readFileSync'] }] */
77+
78+
fs.readFileSync(somePath);
79+
```
80+
5981
## 🔎 Implementation
6082

6183
- [Rule source](../../lib/rules/no-sync.js)

lib/rules/no-sync.js

+19-19
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,13 @@
44
*/
55
"use strict"
66

7-
const allowedAtRootLevelSelector = [
7+
const selectors = [
88
// fs.readFileSync()
9-
":function MemberExpression > Identifier[name=/Sync$/]",
109
// readFileSync.call(null, 'path')
11-
":function MemberExpression > Identifier[name=/Sync$/]",
10+
"CallExpression > MemberExpression.callee Identifier[name=/Sync$/]",
1211
// readFileSync()
13-
":function :not(MemberExpression) > Identifier[name=/Sync$/]",
14-
].join(",")
15-
16-
const disallowedAtRootLevelSelector = [
17-
// fs.readFileSync()
18-
"MemberExpression > Identifier[name=/Sync$/]",
19-
// readFileSync.call(null, 'path')
20-
"MemberExpression > Identifier[name=/Sync$/]",
21-
// readFileSync()
22-
":not(MemberExpression) > Identifier[name=/Sync$/]",
23-
].join(",")
12+
"CallExpression > Identifier[name=/Sync$/]",
13+
]
2414

2515
/** @type {import('eslint').Rule.RuleModule} */
2616
module.exports = {
@@ -40,6 +30,11 @@ module.exports = {
4030
type: "boolean",
4131
default: false,
4232
},
33+
ignores: {
34+
type: "array",
35+
items: { type: "string" },
36+
default: [],
37+
},
4338
},
4439
additionalProperties: false,
4540
},
@@ -50,17 +45,22 @@ module.exports = {
5045
},
5146

5247
create(context) {
53-
const selector = context.options[0]?.allowAtRootLevel
54-
? allowedAtRootLevelSelector
55-
: disallowedAtRootLevelSelector
48+
const options = context.options[0] ?? {}
49+
const ignores = options.ignores ?? []
5650

51+
const selector = options.allowAtRootLevel
52+
? selectors.map(selector => `:function ${selector}`)
53+
: selectors
5754
return {
5855
/**
59-
* [node description]
6056
* @param {import('estree').Identifier & {parent: import('estree').Node}} node
6157
* @returns {void}
6258
*/
63-
[selector](node) {
59+
[selector.join(",")](node) {
60+
if (ignores.includes(node.name)) {
61+
return
62+
}
63+
6464
context.report({
6565
node: node.parent,
6666
messageId: "noSync",

tests/lib/rules/no-sync.js

+20-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ const rule = require("../../../lib/rules/no-sync")
1010
new RuleTester().run("no-sync", rule, {
1111
valid: [
1212
"var foo = fs.foo.foo();",
13+
// Allow non-function called to be ignored
14+
"fs.fooSync;",
15+
"fooSync;",
16+
"() => fooSync;",
1317
{
1418
code: "var foo = fs.fooSync;",
1519
options: [{ allowAtRootLevel: true }],
@@ -26,6 +30,11 @@ new RuleTester().run("no-sync", rule, {
2630
code: "if (true) {fooSync();}",
2731
options: [{ allowAtRootLevel: true }],
2832
},
33+
// ignores
34+
{
35+
code: "fooSync();",
36+
options: [{ ignores: ["fooSync"] }],
37+
},
2938
],
3039
invalid: [
3140
{
@@ -90,7 +99,7 @@ new RuleTester().run("no-sync", rule, {
9099
],
91100
},
92101
{
93-
code: "var foo = fs.fooSync;",
102+
code: "function someFunction() {fs.fooSync();}",
94103
errors: [
95104
{
96105
messageId: "noSync",
@@ -101,6 +110,7 @@ new RuleTester().run("no-sync", rule, {
101110
},
102111
{
103112
code: "function someFunction() {fs.fooSync();}",
113+
options: [{ allowAtRootLevel: true }],
104114
errors: [
105115
{
106116
messageId: "noSync",
@@ -110,7 +120,7 @@ new RuleTester().run("no-sync", rule, {
110120
],
111121
},
112122
{
113-
code: "function someFunction() {fs.fooSync();}",
123+
code: "var a = function someFunction() {fs.fooSync();}",
114124
options: [{ allowAtRootLevel: true }],
115125
errors: [
116126
{
@@ -120,9 +130,15 @@ new RuleTester().run("no-sync", rule, {
120130
},
121131
],
122132
},
133+
// ignores
123134
{
124-
code: "var a = function someFunction() {fs.fooSync();}",
125-
options: [{ allowAtRootLevel: true }],
135+
code: "() => {fs.fooSync();}",
136+
options: [
137+
{
138+
allowAtRootLevel: true,
139+
ignores: ["barSync"],
140+
},
141+
],
126142
errors: [
127143
{
128144
messageId: "noSync",

0 commit comments

Comments
 (0)