Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

id-blacklist catches calls to Number #12567

Closed
hnipps opened this issue Nov 14, 2019 · 25 comments · Fixed by #12987
Closed

id-blacklist catches calls to Number #12567

hnipps opened this issue Nov 14, 2019 · 25 comments · Fixed by #12987
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly rule Relates to ESLint's core rules

Comments

@hnipps
Copy link

hnipps commented Nov 14, 2019

Tell us about your environment

  • ESLint Version: 6.1.0
  • Node Version: 10.16.3
  • npm Version: 6.13.0

What parser (default, Babel-ESLint, etc.) are you using?
@typescript-eslint/parser

Please show your full configuration:

Configuration
module.exports = {
  "env": {
    "browser": true,
    "es6": true,
    "node": true
  },
  "extends": [],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "tsconfig.json",
    "sourceType": "module"
  },
  "plugins": [
    "@typescript-eslint",
    "@typescript-eslint/tslint",
    "import",
    "s2-app"
  ],
  "rules": {
    "s2-app/no-template-literals": 1,
    "s2-app/no-first": 1,
    "strict": [
      2,
      "safe"
    ],
    "no-var": "error",
    "prefer-const": "error",
    "no-shadow": [
      "error",
      {
        "hoist": "all"
      }
    ],
    "no-shadow-restricted-names": [
      2
    ],
    "@typescript-eslint/no-unused-vars": [
      2,
      {
        "vars": "all",
        "args": "after-used"
      }
    ],
    "no-use-before-define": [
      0,
      "nofunc"
    ],
    "comma-dangle": [
      2,
      "always-multiline"
    ],
    "no-cond-assign": "off",
    "no-console": [
      "error",
      {
        "allow": [
          "dirxml",
          "warn",
          "error",
          "dir",
          "timeLog",
          "assert",
          "clear",
          "count",
          "countReset",
          "group",
          "groupCollapsed",
          "groupEnd",
          "table",
          "Console",
          "markTimeline",
          "profile",
          "profileEnd",
          "timeline",
          "timelineEnd",
          "timeStamp",
          "context"
        ]
      }
    ],
    "no-debugger": "error",
    "no-alert": [
      1
    ],
    "no-constant-condition": [
      1
    ],
    "no-dupe-keys": [
      2
    ],
    "no-duplicate-case": [
      2
    ],
    "no-empty": "error",
    "no-ex-assign": [
      2
    ],
    "no-extra-boolean-cast": [
      0
    ],
    "no-extra-semi": [
      2
    ],
    "no-func-assign": [
      2
    ],
    "no-inner-declarations": [
      2,
      "both"
    ],
    "no-invalid-regexp": [
      2
    ],
    "no-irregular-whitespace": [
      2
    ],
    "no-obj-calls": [
      2
    ],
    "no-sparse-arrays": [
      2
    ],
    "no-unreachable": [
      2
    ],
    "use-isnan": "error",
    "block-scoped-var": [
      0
    ],
    "consistent-return": [
      2
    ],
    "curly": "error",
    "default-case": "off",
    "dot-notation": "off",
    "eqeqeq": [
      "error",
      "smart"
    ],
    "guard-for-in": "error",
    "no-caller": "error",
    "no-else-return": [
      2
    ],
    "no-eq-null": [
      2
    ],
    "no-eval": "error",
    "no-extra-bind": [
      2
    ],
    "no-fallthrough": "error",
    "no-floating-decimal": [
      2
    ],
    "no-implied-eval": [
      2
    ],
    "no-lone-blocks": [
      2
    ],
    "no-loop-func": [
      2
    ],
    "no-multi-str": [
      2
    ],
    "no-native-reassign": [
      2
    ],
    "no-new": [
      2
    ],
    "no-new-func": [
      2
    ],
    "no-new-wrappers": "error",
    "no-octal": [
      2
    ],
    "no-octal-escape": [
      2
    ],
    "no-param-reassign": [
      2
    ],
    "no-proto": [
      2
    ],
    "no-redeclare": "error",
    "no-return-assign": [
      2
    ],
    "no-script-url": [
      2
    ],
    "no-self-compare": [
      2
    ],
    "no-sequences": [
      2
    ],
    "no-throw-literal": [
      2
    ],
    "no-with": [
      2
    ],
    "radix": "error",
    "vars-on-top": [
      2
    ],
    "wrap-iife": [
      2,
      "any"
    ],
    "yoda": [
      2
    ],
    "indent": [
      2,
      2
    ],
    "brace-style": [
      2,
      "1tbs",
      {
        "allowSingleLine": true
      }
    ],
    "quotes": [
      2,
      "single",
      "avoid-escape"
    ],
    "camelcase": "error",
    "comma-spacing": [
      2,
      {
        "before": false,
        "after": true
      }
    ],
    "comma-style": [
      2,
      "last"
    ],
    "eol-last": "error",
    "func-names": [
      0
    ],
    "key-spacing": [
      2,
      {
        "beforeColon": false,
        "afterColon": true
      }
    ],
    "keyword-spacing": [
      2
    ],
    "max-len": [
      "error",
      {
        "code": 150
      }
    ],
    "new-cap": [
      2,
      {
        "newIsCap": true,
        "capIsNew": false,
        "properties": true
      }
    ],
    "no-multiple-empty-lines": "error",
    "no-nested-ternary": [
      2
    ],
    "no-new-object": [
      2
    ],
    "no-spaced-func": [
      2
    ],
    "no-trailing-spaces": "error",
    "no-extra-parens": [
      2,
      "functions"
    ],
    "no-underscore-dangle": "error",
    "no-warning-comments": [
      0
    ],
    "object-curly-spacing": [
      2,
      "always"
    ],
    "one-var": [
      "error",
      "never"
    ],
    "padded-blocks": [
      2,
      "never"
    ],
    "semi": [
      2,
      "always"
    ],
    "semi-spacing": [
      2,
      {
        "before": false,
        "after": true
      }
    ],
    "space-before-blocks": [
      2
    ],
    "space-before-function-paren": [
      2,
      {
        "anonymous": "always",
        "named": "never",
        "asyncArrow": "always"
      }
    ],
    "space-infix-ops": [
      2
    ],
    "spaced-comment": "error",
    "@typescript-eslint/adjacent-overload-signatures": "error",
    "@typescript-eslint/ban-types": "error",
    "@typescript-eslint/class-name-casing": "error",
    "@typescript-eslint/consistent-type-assertions": "error",
    "@typescript-eslint/explicit-member-accessibility": [
      "error",
      {
        "accessibility": "no-public"
      }
    ],
    "@typescript-eslint/indent": "off",
    "@typescript-eslint/interface-name-prefix": "error",
    "@typescript-eslint/member-delimiter-style": ["error", {
      "multiline": {
        "delimiter": "semi",
        "requireLast": true
      },
      "singleline": {
        "delimiter": "semi",
        "requireLast": false
      }
    }],
    "@typescript-eslint/member-ordering": "error",
    "@typescript-eslint/no-empty-function": "error",
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/no-inferrable-types": "error",
    "@typescript-eslint/no-namespace": "error",
    "@typescript-eslint/no-non-null-assertion": "error",
    "@typescript-eslint/no-require-imports": "off",
    "@typescript-eslint/no-use-before-declare": "off",
    "@typescript-eslint/no-var-requires": "off",
    "@typescript-eslint/prefer-namespace-keyword": "error",
    "@typescript-eslint/quotes": [
      "error",
      "single"
    ],
    "@typescript-eslint/restrict-plus-operands": "off",
    "@typescript-eslint/semi": [
      "error",
      "always"
    ],
    "@typescript-eslint/triple-slash-reference": "error",
    "@typescript-eslint/type-annotation-spacing": "error",
    "arrow-parens": [
      "off",
      "as-needed"
    ],
    "capitalized-comments": "error",
    "constructor-super": "error",
    "id-blacklist": [
      "error",
      "any",
      "Number",
      "number",
      "String",
      "string",
      "Boolean",
      "boolean",
      "Undefined",
      "undefined"
    ],
    "id-match": "error",
    "import/no-default-export": "error",
    "import/order": "off",
    "linebreak-style": "off",
    "max-classes-per-file": [
      "error",
      1
    ],
    "max-lines": "off",
    "new-parens": "error",
    "no-bitwise": "error",
    "no-duplicate-imports": "error",
    "no-invalid-this": "error",
    "no-null/no-null": "off",
    "no-unsafe-finally": "error",
    "no-unused-expressions": "error",
    "no-unused-labels": "error",
    "prefer-arrow/prefer-arrow-functions": "off",
    "unicorn/filename-case": [
      "error",
      {
        "case": "kebabCase"
      }
    ],
    "@typescript-eslint/tslint/config": [
      "error",
      {
        "rules": {
          "ban": [
            true,
            {
              "name": "Boolean",
              "message": "Use '!!' to determine a value's truthy value."
            }
          ],
          "component-class-suffix": true,
          "component-selector": [
            true,
            "element",
            [
              "ps"
            ],
            "kebab-case"
          ],
          "directive-class-suffix": true,
          "directive-selector": [
            true,
            "attribute",
            [
              "ps"
            ],
            "kebab-case"
          ],
          "import-destructuring-spacing": true,
          "jsdoc-format": true,
          "max-interfaces-per-file": [
            true,
            1
          ],
          "no-analytics-on-ng-tags": true,
          "no-attribute-parameter-decorator": true,
          "no-event-id-on-ng-tags": true,
          "no-forward-ref": true,
          "no-input-rename": true,
          "no-mergeable-namespace": true,
          "no-output-rename": true,
          "one-line": [
            true,
            "check-catch",
            "check-else",
            "check-finally",
            "check-open-brace",
            "check-whitespace"
          ],
          "origin-ordered-imports": true,
          "rxjs-no-unsafe-catch": true,
          "rxjs-no-unsafe-first": true,
          "rxjs-no-unsafe-switchmap": true,
          "rxjs-no-unsafe-takeuntil": true,
          "trailing-comma": [
            true,
            {
              "multiline": "never",
              "singleline": "never"
            }
          ],
          "typedef": [
            true,
            "call-signature"
          ],
          "use-input-property-decorator": true,
          "use-life-cycle-interface": true,
          "use-output-property-decorator": true,
          "use-pipe-transform-interface": true,
          "whitespace": [
            true,
            "check-branch",
            "check-decl",
            "check-operator",
            "check-module",
            "check-separator",
            "check-type"
          ]
        }
      }
    ]
  },
  "settings": {}
};

