biomejs / biome

A toolchain for web projects, aimed to provide functionalities to maintain them. Biome offers formatter and linter, usable via CLI and LSP.
https://biomejs.dev
Apache License 2.0
14.24k stars 440 forks source link

One does not simply enable just one lint rule #1768

Closed chekrd closed 7 months ago

chekrd commented 7 months ago

Environment information

CLI:
  Version:                      1.5.3
  Color support:                true

Platform:
  CPU Architecture:             aarch64
  OS:                           macos

Environment:
  BIOME_LOG_DIR:                unset
  NO_COLOR:                     unset
  TERM:                         "xterm-256color"
  JS_RUNTIME_VERSION:           "v21.6.1"
  JS_RUNTIME_NAME:              "node"
  NODE_PACKAGE_MANAGER:         "npm/10.2.4"

Biome Configuration:
  Status:                       Loaded successfully
  Formatter disabled:           false
  Linter disabled:              false
  Organize imports disabled:    false
  VCS disabled:                 true

Workspace:
  Open Documents:               0

Rule name

All lint rules

Playground link

No link, because it is not possible to enable just one lint rule in the playground.

Expected result

Hi, thanks for you work!

How can I enable just a specific set of lint rules and disable all the others? Our usecase is that we manually pick what rules are enabled (reasons are that we are migrating a very large codebase from ESLint to Biome + some Biome recommended lint rules are buggy right now). I have created this as a bug, because in @1.4.1 following did what we needed:

 "linter": {
    "enabled": true,
    "rules": {
      "recommended": false,
      "complexity": {
        "useFlatMap": "error"
      }
    }
  },

But in Biome @1.5.3 this does not work anymore. What I have tried (but nothing worked):

All rules are applied:

"linter": {
  "enabled": true,
  "rules": {
    "complexity": {
      "useFlatMap": "error"
    }
  }
},

"linter": {
  "enabled": true,
  "rules": {
    "recommended": false,
    "complexity": {
      "useFlatMap": "error"
    }
  }
},

All rules of complexity group are applied:

"linter": {
  "enabled": true,
  "rules": {
    "all": false,
    "complexity": {
      "useFlatMap": "error"
    }
  }
},

No rule is applied:

"linter": {
  "enabled": true,
  "rules": {
    "all": false, // the same when ”recommended”: false instead of “all”: false
    "complexity": {
      "all": false, // the same when ”recommended”: false instead of “all”: false
      "useFlatMap": "error"
    }
  }
},

 "linter": {
    "enabled": true,
    "rules": {
      "recommended": false,
      "a11y": {
        "recommended": false
      },
      "complexity": {
        "recommended": false,
        "useFlatMap": "error"
      },
      "nursery": {
        "recommended": false
      },
      "correctness": {
        "recommended": false
      },
      "performance": {
        "recommended": false
      },
      "security": {
        "recommended": false
      },
      "style": {
        "recommended": false
      },
      "suspicious": {
        "recommended": false
      }
    }
  },

Scary workaround

The only way we can enable what we need is to toggle all rules within a touched group. But this is kind of crazy as we have at least one rule enabled in every group, so we must copy paste the whole "rules" schema and disable unwanted rules one by one:

