Skip to content

Commit

Permalink
feat(no-sync): Add ignores option (#386)
Browse files Browse the repository at this point in the history
Co-authored-by: scagood <2230835+scagood@users.noreply.github.com>
  • Loading branch information
aladdin-add and scagood authored Nov 18, 2024
1 parent 2f60954 commit c8fbf00
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 23 deletions.
22 changes: 22 additions & 0 deletions docs/rules/no-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This rule is aimed at preventing synchronous methods from being called in Node.j

### Options

#### allowAtRootLevel

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`.

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

#### ignores

You can `ignore` specific function names using this option.

Examples of **incorrect** code for this rule with the `{ ignores: ['readFileSync'] }` option:

```js
/*eslint n/no-sync: ["error", { ignores: ['readFileSync'] }] */

fs.readdirSync(somePath);
```

Examples of **correct** code for this rule with the `{ ignores: ['readFileSync'] }` option:

```js
/*eslint n/no-sync: ["error", { ignores: ['readFileSync'] }] */

fs.readFileSync(somePath);
```

## 🔎 Implementation

- [Rule source](../../lib/rules/no-sync.js)
Expand Down
38 changes: 19 additions & 19 deletions lib/rules/no-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,13 @@
*/
"use strict"

const allowedAtRootLevelSelector = [
const selectors = [
// fs.readFileSync()
":function MemberExpression > Identifier[name=/Sync$/]",
// readFileSync.call(null, 'path')
":function MemberExpression > Identifier[name=/Sync$/]",
"CallExpression > MemberExpression.callee Identifier[name=/Sync$/]",
// readFileSync()
":function :not(MemberExpression) > Identifier[name=/Sync$/]",
].join(",")

const disallowedAtRootLevelSelector = [
// fs.readFileSync()
"MemberExpression > Identifier[name=/Sync$/]",
// readFileSync.call(null, 'path')
"MemberExpression > Identifier[name=/Sync$/]",
// readFileSync()
":not(MemberExpression) > Identifier[name=/Sync$/]",
].join(",")
"CallExpression > Identifier[name=/Sync$/]",
]

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
Expand All @@ -40,6 +30,11 @@ module.exports = {
type: "boolean",
default: false,
},
ignores: {
type: "array",
items: { type: "string" },
default: [],
},
},
additionalProperties: false,
},
Expand All @@ -50,17 +45,22 @@ module.exports = {
},

create(context) {
const selector = context.options[0]?.allowAtRootLevel
? allowedAtRootLevelSelector
: disallowedAtRootLevelSelector
const options = context.options[0] ?? {}
const ignores = options.ignores ?? []

const selector = options.allowAtRootLevel
? selectors.map(selector => `:function ${selector}`)
: selectors
return {
/**
* [node description]
* @param {import('estree').Identifier & {parent: import('estree').Node}} node
* @returns {void}
*/
[selector](node) {
[selector.join(",")](node) {
if (ignores.includes(node.name)) {
return
}

context.report({
node: node.parent,
messageId: "noSync",
Expand Down
24 changes: 20 additions & 4 deletions tests/lib/rules/no-sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ const rule = require("../../../lib/rules/no-sync")
new RuleTester().run("no-sync", rule, {
valid: [
"var foo = fs.foo.foo();",
// Allow non-function called to be ignored
"fs.fooSync;",
"fooSync;",
"() => fooSync;",
{
code: "var foo = fs.fooSync;",
options: [{ allowAtRootLevel: true }],
Expand All @@ -26,6 +30,11 @@ new RuleTester().run("no-sync", rule, {
code: "if (true) {fooSync();}",
options: [{ allowAtRootLevel: true }],
},
// ignores
{
code: "fooSync();",
options: [{ ignores: ["fooSync"] }],
},
],
invalid: [
{
Expand Down Expand Up @@ -90,7 +99,7 @@ new RuleTester().run("no-sync", rule, {
],
},
{
code: "var foo = fs.fooSync;",
code: "function someFunction() {fs.fooSync();}",
errors: [
{
messageId: "noSync",
Expand All @@ -101,6 +110,7 @@ new RuleTester().run("no-sync", rule, {
},
{
code: "function someFunction() {fs.fooSync();}",
options: [{ allowAtRootLevel: true }],
errors: [
{
messageId: "noSync",
Expand All @@ -110,7 +120,7 @@ new RuleTester().run("no-sync", rule, {
],
},
{
code: "function someFunction() {fs.fooSync();}",
code: "var a = function someFunction() {fs.fooSync();}",
options: [{ allowAtRootLevel: true }],
errors: [
{
Expand All @@ -120,9 +130,15 @@ new RuleTester().run("no-sync", rule, {
},
],
},
// ignores
{
code: "var a = function someFunction() {fs.fooSync();}",
options: [{ allowAtRootLevel: true }],
code: "() => {fs.fooSync();}",
options: [
{
allowAtRootLevel: true,
ignores: ["barSync"],
},
],
errors: [
{
messageId: "noSync",
Expand Down

0 comments on commit c8fbf00

Please sign in to comment.