What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.

isSessionOverrideProvided(): boolean {
    return !isNaN(Number.parseInt(this.sessionForm.value.accessCount, 10));
  }

Run via VSCode ESLint plugin, should be something like:

eslint ./src/**/*.ts -c .eslintrc.js

VSCode ESLint settings:

{
  "eslint.lintTask.options": "./src/**/*.ts",
  "eslint.lintTask.enable": true,
  "eslint.options": {
    "configFile": ".eslintrc.js"
  },
  "eslint.validate": [
    "javascript",
    "typescript"
  ],
  "eslint.enable": true
}

What did you expect to happen?
The call to Number.parseInt() would not be caught by the ESLint id-blacklist rule.

What actually happened? Please include the actual, raw output from ESLint.
The call to Number.parseInt() is caught by eslint - Identifier 'Number' is blacklisted.

Are you willing to submit a pull request to fix this bug?
No

@hnipps hnipps added bug ESLint is working incorrectly triage An ESLint team member will look at this issue soon labels Nov 14, 2019
@platinumazure
Copy link
Member

Hi @hnipps, thanks for the issue.

This is in your configuration:

    "id-blacklist": [
      "error",
      "any",
      "Number",
      "number",
      "String",
      "string",
      "Boolean",
      "boolean",
      "Undefined",
      "undefined"
    ],