"linter": {
    "enabled": true,
    "rules": {
      "all": false,
      "complexity": {
        "noBannedTypes": "off",
        "noExcessiveCognitiveComplexity": "off",
        "noExtraBooleanCast": "off",
        "noForEach": "off",
        "noMultipleSpacesInRegularExpressionLiterals": "off",
        "noStaticOnlyClass": "off",
        "noThisInStatic": "off",
        "noUselessCatch": "off",
        "noUselessConstructor": "off",
        "noUselessEmptyExport": "off",
        "noUselessFragments": "off",
        "noUselessLabel": "off",
        "noUselessRename": "off",
        "noUselessSwitchCase": "off",
        "noUselessThisAlias": "off",
        "noUselessTypeConstraint": "off",
        "noVoid": "off",
        "noWith": "off",
        "useArrowFunction": "off",
        "useFlatMap": "error", // this one is enabled
        "useLiteralKeys": "off",
        "useOptionalChain": "off",
        "useSimpleNumberKeys": "off",
        "useSimplifiedLogicExpression": "off"
      }
    }

Adding an example to the docs page about how to disable all recommended rules and enable just a few would be great! 🙂

Code of Conduct

ematipico commented 7 months ago

This sounds like a nasty bug, I wonder what changed in these versions...

Thank you for taking the time to show us possible combinations/cases, they will help us to identify the problem.

Conaclos commented 7 months ago

Hi! I tried to reproduce your issue, however I got the expected behavior:

❯ cat biome.json
{
 "linter": {
   "enabled": true,
   "rules": {
     "recommended": false,
     "complexity": {
       "useFlatMap": "error"
     }
   }
 }
}

❯ cat index.js
debugger; // should trigger noDebugger
new RegExp("abc", "u"); // should trigger useRegexLiterals

❯ npx @biomejs/biome@1.5.3 lint index.js
Checked 1 file(s) in 347µs

Could you provide a reproduction?

chekrd commented 7 months ago

Hi @Conaclos, my bad, I didn’t specify before, that the issue appears when using ci command:

❯ cat biome.json
{
 "linter": {
   "enabled": true,
   "rules": {
     "recommended": false,
     "complexity": {
       "useFlatMap": "error"
     }
   }
 }
}

❯ cat index.js
debugger; // should trigger noDebugger
new RegExp("abc", "u"); // should trigger useRegexLiterals
[].map((i) => i).flat(); // should trigger useFlatMap

❯ npx @biomejs/biome@1.5.3 ci index.js
index.js:1:1 lint/suspicious/noDebugger  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ This is an unexpected use of the debugger statement.

  > 1 │ debugger; // should trigger noDebugger
      │ ^^^^^^^^^
    2 │ new RegExp("abc", "u"); // should trigger useRegexLiterals
    3 │ [].map((i) => i).flat(); // should trigger useFlatMap

  ℹ Unsafe fix: Remove debugger statement

    1 │ debugger;·//·should·trigger·noDebugger
      │ --------------------------------------

index.js:3:1 lint/complexity/useFlatMap  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ The call chain .map().flat() can be replaced with a single .flatMap() call.

    1 │ debugger; // should trigger noDebugger
    2 │ new RegExp("abc", "u"); // should trigger useRegexLiterals
  > 3 │ [].map((i) => i).flat(); // should trigger useFlatMap
      │ ^^^^^^^^^^^^^^^^^^^^^^^

  ℹ Safe fix: Replace the chain with .flatMap().

    1 1 │   debugger; // should trigger noDebugger
    2 2 │   new RegExp("abc", "u"); // should trigger useRegexLiterals
    3   │ - [].map((i)·=>·i).flat();·//·should·trigger·useFlatMap
      3 │ + [].flatMap((i)·=>·i);·//·should·trigger·useFlatMap

index.js:2:1 lint/complexity/useRegexLiterals  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ Use a regular expression literal instead of the RegExp constructor.

    1 │ debugger; // should trigger noDebugger
  > 2 │ new RegExp("abc", "u"); // should trigger useRegexLiterals
      │ ^^^^^^^^^^^^^^^^^^^^^^
    3 │ [].map((i) => i).flat(); // should trigger useFlatMap

  ℹ Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.

  ℹ Safe fix: Use a literal notation instead.

    1 1 │   debugger; // should trigger noDebugger
    2   │ - new·RegExp("abc",·"u");·//·should·trigger·useRegexLiterals
      2 │ + /abc/u;·//·should·trigger·useRegexLiterals
    3 3 │   [].map((i) => i).flat(); // should trigger useFlatMap

index.js lint ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ The file contains diagnostics that needs to be addressed.

index.js format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ File content differs from formatting output

    1 1 │   debugger; // should trigger noDebugger
    2 2 │   new RegExp("abc", "u"); // should trigger useRegexLiterals
    3   │ - [].map((i)·=>·i).flat();·//·should·trigger·useFlatMap
      3 │ + [].map((i)·=>·i).flat();·//·should·trigger·useFlatMap
      4 │ +

index.js ci ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ The file contains diagnostics that needs to be addressed.

Checked 1 file(s) in 17ms
Found 6 error(s)
ci ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ Some errors were emitted while running checks.

Lint command output looks fine:

❯ cat biome.json
{
 "linter": {
   "enabled": true,
   "rules": {
     "recommended": false,
     "complexity": {
       "useFlatMap": "error"
     }
   }
 }
}

❯ cat index.js
debugger; // should trigger noDebugger
new RegExp("abc", "u"); // should trigger useRegexLiterals
[].map((i) => i).flat(); // should trigger useFlatMap

❯ npx @biomejs/biome@1.5.3 lint index.js
index.js:3:1 lint/complexity/useFlatMap  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ The call chain .map().flat() can be replaced with a single .flatMap() call.

    1 │ debugger; // should trigger noDebugger
    2 │ new RegExp("abc", "u"); // should trigger useRegexLiterals
  > 3 │ [].map((i) => i).flat(); // should trigger useFlatMap
      │ ^^^^^^^^^^^^^^^^^^^^^^^

  ℹ Safe fix: Replace the chain with .flatMap().

    1 1 │   debugger; // should trigger noDebugger
    2 2 │   new RegExp("abc", "u"); // should trigger useRegexLiterals
    3   │ - [].map((i)·=>·i).flat();·//·should·trigger·useFlatMap
      3 │ + [].flatMap((i)·=>·i);·//·should·trigger·useFlatMap

index.js lint ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ The file contains diagnostics that needs to be addressed.

Checked 1 file(s) in 5ms
Found 2 error(s)
lint ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

  ✖ Some errors were emitted while running checks.
Conaclos commented 7 months ago

NOTE: This doesn't affect biome check.

ematipico commented 7 months ago

Fixed by https://github.com/biomejs/biome/pull/1804