From 544273fb31ac760cd25130694ee4cfff9f5c438f Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Tue, 20 Sep 2022 21:05:52 +0800 Subject: [PATCH 01/14] Add `no-typeof-undefined` rule --- configs/recommended.js | 1 + docs/rules/no-typeof-undefined.md | 22 ++ readme.md | 223 ++++++++++---------- rules/no-typeof-undefined.js | 74 +++++++ test/no-typeof-undefined.mjs | 63 ++++++ test/snapshots/no-typeof-undefined.mjs.md | 101 +++++++++ test/snapshots/no-typeof-undefined.mjs.snap | Bin 0 -> 394 bytes 7 files changed, 372 insertions(+), 112 deletions(-) create mode 100644 docs/rules/no-typeof-undefined.md create mode 100644 rules/no-typeof-undefined.js create mode 100644 test/no-typeof-undefined.mjs create mode 100644 test/snapshots/no-typeof-undefined.mjs.md create mode 100644 test/snapshots/no-typeof-undefined.mjs.snap diff --git a/configs/recommended.js b/configs/recommended.js index 158d265bdf..7196c57a90 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -52,6 +52,7 @@ module.exports = { 'unicorn/no-static-only-class': 'error', 'unicorn/no-thenable': 'error', 'unicorn/no-this-assignment': 'error', + 'unicorn/no-typeof-undefined': 'error', 'unicorn/no-unnecessary-await': 'error', 'unicorn/no-unreadable-array-destructuring': 'error', 'unicorn/no-unreadable-iife': 'error', diff --git a/docs/rules/no-typeof-undefined.md b/docs/rules/no-typeof-undefined.md new file mode 100644 index 0000000000..dea8c1672c --- /dev/null +++ b/docs/rules/no-typeof-undefined.md @@ -0,0 +1,22 @@ +# Enforce compare with `undefined` directly + + + +βœ… *This rule is part of the [recommended](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) config.* + +πŸ”§πŸ’‘ *This rule is [auto-fixable](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) and provides [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).* + + + + +## Fail + +```js +const foo = 'unicorn'; +``` + +## Pass + +```js +const foo = 'πŸ¦„'; +``` diff --git a/readme.md b/readme.md index ea819880ce..1c9b841d8b 100644 --- a/readme.md +++ b/readme.md @@ -50,118 +50,117 @@ Use a [preset config](#preset-configs) or configure each rules in `package.json` πŸ”§ Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ πŸ’‘ Manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). -| NameΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  | Description | βœ… | πŸ”§ | πŸ’‘ | -| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | βœ… | πŸ”§ | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | βœ… | πŸ”§ | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | βœ… | πŸ”§ | πŸ’‘ | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | βœ… | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | πŸ”§ | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | βœ… | πŸ”§ | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | βœ… | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase values. | βœ… | πŸ”§ | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | βœ… | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | βœ… | πŸ”§ | πŸ’‘ | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | βœ… | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | βœ… | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | βœ… | πŸ”§ | | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | βœ… | | | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | βœ… | | πŸ’‘ | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | βœ… | πŸ”§ | πŸ’‘ | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | βœ… | πŸ”§ | πŸ’‘ | -| [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. | βœ… | πŸ”§ | πŸ’‘ | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | βœ… | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | βœ… | πŸ”§ | | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | βœ… | πŸ”§ | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | βœ… | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | βœ… | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | βœ… | πŸ”§ | | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | βœ… | πŸ”§ | | -| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. | βœ… | πŸ”§ | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | βœ… | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | βœ… | πŸ”§ | | -| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | βœ… | πŸ”§ | | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | βœ… | πŸ”§ | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | βœ… | πŸ”§ | πŸ’‘ | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | βœ… | πŸ”§ | πŸ’‘ | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | βœ… | πŸ”§ | πŸ’‘ | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | βœ… | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | βœ… | | | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | βœ… | πŸ”§ | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | βœ… | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | βœ… | | | -| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | βœ… | πŸ”§ | | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | βœ… | πŸ”§ | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | βœ… | | | -| [no-unsafe-regex](docs/rules/no-unsafe-regex.md) | Disallow unsafe regular expressions. | | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | βœ… | πŸ”§ | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | βœ… | πŸ”§ | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | βœ… | πŸ”§ | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | βœ… | πŸ”§ | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | βœ… | | πŸ’‘ | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | βœ… | πŸ”§ | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | βœ… | πŸ”§ | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | βœ… | πŸ”§ | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | βœ… | πŸ”§ | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | βœ… | πŸ”§ | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | βœ… | πŸ”§ | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | βœ… | πŸ”§ | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | | πŸ”§ | πŸ’‘ | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | βœ… | | πŸ’‘ | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | βœ… | πŸ”§ | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | βœ… | πŸ”§ | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | βœ… | πŸ”§ | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | βœ… | | πŸ’‘ | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | πŸ”§ | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | βœ… | πŸ”§ | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | βœ… | | πŸ’‘ | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | βœ… | πŸ”§ | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | βœ… | πŸ”§ | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | βœ… | πŸ”§ | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()`. | βœ… | πŸ”§ | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | βœ… | πŸ”§ | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | βœ… | πŸ”§ | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | βœ… | πŸ”§ | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | βœ… | πŸ”§ | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`. | βœ… | πŸ”§ | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | βœ… | πŸ”§ | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | βœ… | πŸ”§ | | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | πŸ”§ | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | βœ… | πŸ”§ | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | βœ… | πŸ”§ | | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | βœ… | πŸ”§ | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | βœ… | πŸ”§ | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | βœ… | | πŸ’‘ | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | βœ… | πŸ”§ | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | βœ… | πŸ”§ | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | βœ… | πŸ”§ | πŸ’‘ | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | βœ… | πŸ”§ | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | βœ… | πŸ”§ | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | πŸ’‘ | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | πŸ”§ | πŸ’‘ | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | βœ… | πŸ”§ | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | βœ… | πŸ”§ | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | βœ… | πŸ”§ | πŸ’‘ | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | βœ… | πŸ”§ | | - - + + +| Name                                         | Description | βœ… | πŸ”§ | πŸ’‘ | +| :-- | :-- | :-- | :-- | :-- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | βœ… | πŸ”§ | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | βœ… | πŸ”§ | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | βœ… | πŸ”§ | πŸ’‘ | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | βœ… | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | πŸ”§ | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | βœ… | πŸ”§ | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | βœ… | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase values. | βœ… | πŸ”§ | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | βœ… | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | βœ… | πŸ”§ | πŸ’‘ | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | βœ… | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | βœ… | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | βœ… | πŸ”§ | | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | βœ… | | | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | βœ… | | πŸ’‘ | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | βœ… | πŸ”§ | πŸ’‘ | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | βœ… | πŸ”§ | πŸ’‘ | +| [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. | βœ… | πŸ”§ | πŸ’‘ | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | βœ… | | | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | βœ… | πŸ”§ | | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | βœ… | πŸ”§ | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | βœ… | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | βœ… | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | βœ… | πŸ”§ | | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | βœ… | πŸ”§ | | +| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. | βœ… | πŸ”§ | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | βœ… | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | βœ… | πŸ”§ | | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | βœ… | πŸ”§ | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | βœ… | πŸ”§ | πŸ’‘ | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | βœ… | πŸ”§ | πŸ’‘ | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | βœ… | πŸ”§ | πŸ’‘ | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | βœ… | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | βœ… | | | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | βœ… | πŸ”§ | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | βœ… | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | βœ… | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Enforce compare with `undefined` directly. | βœ… | πŸ”§ | πŸ’‘ | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | βœ… | πŸ”§ | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | βœ… | | | +| [no-unsafe-regex](docs/rules/no-unsafe-regex.md) | Disallow unsafe regular expressions. | | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | βœ… | πŸ”§ | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | βœ… | πŸ”§ | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | βœ… | πŸ”§ | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | βœ… | πŸ”§ | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | βœ… | | πŸ’‘ | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | βœ… | πŸ”§ | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | βœ… | πŸ”§ | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | βœ… | πŸ”§ | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | βœ… | πŸ”§ | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | βœ… | πŸ”§ | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | βœ… | πŸ”§ | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | βœ… | πŸ”§ | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | | πŸ”§ | πŸ’‘ | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | βœ… | | πŸ’‘ | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | βœ… | πŸ”§ | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | βœ… | πŸ”§ | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | βœ… | πŸ”§ | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | βœ… | | πŸ’‘ | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | πŸ”§ | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | βœ… | πŸ”§ | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | βœ… | | πŸ’‘ | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | βœ… | πŸ”§ | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | βœ… | πŸ”§ | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | βœ… | πŸ”§ | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()`. | βœ… | πŸ”§ | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | βœ… | πŸ”§ | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | βœ… | πŸ”§ | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | βœ… | πŸ”§ | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | βœ… | πŸ”§ | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`. | βœ… | πŸ”§ | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | βœ… | πŸ”§ | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | βœ… | πŸ”§ | | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | πŸ”§ | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | βœ… | πŸ”§ | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | βœ… | πŸ”§ | | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | βœ… | πŸ”§ | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | βœ… | πŸ”§ | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | βœ… | | πŸ’‘ | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | βœ… | πŸ”§ | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | βœ… | πŸ”§ | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | βœ… | πŸ”§ | πŸ’‘ | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | βœ… | πŸ”§ | | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | βœ… | πŸ”§ | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | πŸ’‘ | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | πŸ”§ | πŸ’‘ | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | βœ… | πŸ”§ | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | βœ… | πŸ”§ | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | βœ… | πŸ”§ | πŸ’‘ | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | βœ… | πŸ”§ | | + ### Deprecated Rules diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js new file mode 100644 index 0000000000..3bbdac8083 --- /dev/null +++ b/rules/no-typeof-undefined.js @@ -0,0 +1,74 @@ +'use strict'; +const {matches} = require('./selectors/index.js'); +const {} = require('./fix/index.js'); +const {removeSpacesAfter} = require('./fix/index.js'); + + +const MESSAGE_ID_ERROR = 'no-typeof-undefined'; +const messages = { + [MESSAGE_ID_ERROR]: 'Compare with `undefined` directly instead of `typeof` check.', +}; + +const selector = [ + 'BinaryExpression', + matches(['===', '!==', '==', '!='].map(operator => `[operator="${operator}"]`)), + '[left.type="UnaryExpression"]', + '[left.operator="typeof"]', + '[left.prefix]', + '[right.type="Literal"]', +].join(''); + +/** @param {import('eslint').Rule.RuleContext} context */ +const create = context => { + return { + [selector](binaryExpression) { + const {left: typeofNode, right: undefinedString} = binaryExpression; + if (undefinedString.value !== "undefined") { + return; + } + + const sourceCode = context.getSourceCode(); + const valueNode = typeofNode.argument; + const typeofToken = sourceCode.getFirstToken(typeofNode); + + return { + node: binaryExpression, + loc: typeofToken.loc, + messageId: MESSAGE_ID_ERROR, + * fix(fixer) { + // Change `==`/`!=` to `===`/`!==` + const {operator} = binaryExpression; + if (operator === '==' || operator === '!=') { + const operatorToken = sourceCode.getTokenAfter( + typeofNode, + token => token.type === 'Punctuator' && token.value === operator, + ); + + yield fixer.insertTextAfter(operatorToken, '='); + } + + yield fixer.replaceText(undefinedString, 'undefined'); + + yield fixer.remove(typeofToken); + yield removeSpacesAfter(typeofToken, sourceCode, fixer); + + // TODO: return or throw, ASI, + } + } + }, + }; +}; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + create, + meta: { + type: 'suggestion', + docs: { + description: 'Enforce compare with `undefined` directly.', + }, + fixable: 'code', + hasSuggestions: true, + messages, + }, +}; diff --git a/test/no-typeof-undefined.mjs b/test/no-typeof-undefined.mjs new file mode 100644 index 0000000000..83d5ea57df --- /dev/null +++ b/test/no-typeof-undefined.mjs @@ -0,0 +1,63 @@ +import outdent from 'outdent'; +import {getTester} from './utils/test.mjs'; + +const {test} = getTester(import.meta); + +test.snapshot({ + valid: [ + 'typeof a.b', + 'typeof a.b > "undefined"', + 'a.b === "undefined"', + 'void a.b === "undefined"', + '+a.b === "undefined"', + '++a.b === "undefined"', + 'a.b++ === "undefined"', + 'foo === undefined', + 'typeof a.b === "string"', + 'typeof a.b === "string"', + '"undefined" === typeof a.b', + 'const UNDEFINED = "undefined"; typeof a.b === UNDEFINED', + 'typeof a.b === `undefined`', + ], + invalid: [ + 'typeof a.b === "undefined"', + 'typeof a.b !== "undefined"', + 'typeof a.b == "undefined"', + 'typeof a.b != "undefined"', + 'typeof a.b == \'undefined\'', + 'typeof undefinedVariableIdentifier == \'undefined\'', + ], +}); + + + + + // 'let foo; + foo === "undefined"', + // 'let foo; void foo === "undefined"', + // 'let foo; typeof foo > "undefined"', + // 'let foo; typeof foo instanceof "undefined"', + // 'let foo; typeof foo in "undefined"', + // Cases we are not checking + // 'var foo; typeof foo === "undefined"', + // 'let foo; typeof foo === "undefined"', + // 'let foo; typeof foo == "undefined"', + // 'let foo; "undefined" === typeof foo', + // 'let foo; const UNDEFINED_TYPE = "undefined"; UNDEFINED_TYPE == typeof foo', + // 'let foo; const UNDEFINED = undefined; typeof UNDEFINED == typeof foo', + // 'let foo; typeof undefined == typeof foo', + // 'let foo; `undefined` === typeof foo', + // 'const foo = 1; typeof foo === "undefined"', + // outdent` + // let foo; + // function bar() { + // typeof foo === "undefined"; + // } + // `, + // 'function foo() {typeof foo === "undefined"}', + // 'function foo(bar) {typeof bar === "undefined"}', + // 'typeof foo.bar === "undefined"', + // // ASI + // outdent` + // foo + // typeof [] === "undefined"; + // `, diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md new file mode 100644 index 0000000000..cd4c9962c6 --- /dev/null +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -0,0 +1,101 @@ +# Snapshot report for `test/no-typeof-undefined.mjs` + +The actual snapshot is saved in `no-typeof-undefined.mjs.snap`. + +Generated by [AVA](https://avajs.dev). + +## Invalid #1 + 1 | typeof a.b === "undefined" + +> Output + + `␊ + 1 | a.b === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof a.b === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #2 + 1 | typeof a.b !== "undefined" + +> Output + + `␊ + 1 | a.b !== undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof a.b !== "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #3 + 1 | typeof a.b == "undefined" + +> Output + + `␊ + 1 | a.b === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof a.b == "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #4 + 1 | typeof a.b != "undefined" + +> Output + + `␊ + 1 | a.b !== undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof a.b != "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #5 + 1 | typeof a.b == 'undefined' + +> Output + + `␊ + 1 | a.b === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof a.b == 'undefined'␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #6 + 1 | typeof undefinedVariableIdentifier == 'undefined' + +> Output + + `␊ + 1 | undefinedVariableIdentifier === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof undefinedVariableIdentifier == 'undefined'␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap new file mode 100644 index 0000000000000000000000000000000000000000..28bbd1687ab4fdd5bc95b7b312ca2c42d56e9112 GIT binary patch literal 394 zcmV;50d@XCRzV&46|If#hy7NC?UW9U!m2FV;`Boq8U*95QsOH>U`j}PWhNI?Too=DW4w`Sd@ba zf*XPO>zdGWOETxK?NI-6dMQKN7bdXi0Vob)W?=X&(D854t*Lr38HX*nTB2E)z@n8< z{27Ru8Q8(DXJlm%WR&DmP%u=eQApHFQc$$DRVd9%NlnYlOHJWIQI^AH2Ub>6S&*8a z23M^FSFQv!M**lH4h$5W^K%Oli&7QJGfOfQ65y&56jCyaQj<$^Dit#Gic3-xQxt%v zB|uC~P)N>5P0rTiBFBN**c?c2_t}!WCxN7x5={`DypCQzJa5KUZi!u|Fa#B50 oQu9hO(=tCDv0gfd{+0rb;0f9wpk;Mc60GXJpRsaA1 literal 0 HcmV?d00001 From ee7d0e8f8f905cfa5811b86326b0ea33483abb53 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 14:57:45 +0800 Subject: [PATCH 02/14] ASI --- rules/no-typeof-undefined.js | 24 ++++++++++++++++++-- test/no-typeof-undefined.mjs | 5 ++++ test/snapshots/no-typeof-undefined.mjs.md | 19 ++++++++++++++++ test/snapshots/no-typeof-undefined.mjs.snap | Bin 394 -> 461 bytes 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index 3bbdac8083..4d0ca49ced 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -2,6 +2,11 @@ const {matches} = require('./selectors/index.js'); const {} = require('./fix/index.js'); const {removeSpacesAfter} = require('./fix/index.js'); +const isOnSameLine = require('./utils/is-on-same-line.js'); +const needsSemicolon = require('./utils/needs-semicolon.js'); +const { + isParenthesized, +} = require('./utils/parentheses.js'); const MESSAGE_ID_ERROR = 'no-typeof-undefined'; @@ -29,7 +34,7 @@ const create = context => { const sourceCode = context.getSourceCode(); const valueNode = typeofNode.argument; - const typeofToken = sourceCode.getFirstToken(typeofNode); + const [typeofToken, secondToken] = sourceCode.getFirstTokens(typeofNode, 2); return { node: binaryExpression, @@ -52,7 +57,22 @@ const create = context => { yield fixer.remove(typeofToken); yield removeSpacesAfter(typeofToken, sourceCode, fixer); - // TODO: return or throw, ASI, + const {parent} = binaryExpression; + if ( + (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement') + && parent.argument === binaryExpression + && !isParenthesized(binaryExpression, sourceCode) + && !isParenthesized(typeofNode, sourceCode) + && !isOnSameLine(firstToken, secondToken) + ) { + yield * addParenthesizesToReturnOrThrowExpression(fixer, parent, sourceCode); + return; + } + + const tokenBefore = sourceCode.getTokenBefore(binaryExpression); + if (needsSemicolon(tokenBefore, sourceCode, secondToken.value)) { + yield fixer.insertTextBefore(binaryExpression, ';'); + } } } }, diff --git a/test/no-typeof-undefined.mjs b/test/no-typeof-undefined.mjs index 83d5ea57df..4be3a154db 100644 --- a/test/no-typeof-undefined.mjs +++ b/test/no-typeof-undefined.mjs @@ -26,6 +26,11 @@ test.snapshot({ 'typeof a.b != "undefined"', 'typeof a.b == \'undefined\'', 'typeof undefinedVariableIdentifier == \'undefined\'', + // ASI + outdent` + foo + typeof [] === "undefined"; + `, ], }); diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md index cd4c9962c6..5dde7ff158 100644 --- a/test/snapshots/no-typeof-undefined.mjs.md +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -99,3 +99,22 @@ Generated by [AVA](https://avajs.dev). > 1 | typeof undefinedVariableIdentifier == 'undefined'␊ | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` + +## Invalid #7 + 1 | foo + 2 | typeof [] === "undefined"; + +> Output + + `␊ + 1 | foo␊ + 2 | ;[] === undefined;␊ + ` + +> Error 1/1 + + `␊ + 1 | foo␊ + > 2 | typeof [] === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap index 28bbd1687ab4fdd5bc95b7b312ca2c42d56e9112..1a0c085927fab66881b47954052bdb9640682857 100644 GIT binary patch literal 461 zcmV;;0W$tURzV$$40ZN$Gmacw-X&yicv3*JnTrV`3dP@nc$Vw7*fWO&CFJ-2E3~?C>?0FcRE`OP zrvvfEQk@UH)+rw|rkyc&E#>oL0*mg0VsmB&hOcWv&n?NEyS799%ju;IXd1gt5 zLIPY>fH$2@1&>sma-Ts5YxW9hjD%4`dkuS=Q09 z3bx2jwMNxZhNQy|tOM$5s6He|Thq$bLY0+7SCW~QnOcO$-Av64s1C<(%peMIEaiYL%|aXisYS43odo~@ Dlb6m} literal 394 zcmV;50d@XCRzV&46|If#hy7NC?UW9U!m2FV;`Boq8U*95QsOH>U`j}PWhNI?Too=DW4w`Sd@ba zf*XPO>zdGWOETxK?NI-6dMQKN7bdXi0Vob)W?=X&(D854t*Lr38HX*nTB2E)z@n8< z{27Ru8Q8(DXJlm%WR&DmP%u=eQApHFQc$$DRVd9%NlnYlOHJWIQI^AH2Ub>6S&*8a z23M^FSFQv!M**lH4h$5W^K%Oli&7QJGfOfQ65y&56jCyaQj<$^Dit#Gic3-xQxt%v zB|uC~P)N>5P0rTiBFBN**c?c2_t}!WCxN7x5={`DypCQzJa5KUZi!u|Fa#B50 oQu9hO(=tCDv0gfd{+0rb;0f9wpk;Mc60GXJpRsaA1 From a5ec7691fdc133708e4a4056be6572a964e52fec Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 15:01:27 +0800 Subject: [PATCH 03/14] Return --- rules/no-typeof-undefined.js | 6 +- test/no-typeof-undefined.mjs | 18 +++++ test/snapshots/no-typeof-undefined.mjs.md | 75 ++++++++++++++++++++ test/snapshots/no-typeof-undefined.mjs.snap | Bin 461 -> 725 bytes 4 files changed, 97 insertions(+), 2 deletions(-) diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index 4d0ca49ced..99e7979846 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -1,6 +1,8 @@ 'use strict'; const {matches} = require('./selectors/index.js'); -const {} = require('./fix/index.js'); +const { + addParenthesizesToReturnOrThrowExpression, +} = require('./fix/index.js'); const {removeSpacesAfter} = require('./fix/index.js'); const isOnSameLine = require('./utils/is-on-same-line.js'); const needsSemicolon = require('./utils/needs-semicolon.js'); @@ -63,7 +65,7 @@ const create = context => { && parent.argument === binaryExpression && !isParenthesized(binaryExpression, sourceCode) && !isParenthesized(typeofNode, sourceCode) - && !isOnSameLine(firstToken, secondToken) + && !isOnSameLine(typeofToken, secondToken) ) { yield * addParenthesizesToReturnOrThrowExpression(fixer, parent, sourceCode); return; diff --git a/test/no-typeof-undefined.mjs b/test/no-typeof-undefined.mjs index 4be3a154db..5156278a85 100644 --- a/test/no-typeof-undefined.mjs +++ b/test/no-typeof-undefined.mjs @@ -31,6 +31,24 @@ test.snapshot({ foo typeof [] === "undefined"; `, + outdent` + function a() { + return typeof // comment + a.b === 'undefined'; + } + `, + outdent` + function a() { + return (typeof // ReturnStatement argument is parenthesized + a.b === 'undefined'); + } + `, + outdent` + function a() { + return (typeof // UnaryExpression is parenthesized + a.b) === 'undefined'; + } + `, ], }); diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md index 5dde7ff158..c53a4cfbf8 100644 --- a/test/snapshots/no-typeof-undefined.mjs.md +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -118,3 +118,78 @@ Generated by [AVA](https://avajs.dev). > 2 | typeof [] === "undefined";␊ | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` + +## Invalid #8 + 1 | function a() { + 2 | return typeof // comment + 3 | a.b === 'undefined'; + 4 | } + +> Output + + `␊ + 1 | function a() {␊ + 2 | return ( // comment␊ + 3 | a.b === undefined);␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | function a() {␊ + > 2 | return typeof // comment␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 3 | a.b === 'undefined';␊ + 4 | }␊ + ` + +## Invalid #9 + 1 | function a() { + 2 | return (typeof // ReturnStatement argument is parenthesized + 3 | a.b === 'undefined'); + 4 | } + +> Output + + `␊ + 1 | function a() {␊ + 2 | return (// ReturnStatement argument is parenthesized␊ + 3 | a.b === undefined);␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | function a() {␊ + > 2 | return (typeof // ReturnStatement argument is parenthesized␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 3 | a.b === 'undefined');␊ + 4 | }␊ + ` + +## Invalid #10 + 1 | function a() { + 2 | return (typeof // UnaryExpression is parenthesized + 3 | a.b) === 'undefined'; + 4 | } + +> Output + + `␊ + 1 | function a() {␊ + 2 | return (// UnaryExpression is parenthesized␊ + 3 | a.b) === undefined;␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | function a() {␊ + > 2 | return (typeof // UnaryExpression is parenthesized␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 3 | a.b) === 'undefined';␊ + 4 | }␊ + ` diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap index 1a0c085927fab66881b47954052bdb9640682857..3e6172c7fb293a0a16e5720cd70f4391a3e273f7 100644 GIT binary patch literal 725 zcmV;`0xJDMRzVptif_7mwdA5M=_3euCmMpphnFk*)De+r8dx;@CgmW%3y&u;?!+ zzRk?Q5TVenp1{`U`^kHu9(R*sI}=zmj0J-ASQ!}V?B!-0Ik>z_$lUOxfMhcl6Ie79 ziq8S@EZ1$ZXATKU$nXDGXm#V*M<%f7S18V7V_?`=s`G)@I^|==v@_cwOnw%}@sW?=%0vT;Cg z0}wMau!BR9k(EJ^QIbnR!BC+_AyF?$LDAM$p)@ZgH7zqQHH8aBSq_&SSXoJBL27;) zT(uHhxf0ME1)zdBFi>#L&n-wSN>wP&EXhzvfU8PSNXaZpO)kl)RLIOLE=f&HQ2?5j z05LT|Avq&8Ia?3a=1`~u(@OJ_OEUBG6cRNw6{>-PMnFN%qSTVoqC5o+1$}*mghvr4|>1)Zq(TP4u*dHEd6k8n#3@ftEq4Nn~y#vb4;`R$9`dutavBElKV}_5PrA zA05Ka5b8d-8DWV$$40ZN$Gmacw-X&yicv3*JnTrV`3dP@nc$Vw7*fWO&CFJ-2E3~?C>?0FcRE`OP zrvvfEQk@UH)+rw|rkyc&E#>oL0*mg0VsmB&hOcWv&n?NEyS799%ju;IXd1gt5 zLIPY>fH$2@1&>sma-Ts5YxW9hjD%4`dkuS=Q09 z3bx2jwMNxZhNQy|tOM$5s6He|Thq$bLY0+7SCW~QnOcO$-Av64s1C<(%peMIEaiYL%|aXisYS43odo~@ Dlb6m} From f0342c025457f8ee61874e612ffa7918134b68ae Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 15:19:09 +0800 Subject: [PATCH 04/14] checkGlobalVariables --- rules/no-typeof-undefined.js | 31 +- test/no-typeof-undefined.mjs | 59 ++-- test/snapshots/no-typeof-undefined.mjs.md | 295 ++++++++++++++++++++ test/snapshots/no-typeof-undefined.mjs.snap | Bin 725 -> 1381 bytes 4 files changed, 352 insertions(+), 33 deletions(-) diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index 99e7979846..d0fc751778 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -1,4 +1,5 @@ 'use strict'; +const isShadowed = require('./utils/is-shadowed.js'); const {matches} = require('./selectors/index.js'); const { addParenthesizesToReturnOrThrowExpression, @@ -27,15 +28,30 @@ const selector = [ /** @param {import('eslint').Rule.RuleContext} context */ const create = context => { + const { + checkGlobalVariables + } = { + checkGlobalVariables: true, + ...context.options[0], + }; + return { [selector](binaryExpression) { const {left: typeofNode, right: undefinedString} = binaryExpression; if (undefinedString.value !== "undefined") { return; } + const valueNode = typeofNode.argument; + + if ( + valueNode.type === 'Identifier' + && !checkGlobalVariables + && !isShadowed(context.getScope(), valueNode) + ) { + return; + } const sourceCode = context.getSourceCode(); - const valueNode = typeofNode.argument; const [typeofToken, secondToken] = sourceCode.getFirstTokens(typeofNode, 2); return { @@ -81,6 +97,19 @@ const create = context => { }; }; +const schema = [ + { + type: 'object', + additionalProperties: false, + properties: { + checkGlobalVariables: { + type: 'boolean', + default: false, + }, + }, + }, +]; + /** @type {import('eslint').Rule.RuleModule} */ module.exports = { create, diff --git a/test/no-typeof-undefined.mjs b/test/no-typeof-undefined.mjs index 5156278a85..c86db3321d 100644 --- a/test/no-typeof-undefined.mjs +++ b/test/no-typeof-undefined.mjs @@ -52,35 +52,30 @@ test.snapshot({ ], }); - - - - // 'let foo; + foo === "undefined"', - // 'let foo; void foo === "undefined"', - // 'let foo; typeof foo > "undefined"', - // 'let foo; typeof foo instanceof "undefined"', - // 'let foo; typeof foo in "undefined"', - // Cases we are not checking - // 'var foo; typeof foo === "undefined"', - // 'let foo; typeof foo === "undefined"', - // 'let foo; typeof foo == "undefined"', - // 'let foo; "undefined" === typeof foo', - // 'let foo; const UNDEFINED_TYPE = "undefined"; UNDEFINED_TYPE == typeof foo', - // 'let foo; const UNDEFINED = undefined; typeof UNDEFINED == typeof foo', - // 'let foo; typeof undefined == typeof foo', - // 'let foo; `undefined` === typeof foo', - // 'const foo = 1; typeof foo === "undefined"', - // outdent` - // let foo; - // function bar() { - // typeof foo === "undefined"; - // } - // `, - // 'function foo() {typeof foo === "undefined"}', - // 'function foo(bar) {typeof bar === "undefined"}', - // 'typeof foo.bar === "undefined"', - // // ASI - // outdent` - // foo - // typeof [] === "undefined"; - // `, +// `checkGlobalVariables: false` +test.snapshot({ + valid: [ + 'typeof foo === "undefined"', + 'foo = 2; typeof foo === "undefined"', + '/* globals foo: readonly */ typeof foo === "undefined"', + '/* globals globalThis: readonly */ typeof globalThis === "undefined"', + ].map(code => ({code, options: [{checkGlobalVariables: false}]})), + invalid: [ + 'let foo; typeof foo === "undefined"', + 'const foo = 1; typeof foo === "undefined"', + 'var foo; typeof foo === "undefined"', + 'var foo; var foo; typeof foo === "undefined"', + 'for (const foo of bar) typeof foo === "undefined";', + outdent` + let foo; + function bar() { + typeof foo === "undefined"; + } + `, + 'function foo() {typeof foo === "undefined"}', + 'function foo(bar) {typeof bar === "undefined"}', + 'function foo({bar}) {typeof bar === "undefined"}', + 'function foo([bar]) {typeof bar === "undefined"}', + 'typeof foo.bar === "undefined"', + ].map(code => ({code, options: [{checkGlobalVariables: false}]})), +}); diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md index c53a4cfbf8..c3a6de25ec 100644 --- a/test/snapshots/no-typeof-undefined.mjs.md +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -193,3 +193,298 @@ Generated by [AVA](https://avajs.dev). 3 | a.b) === 'undefined';␊ 4 | }␊ ` + +## Invalid #1 + 1 | let foo; typeof foo === "undefined" + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | let foo; foo === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | let foo; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #2 + 1 | const foo = 1; typeof foo === "undefined" + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | const foo = 1; foo === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | const foo = 1; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #3 + 1 | var foo; typeof foo === "undefined" + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | var foo; foo === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | var foo; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #4 + 1 | var foo; var foo; typeof foo === "undefined" + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | var foo; var foo; foo === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | var foo; var foo; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #5 + 1 | for (const foo of bar) typeof foo === "undefined"; + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | for (const foo of bar) foo === undefined;␊ + ` + +> Error 1/1 + + `␊ + > 1 | for (const foo of bar) typeof foo === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #6 + 1 | let foo; + 2 | function bar() { + 3 | typeof foo === "undefined"; + 4 | } + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | let foo;␊ + 2 | function bar() {␊ + 3 | foo === undefined;␊ + 4 | }␊ + ` + +> Error 1/1 + + `␊ + 1 | let foo;␊ + 2 | function bar() {␊ + > 3 | typeof foo === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 4 | }␊ + ` + +## Invalid #7 + 1 | function foo() {typeof foo === "undefined"} + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | function foo() {foo === undefined}␊ + ` + +> Error 1/1 + + `␊ + > 1 | function foo() {typeof foo === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #8 + 1 | function foo(bar) {typeof bar === "undefined"} + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | function foo(bar) {bar === undefined}␊ + ` + +> Error 1/1 + + `␊ + > 1 | function foo(bar) {typeof bar === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #9 + 1 | function foo({bar}) {typeof bar === "undefined"} + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | function foo({bar}) {bar === undefined}␊ + ` + +> Error 1/1 + + `␊ + > 1 | function foo({bar}) {typeof bar === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #10 + 1 | function foo([bar]) {typeof bar === "undefined"} + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | function foo([bar]) {bar === undefined}␊ + ` + +> Error 1/1 + + `␊ + > 1 | function foo([bar]) {typeof bar === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` + +## Invalid #11 + 1 | typeof foo.bar === "undefined" + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | foo.bar === undefined␊ + ` + +> Error 1/1 + + `␊ + > 1 | typeof foo.bar === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap index 3e6172c7fb293a0a16e5720cd70f4391a3e273f7..b107f6889520999422a223682fe93e1fa623fcc5 100644 GIT binary patch delta 1007 zcmV;)D>p1s00fHJ45k7AdXOIS5IK; z^Zn$#P>;Jwv7HGlYQqY_B5Vu{r5m(w=WlLUqkZ(x|EA85BFtdXKqzj6VqSIzhMHwx zJ()eDed>?3#om6x=*tWi^@8FmC}!heV5qZ~n{nje@-88B!+(j>7Hh9tH+dF*2e5=X0YgcDAwSD z;Nw6%_12183r+GXKSx_`vHYy>$P5-`;fCO7C}!tjV3_5)E%wYIK?(W&{|c>c9Q()w z7S)5|#R_5PTMhSKoXpyFqTg*WR$ikNhn7fwp`7wb-Mff4O7l^OVZ+KcDwK;I+U8x|+ z)g3I%V9`@h%q{@IYk~OA!TUPq8!Q(JvHw!&DtP9=3}F_11;t8&5WEkFzpe>AwH@!FhtSIRPgDf2hwD4V0(`yG99YjC)RgQesY6 zVo_#dQch~Il9fVQVoq@?P(>|QEUIQ%L@LosN-RPRQdFe{sAU7P4my+%xx^-=(7eQ= zO4o{lqSWGIkUD%RNE1B=VNF3NNligSIDwW4N0Z1hg`$L`1PzliU=jc(1#1w2FZI+x zQx9A{eS94h7FB%x;v1G>|O!r`kKZ?Rf3tRXAJ%^F~(SoKIYtSG<1xvoi zO%*Cs4-i<%1~&s15}ql*UPWeFW-7j(8&fj_YD&j%3_Z$uB6BE~;V3$FHz`Vjy4aE+ dxDFwhK__EPg%G`DWlw5^3;-JSAUkpw005!Wz|H^w delta 346 zcmV-g0j2)s3e^QNK~_N^Q*L2!b7*gLAa*he0ss$y;Q_Ncn?I)KYvip;^;j7g>g?ra967kW zOUT^tq<~~I7ZX@C6pGIQ@hsPEv1bkmO33g3S7>$P*heO?=vOGtV`E_0SgP}Z*E;26 z#*?>Ydh4xoLLd%r_ksAgK*zsDx2EdF zWE{5OYKdlH0*kV7KyU*PGc&M*Ly@y|0w)1=m`iLRhvp>~Rk~Ib6r~mygVf;*TTS$| zg*9wXk{Y%|IDwWys!3#SBeJy2##UO=qp(DFpDju5L-qckbRQkU&k*W9xEW!IMVX07 sIjNp0z_gf|mYG_F$K6cL45$vrZ_FSHa4glkEzLq40J6*deA)>B01KX@VE_OC From 5660a4f0da6c0a25566f62198a86b768c7051805 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 15:39:13 +0800 Subject: [PATCH 05/14] Docs --- docs/rules/no-typeof-undefined.md | 43 ++++-- readme.md | 224 +++++++++++++++--------------- rules/no-typeof-undefined.js | 12 +- test/no-typeof-undefined.mjs | 4 + 4 files changed, 158 insertions(+), 125 deletions(-) diff --git a/docs/rules/no-typeof-undefined.md b/docs/rules/no-typeof-undefined.md index dea8c1672c..4408edcac8 100644 --- a/docs/rules/no-typeof-undefined.md +++ b/docs/rules/no-typeof-undefined.md @@ -1,22 +1,49 @@ # Enforce compare with `undefined` directly - - -βœ… *This rule is part of the [recommended](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) config.* +βœ… This rule is enabled in the `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). -πŸ”§πŸ’‘ *This rule is [auto-fixable](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) and provides [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).* - +πŸ”§ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). - + + + +Enforce compare value with `undefined` directly instead of compare `typeof value` with `'undefined'`. ## Fail ```js -const foo = 'unicorn'; +if (typeof foo === 'undefined') {} +``` + +```js +if (typeof foo !== 'undefined') {} ``` ## Pass ```js -const foo = 'πŸ¦„'; +if (foo === undefined) {} +``` + +```js +if (foo !== undefined) {} +``` + +## Options + +### checkGlobalVariables + +Type: `boolean`\ +Default: `true` + +Set it to `false` to ignore variables not defined in file. + +```js +// eslint unicorn/no-typeof-undefined: ["error", {"checkGlobalVariables": false}] +if (typeof undefinedVariable === 'undefined') {} // Passes +``` + +```js +// eslint unicorn/no-typeof-undefined: ["error", {"checkGlobalVariables": false}] +if (typeof Array === 'undefined') {} // Passes ``` diff --git a/readme.md b/readme.md index 1c9b841d8b..b8250b31b2 100644 --- a/readme.md +++ b/readme.md @@ -50,117 +50,119 @@ Use a [preset config](#preset-configs) or configure each rules in `package.json` πŸ”§ Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ πŸ’‘ Manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). - - -| Name                                         | Description | βœ… | πŸ”§ | πŸ’‘ | -| :-- | :-- | :-- | :-- | :-- | -| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | βœ… | πŸ”§ | | -| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | βœ… | πŸ”§ | | -| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | βœ… | πŸ”§ | πŸ’‘ | -| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | βœ… | | | -| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | πŸ”§ | | -| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | βœ… | πŸ”§ | | -| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | βœ… | | | -| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase values. | βœ… | πŸ”§ | | -| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | βœ… | | | -| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | βœ… | πŸ”§ | πŸ’‘ | -| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | βœ… | | | -| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | βœ… | | | -| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | βœ… | πŸ”§ | | -| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | βœ… | | | -| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | βœ… | | πŸ’‘ | -| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | βœ… | πŸ”§ | πŸ’‘ | -| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | βœ… | πŸ”§ | πŸ’‘ | -| [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. | βœ… | πŸ”§ | πŸ’‘ | -| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | βœ… | | | -| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | βœ… | πŸ”§ | | -| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | βœ… | πŸ”§ | | -| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | βœ… | | | -| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | βœ… | | | -| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | βœ… | πŸ”§ | | -| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | βœ… | πŸ”§ | | -| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. | βœ… | πŸ”§ | | -| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | βœ… | | | -| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | -| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | βœ… | πŸ”§ | | -| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | βœ… | πŸ”§ | | -| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | βœ… | πŸ”§ | πŸ’‘ | -| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | βœ… | πŸ”§ | πŸ’‘ | -| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | βœ… | πŸ”§ | πŸ’‘ | -| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | βœ… | | | -| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | βœ… | | | -| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | βœ… | πŸ”§ | | -| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | βœ… | | | -| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | βœ… | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Enforce compare with `undefined` directly. | βœ… | πŸ”§ | πŸ’‘ | -| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | βœ… | πŸ”§ | | -| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | βœ… | | | -| [no-unsafe-regex](docs/rules/no-unsafe-regex.md) | Disallow unsafe regular expressions. | | | | -| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | -| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | βœ… | πŸ”§ | | -| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | βœ… | πŸ”§ | | -| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | βœ… | πŸ”§ | | -| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | βœ… | πŸ”§ | | -| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | βœ… | | πŸ’‘ | -| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | βœ… | πŸ”§ | | -| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | βœ… | πŸ”§ | | -| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | βœ… | πŸ”§ | | -| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | βœ… | πŸ”§ | | -| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | βœ… | πŸ”§ | | -| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | βœ… | πŸ”§ | | -| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | βœ… | πŸ”§ | | -| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | | πŸ”§ | πŸ’‘ | -| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | βœ… | | πŸ’‘ | -| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | βœ… | πŸ”§ | | -| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | βœ… | πŸ”§ | | -| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | βœ… | πŸ”§ | | -| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | βœ… | | πŸ’‘ | -| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | | | | -| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | πŸ”§ | | -| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | βœ… | πŸ”§ | | -| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | βœ… | | πŸ’‘ | -| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | βœ… | πŸ”§ | | -| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | βœ… | πŸ”§ | | -| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | βœ… | πŸ”§ | | -| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()`. | βœ… | πŸ”§ | | -| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | βœ… | πŸ”§ | | -| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | βœ… | πŸ”§ | | -| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | βœ… | πŸ”§ | | -| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | βœ… | πŸ”§ | | -| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`. | βœ… | πŸ”§ | | -| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | βœ… | πŸ”§ | | -| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | βœ… | πŸ”§ | | -| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | πŸ”§ | | -| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | βœ… | πŸ”§ | | -| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | βœ… | πŸ”§ | πŸ’‘ | -| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | βœ… | πŸ”§ | | -| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | βœ… | πŸ”§ | | -| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | βœ… | πŸ”§ | | -| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | βœ… | | πŸ’‘ | -| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | βœ… | πŸ”§ | | -| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | βœ… | πŸ”§ | | -| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | βœ… | πŸ”§ | πŸ’‘ | -| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | βœ… | πŸ”§ | | -| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | βœ… | πŸ”§ | | -| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | πŸ’‘ | -| [string-content](docs/rules/string-content.md) | Enforce better string content. | | πŸ”§ | πŸ’‘ | -| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | βœ… | πŸ”§ | | -| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | βœ… | πŸ”§ | | -| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | βœ… | πŸ”§ | πŸ’‘ | -| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | βœ… | πŸ”§ | | - +| NameΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  | Description | βœ… | πŸ”§ | πŸ’‘ | +| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- | +| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | βœ… | πŸ”§ | | +| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | βœ… | πŸ”§ | | +| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | βœ… | πŸ”§ | πŸ’‘ | +| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | βœ… | | | +| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | πŸ”§ | | +| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | βœ… | πŸ”§ | | +| [error-message](docs/rules/error-message.md) | Enforce passing a `message` value when creating a built-in error. | βœ… | | | +| [escape-case](docs/rules/escape-case.md) | Require escape sequences to use uppercase values. | βœ… | πŸ”§ | | +| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. | βœ… | | | +| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. | βœ… | πŸ”§ | πŸ’‘ | +| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. | βœ… | | | +| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | βœ… | | | +| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | βœ… | πŸ”§ | | +| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | βœ… | | | +| [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | βœ… | | πŸ’‘ | +| [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | βœ… | πŸ”§ | πŸ’‘ | +| [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | βœ… | πŸ”§ | πŸ’‘ | +| [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. | βœ… | πŸ”§ | πŸ’‘ | +| [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | βœ… | | | +| [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | βœ… | πŸ”§ | | +| [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | βœ… | πŸ”§ | | +| [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | βœ… | | | +| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | βœ… | | | +| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | βœ… | πŸ”§ | | +| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | βœ… | πŸ”§ | | +| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. | βœ… | πŸ”§ | | +| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | βœ… | | | +| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | | +| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | βœ… | πŸ”§ | | +| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | βœ… | πŸ”§ | | +| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | βœ… | πŸ”§ | | +| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | βœ… | πŸ”§ | πŸ’‘ | +| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | βœ… | πŸ”§ | πŸ’‘ | +| [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | βœ… | πŸ”§ | πŸ’‘ | +| [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | βœ… | | | +| [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | βœ… | | | +| [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | βœ… | πŸ”§ | | +| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | βœ… | | | +| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | βœ… | | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Enforce compare with `undefined` directly. | βœ… | πŸ”§ | | +| [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | βœ… | πŸ”§ | | +| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | βœ… | πŸ”§ | | +| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | βœ… | | | +| [no-unsafe-regex](docs/rules/no-unsafe-regex.md) | Disallow unsafe regular expressions. | | | | +| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | | +| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | βœ… | πŸ”§ | | +| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | βœ… | πŸ”§ | | +| [no-useless-promise-resolve-reject](docs/rules/no-useless-promise-resolve-reject.md) | Disallow returning/yielding `Promise.resolve/reject()` in async functions or promise callbacks | βœ… | πŸ”§ | | +| [no-useless-spread](docs/rules/no-useless-spread.md) | Disallow unnecessary spread. | βœ… | πŸ”§ | | +| [no-useless-switch-case](docs/rules/no-useless-switch-case.md) | Disallow useless case in switch statements. | βœ… | | πŸ’‘ | +| [no-useless-undefined](docs/rules/no-useless-undefined.md) | Disallow useless `undefined`. | βœ… | πŸ”§ | | +| [no-zero-fractions](docs/rules/no-zero-fractions.md) | Disallow number literals with zero fractions or dangling dots. | βœ… | πŸ”§ | | +| [number-literal-case](docs/rules/number-literal-case.md) | Enforce proper case for numeric literals. | βœ… | πŸ”§ | | +| [numeric-separators-style](docs/rules/numeric-separators-style.md) | Enforce the style of numeric separators by correctly grouping digits. | βœ… | πŸ”§ | | +| [prefer-add-event-listener](docs/rules/prefer-add-event-listener.md) | Prefer `.addEventListener()` and `.removeEventListener()` over `on`-functions. | βœ… | πŸ”§ | | +| [prefer-array-find](docs/rules/prefer-array-find.md) | Prefer `.find(…)` and `.findLast(…)` over the first or last element from `.filter(…)`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | βœ… | πŸ”§ | | +| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | βœ… | πŸ”§ | | +| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | | πŸ”§ | πŸ’‘ | +| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | βœ… | | πŸ’‘ | +| [prefer-date-now](docs/rules/prefer-date-now.md) | Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch. | βœ… | πŸ”§ | | +| [prefer-default-parameters](docs/rules/prefer-default-parameters.md) | Prefer default parameters over reassignment. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-dom-node-append](docs/rules/prefer-dom-node-append.md) | Prefer `Node#append()` over `Node#appendChild()`. | βœ… | πŸ”§ | | +| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. | βœ… | πŸ”§ | | +| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | βœ… | | πŸ’‘ | +| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | | | | +| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | πŸ”§ | | +| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | βœ… | πŸ”§ | | +| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | βœ… | | πŸ’‘ | +| [prefer-math-trunc](docs/rules/prefer-math-trunc.md) | Enforce the use of `Math.trunc` instead of bitwise operators. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-modern-dom-apis](docs/rules/prefer-modern-dom-apis.md) | Prefer `.before()` over `.insertBefore()`, `.replaceWith()` over `.replaceChild()`, prefer one of `.before()`, `.after()`, `.append()` or `.prepend()` over `insertAdjacentText()` and `insertAdjacentElement()`. | βœ… | πŸ”§ | | +| [prefer-modern-math-apis](docs/rules/prefer-modern-math-apis.md) | Prefer modern `Math` APIs over legacy patterns. | βœ… | πŸ”§ | | +| [prefer-module](docs/rules/prefer-module.md) | Prefer JavaScript modules (ESM) over CommonJS. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-native-coercion-functions](docs/rules/prefer-native-coercion-functions.md) | Prefer using `String`, `Number`, `BigInt`, `Boolean`, and `Symbol` directly. | βœ… | πŸ”§ | | +| [prefer-negative-index](docs/rules/prefer-negative-index.md) | Prefer negative index over `.length - index` for `{String,Array,TypedArray}#{slice,at}()` and `Array#splice()`. | βœ… | πŸ”§ | | +| [prefer-node-protocol](docs/rules/prefer-node-protocol.md) | Prefer using the `node:` protocol when importing Node.js builtin modules. | βœ… | πŸ”§ | | +| [prefer-number-properties](docs/rules/prefer-number-properties.md) | Prefer `Number` static properties over global ones. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-object-from-entries](docs/rules/prefer-object-from-entries.md) | Prefer using `Object.fromEntries(…)` to transform a list of key-value pairs into an object. | βœ… | πŸ”§ | | +| [prefer-optional-catch-binding](docs/rules/prefer-optional-catch-binding.md) | Prefer omitting the `catch` binding parameter. | βœ… | πŸ”§ | | +| [prefer-prototype-methods](docs/rules/prefer-prototype-methods.md) | Prefer borrowing methods from the prototype instead of the instance. | βœ… | πŸ”§ | | +| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()`. | βœ… | πŸ”§ | | +| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | βœ… | πŸ”§ | | +| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | βœ… | πŸ”§ | | +| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#slice()` and `String#split('')`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | | πŸ”§ | | +| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | βœ… | πŸ”§ | | +| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | βœ… | πŸ”§ | πŸ’‘ | +| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | βœ… | πŸ”§ | | +| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | βœ… | πŸ”§ | | +| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | βœ… | πŸ”§ | | +| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | βœ… | | πŸ’‘ | +| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | βœ… | πŸ”§ | | +| [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | βœ… | πŸ”§ | | +| [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | βœ… | πŸ”§ | πŸ’‘ | +| [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | βœ… | πŸ”§ | | +| [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | βœ… | πŸ”§ | | +| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | πŸ’‘ | +| [string-content](docs/rules/string-content.md) | Enforce better string content. | | πŸ”§ | πŸ’‘ | +| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | βœ… | πŸ”§ | | +| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | βœ… | πŸ”§ | | +| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | βœ… | πŸ”§ | πŸ’‘ | +| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | βœ… | πŸ”§ | | + + ### Deprecated Rules diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index d0fc751778..ae4046dbad 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -11,7 +11,6 @@ const { isParenthesized, } = require('./utils/parentheses.js'); - const MESSAGE_ID_ERROR = 'no-typeof-undefined'; const messages = { [MESSAGE_ID_ERROR]: 'Compare with `undefined` directly instead of `typeof` check.', @@ -29,7 +28,7 @@ const selector = [ /** @param {import('eslint').Rule.RuleContext} context */ const create = context => { const { - checkGlobalVariables + checkGlobalVariables, } = { checkGlobalVariables: true, ...context.options[0], @@ -38,9 +37,10 @@ const create = context => { return { [selector](binaryExpression) { const {left: typeofNode, right: undefinedString} = binaryExpression; - if (undefinedString.value !== "undefined") { + if (undefinedString.value !== 'undefined') { return; } + const valueNode = typeofNode.argument; if ( @@ -91,8 +91,8 @@ const create = context => { if (needsSemicolon(tokenBefore, sourceCode, secondToken.value)) { yield fixer.insertTextBefore(binaryExpression, ';'); } - } - } + }, + }; }, }; }; @@ -119,7 +119,7 @@ module.exports = { description: 'Enforce compare with `undefined` directly.', }, fixable: 'code', - hasSuggestions: true, + schema, messages, }, }; diff --git a/test/no-typeof-undefined.mjs b/test/no-typeof-undefined.mjs index c86db3321d..02e1b28d82 100644 --- a/test/no-typeof-undefined.mjs +++ b/test/no-typeof-undefined.mjs @@ -77,5 +77,9 @@ test.snapshot({ 'function foo({bar}) {typeof bar === "undefined"}', 'function foo([bar]) {typeof bar === "undefined"}', 'typeof foo.bar === "undefined"', + outdent` + import foo from 'foo'; + typeof foo.bar === "undefined" + `, ].map(code => ({code, options: [{checkGlobalVariables: false}]})), }); From 1daf95ebdc047eab73e125de5e14b28ed4896d88 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 15:43:21 +0800 Subject: [PATCH 06/14] More tests --- test/snapshots/no-typeof-undefined.mjs.md | 29 ++++++++++++++++++++ test/snapshots/no-typeof-undefined.mjs.snap | Bin 1381 -> 1445 bytes 2 files changed, 29 insertions(+) diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md index c3a6de25ec..52b5441eda 100644 --- a/test/snapshots/no-typeof-undefined.mjs.md +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -488,3 +488,32 @@ Generated by [AVA](https://avajs.dev). > 1 | typeof foo.bar === "undefined"␊ | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` + +## Invalid #12 + 1 | import foo from 'foo'; + 2 | typeof foo.bar === "undefined" + +> Options + + `␊ + [␊ + {␊ + "checkGlobalVariables": false␊ + }␊ + ]␊ + ` + +> Output + + `␊ + 1 | import foo from 'foo';␊ + 2 | foo.bar === undefined␊ + ` + +> Error 1/1 + + `␊ + 1 | import foo from 'foo';␊ + > 2 | typeof foo.bar === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ` diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap index b107f6889520999422a223682fe93e1fa623fcc5..899de3aad6c9666148418c1cac7195ec628338ba 100644 GIT binary patch literal 1445 zcmV;W1zP$+RzV48bKK{nUwcf?UU4pnO9FO?{40Fu%E*0IKc?o zNh)Qmc;H-oXVci*WzErz{WNCR`tc|tm_T^+gru#kGpD+HP}Wq@{^hqcW>funXb65n z$cOu7MavquUEA8C2-*|5pTcb6G9JkR0NA=>M@*-8pN#!{;-5XwkFKII%MlzSP%HF9?T* zTZdbcOqJIQQqQDbkGr47Z1inBstM#P0C;`N*~0!$Lf78eed}rEQ12*(*&PI5Ahe!+ zIk8r)`s1Vad}UC_hISgW{=qyp6I?}T|L)5Au88K$b9v0@%IY39joH|hJW2?HLjd@| zw(<8BX`0cJSNl`8*n+oHm`x_=M7Yqr`-*wp>8!&S*JX#d*ZI+y{gpr-%3}cG`<_c1 zQ@T=H!UD!&z4_<+Xv_wM@z_Lg3E{@c+<|v=M?30dV_&@sv||)zBW~x>h45EM-K}H8 zhZK*Oe0q=cxdJ~5vlj@mR-qAfFE%NIZw`(>(%X}`^Y{Rb*+zmsg3{Fh&>#R;kHjB@ zO2VZO#=~mJDAX`AJssMN8dj?_vKpyim|mKJhgmDltV!z}9pxMzh3r5y;0gS|O(uhx z;aFI%vzEXj=cpp6(Q$0CRbL5pMvIkYG!R)U;;k0J;u5yFR3ThBmuygLGZtHQCL?6z zF|Z1e35X2jSgVaQLOG0!gT*F;fi+sut3>;&K>H@sr@9oAhTbKicQt|~s16{$MuuPw z;<{iVyT^f$e-^@X*R9K(^JU_Dm)zypy2(T|Nh>H6x}7GRQ8r};?;-Jw%$pL^w8aW) znO8wYQfK3zIabEX+9ih!_mmC)&{?2;FGgz#YtijQ={oDE4|)}K`DEBnF=-1`Q-;Ve?#KFAd(-TCS1d zDz{XaIo4vakMmSwF|I8}w8Z*mTVh^pVKFN!#>=KVuf&NWnv|gwK&g<1OTt6;>>}CY z96y;xZc+#?q&y4nxSqAn%5mrT|Il$SuSun1*Cd~BWpd(Nu?ell%M0UY3J+Beh_f!! zypNJECTXl|b$VH*)Jwp%PUldtJ}QdJrE(p|zoV<8(~O)cxRp**%FXd`6nJSjgSYEm zN5@4qaA6Jvk(NKT0eI+HA`L)zqWEM3ha7k*JtM;xi|X8z1^ zbMyF?N^!228RU?>3VB$Aa&+1i&?VPjb7~|unptif_7mwdA5M=_3euCmMpphnFk*)De+r8dx;@CgmW%3y&u;?!+ zz72Fq_$tPgW$S`#_Fqz;QL*~e6=txg1PcT^L-9c%j!W{U>-hRU9 z%M2Fvg5oMDX5(OBsI!-wapd6gE+KQnlLC^>Tufk5T_|1##N8Sz}qDP=zA#E;DX@eKs@!dv;Akjj=V4%&<+?5Q%ppMu`ThS2t!^Cq$OIPEgW}~tykgrV<-0mfp}x7 z&IexWl#dzH&X~KF^7%1=MMd}_xEF}8&u@5IAhkJg=3S{E$<-Y!%wW+|P|Pj>!E1r| z&cXXS<{K;*3bFrE=qh;Tzzi0B1;t8&5WEkFzpe>AwH@!Fhs_l|hhEl1o9sP@zU4Q7=hB(biU>G%qDJEi*4Qg$qSl4woHRSxIF< zYJM7AwGv#p63`q4pn^CsP;k!AEl4a%RVdFa$xujut4dHv$t+4uF3G7>$jmD)Nli>q z0GgHnF*QLUIU_YWTMyOdP^bgbO7oISGV}8k5;Zgxs)2$=Ktax;)RNMoJOvE}eSL-G z{M_8syb_?4F-VFNazOeo|siSYlCTVp2|Ov67WST4GLdDo{l&S1hV#Swt$)OG+$44N_F41*l~M zvJN_w54pr9rO>>@qDt3_f}+&oVvss~DM%AN2VqS?CrM2~L^y$#2}hI2GKHdqqXZ3; zGGGz_CIxE{fiLycK~oQ0Jt7(5NJ0wK3?AxxJSVk;B#*<@51_}1Yz1UvYX#6FlT#Ei z8c@$A=L2nn1h0Z2q3B`iVt{%UO&jsCG#C@9HhS(PGMh3@U_j5OWMtSu8YrG%tuOTNbyDpU^;Sjh%A0~QjVDZpMuW?E({zMdOXGXrW$$8QWh%6TGlD3;+U nI(0WGN`kuBk|4MaA(%lYV@-t+y<}xiYJ>~`8ucJMau)yqLXKsF From d79e7698bf1c9a70c16da1790f9f3c649a067b64 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 15:49:11 +0800 Subject: [PATCH 07/14] Minor tweak --- rules/no-typeof-undefined.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index ae4046dbad..8e99771353 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -79,9 +79,9 @@ const create = context => { if ( (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement') && parent.argument === binaryExpression + && !isOnSameLine(typeofToken, secondToken) && !isParenthesized(binaryExpression, sourceCode) && !isParenthesized(typeofNode, sourceCode) - && !isOnSameLine(typeofToken, secondToken) ) { yield * addParenthesizesToReturnOrThrowExpression(fixer, parent, sourceCode); return; From 87974fce904a4f6ff3ba324683a118695ef296dc Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 15:52:19 +0800 Subject: [PATCH 08/14] Fix codebase violation --- rules/no-static-only-class.js | 2 +- rules/utils/is-same-reference.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/no-static-only-class.js b/rules/no-static-only-class.js index 89268ec7f3..4fdcb932fb 100644 --- a/rules/no-static-only-class.js +++ b/rules/no-static-only-class.js @@ -49,7 +49,7 @@ function isStaticMember(node) { if ( isDeclare || isReadonly - || typeof accessibility !== 'undefined' + || accessibility !== undefined || (Array.isArray(decorators) && decorators.length > 0) // TODO: Remove this when we drop support for `@typescript-eslint/parser` v4 || key.type === 'TSPrivateIdentifier' diff --git a/rules/utils/is-same-reference.js b/rules/utils/is-same-reference.js index 6f388a5372..21a4c80d4d 100644 --- a/rules/utils/is-same-reference.js +++ b/rules/utils/is-same-reference.js @@ -145,7 +145,7 @@ function isSameReference(left, right) { const nameA = getStaticPropertyName(left); // `x.y = x["y"]` - if (typeof nameA !== 'undefined') { + if (nameA !== undefined) { return ( isSameReference(left.object, right.object) && nameA === getStaticPropertyName(right) From fcce7a216a1aff554c88e3a0085f8719fdd1e162 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 17:51:51 +0800 Subject: [PATCH 09/14] `checkGlobalVariables: false` by default --- docs/rules/no-typeof-undefined.md | 30 +- readme.md | 2 +- rules/no-typeof-undefined.js | 101 +++--- test/no-typeof-undefined.mjs | 63 ++-- test/snapshots/no-typeof-undefined.mjs.md | 375 ++++++++------------ test/snapshots/no-typeof-undefined.mjs.snap | Bin 1445 -> 1554 bytes 6 files changed, 265 insertions(+), 306 deletions(-) diff --git a/docs/rules/no-typeof-undefined.md b/docs/rules/no-typeof-undefined.md index 4408edcac8..54ed6ad0ff 100644 --- a/docs/rules/no-typeof-undefined.md +++ b/docs/rules/no-typeof-undefined.md @@ -2,7 +2,7 @@ βœ… This rule is enabled in the `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). -πŸ”§ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). +πŸ”§πŸ’‘ This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). @@ -12,21 +12,27 @@ Enforce compare value with `undefined` directly instead of compare `typeof value ## Fail ```js -if (typeof foo === 'undefined') {} +function foo(bar) { + if (typeof bar === 'undefined') {} +} ``` ```js -if (typeof foo !== 'undefined') {} +import foo from './foo.js'; +if (typeof foo.bar !== 'undefined') {} ``` ## Pass ```js -if (foo === undefined) {} +function foo(bar) { + if (foo === undefined) {} +} ``` ```js -if (foo !== undefined) {} +import foo from './foo.js'; +if (foo.bar !== undefined) {} ``` ## Options @@ -34,16 +40,18 @@ if (foo !== undefined) {} ### checkGlobalVariables Type: `boolean`\ -Default: `true` +Default: `false` -Set it to `false` to ignore variables not defined in file. +This rule ignores variables not defined in file by default. + +Set it to `true` to check all variables. ```js -// eslint unicorn/no-typeof-undefined: ["error", {"checkGlobalVariables": false}] -if (typeof undefinedVariable === 'undefined') {} // Passes +// eslint unicorn/no-typeof-undefined: ["error", {"checkGlobalVariables": true}] +if (typeof undefinedVariable === 'undefined') {} // Fails ``` ```js -// eslint unicorn/no-typeof-undefined: ["error", {"checkGlobalVariables": false}] -if (typeof Array === 'undefined') {} // Passes +// eslint unicorn/no-typeof-undefined: ["error", {"checkGlobalVariables": true}] +if (typeof Array === 'undefined') {} // Fails ``` diff --git a/readme.md b/readme.md index b8250b31b2..74ad3324b9 100644 --- a/readme.md +++ b/readme.md @@ -91,7 +91,7 @@ Use a [preset config](#preset-configs) or configure each rules in `package.json` | [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | βœ… | πŸ”§ | | | [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | βœ… | | | | [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | βœ… | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Enforce compare with `undefined` directly. | βœ… | πŸ”§ | | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Enforce compare with `undefined` directly. | βœ… | πŸ”§ | πŸ’‘ | | [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | βœ… | πŸ”§ | | | [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | βœ… | πŸ”§ | | | [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | βœ… | | | diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index 8e99771353..1b8755a4fd 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -11,9 +11,11 @@ const { isParenthesized, } = require('./utils/parentheses.js'); -const MESSAGE_ID_ERROR = 'no-typeof-undefined'; +const MESSAGE_ID_ERROR = 'no-typeof-undefined/error'; +const MESSAGE_ID_SUGGESTION = 'no-typeof-undefined/suggestion'; const messages = { [MESSAGE_ID_ERROR]: 'Compare with `undefined` directly instead of `typeof` check.', + [MESSAGE_ID_SUGGESTION]: 'Switch to `… {{operator}} undefined`.', }; const selector = [ @@ -30,69 +32,81 @@ const create = context => { const { checkGlobalVariables, } = { - checkGlobalVariables: true, + checkGlobalVariables: false, ...context.options[0], }; return { [selector](binaryExpression) { - const {left: typeofNode, right: undefinedString} = binaryExpression; + const {left: typeofNode, right: undefinedString, operator} = binaryExpression; if (undefinedString.value !== 'undefined') { return; } const valueNode = typeofNode.argument; + const isGlobalVariable = valueNode.type === 'Identifier' + && !isShadowed(context.getScope(), valueNode); - if ( - valueNode.type === 'Identifier' - && !checkGlobalVariables - && !isShadowed(context.getScope(), valueNode) - ) { + if (!checkGlobalVariables && isGlobalVariable) { return; } const sourceCode = context.getSourceCode(); const [typeofToken, secondToken] = sourceCode.getFirstTokens(typeofNode, 2); - return { + const fix = function * (fixer) { + // Change `==`/`!=` to `===`/`!==` + if (operator === '==' || operator === '!=') { + const operatorToken = sourceCode.getTokenAfter( + typeofNode, + token => token.type === 'Punctuator' && token.value === operator, + ); + + yield fixer.insertTextAfter(operatorToken, '='); + } + + yield fixer.replaceText(undefinedString, 'undefined'); + + yield fixer.remove(typeofToken); + yield removeSpacesAfter(typeofToken, sourceCode, fixer); + + const {parent} = binaryExpression; + if ( + (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement') + && parent.argument === binaryExpression + && !isOnSameLine(typeofToken, secondToken) + && !isParenthesized(binaryExpression, sourceCode) + && !isParenthesized(typeofNode, sourceCode) + ) { + yield * addParenthesizesToReturnOrThrowExpression(fixer, parent, sourceCode); + return; + } + + const tokenBefore = sourceCode.getTokenBefore(binaryExpression); + if (needsSemicolon(tokenBefore, sourceCode, secondToken.value)) { + yield fixer.insertTextBefore(binaryExpression, ';'); + } + } + + const problem = { node: binaryExpression, loc: typeofToken.loc, messageId: MESSAGE_ID_ERROR, - * fix(fixer) { - // Change `==`/`!=` to `===`/`!==` - const {operator} = binaryExpression; - if (operator === '==' || operator === '!=') { - const operatorToken = sourceCode.getTokenAfter( - typeofNode, - token => token.type === 'Punctuator' && token.value === operator, - ); - - yield fixer.insertTextAfter(operatorToken, '='); - } - - yield fixer.replaceText(undefinedString, 'undefined'); - - yield fixer.remove(typeofToken); - yield removeSpacesAfter(typeofToken, sourceCode, fixer); - - const {parent} = binaryExpression; - if ( - (parent.type === 'ReturnStatement' || parent.type === 'ThrowStatement') - && parent.argument === binaryExpression - && !isOnSameLine(typeofToken, secondToken) - && !isParenthesized(binaryExpression, sourceCode) - && !isParenthesized(typeofNode, sourceCode) - ) { - yield * addParenthesizesToReturnOrThrowExpression(fixer, parent, sourceCode); - return; - } - - const tokenBefore = sourceCode.getTokenBefore(binaryExpression); - if (needsSemicolon(tokenBefore, sourceCode, secondToken.value)) { - yield fixer.insertTextBefore(binaryExpression, ';'); - } - }, }; + + if (isGlobalVariable) { + problem.suggest = [ + { + messageId: MESSAGE_ID_SUGGESTION, + data: {operator: operator.startsWith('!') ? '!==' : '==='}, + fix, + }, + ]; + } else { + problem.fix = fix; + } + + return problem; }, }; }; @@ -121,5 +135,6 @@ module.exports = { fixable: 'code', schema, messages, + hasSuggestions: true, }, }; diff --git a/test/no-typeof-undefined.mjs b/test/no-typeof-undefined.mjs index 02e1b28d82..d5895737f8 100644 --- a/test/no-typeof-undefined.mjs +++ b/test/no-typeof-undefined.mjs @@ -14,7 +14,11 @@ test.snapshot({ 'a.b++ === "undefined"', 'foo === undefined', 'typeof a.b === "string"', - 'typeof a.b === "string"', + 'typeof foo === "undefined"', + 'foo = 2; typeof foo === "undefined"', + '/* globals foo: readonly */ typeof foo === "undefined"', + '/* globals globalThis: readonly */ typeof globalThis === "undefined"', + // Cases we are not checking '"undefined" === typeof a.b', 'const UNDEFINED = "undefined"; typeof a.b === UNDEFINED', 'typeof a.b === `undefined`', @@ -25,12 +29,35 @@ test.snapshot({ 'typeof a.b == "undefined"', 'typeof a.b != "undefined"', 'typeof a.b == \'undefined\'', - 'typeof undefinedVariableIdentifier == \'undefined\'', + 'let foo; typeof foo === "undefined"', + 'const foo = 1; typeof foo === "undefined"', + 'var foo; typeof foo === "undefined"', + 'var foo; var foo; typeof foo === "undefined"', + 'for (const foo of bar) typeof foo === "undefined";', + outdent` + let foo; + function bar() { + typeof foo === "undefined"; + } + `, + 'function foo() {typeof foo === "undefined"}', + 'function foo(bar) {typeof bar === "undefined"}', + 'function foo({bar}) {typeof bar === "undefined"}', + 'function foo([bar]) {typeof bar === "undefined"}', + 'typeof foo.bar === "undefined"', + outdent` + import foo from 'foo'; + typeof foo.bar === "undefined" + `, // ASI outdent` foo typeof [] === "undefined"; `, + outdent` + foo + typeof (a ? b : c) === "undefined"; + `, outdent` function a() { return typeof // comment @@ -52,34 +79,12 @@ test.snapshot({ ], }); -// `checkGlobalVariables: false` +// `checkGlobalVariables: true` test.snapshot({ valid: [ - 'typeof foo === "undefined"', - 'foo = 2; typeof foo === "undefined"', - '/* globals foo: readonly */ typeof foo === "undefined"', - '/* globals globalThis: readonly */ typeof globalThis === "undefined"', - ].map(code => ({code, options: [{checkGlobalVariables: false}]})), + ], invalid: [ - 'let foo; typeof foo === "undefined"', - 'const foo = 1; typeof foo === "undefined"', - 'var foo; typeof foo === "undefined"', - 'var foo; var foo; typeof foo === "undefined"', - 'for (const foo of bar) typeof foo === "undefined";', - outdent` - let foo; - function bar() { - typeof foo === "undefined"; - } - `, - 'function foo() {typeof foo === "undefined"}', - 'function foo(bar) {typeof bar === "undefined"}', - 'function foo({bar}) {typeof bar === "undefined"}', - 'function foo([bar]) {typeof bar === "undefined"}', - 'typeof foo.bar === "undefined"', - outdent` - import foo from 'foo'; - typeof foo.bar === "undefined" - `, - ].map(code => ({code, options: [{checkGlobalVariables: false}]})), + 'typeof undefinedVariableIdentifier === "undefined"', + 'typeof Array !== "undefined"', + ].map(code => ({code, options: [{checkGlobalVariables: true}]})), }); diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md index 52b5441eda..2d08b98b5c 100644 --- a/test/snapshots/no-typeof-undefined.mjs.md +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -85,435 +85,366 @@ Generated by [AVA](https://avajs.dev). ` ## Invalid #6 - 1 | typeof undefinedVariableIdentifier == 'undefined' + 1 | let foo; typeof foo === "undefined" > Output `␊ - 1 | undefinedVariableIdentifier === undefined␊ + 1 | let foo; foo === undefined␊ ` > Error 1/1 `␊ - > 1 | typeof undefinedVariableIdentifier == 'undefined'␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + > 1 | let foo; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` ## Invalid #7 - 1 | foo - 2 | typeof [] === "undefined"; + 1 | const foo = 1; typeof foo === "undefined" > Output `␊ - 1 | foo␊ - 2 | ;[] === undefined;␊ + 1 | const foo = 1; foo === undefined␊ ` > Error 1/1 `␊ - 1 | foo␊ - > 2 | typeof [] === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + > 1 | const foo = 1; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` ## Invalid #8 - 1 | function a() { - 2 | return typeof // comment - 3 | a.b === 'undefined'; - 4 | } + 1 | var foo; typeof foo === "undefined" > Output `␊ - 1 | function a() {␊ - 2 | return ( // comment␊ - 3 | a.b === undefined);␊ - 4 | }␊ + 1 | var foo; foo === undefined␊ ` > Error 1/1 `␊ - 1 | function a() {␊ - > 2 | return typeof // comment␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ - 3 | a.b === 'undefined';␊ - 4 | }␊ + > 1 | var foo; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` ## Invalid #9 - 1 | function a() { - 2 | return (typeof // ReturnStatement argument is parenthesized - 3 | a.b === 'undefined'); - 4 | } + 1 | var foo; var foo; typeof foo === "undefined" > Output `␊ - 1 | function a() {␊ - 2 | return (// ReturnStatement argument is parenthesized␊ - 3 | a.b === undefined);␊ - 4 | }␊ + 1 | var foo; var foo; foo === undefined␊ ` > Error 1/1 `␊ - 1 | function a() {␊ - > 2 | return (typeof // ReturnStatement argument is parenthesized␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ - 3 | a.b === 'undefined');␊ - 4 | }␊ + > 1 | var foo; var foo; typeof foo === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` ## Invalid #10 - 1 | function a() { - 2 | return (typeof // UnaryExpression is parenthesized - 3 | a.b) === 'undefined'; - 4 | } + 1 | for (const foo of bar) typeof foo === "undefined"; > Output `␊ - 1 | function a() {␊ - 2 | return (// UnaryExpression is parenthesized␊ - 3 | a.b) === undefined;␊ - 4 | }␊ + 1 | for (const foo of bar) foo === undefined;␊ ` > Error 1/1 `␊ - 1 | function a() {␊ - > 2 | return (typeof // UnaryExpression is parenthesized␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ - 3 | a.b) === 'undefined';␊ - 4 | }␊ + > 1 | for (const foo of bar) typeof foo === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #1 - 1 | let foo; typeof foo === "undefined" - -> Options - - `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ - ` +## Invalid #11 + 1 | let foo; + 2 | function bar() { + 3 | typeof foo === "undefined"; + 4 | } > Output `␊ - 1 | let foo; foo === undefined␊ + 1 | let foo;␊ + 2 | function bar() {␊ + 3 | foo === undefined;␊ + 4 | }␊ ` > Error 1/1 `␊ - > 1 | let foo; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 1 | let foo;␊ + 2 | function bar() {␊ + > 3 | typeof foo === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 4 | }␊ ` -## Invalid #2 - 1 | const foo = 1; typeof foo === "undefined" - -> Options - - `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ - ` +## Invalid #12 + 1 | function foo() {typeof foo === "undefined"} > Output `␊ - 1 | const foo = 1; foo === undefined␊ + 1 | function foo() {foo === undefined}␊ ` > Error 1/1 `␊ - > 1 | const foo = 1; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + > 1 | function foo() {typeof foo === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #3 - 1 | var foo; typeof foo === "undefined" - -> Options - - `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ - ` +## Invalid #13 + 1 | function foo(bar) {typeof bar === "undefined"} > Output `␊ - 1 | var foo; foo === undefined␊ + 1 | function foo(bar) {bar === undefined}␊ ` > Error 1/1 `␊ - > 1 | var foo; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + > 1 | function foo(bar) {typeof bar === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #4 - 1 | var foo; var foo; typeof foo === "undefined" - -> Options - - `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ - ` +## Invalid #14 + 1 | function foo({bar}) {typeof bar === "undefined"} > Output `␊ - 1 | var foo; var foo; foo === undefined␊ + 1 | function foo({bar}) {bar === undefined}␊ ` > Error 1/1 `␊ - > 1 | var foo; var foo; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + > 1 | function foo({bar}) {typeof bar === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #5 - 1 | for (const foo of bar) typeof foo === "undefined"; - -> Options - - `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ - ` +## Invalid #15 + 1 | function foo([bar]) {typeof bar === "undefined"} > Output `␊ - 1 | for (const foo of bar) foo === undefined;␊ + 1 | function foo([bar]) {bar === undefined}␊ ` > Error 1/1 `␊ - > 1 | for (const foo of bar) typeof foo === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + > 1 | function foo([bar]) {typeof bar === "undefined"}␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #6 - 1 | let foo; - 2 | function bar() { - 3 | typeof foo === "undefined"; - 4 | } - -> Options - - `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ - ` +## Invalid #16 + 1 | typeof foo.bar === "undefined" > Output `␊ - 1 | let foo;␊ - 2 | function bar() {␊ - 3 | foo === undefined;␊ - 4 | }␊ + 1 | foo.bar === undefined␊ ` > Error 1/1 `␊ - 1 | let foo;␊ - 2 | function bar() {␊ - > 3 | typeof foo === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ - 4 | }␊ + > 1 | typeof foo.bar === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #7 - 1 | function foo() {typeof foo === "undefined"} +## Invalid #17 + 1 | import foo from 'foo'; + 2 | typeof foo.bar === "undefined" -> Options +> Output `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ + 1 | import foo from 'foo';␊ + 2 | foo.bar === undefined␊ ` -> Output +> Error 1/1 `␊ - 1 | function foo() {foo === undefined}␊ + 1 | import foo from 'foo';␊ + > 2 | typeof foo.bar === "undefined"␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -> Error 1/1 +## Invalid #18 + 1 | foo + 2 | typeof [] === "undefined"; + +> Output `␊ - > 1 | function foo() {typeof foo === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 1 | foo␊ + 2 | ;[] === undefined;␊ ` -## Invalid #8 - 1 | function foo(bar) {typeof bar === "undefined"} - -> Options +> Error 1/1 `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ + 1 | foo␊ + > 2 | typeof [] === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` +## Invalid #19 + 1 | foo + 2 | typeof (a ? b : c) === "undefined"; + > Output `␊ - 1 | function foo(bar) {bar === undefined}␊ + 1 | foo␊ + 2 | ;(a ? b : c) === undefined;␊ ` > Error 1/1 `␊ - > 1 | function foo(bar) {typeof bar === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 1 | foo␊ + > 2 | typeof (a ? b : c) === "undefined";␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ ` -## Invalid #9 - 1 | function foo({bar}) {typeof bar === "undefined"} +## Invalid #20 + 1 | function a() { + 2 | return typeof // comment + 3 | a.b === 'undefined'; + 4 | } -> Options +> Output `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ + 1 | function a() {␊ + 2 | return ( // comment␊ + 3 | a.b === undefined);␊ + 4 | }␊ ` -> Output +> Error 1/1 `␊ - 1 | function foo({bar}) {bar === undefined}␊ + 1 | function a() {␊ + > 2 | return typeof // comment␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 3 | a.b === 'undefined';␊ + 4 | }␊ ` -> Error 1/1 +## Invalid #21 + 1 | function a() { + 2 | return (typeof // ReturnStatement argument is parenthesized + 3 | a.b === 'undefined'); + 4 | } + +> Output `␊ - > 1 | function foo({bar}) {typeof bar === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 1 | function a() {␊ + 2 | return (// ReturnStatement argument is parenthesized␊ + 3 | a.b === undefined);␊ + 4 | }␊ ` -## Invalid #10 - 1 | function foo([bar]) {typeof bar === "undefined"} - -> Options +> Error 1/1 `␊ - [␊ - {␊ - "checkGlobalVariables": false␊ - }␊ - ]␊ + 1 | function a() {␊ + > 2 | return (typeof // ReturnStatement argument is parenthesized␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 3 | a.b === 'undefined');␊ + 4 | }␊ ` +## Invalid #22 + 1 | function a() { + 2 | return (typeof // UnaryExpression is parenthesized + 3 | a.b) === 'undefined'; + 4 | } + > Output `␊ - 1 | function foo([bar]) {bar === undefined}␊ + 1 | function a() {␊ + 2 | return (// UnaryExpression is parenthesized␊ + 3 | a.b) === undefined;␊ + 4 | }␊ ` > Error 1/1 `␊ - > 1 | function foo([bar]) {typeof bar === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 1 | function a() {␊ + > 2 | return (typeof // UnaryExpression is parenthesized␊ + | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + 3 | a.b) === 'undefined';␊ + 4 | }␊ ` -## Invalid #11 - 1 | typeof foo.bar === "undefined" +## Invalid #1 + 1 | typeof undefinedVariableIdentifier === "undefined" > Options `␊ [␊ {␊ - "checkGlobalVariables": false␊ + "checkGlobalVariables": true␊ }␊ ]␊ ` -> Output - - `␊ - 1 | foo.bar === undefined␊ - ` - > Error 1/1 `␊ - > 1 | typeof foo.bar === "undefined"␊ + > 1 | typeof undefinedVariableIdentifier === "undefined"␊ | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Switch to \`… === undefined\`.␊ + 1 | undefinedVariableIdentifier === undefined␊ ` -## Invalid #12 - 1 | import foo from 'foo'; - 2 | typeof foo.bar === "undefined" +## Invalid #2 + 1 | typeof Array !== "undefined" > Options `␊ [␊ {␊ - "checkGlobalVariables": false␊ + "checkGlobalVariables": true␊ }␊ ]␊ ` -> Output - - `␊ - 1 | import foo from 'foo';␊ - 2 | foo.bar === undefined␊ - ` - > Error 1/1 `␊ - 1 | import foo from 'foo';␊ - > 2 | typeof foo.bar === "undefined"␊ + > 1 | typeof Array !== "undefined"␊ | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + ␊ + --------------------------------------------------------------------------------␊ + Suggestion 1/1: Switch to \`… !== undefined\`.␊ + 1 | Array !== undefined␊ ` diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap index 899de3aad6c9666148418c1cac7195ec628338ba..b001f123ae50670475d3be729a8e689c8170d83e 100644 GIT binary patch literal 1554 zcmV+t2JQJlRzVp-_6N)&v)+k zJKy=f^PMxU7XZTnNI#X`r{n0gR-^LP*_QNu5ICPP6nik@?rx8J?R?dPFV@7ono^ax z9TMp!ib4qh$?L9P`)%*A%(UyVs~%>=_k%>bjv^Be`SgH-%-uD*LnXgzjK>z4c0nRt zPmzZ$QRlBYcJK02yWV=(lF;5U@e@d-t0~fA02tdjOLZo(O*(mw<;epbxz9r)wNu3Q z24G^`*+VPOTpjmH$L~95mUOm2BF&|^hoQGlGbIlF`S!f#mp*%VwMYtyG_#Kjv!nnR zzcy4IPuM;FK}x~#Q%jRyghaZ8qHkXS9Ph}#IW4WfoX=b?nBDwbBP7zv6c;fT7tUX? zF##wym(?mp9^5t$5@~;#3(XiyCyi|W?!dN&A>-9Y2gNOuLn7TzF+mQ%@=b5Pn{)d5 zIMq4BmiSEz>miZqDXw6wJ9%uwk+#YUnKP4HvKmg~Idw`$^mBpf4?xpQIrzbPvmN|- z@|VIpy>CDw{ffdc0Dup2_7tCJA3Qu^|D%PP^BtX#NLNwB3CC}aWg8BB}H6QJOMEWg-aVP*cn~Lw;ZJ(=6_;F)n!}KlFAdz07Xd4E= z{XzAQKE3dsYQE{<1o`r!7)Yc)QOtV+fL=gKB1F;~43>pXr?uu}S*U5vX+AI|e$D%4TZ$dgx zHytvVIabe?S0l64&a;dG;n8%iQFTafV)YADLL1_!4UDQ3CHmSb>{gBqRC^6{_x7MGBOWf%G8 zvM@6DH$By(pDJ#%+jnbLCBo}@uM=U{P%T6wXMrA#8s zt5Z0Rsg7V~m5&bdBhPb`m9ch`SJWA54a&oI=}m~YA>Gxwt->uur=n}ZOEbuJljI-x zUB|m*seibK9_3+Q56_5gSUBSbP^b+EW|7^>yH$yB3AR;*os-)i48bKK{nUwcf?UU4pnO9FO?{40Fu%E*0IKc?o zNh)Qmc;H-oXVci*WzErz{WNCR`tc|tm_T^+gru#kGpD+HP}Wq@{^hqcW>funXb65n z$cOu7MavquUEA8C2-*|5pTcb6G9JkR0NA=>M@*-8pN#!{;-5XwkFKII%MlzSP%HF9?T* zTZdbcOqJIQQqQDbkGr47Z1inBstM#P0C;`N*~0!$Lf78eed}rEQ12*(*&PI5Ahe!+ zIk8r)`s1Vad}UC_hISgW{=qyp6I?}T|L)5Au88K$b9v0@%IY39joH|hJW2?HLjd@| zw(<8BX`0cJSNl`8*n+oHm`x_=M7Yqr`-*wp>8!&S*JX#d*ZI+y{gpr-%3}cG`<_c1 zQ@T=H!UD!&z4_<+Xv_wM@z_Lg3E{@c+<|v=M?30dV_&@sv||)zBW~x>h45EM-K}H8 zhZK*Oe0q=cxdJ~5vlj@mR-qAfFE%NIZw`(>(%X}`^Y{Rb*+zmsg3{Fh&>#R;kHjB@ zO2VZO#=~mJDAX`AJssMN8dj?_vKpyim|mKJhgmDltV!z}9pxMzh3r5y;0gS|O(uhx z;aFI%vzEXj=cpp6(Q$0CRbL5pMvIkYG!R)U;;k0J;u5yFR3ThBmuygLGZtHQCL?6z zF|Z1e35X2jSgVaQLOG0!gT*F;fi+sut3>;&K>H@sr@9oAhTbKicQt|~s16{$MuuPw z;<{iVyT^f$e-^@X*R9K(^JU_Dm)zypy2(T|Nh>H6x}7GRQ8r};?;-Jw%$pL^w8aW) znO8wYQfK3zIabEX+9ih!_mmC)&{?2;FGgz#YtijQ={oDE4|)}K`DEBnF=-1`Q-;Ve?#KFAd(-TCS1d zDz{XaIo4vakMmSwF|I8}w8Z*mTVh^pVKFN!#>=KVuf&NWnv|gwK&g<1OTt6;>>}CY z96y;xZc+#?q&y4nxSqAn%5mrT|Il$SuSun1*Cd~BWpd(Nu?ell%M0UY3J+Beh_f!! zypNJECTXl|b$VH*)Jwp%PUldtJ}QdJrE(p|zoV<8(~O)cxRp**%FXd`6nJSjgSYEm zN5@4qaA6Jvk(NKT0eI+HA`L)zqWEM3ha7k*JtM;xi|X8z1^ zbMyF?N^!228RU?>3VB$Aa&+1i&?VPjb7~|un Date: Thu, 17 Nov 2022 17:58:14 +0800 Subject: [PATCH 10/14] Linting --- rules/no-typeof-undefined.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index 1b8755a4fd..ab8292321f 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -86,7 +86,7 @@ const create = context => { if (needsSemicolon(tokenBefore, sourceCode, secondToken.value)) { yield fixer.insertTextBefore(binaryExpression, ';'); } - } + }; const problem = { node: binaryExpression, @@ -133,8 +133,8 @@ module.exports = { description: 'Enforce compare with `undefined` directly.', }, fixable: 'code', + hasSuggestions: true, schema, messages, - hasSuggestions: true, }, }; From 2f1768c73635b94af6968480aeedde1de5dc2433 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 17 Nov 2022 18:07:06 +0800 Subject: [PATCH 11/14] Update no-typeof-undefined.md --- docs/rules/no-typeof-undefined.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/rules/no-typeof-undefined.md b/docs/rules/no-typeof-undefined.md index 54ed6ad0ff..c98a207164 100644 --- a/docs/rules/no-typeof-undefined.md +++ b/docs/rules/no-typeof-undefined.md @@ -19,6 +19,7 @@ function foo(bar) { ```js import foo from './foo.js'; + if (typeof foo.bar !== 'undefined') {} ``` @@ -32,6 +33,7 @@ function foo(bar) { ```js import foo from './foo.js'; + if (foo.bar !== undefined) {} ``` From ef7f443b2ef9dd9d75be6244005cfb0050aea515 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Sun, 20 Nov 2022 23:29:56 +0800 Subject: [PATCH 12/14] Apply suggestions from code review Co-authored-by: Sindre Sorhus --- docs/rules/no-typeof-undefined.md | 6 +++--- rules/no-typeof-undefined.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/rules/no-typeof-undefined.md b/docs/rules/no-typeof-undefined.md index c98a207164..a0d99effe1 100644 --- a/docs/rules/no-typeof-undefined.md +++ b/docs/rules/no-typeof-undefined.md @@ -1,4 +1,4 @@ -# Enforce compare with `undefined` directly +# Disallow comparing `undefined` using `typeof` βœ… This rule is enabled in the `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs). @@ -7,7 +7,7 @@ -Enforce compare value with `undefined` directly instead of compare `typeof value` with `'undefined'`. +Checking if a value is `undefined` by using `typeof value === 'undefined'` is needlessly verbose. It's generally better to compare against `undefined` directly. The only time `typeof` is needed is when a global variable potentially does not exists, in which case, using `globalThis.value === undefined` may be better. ## Fail @@ -44,7 +44,7 @@ if (foo.bar !== undefined) {} Type: `boolean`\ Default: `false` -This rule ignores variables not defined in file by default. +The rule ignores variables not defined in the file by default. Set it to `true` to check all variables. diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index ab8292321f..1361fff790 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -14,7 +14,7 @@ const { const MESSAGE_ID_ERROR = 'no-typeof-undefined/error'; const MESSAGE_ID_SUGGESTION = 'no-typeof-undefined/suggestion'; const messages = { - [MESSAGE_ID_ERROR]: 'Compare with `undefined` directly instead of `typeof` check.', + [MESSAGE_ID_ERROR]: 'Compare with `undefined` directly instead of using `typeof`.', [MESSAGE_ID_SUGGESTION]: 'Switch to `… {{operator}} undefined`.', }; From a9328a1a9105f603bb11edce19f0e748429334b4 Mon Sep 17 00:00:00 2001 From: fisker Date: Sun, 20 Nov 2022 23:32:00 +0800 Subject: [PATCH 13/14] Update snapshot --- test/snapshots/no-typeof-undefined.mjs.md | 48 ++++++++++---------- test/snapshots/no-typeof-undefined.mjs.snap | Bin 1554 -> 1557 bytes 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/test/snapshots/no-typeof-undefined.mjs.md b/test/snapshots/no-typeof-undefined.mjs.md index 2d08b98b5c..0b0a257788 100644 --- a/test/snapshots/no-typeof-undefined.mjs.md +++ b/test/snapshots/no-typeof-undefined.mjs.md @@ -17,7 +17,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof a.b === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #2 @@ -33,7 +33,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof a.b !== "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #3 @@ -49,7 +49,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof a.b == "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #4 @@ -65,7 +65,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof a.b != "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #5 @@ -81,7 +81,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof a.b == 'undefined'␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #6 @@ -97,7 +97,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | let foo; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #7 @@ -113,7 +113,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | const foo = 1; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #8 @@ -129,7 +129,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | var foo; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #9 @@ -145,7 +145,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | var foo; var foo; typeof foo === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #10 @@ -161,7 +161,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | for (const foo of bar) typeof foo === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #11 @@ -185,7 +185,7 @@ Generated by [AVA](https://avajs.dev). 1 | let foo;␊ 2 | function bar() {␊ > 3 | typeof foo === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ 4 | }␊ ` @@ -202,7 +202,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | function foo() {typeof foo === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #13 @@ -218,7 +218,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | function foo(bar) {typeof bar === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #14 @@ -234,7 +234,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | function foo({bar}) {typeof bar === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #15 @@ -250,7 +250,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | function foo([bar]) {typeof bar === "undefined"}␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #16 @@ -266,7 +266,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof foo.bar === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #17 @@ -285,7 +285,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | import foo from 'foo';␊ > 2 | typeof foo.bar === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #18 @@ -304,7 +304,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | foo␊ > 2 | typeof [] === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #19 @@ -323,7 +323,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | foo␊ > 2 | typeof (a ? b : c) === "undefined";␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ` ## Invalid #20 @@ -346,7 +346,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | function a() {␊ > 2 | return typeof // comment␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ 3 | a.b === 'undefined';␊ 4 | }␊ ` @@ -371,7 +371,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | function a() {␊ > 2 | return (typeof // ReturnStatement argument is parenthesized␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ 3 | a.b === 'undefined');␊ 4 | }␊ ` @@ -396,7 +396,7 @@ Generated by [AVA](https://avajs.dev). `␊ 1 | function a() {␊ > 2 | return (typeof // UnaryExpression is parenthesized␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ 3 | a.b) === 'undefined';␊ 4 | }␊ ` @@ -418,7 +418,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof undefinedVariableIdentifier === "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/1: Switch to \`… === undefined\`.␊ @@ -442,7 +442,7 @@ Generated by [AVA](https://avajs.dev). `␊ > 1 | typeof Array !== "undefined"␊ - | ^^^^^^ Compare with \`undefined\` directly instead of \`typeof\` check.␊ + | ^^^^^^ Compare with \`undefined\` directly instead of using \`typeof\`.␊ ␊ --------------------------------------------------------------------------------␊ Suggestion 1/1: Switch to \`… !== undefined\`.␊ diff --git a/test/snapshots/no-typeof-undefined.mjs.snap b/test/snapshots/no-typeof-undefined.mjs.snap index b001f123ae50670475d3be729a8e689c8170d83e..21bc6a0339ed7885d23bc23b936454d1a294d143 100644 GIT binary patch literal 1557 zcmV+w2I~1iRzVpUvu*HeCK|@ zbME&$-#KG@05BAQv@=<~T93EwF{y8zZ%R7=f%6$nu@58e?vA+EE>=DGVs*@`DOHI( zAhBMdD3Ae=ytcjVxBWvhMz+VUe3%~J2NLUAiVQsD)BW-@_STdfDgISwI#gqGF`pFm<=MKLl4fH562HRlqW<&$Pxo;=i=^E@P0J4I|y z04BtpKeFQ7^|7zC{=REQaYqv*)*Om^7zXQ9bK>BiZ_jOf>9dE|3+0elGkUo&Qx1UX zYh%^PguUY)q~xDGvn2UNNUVz~diMsv@s9GFv-0|@dCb-PS&h%FgTy+C;xfjff_cj~ zB>?r7vRc*f!`tUVV(qJNp%G)r#NmzK9opV7Xq@)=fVibfNUR4b#w!6>w)xF>v(L7V z)m$)cjo-YW9ulj8;u^-<(S%U9~YRu0IZ*(1V31BwtzoR z|59+L=M6}#Ur`wQ0q{ZgzM@kt1BWIYe6&D!v9$vd>q?54{s8P`RPvWUynm}#!;RBw zWj%t#s-yTGW7p&xM;nVbUY>ID!sJCw#VL?j3u0XuKLGcro0ON+W=K(A9udF)?qAa& zvDzuXKmhhQ(*EeDH+GocKQ%7f(LVINz5lII+FfxG>8%||;Sv3^To8VtbA^+k8?w#?Bd{J3dd!?dkaA+cVgXdVK< z{Q>olKE3pwW}f-*c;&Lf7)Y!?QOtb;fF3|jGDOxB43v#fBBVu&k;!JmtMEM;7rAsw-HV2~oc!k7JS^cSX3v>*PUGY?ca!XHgX=m{EzR zTM069JZlijs}X0l3oK(qcr=HdvzDO}*VrW*aSU-Z21Zkg5`AM8cPqyMYP|uvd;3Hf zsQ^d0C&^(o2%OF8oGn!;!>dsZ{uR$}t;iLw12k$0UrNM1gb$Hg%0%J`JGnf6a*PVc zMn4|~&k7FSic}~)9T{vE3u_hdU(Y)KQaD#Y#9i(DL^AMyev|MykbXy&=pA%AL@#nq zf+CE}{X#b{*x#St@M2 zKw>fRHVaC{EixCQU8Yj!hjMXT1~U?DsN{OxHu081G{DK$OEbuJ zljNWHo#(r3iGR9>p5*4AD zAFfA;70!IA3MU#uIm}xHcA@vO3UQ24R`h=(bYuL4&J%~*dAbo79h`|{BS|Of@|P(o ze_fFevij5glF(fzxa9(W3bcA8b(X{qD_J0J0U?f?A#gp9#8P0VHRoT3XH%y4-bgp%N(S^ z*^x6At6*mB+#*c8+vk^aA)Q}T-UCc`V(~rVMEZ;qgrN6;>%BKnF=!$xMLJ|qcY1;F zMz9M6{{f)KmVsR@9;VNN+WO3&9eyq!c2;{3IMJKn~$EN7^{=ZPP zgepmSR)(+6URc4icDu7*XG#>1Ws*vCyt_&iLI{x*Aa#hhEFmVY#1&xVDz$$A!DM{p HkQe{}3WV~w literal 1554 zcmV+t2JQJlRzVp-_6N)&v)+k zJKy=f^PMxU7XZTnNI#X`r{n0gR-^LP*_QNu5ICPP6nik@?rx8J?R?dPFV@7ono^ax z9TMp!ib4qh$?L9P`)%*A%(UyVs~%>=_k%>bjv^Be`SgH-%-uD*LnXgzjK>z4c0nRt zPmzZ$QRlBYcJK02yWV=(lF;5U@e@d-t0~fA02tdjOLZo(O*(mw<;epbxz9r)wNu3Q z24G^`*+VPOTpjmH$L~95mUOm2BF&|^hoQGlGbIlF`S!f#mp*%VwMYtyG_#Kjv!nnR zzcy4IPuM;FK}x~#Q%jRyghaZ8qHkXS9Ph}#IW4WfoX=b?nBDwbBP7zv6c;fT7tUX? zF##wym(?mp9^5t$5@~;#3(XiyCyi|W?!dN&A>-9Y2gNOuLn7TzF+mQ%@=b5Pn{)d5 zIMq4BmiSEz>miZqDXw6wJ9%uwk+#YUnKP4HvKmg~Idw`$^mBpf4?xpQIrzbPvmN|- z@|VIpy>CDw{ffdc0Dup2_7tCJA3Qu^|D%PP^BtX#NLNwB3CC}aWg8BB}H6QJOMEWg-aVP*cn~Lw;ZJ(=6_;F)n!}KlFAdz07Xd4E= z{XzAQKE3dsYQE{<1o`r!7)Yc)QOtV+fL=gKB1F;~43>pXr?uu}S*U5vX+AI|e$D%4TZ$dgx zHytvVIabe?S0l64&a;dG;n8%iQFTafV)YADLL1_!4UDQ3CHmSb>{gBqRC^6{_x7MGBOWf%G8 zvM@6DH$By(pDJ#%+jnbLCBo}@uM=U{P%T6wXMrA#8s zt5Z0Rsg7V~m5&bdBhPb`m9ch`SJWA54a&oI=}m~YA>Gxwt->uur=n}ZOEbuJljI-x zUB|m*seibK9_3+Q56_5gSUBSbP^b+EW|7^>yH$yB3AR;*os-)i Date: Sun, 20 Nov 2022 23:38:06 +0800 Subject: [PATCH 14/14] Fix description --- readme.md | 2 +- rules/no-typeof-undefined.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 74ad3324b9..76e8eb26d4 100644 --- a/readme.md +++ b/readme.md @@ -91,7 +91,7 @@ Use a [preset config](#preset-configs) or configure each rules in `package.json` | [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | βœ… | πŸ”§ | | | [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | βœ… | | | | [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | βœ… | | | -| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Enforce compare with `undefined` directly. | βœ… | πŸ”§ | πŸ’‘ | +| [no-typeof-undefined](docs/rules/no-typeof-undefined.md) | Disallow comparing `undefined` using `typeof`. | βœ… | πŸ”§ | πŸ’‘ | | [no-unnecessary-await](docs/rules/no-unnecessary-await.md) | Disallow awaiting non-promise values. | βœ… | πŸ”§ | | | [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | βœ… | πŸ”§ | | | [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | βœ… | | | diff --git a/rules/no-typeof-undefined.js b/rules/no-typeof-undefined.js index 1361fff790..3ad5e6ef55 100644 --- a/rules/no-typeof-undefined.js +++ b/rules/no-typeof-undefined.js @@ -130,7 +130,7 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'Enforce compare with `undefined` directly.', + description: 'Disallow comparing `undefined` using `typeof`.', }, fixable: 'code', hasSuggestions: true,