Based on this configuration, I think it's correct that the id-blacklist rule is flagging Number as blacklisted. If you want to change this behavior, you should remove "Number" from your id-blacklist configuration.

@hnipps
Copy link
Author

hnipps commented Nov 14, 2019

@platinumazure the documentation seems to say that the rule will only flag instances where the blacklisted id is assigned a value and will not flag instances when existing functions are called or property names are referenced.

In my case I'm not assigning anything to Number I'm just calling a method of the object.

Did I misunderstand the docs?

@platinumazure
Copy link
Member

@hnipps Thanks for clarifying and for drawing my attention to the documentation. I can see how this is confusing.

There's a comment in the documentation after a few examples that says: "all function calls are ignored". However, in those examples, the identifier is either a standalone identifier, or the property of a member expression. For whatever reason, identifiers that are objects of the member expression are always reported.

I'm not sure what the correct behavior should be here. 😄 I am hoping another team member can provide historical context.

@hnipps
Copy link
Author

hnipps commented Nov 14, 2019

Thanks @platinumazure .

Some more context: I came across this issue while migrating from TSLint to ESLint using tslint-to-eslint-config.

We were using the TSLint "variable-name" rule with the "ban-keywords" option and I suppose "id-blacklist" is the ESLint equivalent of that rule.

@kaicataldo
Copy link
Member

I'm also missing the historical context here, but I agree that this seems like a bug.

@kaicataldo kaicataldo added evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion rule Relates to ESLint's core rules and removed triage An ESLint team member will look at this issue soon labels Nov 14, 2019
@mdjermanovic
Copy link
Member

mdjermanovic commented Nov 21, 2019

It seems that each of the 'naming' rules has its own logic on which Identifier nodes should be checked.

Rules: camelcase, id-blacklist, id-length, id-match, no-underscore-dangle.

Would it make sense to have a consistent logic, e.g., to check only places where variables/properties are created in all 5 rules? Or maybe to make one id-style rule which would replace all 5 rules.

@Ionaru
Copy link

Ionaru commented Nov 25, 2019

It seems the "ban-keywords" option in the TSLint "variable-name" rule should actually be translated to a combination of ESLint rules:

With these results enabled, it gives me the expected result and works equivalent to the TSLint rule.
.eslintrc.js

module.exports = {
    "env": {
        "es6": true,
        "node": true
    },
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "project": "tsconfig.json",
        "sourceType": "module"
    },
    "plugins": [
        "@typescript-eslint"
    ],
    "rules": {
        "no-redeclare": [
            "error",
        ],
        "no-shadow": [
            "error",
            {
                "builtinGlobals": true
            }
        ],
    }
};

index.ts

const Object = 0; // 'Object' is already declared in the upper scope
class Number {} // 'Number' is already declared in the upper scope
function foo(undefined: number) {} // 'undefined' is already declared in the upper scope

This is probably an issue with the tslint-to-eslint-config scripts.

But "id-blacklist" is giving me strange behaviour as well, if I change the eslint rules to have the "id-blacklist" rule, then suddenly perfectly valid code is flagged as an error.

.eslintrc.js

...
    "rules": {
        "id-blacklist": [
            "error",
            "undefined",
        ],
    }
...

index.ts

let foo = undefined; // Identifier 'undefined' is blacklisted

Suddenly, using undefined in the code is not OK anymore, but I never use undefined as an identifier, only as a value.

It seems that "id-blacklist" is too aggressive in its flagging, and not a correct translation of the "ban-keywords" option in the TSLint "variable-name" rule.

@mdjermanovic
Copy link
Member

This also looks like a bug as the rule effectively restricts importing foo although it's renamed:

/*eslint id-blacklist: ["error", "foo"]*/

import { foo as bar } from "mod"; // error: Identifier 'foo' is blacklisted.

Online demo

Since the rule is in the Stylistic Issues category it doesn't seem it should restrict imports (it might just enforce renaming) or restrict use of the existing globals like undefined.

@eslint-deprecated eslint-deprecated bot added the auto closed The bot closed this issue label Dec 27, 2019
@eslint-deprecated
Copy link

Unfortunately, it looks like there wasn't enough interest from the team
or community to implement this change. While we wish we'd be able to
accommodate everyone's requests, we do need to prioritize. We've found
that issues failing to reach accepted status after 21 days tend to
never be accepted, and as such, we close those issues.
This doesn't mean the idea isn't interesting or useful, just that it's
not something the team can commit to.

Thanks for contributing to ESLint and we appreciate your understanding.

@kaicataldo kaicataldo reopened this Jan 3, 2020
@kaicataldo
Copy link
Member

Reopening since this is likely a bug we should fix.

@agonzalezjr
Copy link

Thanks @kaicataldo 👍

I also think this is a valid bug. I am hitting the issue with valid uses of undefined being flagged everywhere as well.

@mdjermanovic mdjermanovic removed the auto closed The bot closed this issue label Jan 8, 2020
@eslint-deprecated eslint-deprecated bot added the auto closed The bot closed this issue label Feb 8, 2020
@eslint-deprecated
Copy link

Unfortunately, it looks like there wasn't enough interest from the team
or community to implement this change. While we wish we'd be able to
accommodate everyone's requests, we do need to prioritize. We've found
that issues failing to reach accepted status after 21 days tend to
never be accepted, and as such, we close those issues.
This doesn't mean the idea isn't interesting or useful, just that it's
not something the team can commit to.

Thanks for contributing to ESLint and we appreciate your understanding.

@mdjermanovic mdjermanovic reopened this Feb 8, 2020
@mdjermanovic mdjermanovic removed the auto closed The bot closed this issue label Feb 8, 2020
@KingDarBoja
Copy link

Just facing this issue and thought the rule was focused on naming variables instead of value identifiers as stated by author.

@mdjermanovic
Copy link
Member

Since it isn't clear whether this is a bug or not, maybe we could add an option to ignore all references to global variables (except for those declared in the same file).

@kaicataldo
Copy link
Member

kaicataldo commented Feb 26, 2020

I still think this is a bug. As stated above, the documentation seems to pretty clearly indicate that this shouldn't warn. I would argue for this being a patch fix, but would love to hear from some other team members as well.

@mdjermanovic
Copy link
Member

The idea with an option was to have both behaviors in the case that someone prefers the actual one, but I also think this is a bug and would agree to just change the default behavior.

This rule already allows all callee identifiers:

It will not catch blacklisted identifiers that are:

function calls (so you can still use functions you do not have control over)

In my opinion, the intention was to allow the use of built-in/environment/third party globals (which are all names "you do not have control over"), but the assumption was they're all functions.

@kaicataldo kaicataldo removed the evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion label Feb 26, 2020
@kaicataldo kaicataldo added the accepted There is consensus among the team that this change meets the criteria for inclusion label Feb 26, 2020
@kaicataldo
Copy link
Member

I'm going to mark this as accepted, since multiple team members agree that this is a bug.

@mdjermanovic
Copy link
Member

@kaicataldo thoughts about rewriting this rule to check and report only places where variables are created (variable declarations, parameters, imports...)?

/* eslint id-blacklist: ["error", "foo"] */

var foo; // report

foo = 1; // don't report

That would fix this issue by itself. Properties would have a separate logic.

A disadvantage of this approach might be that it would stop reporting identifiers in experimental syntax:

/* eslint id-blacklist: ["error", "foo"] */

class A {
    #foo; // this wouldn't be reported anymore
}

though, that could be a good thing because there are some false positives with babel-eslint at the moment:

/* eslint id-blacklist: ["error", "foo"] */

a = b?.foo; // this is an error in the actual version, but it shouldn't be

It would also stop reporting identifiers in typescript specific syntax, but typescript users have an alternative in @typescript-eslint/naming-convention.

@ljharb
Copy link
Sponsor Contributor

ljharb commented Feb 26, 2020

@mdjermanovic in #foo, the # is part of the name, so foo shouldn't warn on that anyways - only #foo should.

@mdjermanovic
Copy link
Member

@mdjermanovic in #foo, the # is part of the name, so foo shouldn't warn on that anyways - only #foo should.

In that case, this is also a false positive in the actual version.

@kaicataldo
Copy link
Member

kaicataldo commented Feb 27, 2020

I think it makes sense to only warn on cases where the author has complete control over naming. It would be great to have id-length, id-blacklist, and id-match all check the same identifiers. I'm actually wondering if it would be better to either have one rule (id-style?) or combine id-length and id-match into id-whitelist? Seems like a worthwhile thing to explore.

My vote would be to treat this issue as a bug fix and then to create a new issue/RFC where we can discuss the direction we'd like to go with rules that enforce Identifier style.

@mdjermanovic
Copy link
Member

I think it makes sense to only warn on cases where the author has complete control over naming. It would be great to have id-length, id-blacklist, and id-match all check the same identifiers. I'm actually wondering if it would be better to either have one rule (id-style?) or combine id-length and id-match into id-whitelist? Seems like a worthwhile thing to explore.

I think we should combine these 3 + camelcase and no-underscore-dangle into one rule, which could be like @typescript-eslint/naming-convention

My vote would be to treat this issue as a bug fix and then to create a new issue/RFC where we can discuss the direction we'd like to go with rules that enforce Identifier style.

Bug fix to just ignore identifiers that represent references to global variables, for the start?

kaicataldo pushed a commit that referenced this issue Mar 23, 2020
…) (#12987)

* Fix: allow references to external globals in id-blacklist (fixes #12567)

* Simplify global reference check
@kuyezhiying
Copy link

I used the latest eslint package with version 7.0.0, but it seems we still have the problem that the rule reports error on the following case:
let foo = undefined; // Identifier 'undefined' is blacklisted

@mdjermanovic
Copy link
Member

I used the latest eslint package with version 7.0.0, but it seems we still have the problem that the rule reports error on the following case:
let foo = undefined; // Identifier 'undefined' is blacklisted

This was supposed to be fixed, and I can't reproduce it in our online demo v7.0.0 now:

/*eslint id-blacklist: ["error", "undefined"] */

let foo = undefined; // no error

function bar() {  
    let foo = undefined; // no error
}

function baz() {
    let undefined; // error
}

@kuyezhiying can you please open a new bug report issue (with all details from the template) so we could check if we have missed something?

@kuyezhiying
Copy link

kuyezhiying commented May 22, 2020

@mdjermanovic Thanks for taking the try. Sorry it was my bad, it's indeed fixed in v7.0.0, it works when I use eslint directly. However, I met the problem because I am using gulp-eslint to setup the workflow, I just found that gulp-eslint has the dependency on eslint v6.0.0 and higher versions, but when I install the latest version of gulp-eslint (v6.0.0), the dependent eslint was v6.8.0 which may not containing the fix.

@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Sep 21, 2020
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label Sep 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion bug ESLint is working incorrectly rule Relates to ESLint's core rules
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants