├── .editorconfig ├── .eslint-doc-generatorrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── rule_change.yml │ └── rule_proposal.yml ├── contributing.md ├── funding.yml ├── pull_request_template.md ├── security.md └── workflows │ ├── main.yml │ ├── smoke-test.yml │ └── title-formatter.yml ├── .gitignore ├── .markdownlint.json ├── .markdownlintignore ├── .npmpackagejsonlintrc.json ├── .npmrc ├── codecov.yml ├── configs └── flat-config-base.js ├── docs ├── deleted-and-deprecated-rules.md ├── new-rule.md ├── rules │ ├── better-regex.md │ ├── catch-error-name.md │ ├── consistent-assert.md │ ├── consistent-date-clone.md │ ├── consistent-destructuring.md │ ├── consistent-empty-array-spread.md │ ├── consistent-existence-index-check.md │ ├── consistent-function-scoping.md │ ├── custom-error-definition.md │ ├── empty-brace-spaces.md │ ├── error-message.md │ ├── escape-case.md │ ├── expiring-todo-comments.md │ ├── explicit-length-check.md │ ├── filename-case.md │ ├── import-style.md │ ├── new-for-builtins.md │ ├── no-abusive-eslint-disable.md │ ├── no-accessor-recursion.md │ ├── no-anonymous-default-export.md │ ├── no-array-callback-reference.md │ ├── no-array-for-each.md │ ├── no-array-method-this-argument.md │ ├── no-array-reduce.md │ ├── no-await-expression-member.md │ ├── no-await-in-promise-methods.md │ ├── no-console-spaces.md │ ├── no-document-cookie.md │ ├── no-empty-file.md │ ├── no-for-loop.md │ ├── no-hex-escape.md │ ├── no-instanceof-builtins.md │ ├── no-invalid-fetch-options.md │ ├── no-invalid-remove-event-listener.md │ ├── no-keyword-prefix.md │ ├── no-lonely-if.md │ ├── no-magic-array-flat-depth.md │ ├── no-named-default.md │ ├── no-negated-condition.md │ ├── no-negation-in-equality-check.md │ ├── no-nested-ternary.md │ ├── no-new-array.md │ ├── no-new-buffer.md │ ├── no-null.md │ ├── no-object-as-default-parameter.md │ ├── no-process-exit.md │ ├── no-single-promise-in-promise-methods.md │ ├── no-static-only-class.md │ ├── no-thenable.md │ ├── no-this-assignment.md │ ├── no-typeof-undefined.md │ ├── no-unnecessary-array-flat-depth.md │ ├── no-unnecessary-array-splice-count.md │ ├── no-unnecessary-await.md │ ├── no-unnecessary-polyfills.md │ ├── no-unnecessary-slice-end.md │ ├── no-unreadable-array-destructuring.md │ ├── no-unreadable-iife.md │ ├── no-unused-properties.md │ ├── no-useless-fallback-in-spread.md │ ├── no-useless-length-check.md │ ├── no-useless-promise-resolve-reject.md │ ├── no-useless-spread.md │ ├── no-useless-switch-case.md │ ├── no-useless-undefined.md │ ├── no-zero-fractions.md │ ├── number-literal-case.md │ ├── numeric-separators-style.md │ ├── prefer-add-event-listener.md │ ├── prefer-array-find.md │ ├── prefer-array-flat-map.md │ ├── prefer-array-flat.md │ ├── prefer-array-index-of.md │ ├── prefer-array-some.md │ ├── prefer-at.md │ ├── prefer-blob-reading-methods.md │ ├── prefer-code-point.md │ ├── prefer-date-now.md │ ├── prefer-default-parameters.md │ ├── prefer-dom-node-append.md │ ├── prefer-dom-node-dataset.md │ ├── prefer-dom-node-remove.md │ ├── prefer-dom-node-text-content.md │ ├── prefer-event-target.md │ ├── prefer-export-from.md │ ├── prefer-global-this.md │ ├── prefer-import-meta-properties.md │ ├── prefer-includes.md │ ├── prefer-json-parse-buffer.md │ ├── prefer-keyboard-event-key.md │ ├── prefer-logical-operator-over-ternary.md │ ├── prefer-math-min-max.md │ ├── prefer-math-trunc.md │ ├── prefer-modern-dom-apis.md │ ├── prefer-modern-math-apis.md │ ├── prefer-module.md │ ├── prefer-native-coercion-functions.md │ ├── prefer-negative-index.md │ ├── prefer-node-protocol.md │ ├── prefer-number-properties.md │ ├── prefer-object-from-entries.md │ ├── prefer-optional-catch-binding.md │ ├── prefer-prototype-methods.md │ ├── prefer-query-selector.md │ ├── prefer-reflect-apply.md │ ├── prefer-regexp-test.md │ ├── prefer-set-has.md │ ├── prefer-set-size.md │ ├── prefer-single-call.md │ ├── prefer-spread.md │ ├── prefer-string-raw.md │ ├── prefer-string-replace-all.md │ ├── prefer-string-slice.md │ ├── prefer-string-starts-ends-with.md │ ├── prefer-string-trim-start-end.md │ ├── prefer-structured-clone.md │ ├── prefer-switch.md │ ├── prefer-ternary.md │ ├── prefer-top-level-await.md │ ├── prefer-type-error.md │ ├── prevent-abbreviations.md │ ├── relative-url-style.md │ ├── require-array-join-separator.md │ ├── require-number-to-fixed-digits-argument.md │ ├── require-post-message-target-origin.md │ ├── string-content.md │ ├── switch-case-braces.md │ ├── template-indent.md │ ├── text-encoding-identifier-case.md │ └── throw-new-error.md └── write-tests.md ├── eslint.config.js ├── eslint.dogfooding.config.js ├── index.d.ts ├── index.js ├── license ├── package.json ├── readme.md ├── rules ├── ast │ ├── call-or-new-expression.js │ ├── function-types.js │ ├── index.js │ ├── is-arrow-function-body.js │ ├── is-directive.js │ ├── is-empty-node.js │ ├── is-expression-statement.js │ ├── is-function.js │ ├── is-member-expression.js │ ├── is-method-call.js │ ├── is-negative-one.js │ ├── is-reference-identifier.js │ ├── is-static-require.js │ ├── is-tagged-template-literal.js │ ├── is-undefined.js │ └── literal.js ├── better-regex.js ├── catch-error-name.js ├── consistent-assert.js ├── consistent-date-clone.js ├── consistent-destructuring.js ├── consistent-empty-array-spread.js ├── consistent-existence-index-check.js ├── consistent-function-scoping.js ├── custom-error-definition.js ├── empty-brace-spaces.js ├── error-message.js ├── escape-case.js ├── expiring-todo-comments.js ├── explicit-length-check.js ├── filename-case.js ├── fix │ ├── add-parenthesizes-to-return-or-throw-expression.js │ ├── append-argument.js │ ├── extend-fix-range.js │ ├── fix-space-around-keywords.js │ ├── index.js │ ├── remove-argument.js │ ├── remove-member-expression-property.js │ ├── remove-method-call.js │ ├── remove-parentheses.js │ ├── remove-spaces-after.js │ ├── remove-specifier.js │ ├── rename-variable.js │ ├── replace-argument.js │ ├── replace-node-or-token-and-spaces-before.js │ ├── replace-reference-identifier.js │ ├── replace-string-raw.js │ ├── replace-template-element.js │ ├── switch-call-expression-to-new-expression.js │ └── switch-new-expression-to-call-expression.js ├── import-style.js ├── index.js ├── new-for-builtins.js ├── no-abusive-eslint-disable.js ├── no-accessor-recursion.js ├── no-anonymous-default-export.js ├── no-array-callback-reference.js ├── no-array-for-each.js ├── no-array-method-this-argument.js ├── no-array-reduce.js ├── no-await-expression-member.js ├── no-await-in-promise-methods.js ├── no-console-spaces.js ├── no-document-cookie.js ├── no-empty-file.js ├── no-for-loop.js ├── no-hex-escape.js ├── no-instanceof-builtins.js ├── no-invalid-fetch-options.js ├── no-invalid-remove-event-listener.js ├── no-keyword-prefix.js ├── no-lonely-if.js ├── no-magic-array-flat-depth.js ├── no-named-default.js ├── no-negated-condition.js ├── no-negation-in-equality-check.js ├── no-nested-ternary.js ├── no-new-array.js ├── no-new-buffer.js ├── no-null.js ├── no-object-as-default-parameter.js ├── no-process-exit.js ├── no-single-promise-in-promise-methods.js ├── no-static-only-class.js ├── no-thenable.js ├── no-this-assignment.js ├── no-typeof-undefined.js ├── no-unnecessary-array-flat-depth.js ├── no-unnecessary-array-splice-count.js ├── no-unnecessary-await.js ├── no-unnecessary-polyfills.js ├── no-unnecessary-slice-end.js ├── no-unreadable-array-destructuring.js ├── no-unreadable-iife.js ├── no-unused-properties.js ├── no-useless-fallback-in-spread.js ├── no-useless-length-check.js ├── no-useless-promise-resolve-reject.js ├── no-useless-spread.js ├── no-useless-switch-case.js ├── no-useless-undefined.js ├── no-zero-fractions.js ├── number-literal-case.js ├── numeric-separators-style.js ├── prefer-add-event-listener.js ├── prefer-array-find.js ├── prefer-array-flat-map.js ├── prefer-array-flat.js ├── prefer-array-index-of.js ├── prefer-array-some.js ├── prefer-at.js ├── prefer-blob-reading-methods.js ├── prefer-code-point.js ├── prefer-date-now.js ├── prefer-default-parameters.js ├── prefer-dom-node-append.js ├── prefer-dom-node-dataset.js ├── prefer-dom-node-remove.js ├── prefer-dom-node-text-content.js ├── prefer-event-target.js ├── prefer-export-from.js ├── prefer-global-this.js ├── prefer-import-meta-properties.js ├── prefer-includes.js ├── prefer-json-parse-buffer.js ├── prefer-keyboard-event-key.js ├── prefer-logical-operator-over-ternary.js ├── prefer-math-min-max.js ├── prefer-math-trunc.js ├── prefer-modern-dom-apis.js ├── prefer-modern-math-apis.js ├── prefer-module.js ├── prefer-native-coercion-functions.js ├── prefer-negative-index.js ├── prefer-node-protocol.js ├── prefer-number-properties.js ├── prefer-object-from-entries.js ├── prefer-optional-catch-binding.js ├── prefer-prototype-methods.js ├── prefer-query-selector.js ├── prefer-reflect-apply.js ├── prefer-regexp-test.js ├── prefer-set-has.js ├── prefer-set-size.js ├── prefer-single-call.js ├── prefer-spread.js ├── prefer-string-raw.js ├── prefer-string-replace-all.js ├── prefer-string-slice.js ├── prefer-string-starts-ends-with.js ├── prefer-string-trim-start-end.js ├── prefer-structured-clone.js ├── prefer-switch.js ├── prefer-ternary.js ├── prefer-top-level-await.js ├── prefer-type-error.js ├── prevent-abbreviations.js ├── relative-url-style.js ├── require-array-join-separator.js ├── require-number-to-fixed-digits-argument.js ├── require-post-message-target-origin.js ├── shared │ ├── abbreviations.js │ ├── builtin-errors.js │ ├── dom-events.js │ ├── event-keys.js │ ├── negative-index.js │ ├── no-unnecessary-length-or-infinity-rule.js │ ├── package-json.js │ ├── simple-array-search-rule.js │ └── typed-array.js ├── string-content.js ├── switch-case-braces.js ├── template-indent.js ├── text-encoding-identifier-case.js ├── throw-new-error.js └── utils │ ├── array-or-object-prototype-property.js │ ├── assert-token.js │ ├── boolean.js │ ├── builtins.js │ ├── cartesian-product-samples.js │ ├── create-deprecated-rules.js │ ├── escape-string.js │ ├── escape-template-element-raw.js │ ├── get-ancestor.js │ ├── get-available-variable-name.js │ ├── get-builtin-rule.js │ ├── get-call-expression-arguments-text.js │ ├── get-call-expression-tokens.js │ ├── get-class-head-location.js │ ├── get-documentation-url.js │ ├── get-indent-string.js │ ├── get-previous-node.js │ ├── get-references.js │ ├── get-scopes.js │ ├── get-switch-case-head-location.js │ ├── get-variable-identifiers.js │ ├── global-reference-tracker.js │ ├── has-optional-chain-element.js │ ├── has-same-range.js │ ├── index.js │ ├── is-function-self-used-inside.js │ ├── is-left-hand-side.js │ ├── is-logical-expression.js │ ├── is-method-named.js │ ├── is-new-expression-with-parentheses.js │ ├── is-node-matches.js │ ├── is-node-value-not-dom-node.js │ ├── is-node-value-not-function.js │ ├── is-number.js │ ├── is-object-method.js │ ├── is-on-same-line.js │ ├── is-same-identifier.js │ ├── is-same-reference.js │ ├── is-shadowed.js │ ├── is-shorthand-export-local.js │ ├── is-shorthand-import-local.js │ ├── is-shorthand-property-assignment-pattern-left.js │ ├── is-shorthand-property-value.js │ ├── is-value-not-usable.js │ ├── needs-semicolon.js │ ├── numeric.js │ ├── parentheses.js │ ├── resolve-variable-name.js │ ├── rule.js │ ├── should-add-parentheses-to-await-expression-argument.js │ ├── should-add-parentheses-to-call-expression-callee.js │ ├── should-add-parentheses-to-conditional-expression-child.js │ ├── should-add-parentheses-to-expression-statement-expression.js │ ├── should-add-parentheses-to-logical-expression-child.js │ ├── should-add-parentheses-to-member-expression-object.js │ ├── should-add-parentheses-to-new-expression-callee.js │ ├── singular.js │ ├── string-cases.js │ └── to-location.js ├── scripts ├── create-rule.js ├── create-rules-index-file.js ├── internal-rules │ ├── fix-snapshot-test.js │ ├── index.js │ ├── no-restricted-property-access.js │ ├── no-test-only.js │ ├── prefer-fixer-remove-range.js │ └── prefer-negative-boolean-attribute.js ├── rename-rule.js └── template │ ├── documentation.md.jst │ ├── rule.js.jst │ └── test.js.jst └── test ├── better-regex.js ├── catch-error-name.js ├── consistent-assert.js ├── consistent-date-clone.js ├── consistent-destructuring.js ├── consistent-empty-array-spread.js ├── consistent-existence-index-check.js ├── consistent-function-scoping.js ├── custom-error-definition.js ├── empty-brace-spaces.js ├── error-message.js ├── escape-case.js ├── expiring-todo-comments.js ├── explicit-length-check.js ├── filename-case.js ├── import-style.js ├── integration ├── fixtures-local │ ├── conflicts-no-array-for-each-and-prevent-abbreviations.js │ └── error-name-conflicts.js ├── projects.js ├── readme.md ├── run-eslint.js └── test.js ├── new-for-builtins.js ├── no-abusive-eslint-disable.js ├── no-accessor-recursion.js ├── no-anonymous-default-export.js ├── no-array-callback-reference.js ├── no-array-for-each.js ├── no-array-method-this-argument.js ├── no-array-reduce.js ├── no-await-expression-member.js ├── no-await-in-promise-methods.js ├── no-console-spaces.js ├── no-document-cookie.js ├── no-empty-file.js ├── no-for-loop.js ├── no-hex-escape.js ├── no-instanceof-builtins.js ├── no-invalid-fetch-options.js ├── no-invalid-remove-event-listener.js ├── no-keyword-prefix.js ├── no-lonely-if.js ├── no-magic-array-flat-depth.js ├── no-named-default.js ├── no-negated-condition.js ├── no-negation-in-equality-check.js ├── no-nested-ternary.js ├── no-new-array.js ├── no-new-buffer.js ├── no-null.js ├── no-object-as-default-parameter.js ├── no-process-exit.js ├── no-single-promise-in-promise-methods.js ├── no-static-only-class.js ├── no-thenable.js ├── no-this-assignment.js ├── no-typeof-undefined.js ├── no-unnecessary-array-flat-depth.js ├── no-unnecessary-array-splice-count.js ├── no-unnecessary-await.js ├── no-unnecessary-polyfills.js ├── no-unnecessary-slice-end.js ├── no-unreadable-array-destructuring.js ├── no-unreadable-iife.js ├── no-unused-properties.js ├── no-useless-fallback-in-spread.js ├── no-useless-length-check.js ├── no-useless-promise-resolve-reject.js ├── no-useless-spread.js ├── no-useless-switch-case.js ├── no-useless-undefined.js ├── no-zero-fractions.js ├── number-literal-case.js ├── numeric-separators-style.js ├── package.js ├── prefer-add-event-listener.js ├── prefer-array-find.js ├── prefer-array-flat-map.js ├── prefer-array-flat.js ├── prefer-array-index-of.js ├── prefer-array-some.js ├── prefer-at.js ├── prefer-blob-reading-methods.js ├── prefer-code-point.js ├── prefer-date-now.js ├── prefer-default-parameters.js ├── prefer-dom-node-append.js ├── prefer-dom-node-dataset.js ├── prefer-dom-node-remove.js ├── prefer-dom-node-text-content.js ├── prefer-event-target.js ├── prefer-export-from.js ├── prefer-global-this.js ├── prefer-import-meta-properties.js ├── prefer-includes.js ├── prefer-json-parse-buffer.js ├── prefer-keyboard-event-key.js ├── prefer-logical-operator-over-ternary.js ├── prefer-math-min-max.js ├── prefer-math-trunc.js ├── prefer-modern-dom-apis.js ├── prefer-modern-math-apis.js ├── prefer-module.js ├── prefer-native-coercion-functions.js ├── prefer-negative-index.js ├── prefer-node-protocol.js ├── prefer-number-properties.js ├── prefer-object-from-entries.js ├── prefer-optional-catch-binding.js ├── prefer-prototype-methods.js ├── prefer-query-selector.js ├── prefer-reflect-apply.js ├── prefer-regexp-test.js ├── prefer-set-has.js ├── prefer-set-size.js ├── prefer-single-call.js ├── prefer-spread.js ├── prefer-string-raw.js ├── prefer-string-replace-all.js ├── prefer-string-slice.js ├── prefer-string-starts-ends-with.js ├── prefer-string-trim-start-end.js ├── prefer-structured-clone.js ├── prefer-switch.js ├── prefer-ternary.js ├── prefer-top-level-await.js ├── prefer-type-error.js ├── prevent-abbreviations.js ├── relative-url-style.js ├── require-array-join-separator.js ├── require-number-to-fixed-digits-argument.js ├── require-post-message-target-origin.js ├── shared ├── no-unnecessary-length-or-infinity-rule-tests.js └── simple-array-search-rule-tests.js ├── smoke └── eslint-remote-tester.config.js ├── snapshots ├── better-regex.js.md ├── better-regex.js.snap ├── consistent-assert.js.md ├── consistent-assert.js.snap ├── consistent-date-clone.js.md ├── consistent-date-clone.js.snap ├── consistent-empty-array-spread.js.md ├── consistent-empty-array-spread.js.snap ├── consistent-existence-index-check.js.md ├── consistent-existence-index-check.js.snap ├── consistent-function-scoping.js.md ├── consistent-function-scoping.js.snap ├── empty-brace-spaces.js.md ├── empty-brace-spaces.js.snap ├── error-message.js.md ├── error-message.js.snap ├── explicit-length-check.js.md ├── explicit-length-check.js.snap ├── filename-case.js.md ├── filename-case.js.snap ├── import-style.js.md ├── import-style.js.snap ├── new-for-builtins.js.md ├── new-for-builtins.js.snap ├── no-abusive-eslint-disable.js.md ├── no-abusive-eslint-disable.js.snap ├── no-accessor-recursion.js.md ├── no-accessor-recursion.js.snap ├── no-anonymous-default-export.js.md ├── no-anonymous-default-export.js.snap ├── no-array-callback-reference.js.md ├── no-array-callback-reference.js.snap ├── no-array-for-each.js.md ├── no-array-for-each.js.snap ├── no-array-method-this-argument.js.md ├── no-array-method-this-argument.js.snap ├── no-await-expression-member.js.md ├── no-await-expression-member.js.snap ├── no-await-in-promise-methods.js.md ├── no-await-in-promise-methods.js.snap ├── no-console-spaces.js.md ├── no-console-spaces.js.snap ├── no-document-cookie.js.md ├── no-document-cookie.js.snap ├── no-empty-file.js.md ├── no-empty-file.js.snap ├── no-for-loop.js.md ├── no-for-loop.js.snap ├── no-hex-escape.js.md ├── no-hex-escape.js.snap ├── no-instanceof-builtins.js.md ├── no-instanceof-builtins.js.snap ├── no-invalid-fetch-options.js.md ├── no-invalid-fetch-options.js.snap ├── no-invalid-remove-event-listener.js.md ├── no-invalid-remove-event-listener.js.snap ├── no-lonely-if.js.md ├── no-lonely-if.js.snap ├── no-magic-array-flat-depth.js.md ├── no-magic-array-flat-depth.js.snap ├── no-named-default.js.md ├── no-named-default.js.snap ├── no-negated-condition.js.md ├── no-negated-condition.js.snap ├── no-negation-in-equality-check.js.md ├── no-negation-in-equality-check.js.snap ├── no-nested-ternary.js.md ├── no-nested-ternary.js.snap ├── no-new-array.js.md ├── no-new-array.js.snap ├── no-new-buffer.js.md ├── no-new-buffer.js.snap ├── no-null.js.md ├── no-null.js.snap ├── no-object-as-default-parameter.js.md ├── no-object-as-default-parameter.js.snap ├── no-process-exit.js.md ├── no-process-exit.js.snap ├── no-single-promise-in-promise-methods.js.md ├── no-single-promise-in-promise-methods.js.snap ├── no-static-only-class.js.md ├── no-static-only-class.js.snap ├── no-thenable.js.md ├── no-thenable.js.snap ├── no-this-assignment.js.md ├── no-this-assignment.js.snap ├── no-typeof-undefined.js.md ├── no-typeof-undefined.js.snap ├── no-unnecessary-array-flat-depth.js.md ├── no-unnecessary-array-flat-depth.js.snap ├── no-unnecessary-array-splice-count.js.md ├── no-unnecessary-array-splice-count.js.snap ├── no-unnecessary-await.js.md ├── no-unnecessary-await.js.snap ├── no-unnecessary-slice-end.js.md ├── no-unnecessary-slice-end.js.snap ├── no-unreadable-array-destructuring.js.md ├── no-unreadable-array-destructuring.js.snap ├── no-unreadable-iife.js.md ├── no-unreadable-iife.js.snap ├── no-unused-properties.js.md ├── no-unused-properties.js.snap ├── no-useless-fallback-in-spread.js.md ├── no-useless-fallback-in-spread.js.snap ├── no-useless-length-check.js.md ├── no-useless-length-check.js.snap ├── no-useless-spread.js.md ├── no-useless-spread.js.snap ├── no-useless-switch-case.js.md ├── no-useless-switch-case.js.snap ├── no-useless-undefined.js.md ├── no-useless-undefined.js.snap ├── no-zero-fractions.js.md ├── no-zero-fractions.js.snap ├── number-literal-case.js.md ├── number-literal-case.js.snap ├── numeric-separators-style.js.md ├── numeric-separators-style.js.snap ├── prefer-add-event-listener.js.md ├── prefer-add-event-listener.js.snap ├── prefer-array-flat-map.js.md ├── prefer-array-flat-map.js.snap ├── prefer-array-flat.js.md ├── prefer-array-flat.js.snap ├── prefer-array-index-of.js.md ├── prefer-array-index-of.js.snap ├── prefer-array-some.js.md ├── prefer-array-some.js.snap ├── prefer-at.js.md ├── prefer-at.js.snap ├── prefer-blob-reading-methods.js.md ├── prefer-blob-reading-methods.js.snap ├── prefer-code-point.js.md ├── prefer-code-point.js.snap ├── prefer-date-now.js.md ├── prefer-date-now.js.snap ├── prefer-dom-node-dataset.js.md ├── prefer-dom-node-dataset.js.snap ├── prefer-dom-node-remove.js.md ├── prefer-dom-node-remove.js.snap ├── prefer-dom-node-text-content.js.md ├── prefer-dom-node-text-content.js.snap ├── prefer-event-target.js.md ├── prefer-event-target.js.snap ├── prefer-export-from.js.md ├── prefer-export-from.js.snap ├── prefer-global-this.js.md ├── prefer-global-this.js.snap ├── prefer-import-meta-properties.js.md ├── prefer-import-meta-properties.js.snap ├── prefer-includes.js.md ├── prefer-includes.js.snap ├── prefer-json-parse-buffer.js.md ├── prefer-json-parse-buffer.js.snap ├── prefer-keyboard-event-key.js.md ├── prefer-keyboard-event-key.js.snap ├── prefer-logical-operator-over-ternary.js.md ├── prefer-logical-operator-over-ternary.js.snap ├── prefer-math-min-max.js.md ├── prefer-math-min-max.js.snap ├── prefer-math-trunc.js.md ├── prefer-math-trunc.js.snap ├── prefer-modern-math-apis.js.md ├── prefer-modern-math-apis.js.snap ├── prefer-module.js.md ├── prefer-module.js.snap ├── prefer-native-coercion-functions.js.md ├── prefer-native-coercion-functions.js.snap ├── prefer-negative-index.js.md ├── prefer-negative-index.js.snap ├── prefer-node-protocol.js.md ├── prefer-node-protocol.js.snap ├── prefer-number-properties.js.md ├── prefer-number-properties.js.snap ├── prefer-object-from-entries.js.md ├── prefer-object-from-entries.js.snap ├── prefer-optional-catch-binding.js.md ├── prefer-optional-catch-binding.js.snap ├── prefer-prototype-methods.js.md ├── prefer-prototype-methods.js.snap ├── prefer-query-selector.js.md ├── prefer-query-selector.js.snap ├── prefer-regexp-test.js.md ├── prefer-regexp-test.js.snap ├── prefer-set-has.js.md ├── prefer-set-has.js.snap ├── prefer-set-size.js.md ├── prefer-set-size.js.snap ├── prefer-single-call.js.md ├── prefer-single-call.js.snap ├── prefer-spread.js.md ├── prefer-spread.js.snap ├── prefer-string-raw.js.md ├── prefer-string-raw.js.snap ├── prefer-string-replace-all.js.md ├── prefer-string-replace-all.js.snap ├── prefer-string-slice.js.md ├── prefer-string-slice.js.snap ├── prefer-string-starts-ends-with.js.md ├── prefer-string-starts-ends-with.js.snap ├── prefer-string-trim-start-end.js.md ├── prefer-string-trim-start-end.js.snap ├── prefer-structured-clone.js.md ├── prefer-structured-clone.js.snap ├── prefer-switch.js.md ├── prefer-switch.js.snap ├── prefer-top-level-await.js.md ├── prefer-top-level-await.js.snap ├── prefer-type-error.js.md ├── prefer-type-error.js.snap ├── relative-url-style.js.md ├── relative-url-style.js.snap ├── require-array-join-separator.js.md ├── require-array-join-separator.js.snap ├── require-number-to-fixed-digits-argument.js.md ├── require-number-to-fixed-digits-argument.js.snap ├── require-post-message-target-origin.js.md ├── require-post-message-target-origin.js.snap ├── switch-case-braces.js.md ├── switch-case-braces.js.snap ├── template-indent.js.md ├── template-indent.js.snap ├── text-encoding-identifier-case.js.md ├── text-encoding-identifier-case.js.snap ├── throw-new-error.js.md └── throw-new-error.js.snap ├── string-content.js ├── switch-case-braces.js ├── template-indent.js ├── text-encoding-identifier-case.js ├── throw-new-error.js ├── unit ├── assert-token.js ├── get-documentation-url.js └── snapshots │ ├── assert-token.js.md │ ├── assert-token.js.snap │ ├── assert-token.mjs.md │ └── assert-token.mjs.snap └── utils ├── default-options.js ├── language-options.js ├── not-dom-node-types.js ├── not-function-types.js ├── parsers.js ├── snapshot-rule-tester.js └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.yml] 11 | indent_style = space 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.eslint-doc-generatorrc.js: -------------------------------------------------------------------------------- 1 | /* eslint unicorn/prevent-abbreviations:"off" -- https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2015 */ 2 | 3 | /** @type {import('eslint-doc-generator').GenerateOptions} */ 4 | const config = { 5 | ignoreConfig: [ 6 | 'all', 7 | 'flat/all', 8 | 'flat/recommended', 9 | ], 10 | ignoreDeprecatedRules: true, 11 | ruleDocTitleFormat: 'desc', 12 | ruleListColumns: [ 13 | 'name', 14 | 'description', 15 | 'configsError', 16 | // Omit `configsOff` since we don't intend to convey meaning by setting rules to `off` in the `recommended` config. 17 | 'configsWarn', 18 | 'fixable', 19 | 'hasSuggestions', 20 | 'requiresTypeChecking', 21 | ], 22 | urlConfigs: 'https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config', 23 | }; 24 | 25 | export default config; 26 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: A rule isn't working as it should? 4 | labels: bug 5 | --- 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ```js 16 | const code = 'that should be ok'; 17 | ``` 18 | -------------------------------------------------------------------------------- /.github/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing guidelines 2 | 3 | ## I have an idea for a new rule 4 | 5 | Open an issue with your proposal. Make sure you elaborate on what problem it solves and include fail/pass examples. [(Example)](https://github.com/sindresorhus/eslint-plugin-unicorn/issues/166) 6 | 7 | ## I have an idea for a new rule and I also want to implement it 8 | 9 | First open an issue with your proposal. When the rule is accepted, see the [docs on creating and submitting a new rule](../docs/new-rule.md). 10 | 11 | ## I want to implement a rule from an open issue 12 | 13 | See the [docs on creating and submitting a new rule](../docs/new-rule.md). 14 | 15 | ## How to write tests 16 | 17 | See the [docs on writing tests](../docs/write-tests.md). 18 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: [sindresorhus, fisker] 2 | open_collective: sindresorhus 3 | buy_me_a_coffee: sindresorhus 4 | custom: https://sindresorhus.com/donate 5 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /.github/security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. 4 | -------------------------------------------------------------------------------- /.github/workflows/smoke-test.yml: -------------------------------------------------------------------------------- 1 | name: Smoke test 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * SUN" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | lint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: actions/setup-node@v4 14 | - run: npm install 15 | - uses: AriPerkkio/eslint-remote-tester-run-action@v5 16 | with: 17 | issue-title: "Results of weekly scheduled smoke test" 18 | eslint-remote-tester-config: test/smoke/eslint-remote-tester.config.js 19 | -------------------------------------------------------------------------------- /.github/workflows/title-formatter.yml: -------------------------------------------------------------------------------- 1 | name: Title formatter 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, edited] 6 | issues: 7 | types: [opened, edited] 8 | 9 | jobs: 10 | Rule: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | pull-requests: write 14 | issues: write 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | sparse-checkout: docs/rules 19 | - name: Auto-format rule names in titles 20 | uses: fregante/keyword-formatter-action@v1 21 | with: 22 | token: ${{ secrets.GITHUB_TOKEN }} 23 | keywords-path: docs/rules 24 | prefix: unicorn/ 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn.lock 3 | coverage 4 | package-lock.json 5 | /test/integration/fixtures 6 | .cache-eslint-remote-tester 7 | eslint-remote-tester-results 8 | *.log 9 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "line-length": false, 3 | "no-duplicate-heading": false, 4 | "no-hard-tabs": false, 5 | "ul-style": { 6 | "style": "dash" 7 | }, 8 | "descriptive-link-text": false 9 | } 10 | -------------------------------------------------------------------------------- /.markdownlintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test/snapshots 3 | test/integration/fixtures 4 | -------------------------------------------------------------------------------- /.npmpackagejsonlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-duplicate-properties": "error", 4 | "no-repeated-dependencies": "error", 5 | "prefer-alphabetical-dependencies": "error", 6 | "prefer-alphabetical-devDependencies": "error", 7 | "prefer-alphabetical-optionalDependencies": "error", 8 | "prefer-alphabetical-bundledDependencies": "error", 9 | "prefer-alphabetical-scripts": "error", 10 | "prefer-caret-version-dependencies": "error", 11 | "prefer-scripts": [ 12 | "error", 13 | [ 14 | "lint", 15 | "test" 16 | ] 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: 99% 6 | threshold: 1% 7 | patch: off 8 | -------------------------------------------------------------------------------- /configs/flat-config-base.js: -------------------------------------------------------------------------------- 1 | import globals from 'globals'; 2 | 3 | const config = { 4 | languageOptions: { 5 | globals: globals.builtin, 6 | }, 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /docs/rules/consistent-date-clone.md: -------------------------------------------------------------------------------- 1 | # Prefer passing `Date` directly to the constructor when cloning 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | The [`Date` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date) can clone a `⁠Date` object directly when passed as an argument, making timestamp conversion unnecessary. 11 | 12 | > Note: Before ES2015, `new Date(date)` converted `date` to a string first, so it's not safe to clone. 13 | 14 | ## Examples 15 | 16 | ```js 17 | // ❌ 18 | new Date(date.getTime()); 19 | 20 | // ✅ 21 | new Date(date); 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/rules/consistent-destructuring.md: -------------------------------------------------------------------------------- 1 | # Use destructured variables over properties 2 | 3 | 🚫 This rule is _disabled_ in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | Enforces the use of already destructured objects and their variables over accessing each property individually. Previous destructurings are easily missed which leads to an inconsistent code style. 11 | 12 | This rule is partly fixable. It does not fix nested destructuring. 13 | 14 | ## Fail 15 | 16 | ```js 17 | const {a} = foo; 18 | console.log(a, foo.b); 19 | ``` 20 | 21 | ```js 22 | const {a} = foo; 23 | console.log(foo.a); 24 | ``` 25 | 26 | ```js 27 | const { 28 | a: { 29 | b 30 | } 31 | } = foo; 32 | console.log(foo.a.c); 33 | ``` 34 | 35 | ```js 36 | const {bar} = foo; 37 | const {a} = foo.bar; 38 | ``` 39 | 40 | ## Pass 41 | 42 | ```js 43 | const {a} = foo; 44 | console.log(a); 45 | ``` 46 | 47 | ```js 48 | console.log(foo.a, foo.b); 49 | ``` 50 | 51 | ```js 52 | const {a} = foo; 53 | console.log(a, foo.b()); 54 | ``` 55 | 56 | ```js 57 | const {a} = foo.bar; 58 | console.log(foo.bar); 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/rules/consistent-empty-array-spread.md: -------------------------------------------------------------------------------- 1 | # Prefer consistent types when spreading a ternary in an array literal 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | When spreading a ternary in an array, we can use both `[]` and `''` as fallbacks, but it's better to have consistent types in both branches. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const array = [ 16 | a, 17 | ...(foo ? [b, c] : ''), 18 | ]; 19 | ``` 20 | 21 | ```js 22 | const array = [ 23 | a, 24 | ...(foo ? 'bc' : []), 25 | ]; 26 | ``` 27 | 28 | ## Pass 29 | 30 | ```js 31 | const array = [ 32 | a, 33 | ...(foo ? [b, c] : []), 34 | ]; 35 | ``` 36 | 37 | ```js 38 | const array = [ 39 | a, 40 | ...(foo ? 'bc' : ''), 41 | ]; 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/rules/empty-brace-spaces.md: -------------------------------------------------------------------------------- 1 | # Enforce no spaces between braces 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | ## Fail 11 | 12 | ```js 13 | class Unicorn { 14 | } 15 | ``` 16 | 17 | ```js 18 | try { 19 | foo(); 20 | } catch { } 21 | ``` 22 | 23 | ## Pass 24 | 25 | ```js 26 | class Unicorn {} 27 | ``` 28 | 29 | ```js 30 | try { 31 | foo(); 32 | } catch {} 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/rules/error-message.md: -------------------------------------------------------------------------------- 1 | # Enforce passing a `message` value when creating a built-in error 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | This rule enforces a `message` value to be passed in when creating an instance of a built-in [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object, which leads to more readable and debuggable code. 9 | 10 | ## Examples 11 | 12 | ```js 13 | // ❌ 14 | throw new Error(); 15 | 16 | // ❌ 17 | throw new Error(''); 18 | 19 | // ✅ 20 | throw new Error('Unexpected property.'); 21 | ``` 22 | 23 | ```js 24 | // ❌ 25 | throw new TypeError(); 26 | 27 | // ✅ 28 | throw new TypeError('Array expected.'); 29 | ``` 30 | 31 | ```js 32 | // ❌ 33 | const error = new AggregateError(errors); 34 | 35 | // ✅ 36 | const error = new AggregateError(errors, 'Promises rejected.'); 37 | ``` 38 | 39 | ```js 40 | // ❌ 41 | const error = new SuppressedError(error, suppressed); 42 | 43 | // ✅ 44 | const error = new SuppressedError(error, suppressed, 'This is a suppressed error.'); 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/rules/no-accessor-recursion.md: -------------------------------------------------------------------------------- 1 | # Disallow recursive access to `this` within getters and setters 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | This rule prevents recursive access to `this` within getter and setter methods in objects and classes, avoiding infinite recursion and stack overflow errors. 9 | 10 | ## Examples 11 | 12 | ```js 13 | // ❌ 14 | const foo = { 15 | get bar() { 16 | return this.bar; 17 | } 18 | }; 19 | 20 | // ✅ 21 | const foo = { 22 | get bar() { 23 | return this.baz; 24 | } 25 | }; 26 | ``` 27 | 28 | ```js 29 | // ❌ 30 | class Foo { 31 | get bar() { 32 | return this.bar; 33 | } 34 | } 35 | 36 | // ✅ 37 | class Foo { 38 | get bar() { 39 | return this.baz; 40 | } 41 | } 42 | ``` 43 | 44 | ```js 45 | // ❌ 46 | const foo = { 47 | set bar(value) { 48 | this.bar = value; 49 | } 50 | }; 51 | 52 | // ✅ 53 | const foo = { 54 | set bar(value) { 55 | this._bar = value; 56 | } 57 | }; 58 | ``` 59 | 60 | ```js 61 | // ❌ 62 | class Foo { 63 | set bar(value) { 64 | this.bar = value; 65 | } 66 | } 67 | 68 | // ✅ 69 | class Foo { 70 | set bar(value) { 71 | this._bar = value; 72 | } 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/rules/no-await-expression-member.md: -------------------------------------------------------------------------------- 1 | # Disallow member access from await expression 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | When accessing a member from an await expression, the await expression has to be parenthesized, which is not readable. 11 | 12 | This rule is fixable for simple member access. 13 | 14 | ## Fail 15 | 16 | ```js 17 | const foo = (await import('./foo.js')).default; 18 | ``` 19 | 20 | ```js 21 | const secondElement = (await getArray())[1]; 22 | ``` 23 | 24 | ```js 25 | const property = (await getObject()).property; 26 | ``` 27 | 28 | ```js 29 | const data = await (await fetch('/foo')).json(); 30 | ``` 31 | 32 | ## Pass 33 | 34 | ```js 35 | const {default: foo} = await import('./foo.js'); 36 | ``` 37 | 38 | ```js 39 | const [, secondElement] = await getArray(); 40 | ``` 41 | 42 | ```js 43 | const {property} = await getObject(); 44 | ``` 45 | 46 | ```js 47 | const response = await fetch('/foo'); 48 | const data = await response.json(); 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/rules/no-await-in-promise-methods.md: -------------------------------------------------------------------------------- 1 | # Disallow using `await` in `Promise` method parameters 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | Using `await` on promises passed as arguments to `Promise.all()`, `Promise.allSettled()`, `Promise.any()`, or `Promise.race()` is likely a mistake. 11 | 12 | ## Fail 13 | 14 | ```js 15 | Promise.all([await promise, anotherPromise]); 16 | 17 | Promise.allSettled([await promise, anotherPromise]); 18 | 19 | Promise.any([await promise, anotherPromise]); 20 | 21 | Promise.race([await promise, anotherPromise]); 22 | ``` 23 | 24 | ## Pass 25 | 26 | ```js 27 | Promise.all([promise, anotherPromise]); 28 | 29 | Promise.allSettled([promise, anotherPromise]); 30 | 31 | Promise.any([promise, anotherPromise]); 32 | 33 | Promise.race([promise, anotherPromise]); 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/rules/no-console-spaces.md: -------------------------------------------------------------------------------- 1 | # Do not use leading/trailing space between `console.log` parameters 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | The [`console.log()` method](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) and similar methods joins the parameters with a space, so adding a leading/trailing space to a parameter, results in two spaces being added. 11 | 12 | ## Fail 13 | 14 | ```js 15 | console.log('abc ', 'def'); 16 | console.log('abc', ' def'); 17 | 18 | console.log("abc ", " def"); 19 | console.log(`abc `, ` def`); 20 | 21 | console.debug('abc ', 'def'); 22 | console.info('abc ', 'def'); 23 | console.warn('abc ', 'def'); 24 | console.error('abc ', 'def'); 25 | ``` 26 | 27 | ## Pass 28 | 29 | ```js 30 | console.log('abc'); 31 | console.log('abc', 'def'); 32 | 33 | console.log('abc '); 34 | console.log(' abc'); 35 | 36 | console.log('abc ', 'def'); 37 | console.log('abc\t', 'def'); 38 | console.log('abc\n', 'def'); 39 | 40 | console.log(` 41 | abc 42 | `); 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/rules/no-document-cookie.md: -------------------------------------------------------------------------------- 1 | # Do not use `document.cookie` directly 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | It's not recommended to use [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) directly as it's easy to get the string wrong. Instead, you should use the [Cookie Store API](https://developer.mozilla.org/en-US/docs/Web/API/Cookie_Store_API) or a [cookie library](https://www.npmjs.com/search?q=cookie). 9 | 10 | ## Fail 11 | 12 | ```js 13 | document.cookie = 14 | 'foo=bar' + 15 | '; Path=/' + 16 | '; Domain=example.com' + 17 | '; expires=Fri, 31 Dec 9999 23:59:59 GMT' + 18 | '; Secure'; 19 | ``` 20 | 21 | ```js 22 | document.cookie += '; foo=bar'; 23 | ``` 24 | 25 | ## Pass 26 | 27 | ```js 28 | await cookieStore.set({ 29 | name: 'foo', 30 | value: 'bar', 31 | expires: Date.now() + 24 * 60 * 60 * 1000, 32 | domain: 'example.com' 33 | }); 34 | ``` 35 | 36 | ```js 37 | const array = document.cookie.split('; '); 38 | ``` 39 | 40 | ```js 41 | import Cookies from 'js-cookie'; 42 | 43 | Cookies.set('foo', 'bar'); 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/rules/no-empty-file.md: -------------------------------------------------------------------------------- 1 | # Disallow empty files 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | Meaningless files clutter a codebase. 9 | 10 | Disallow any files only containing the following: 11 | 12 | - Whitespace 13 | - Comments 14 | - Directives 15 | - Empty statements 16 | - Empty block statements 17 | - Hashbang 18 | 19 | ## Fail 20 | 21 | ```js 22 | 23 | ``` 24 | 25 | ```js 26 | // Comment 27 | ``` 28 | 29 | ```js 30 | /* Comment */ 31 | ``` 32 | 33 | ```js 34 | 'use strict'; 35 | ``` 36 | 37 | ```js 38 | ; 39 | ``` 40 | 41 | ```js 42 | { 43 | } 44 | ``` 45 | 46 | ```js 47 | #!/usr/bin/env node 48 | ``` 49 | 50 | ## Pass 51 | 52 | ```js 53 | const x = 0; 54 | ``` 55 | 56 | ```js 57 | 'use strict'; 58 | const x = 0; 59 | ``` 60 | 61 | ```js 62 | ;; 63 | const x = 0; 64 | ``` 65 | 66 | ```js 67 | { 68 | const x = 0; 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/rules/no-hex-escape.md: -------------------------------------------------------------------------------- 1 | # Enforce the use of Unicode escapes instead of hexadecimal escapes 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | Enforces a convention of using [Unicode escapes](https://mathiasbynens.be/notes/javascript-escapes#unicode) instead of [hexadecimal escapes](https://mathiasbynens.be/notes/javascript-escapes#hexadecimal) for consistency and clarity. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const foo = '\x1B'; 16 | const foo = `\x1B${bar}`; 17 | ``` 18 | 19 | ## Pass 20 | 21 | ```js 22 | const foo = '\u001B'; 23 | const foo = `\u001B${bar}`; 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/rules/no-invalid-fetch-options.md: -------------------------------------------------------------------------------- 1 | # Disallow invalid options in `fetch()` and `new Request()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) throws a `TypeError` when the method is `GET` or `HEAD` and a body is provided. 9 | 10 | ## Fail 11 | 12 | ```js 13 | const response = await fetch('/', {body: 'foo=bar'}); 14 | ``` 15 | 16 | ```js 17 | const request = new Request('/', {body: 'foo=bar'}); 18 | ``` 19 | 20 | ```js 21 | const response = await fetch('/', {method: 'GET', body: 'foo=bar'}); 22 | ``` 23 | 24 | ```js 25 | const request = new Request('/', {method: 'GET', body: 'foo=bar'}); 26 | ``` 27 | 28 | ## Pass 29 | 30 | ```js 31 | const response = await fetch('/', {method: 'HEAD'}); 32 | ``` 33 | 34 | ```js 35 | const request = new Request('/', {method: 'HEAD'}); 36 | ``` 37 | 38 | ```js 39 | const response = await fetch('/', {method: 'POST', body: 'foo=bar'}); 40 | ``` 41 | 42 | ```js 43 | const request = new Request('/', {method: 'POST', body: 'foo=bar'}); 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/rules/no-magic-array-flat-depth.md: -------------------------------------------------------------------------------- 1 | # Disallow a magic number as the `depth` argument in `Array#flat(…).` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | When calling [`Array#flat(depth)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat), the depth argument should normally be `1` or `Infinity`, otherwise it should be a meaningful variable name or explained with a comment. 9 | 10 | ## Fail 11 | 12 | ```js 13 | const foo = array.flat(2); 14 | ``` 15 | 16 | ```js 17 | const foo = array.flat(99); 18 | ``` 19 | 20 | ## Pass 21 | 22 | ```js 23 | const foo = array.flat(); 24 | ``` 25 | 26 | ```js 27 | const foo = array.flat(Number.POSITIVE_INFINITY); 28 | ``` 29 | 30 | ```js 31 | const foo = array.flat(Infinity); 32 | ``` 33 | 34 | ```js 35 | const foo = array.flat(depth); 36 | ``` 37 | 38 | ```js 39 | const foo = array.flat(/* The depth is always 2 */ 2); 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/rules/no-negation-in-equality-check.md: -------------------------------------------------------------------------------- 1 | # Disallow negated expression in equality check 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | Using a negated expression in equality check is most likely a mistake. 11 | 12 | ## Fail 13 | 14 | ```js 15 | if (!foo === bar) {} 16 | ``` 17 | 18 | ```js 19 | if (!foo !== bar) {} 20 | ``` 21 | 22 | ## Pass 23 | 24 | ```js 25 | if (foo !== bar) {} 26 | ``` 27 | 28 | ```js 29 | if (!(foo === bar)) {} 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/rules/no-object-as-default-parameter.md: -------------------------------------------------------------------------------- 1 | # Disallow the use of objects as default parameters 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | Default parameters should not be passed to a function through an object literal. The `foo = {a: false}` parameter works fine if only used with one option. As soon as additional options are added, you risk replacing the whole `foo = {a: false, b: true}` object when passing only one option: `{a: true}`. For this reason, object destructuring should be used instead. 9 | 10 | ## Fail 11 | 12 | ```js 13 | const abc = (foo = {a: false}) => {}; 14 | ``` 15 | 16 | ```js 17 | function foo({a} = {a: false}) {} 18 | ``` 19 | 20 | ```js 21 | const abc = (foo = {a: false, b: 123}) => {}; 22 | ``` 23 | 24 | ## Pass 25 | 26 | ```js 27 | const abc = (foo = {}) => {}; 28 | ``` 29 | 30 | ```js 31 | function foo(options) { 32 | const {a} = {a: false, ...options}; 33 | } 34 | ``` 35 | 36 | ```js 37 | const abc = (foo = false) => {}; 38 | ``` 39 | 40 | ```js 41 | const foo = ({a = false, b = 123}) => {}; 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/rules/no-process-exit.md: -------------------------------------------------------------------------------- 1 | # Disallow `process.exit()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | This rule is an extension to ESLint's [`no-process-exit` rule](https://eslint.org/docs/rules/no-process-exit), that allows `process.exit()` to be called in files that start with a [hashbang](https://en.wikipedia.org/wiki/Shebang_(Unix)) → `#!/usr/bin/env node`. It also allows `process.exit()` to be called in `process.on('', func)` event handlers and in files that imports `worker_threads`. 9 | 10 | ## Fail 11 | 12 | ```js 13 | process.exit(0); 14 | ``` 15 | 16 | ## Pass 17 | 18 | ```js 19 | #!/usr/bin/env node 20 | process.exit(0); 21 | ``` 22 | 23 | ```js 24 | process.on('SIGINT', () => { 25 | console.log('Got SIGINT'); 26 | process.exit(1); 27 | }); 28 | ``` 29 | 30 | ```js 31 | import workerThreads from 'node:worker_threads'; 32 | 33 | try { 34 | // Do something… 35 | process.exit(0); 36 | } catch (_) { 37 | process.exit(1); 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/rules/no-static-only-class.md: -------------------------------------------------------------------------------- 1 | # Disallow classes that only have static members 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | A class with only static members could just be an object instead. 11 | 12 | ## Fail 13 | 14 | ```js 15 | class X { 16 | static foo = false; 17 | static bar() {}; 18 | } 19 | ``` 20 | 21 | ## Pass 22 | 23 | ```js 24 | const X = { 25 | foo: false, 26 | bar() {} 27 | }; 28 | ``` 29 | 30 | ```js 31 | class X { 32 | static foo = false; 33 | static bar() {}; 34 | 35 | constructor() {} 36 | } 37 | ``` 38 | 39 | ```js 40 | class X { 41 | static foo = false; 42 | static bar() {}; 43 | 44 | unicorn() {} 45 | } 46 | ``` 47 | 48 | ```js 49 | class X { 50 | static #foo = false; 51 | static bar() {} 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/rules/no-this-assignment.md: -------------------------------------------------------------------------------- 1 | # Disallow assigning `this` to a variable 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | `this` should be used directly. If you want a reference to `this` from a higher scope, consider using [arrow function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) or [`Function#bind()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind). 9 | 10 | ## Fail 11 | 12 | ```js 13 | const foo = this; 14 | 15 | setTimeout(function () { 16 | foo.bar(); 17 | }, 1000); 18 | ``` 19 | 20 | ```js 21 | const foo = this; 22 | 23 | class Bar { 24 | method() { 25 | foo.baz(); 26 | } 27 | } 28 | 29 | new Bar().method(); 30 | ``` 31 | 32 | ## Pass 33 | 34 | ```js 35 | setTimeout(() => { 36 | this.bar(); 37 | }, 1000); 38 | ``` 39 | 40 | ```js 41 | setTimeout(function () { 42 | this.bar(); 43 | }.bind(this), 1000); 44 | ``` 45 | 46 | ```js 47 | class Bar { 48 | constructor(fooInstance) { 49 | this.fooInstance = fooInstance; 50 | } 51 | method() { 52 | this.fooInstance.baz(); 53 | } 54 | } 55 | 56 | new Bar(this).method(); 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/rules/no-unnecessary-array-flat-depth.md: -------------------------------------------------------------------------------- 1 | # Disallow using `1` as the `depth` argument of `Array#flat()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | Passing `1` as the `depth` argument to [`Array#flat(depth)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) is unnecessary. 11 | 12 | ## Examples 13 | 14 | ```js 15 | // ❌ 16 | foo.flat(1); 17 | 18 | // ✅ 19 | foo.flat(); 20 | ``` 21 | 22 | ```js 23 | // ❌ 24 | foo?.flat(1); 25 | 26 | // ✅ 27 | foo?.flat(); 28 | ``` 29 | -------------------------------------------------------------------------------- /docs/rules/no-unnecessary-await.md: -------------------------------------------------------------------------------- 1 | # Disallow awaiting non-promise values 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | The [`await` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) should only be used on [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) values. 11 | 12 | ## Fail 13 | 14 | ```js 15 | await await promise; 16 | ``` 17 | 18 | ```js 19 | await [promise1, promise2]; 20 | ``` 21 | 22 | ## Pass 23 | 24 | ```js 25 | await promise; 26 | ``` 27 | 28 | ```js 29 | await Promise.allSettled([promise1, promise2]); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/rules/no-unnecessary-slice-end.md: -------------------------------------------------------------------------------- 1 | # Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | When calling `{String,Array,TypedArray}#slice(start, end)`, omitting the `end` argument defaults it to the object's `.length`. Passing it explicitly or using `Infinity` is unnecessary. 11 | 12 | ## Examples 13 | 14 | ```js 15 | // ❌ 16 | const foo = string.slice(1, string.length); 17 | 18 | // ✅ 19 | const foo = string.slice(1); 20 | ``` 21 | 22 | ```js 23 | // ❌ 24 | const foo = string.slice(1, Infinity); 25 | 26 | // ✅ 27 | const foo = string.slice(1); 28 | ``` 29 | 30 | ```js 31 | // ❌ 32 | const foo = string.slice(1, Number.POSITIVE_INFINITY); 33 | 34 | // ✅ 35 | const foo = string.slice(1); 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/rules/no-unreadable-iife.md: -------------------------------------------------------------------------------- 1 | # Disallow unreadable IIFEs 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | [IIFE](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression) with parenthesized arrow function body is considered unreadable. 9 | 10 | ## Fail 11 | 12 | ```js 13 | const foo = (bar => (bar ? bar.baz : baz))(getBar()); 14 | ``` 15 | 16 | ```js 17 | const foo = ((bar, baz) => ({bar, baz}))(bar, baz); 18 | ``` 19 | 20 | ## Pass 21 | 22 | ```js 23 | const bar = getBar(); 24 | const foo = bar ? bar.baz : baz; 25 | ``` 26 | 27 | ```js 28 | const getBaz = bar => (bar ? bar.baz : baz); 29 | const foo = getBaz(getBar()); 30 | ``` 31 | 32 | ```js 33 | const foo = (bar => { 34 | return bar ? bar.baz : baz; 35 | })(getBar()); 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/rules/no-useless-fallback-in-spread.md: -------------------------------------------------------------------------------- 1 | # Disallow useless fallback when spreading in object literals 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | Spreading [falsy values](https://developer.mozilla.org/en-US/docs/Glossary/Falsy) in object literals won't add any unexpected properties, so it's unnecessary to add an empty object as fallback. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const object = {...(foo || {})}; 16 | ``` 17 | 18 | ```js 19 | const object = {...(foo ?? {})}; 20 | ``` 21 | 22 | ## Pass 23 | 24 | ```js 25 | const object = {...foo}; 26 | ``` 27 | 28 | ```js 29 | const object = {...(foo && {})}; 30 | ``` 31 | 32 | ```js 33 | const array = [...(foo || [])]; 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/rules/no-useless-switch-case.md: -------------------------------------------------------------------------------- 1 | # Disallow useless case in switch statements 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | An empty case before the last default case is useless. 11 | 12 | ## Fail 13 | 14 | ```js 15 | switch (foo) { 16 | case 1: 17 | default: 18 | handleDefaultCase(); 19 | break; 20 | } 21 | ``` 22 | 23 | ## Pass 24 | 25 | ```js 26 | switch (foo) { 27 | case 1: 28 | case 2: 29 | handleCase1And2(); 30 | break; 31 | } 32 | ``` 33 | 34 | ```js 35 | switch (foo) { 36 | case 1: 37 | handleCase1(); 38 | break; 39 | default: 40 | handleDefaultCase(); 41 | break; 42 | } 43 | ``` 44 | 45 | ```js 46 | switch (foo) { 47 | case 1: 48 | handleCase1(); 49 | // Fallthrough 50 | default: 51 | handleDefaultCase(); 52 | break; 53 | } 54 | ``` 55 | 56 | ```js 57 | switch (foo) { 58 | // This is actually useless, but we only check cases where the last case is the `default` case 59 | case 1: 60 | default: 61 | handleDefaultCase(); 62 | break; 63 | case 2: 64 | handleCase2(); 65 | break; 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/rules/no-zero-fractions.md: -------------------------------------------------------------------------------- 1 | # Disallow number literals with zero fractions or dangling dots 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | There is no difference in JavaScript between, for example, `1`, `1.0` and `1.`, so prefer the former for consistency and brevity. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const foo = 1.0; 16 | ``` 17 | 18 | ```js 19 | const foo = -1.0; 20 | ``` 21 | 22 | ```js 23 | const foo = 123_456.000_000; 24 | ``` 25 | 26 | ```js 27 | const foo = 1.; 28 | ``` 29 | 30 | ```js 31 | const foo = 123.111000000; 32 | ``` 33 | 34 | ```js 35 | const foo = 123.00e20; 36 | ``` 37 | 38 | ## Pass 39 | 40 | ```js 41 | const foo = 1; 42 | ``` 43 | 44 | ```js 45 | const foo = -1; 46 | ``` 47 | 48 | ```js 49 | const foo = 123456; 50 | ``` 51 | 52 | ```js 53 | const foo = 1.1; 54 | ``` 55 | 56 | ```js 57 | const foo = -1.1; 58 | ``` 59 | 60 | ```js 61 | const foo = 123.456; 62 | ``` 63 | 64 | ```js 65 | const foo = 1e3; 66 | ``` 67 | -------------------------------------------------------------------------------- /docs/rules/prefer-blob-reading-methods.md: -------------------------------------------------------------------------------- 1 | # Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | `FileReader` predates promises, and the newer [`Blob#arrayBuffer()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer) and [`Blob#text()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/text) methods are much cleaner and easier to use. 9 | 10 | ## Fail 11 | 12 | ```js 13 | const arrayBuffer = await new Promise((resolve, reject) => { 14 | const fileReader = new FileReader(); 15 | fileReader.addEventListener('load', () => { 16 | resolve(fileReader.result); 17 | }); 18 | fileReader.addEventListener('error', () => { 19 | reject(fileReader.error); 20 | }); 21 | fileReader.readAsArrayBuffer(blob); 22 | }); 23 | ``` 24 | 25 | ```js 26 | fileReader.readAsText(blob); 27 | ``` 28 | 29 | ## Pass 30 | 31 | ```js 32 | const arrayBuffer = await blob.arrayBuffer(); 33 | ``` 34 | 35 | ```js 36 | const text = await blob.text(); 37 | ``` 38 | 39 | ```js 40 | fileReader.readAsText(blob, 'ascii'); 41 | ``` 42 | 43 | ```js 44 | fileReader.readAsDataURL(blob); 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/rules/prefer-code-point.md: -------------------------------------------------------------------------------- 1 | # Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | Unicode is better supported in [`String#codePointAt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) and [`String.fromCodePoint()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint). 11 | 12 | - [Difference between `String.fromCodePoint()` and `String.fromCharCode()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint#compared_to_fromcharcode) 13 | 14 | ## Fail 15 | 16 | ```js 17 | const unicorn = '🦄'.charCodeAt(0).toString(16); 18 | ``` 19 | 20 | ```js 21 | const unicorn = String.fromCharCode(0x1f984); 22 | ``` 23 | 24 | ## Pass 25 | 26 | ```js 27 | const unicorn = '🦄'.codePointAt(0).toString(16); 28 | ``` 29 | 30 | ```js 31 | const unicorn = String.fromCodePoint(0x1f984); 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/rules/prefer-date-now.md: -------------------------------------------------------------------------------- 1 | # Prefer `Date.now()` to get the number of milliseconds since the Unix Epoch 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | [`Date.now()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now) is shorter and nicer than [`new Date().getTime()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime), and avoids unnecessary instantiation of `Date` objects. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const foo = new Date().getTime(); 16 | ``` 17 | 18 | ```js 19 | const foo = new Date().valueOf(); 20 | ``` 21 | 22 | ```js 23 | const foo = +new Date; 24 | ``` 25 | 26 | ```js 27 | const foo = Number(new Date()); 28 | ``` 29 | 30 | ```js 31 | const foo = new Date() * 2; 32 | ``` 33 | 34 | ## Pass 35 | 36 | ```js 37 | const foo = Date.now(); 38 | ``` 39 | 40 | ```js 41 | const foo = Date.now() * 2; 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/rules/prefer-dom-node-append.md: -------------------------------------------------------------------------------- 1 | # Prefer `Node#append()` over `Node#appendChild()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | Enforces the use of, for example, `document.body.append(div);` over `document.body.appendChild(div);` for DOM nodes. There are [some advantages of using `Node#append()`](https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append), like the ability to append multiple nodes and to append both [`DOMString`](https://developer.mozilla.org/en-US/docs/Web/API/DOMString) and DOM node objects. 11 | 12 | ## Fail 13 | 14 | ```js 15 | foo.appendChild(bar); 16 | ``` 17 | 18 | ## Pass 19 | 20 | ```js 21 | foo.append(bar); 22 | foo.append('bar'); 23 | foo.append(bar, 'baz'); 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/rules/prefer-dom-node-remove.md: -------------------------------------------------------------------------------- 1 | # Prefer `childNode.remove()` over `parentNode.removeChild(childNode)` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧💡 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/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | Enforces the use of, for example, `child.remove();` over `child.parentNode.removeChild(child);`. The DOM function [`Node#remove()`](https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove) is preferred over the indirect removal of an object with [`Node#removeChild()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild). 11 | 12 | ## Fail 13 | 14 | ```js 15 | parentNode.removeChild(foo); 16 | parentNode.removeChild(this); 17 | ``` 18 | 19 | ## Pass 20 | 21 | ```js 22 | foo.remove(); 23 | this.remove(); 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/rules/prefer-dom-node-text-content.md: -------------------------------------------------------------------------------- 1 | # Prefer `.textContent` over `.innerText` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | Enforces the use of `.textContent` over `.innerText` for DOM nodes. 11 | 12 | There are [some advantages of using `.textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent), like performance and more predictable behavior when updating it. 13 | 14 | Note that there are [differences](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext) between them. 15 | 16 | ## Fail 17 | 18 | ```js 19 | const text = foo.innerText; 20 | ``` 21 | 22 | ```js 23 | const {innerText} = foo; 24 | ``` 25 | 26 | ```js 27 | foo.innerText = '🦄'; 28 | ``` 29 | 30 | ## Pass 31 | 32 | ```js 33 | const text = foo.textContent; 34 | ``` 35 | 36 | ```js 37 | const {textContent} = foo; 38 | ``` 39 | 40 | ```js 41 | foo.textContent = '🦄'; 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/rules/prefer-event-target.md: -------------------------------------------------------------------------------- 1 | # Prefer `EventTarget` over `EventEmitter` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 6 | 7 | 8 | While [`EventEmitter`](https://nodejs.org/api/events.html#class-eventemitter) is only available in Node.js, [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) is also available in _Deno_ and browsers. 9 | 10 | This rule reduces the bundle size and makes your code more cross-platform friendly. 11 | 12 | See the [differences](https://nodejs.org/api/events.html#eventtarget-and-event-api) between `EventEmitter` and `EventTarget`. 13 | 14 | ## Fail 15 | 16 | ```js 17 | import {EventEmitter} from 'node:event'; 18 | 19 | class Foo extends EventEmitter {} 20 | ``` 21 | 22 | ```js 23 | const emitter = new EventEmitter(); 24 | ``` 25 | 26 | ## Pass 27 | 28 | ```js 29 | class Foo extends EventTarget {} 30 | ``` 31 | 32 | ```js 33 | const target = new EventTarget(); 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/rules/prefer-node-protocol.md: -------------------------------------------------------------------------------- 1 | # Prefer using the `node:` protocol when importing Node.js builtin modules 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | When getting builtin modules, it's better to use the [`node:` protocol](https://nodejs.org/api/esm.html#node-imports) as it makes it perfectly clear that the package is a Node.js builtin module. 11 | 12 | ## Examples 13 | 14 | ```js 15 | // ❌ 16 | import dgram from 'dgram'; 17 | 18 | // ✅ 19 | import dgram from 'node:dgram'; 20 | ``` 21 | 22 | ```js 23 | // ❌ 24 | export {strict as default} from 'assert'; 25 | 26 | // ✅ 27 | export {strict as default} from 'node:assert'; 28 | ``` 29 | 30 | ```js 31 | // ❌ 32 | import fs from 'fs/promises'; 33 | 34 | // ✅ 35 | import fs from 'node:fs/promises'; 36 | ``` 37 | 38 | ```js 39 | // ❌ 40 | const fs = require('fs/promises'); 41 | 42 | // ✅ 43 | const fs = require('node:fs/promises'); 44 | ``` 45 | 46 | ```js 47 | // ❌ 48 | const fs = process.getBuiltinModule('fs/promises'); 49 | 50 | // ✅ 51 | const fs = process.getBuiltinModule('node:fs/promises'); 52 | ``` 53 | -------------------------------------------------------------------------------- /docs/rules/prefer-optional-catch-binding.md: -------------------------------------------------------------------------------- 1 | # Prefer omitting the `catch` binding parameter 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | If the `catch` binding parameter is not used, it should be omitted. 11 | 12 | ## Fail 13 | 14 | ```js 15 | try {} catch (notUsedError) {} 16 | ``` 17 | 18 | ```js 19 | try {} catch ({message}) {} 20 | ``` 21 | 22 | ## Pass 23 | 24 | ```js 25 | try {} catch {} 26 | ``` 27 | 28 | ```js 29 | try {} catch (error) { 30 | console.error(error); 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/rules/prefer-prototype-methods.md: -------------------------------------------------------------------------------- 1 | # Prefer borrowing methods from the prototype instead of the instance 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | When “borrowing” a method from `Array` or `Object`, it's clearer to get it from the prototype than from an instance. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const array = [].slice.apply(bar); 16 | ``` 17 | 18 | ```js 19 | const type = {}.toString.call(foo); 20 | ``` 21 | 22 | ```js 23 | Reflect.apply([].forEach, arrayLike, [callback]); 24 | ``` 25 | 26 | ```js 27 | const type = globalThis.toString.call(foo); 28 | ``` 29 | 30 | ## Pass 31 | 32 | ```js 33 | const array = Array.prototype.slice.apply(bar); 34 | ``` 35 | 36 | ```js 37 | const type = Object.prototype.toString.call(foo); 38 | ``` 39 | 40 | ```js 41 | Reflect.apply(Array.prototype.forEach, arrayLike, [callback]); 42 | ``` 43 | 44 | ```js 45 | const maxValue = Math.max.apply(Math, numbers); 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/rules/prefer-query-selector.md: -------------------------------------------------------------------------------- 1 | # Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | It's better to use the same method to query DOM elements. This helps keep consistency and it lends itself to future improvements (e.g. more specific selectors). 11 | 12 | ## Fail 13 | 14 | ```js 15 | document.getElementById('foo'); 16 | document.getElementsByClassName('foo bar'); 17 | document.getElementsByTagName('main'); 18 | document.getElementsByClassName(fn()); 19 | ``` 20 | 21 | ## Pass 22 | 23 | ```js 24 | document.querySelector('#foo'); 25 | document.querySelector('.bar'); 26 | document.querySelector('main #foo .bar'); 27 | document.querySelectorAll('.foo .bar'); 28 | document.querySelectorAll('li a'); 29 | document.querySelector('li').querySelectorAll('a'); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/rules/prefer-reflect-apply.md: -------------------------------------------------------------------------------- 1 | # Prefer `Reflect.apply()` over `Function#apply()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | [`Reflect.apply()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/apply) is arguably less verbose and easier to understand. In addition, when you accept arbitrary methods, it's not safe to assume `.apply()` exists or is not overridden. 11 | 12 | ## Fail 13 | 14 | ```js 15 | function foo() {} 16 | 17 | foo.apply(null, [42]); 18 | Function.prototype.apply.call(foo, null, [42]); 19 | foo.apply(this, [42]); 20 | Function.prototype.apply.call(foo, this, [42]); 21 | foo.apply(null, arguments); 22 | Function.prototype.apply.call(foo, null, arguments); 23 | foo.apply(this, arguments); 24 | Function.prototype.apply.call(foo, this, arguments); 25 | ``` 26 | 27 | ## Pass 28 | 29 | ```js 30 | function foo() {} 31 | 32 | Reflect.apply(foo, null, [42]); 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/rules/prefer-set-has.md: -------------------------------------------------------------------------------- 1 | # Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧💡 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/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | [`Set#has()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) is faster than [`Array#includes()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes). 11 | 12 | ## Fail 13 | 14 | ```js 15 | const array = [1, 2, 3]; 16 | const hasValue = value => array.includes(value); 17 | ``` 18 | 19 | ## Pass 20 | 21 | ```js 22 | const set = new Set([1, 2, 3]); 23 | const hasValue = value => set.has(value); 24 | ``` 25 | 26 | ```js 27 | // This array is not only checking existence. 28 | const array = [1, 2]; 29 | const hasValue = value => array.includes(value); 30 | array.push(3); 31 | ``` 32 | 33 | ```js 34 | // This array is only checked once. 35 | const array = [1, 2, 3]; 36 | const hasOne = array.includes(1); 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/rules/prefer-set-size.md: -------------------------------------------------------------------------------- 1 | # Prefer using `Set#size` instead of `Array#length` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | Prefer using `Set#size` directly instead of first converting it to an array and then using its `.length` property. 11 | 12 | ## Fail 13 | 14 | ```js 15 | function isUnique(array) { 16 | return [...new Set(array)].length === array.length; 17 | } 18 | ``` 19 | 20 | ## Pass 21 | 22 | ```js 23 | function isUnique(array) { 24 | return new Set(array).size === array.length; 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/rules/prefer-string-raw.md: -------------------------------------------------------------------------------- 1 | # Prefer using the `String.raw` tag to avoid escaping `\` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | [`String.raw`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw) can be used to avoid escaping `\`. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const file = "C:\\windows\\style\\path\\to\\file.js"; 16 | ``` 17 | 18 | ```js 19 | const regexp = new RegExp('foo\\.bar'); 20 | ``` 21 | 22 | ## Pass 23 | 24 | ```js 25 | const file = String.raw`C:\windows\style\path\to\file.js`; 26 | ``` 27 | 28 | ```js 29 | const regexp = new RegExp(String.raw`foo\.bar`); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/rules/prefer-string-slice.md: -------------------------------------------------------------------------------- 1 | # Prefer `String#slice()` over `String#substr()` and `String#substring()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | [`String#substr()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr) and [`String#substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) are the two lesser known legacy ways to slice a string. It's better to use [`String#slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) as it's a more popular option with clearer behavior that has a consistent [`Array` counterpart](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice). 11 | 12 | ## Fail 13 | 14 | ```js 15 | foo.substr(start, length); 16 | foo.substring(indexStart, indexEnd); 17 | ``` 18 | 19 | ## Pass 20 | 21 | ```js 22 | foo.slice(beginIndex, endIndex); 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/rules/prefer-top-level-await.md: -------------------------------------------------------------------------------- 1 | # Prefer top-level await over top-level promises and async function calls 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | [Top-level await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await) is more readable and can prevent unhandled rejections. 11 | 12 | ## Fail 13 | 14 | ```js 15 | (async () => { 16 | try { 17 | await run(); 18 | } catch (error) { 19 | console.error(error); 20 | process.exit(1); 21 | } 22 | })(); 23 | ``` 24 | 25 | ```js 26 | run().catch(error => { 27 | console.error(error); 28 | process.exit(1); 29 | }); 30 | ``` 31 | 32 | ```js 33 | async function main() { 34 | try { 35 | await run(); 36 | } catch (error) { 37 | console.error(error); 38 | process.exit(1); 39 | } 40 | } 41 | 42 | main(); 43 | ``` 44 | 45 | ## Pass 46 | 47 | ```js 48 | await run(); 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/rules/relative-url-style.md: -------------------------------------------------------------------------------- 1 | # Enforce consistent relative URL style 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧💡 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/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | When using a relative URL in [`new URL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL), the URL should either never or always use the `./` prefix consistently. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const url = new URL('./foo', base); 16 | ``` 17 | 18 | ## Pass 19 | 20 | ```js 21 | const url = new URL('foo', base); 22 | ``` 23 | 24 | ## Options 25 | 26 | Type: `string`\ 27 | Default: `'never'` 28 | 29 | - `'never'` (default) 30 | - Never use a `./` prefix. 31 | - `'always'` 32 | - Always add a `./` prefix to the relative URL when possible. 33 | 34 | ```js 35 | // eslint unicorn/relative-url-style: ["error", "always"] 36 | const url = new URL('foo', base); // Fail 37 | const url = new URL('./foo', base); // Pass 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/rules/require-array-join-separator.md: -------------------------------------------------------------------------------- 1 | # Enforce using the separator argument with `Array#join()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | It's better to make it clear what the separator is when calling [Array#join()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join), instead of relying on the default comma (`','`) separator. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const string = array.join(); 16 | ``` 17 | 18 | ```js 19 | const string = Array.prototype.join.call(arrayLike); 20 | ``` 21 | 22 | ```js 23 | const string = [].join.call(arrayLike); 24 | ``` 25 | 26 | ## Pass 27 | 28 | ```js 29 | const string = array.join(','); 30 | ``` 31 | 32 | ```js 33 | const string = array.join('|'); 34 | ``` 35 | 36 | ```js 37 | const string = Array.prototype.join.call(arrayLike, ''); 38 | ``` 39 | 40 | ```js 41 | const string = [].join.call(arrayLike, '\n'); 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/rules/require-number-to-fixed-digits-argument.md: -------------------------------------------------------------------------------- 1 | # Enforce using the digits argument with `Number#toFixed()` 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | It's better to make it clear what the value of the `digits` argument is when calling [Number#toFixed()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed), instead of relying on the default value of `0`. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const string = number.toFixed(); 16 | ``` 17 | 18 | ## Pass 19 | 20 | ```js 21 | const string = foo.toFixed(0); 22 | ``` 23 | 24 | ```js 25 | const string = foo.toFixed(2); 26 | ``` 27 | 28 | ```js 29 | const integer = Math.floor(foo); 30 | ``` 31 | 32 | ```js 33 | const integer = Math.ceil(foo); 34 | ``` 35 | 36 | ```js 37 | const integer = Math.round(foo); 38 | ``` 39 | 40 | ```js 41 | const integer = Math.trunc(foo); 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/rules/text-encoding-identifier-case.md: -------------------------------------------------------------------------------- 1 | # Enforce consistent case for text encoding identifiers 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧💡 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/latest/use/core-concepts#rule-suggestions). 6 | 7 | 8 | 9 | 10 | - Enforce `'utf8'` for [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoding. 11 | - Enforce `'ascii'` for [ASCII](https://en.wikipedia.org/wiki/ASCII) encoding. 12 | 13 | This rule only auto-fix encoding in `fs.readFile()` and `fs.readFileSync()`. 14 | 15 | ## Fail 16 | 17 | ```js 18 | await fs.readFile(file, 'UTF-8'); 19 | ``` 20 | 21 | ```js 22 | await fs.readFile(file, 'ASCII'); 23 | ``` 24 | 25 | ```js 26 | const string = buffer.toString('utf-8'); 27 | ``` 28 | 29 | ## Pass 30 | 31 | ```js 32 | await fs.readFile(file, 'utf8'); 33 | ``` 34 | 35 | ```js 36 | await fs.readFile(file, 'ascii'); 37 | ``` 38 | 39 | ```js 40 | const string = buffer.toString('utf8'); 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/rules/throw-new-error.md: -------------------------------------------------------------------------------- 1 | # Require `new` when creating an error 2 | 3 | 💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config). 4 | 5 | 🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). 6 | 7 | 8 | 9 | 10 | While it's possible to create a new error without using the `new` keyword, it's better to be explicit. 11 | 12 | ## Fail 13 | 14 | ```js 15 | const error = Error('unicorn'); 16 | ``` 17 | 18 | ```js 19 | throw TypeError('unicorn'); 20 | ``` 21 | 22 | ```js 23 | throw lib.TypeError('unicorn'); 24 | ``` 25 | 26 | ## Pass 27 | 28 | ```js 29 | const error = new Error('unicorn'); 30 | ``` 31 | 32 | ```js 33 | throw new TypeError('unicorn'); 34 | ``` 35 | 36 | ```js 37 | throw new lib.TypeError('unicorn'); 38 | ``` 39 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import type {ESLint, Linter} from 'eslint'; 2 | 3 | declare const eslintPluginUnicorn: ESLint.Plugin & { 4 | configs: { 5 | recommended: Linter.FlatConfig; 6 | all: Linter.FlatConfig; 7 | 8 | /** @deprecated Use `all` instead. The `flat/` prefix is no longer needed. */ 9 | 'flat/all': Linter.FlatConfig; 10 | 11 | /** @deprecated Use `recommended` instead. The `flat/` prefix is no longer needed. */ 12 | 'flat/recommended': Linter.FlatConfig; 13 | }; 14 | }; 15 | 16 | export default eslintPluginUnicorn; 17 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /rules/ast/function-types.js: -------------------------------------------------------------------------------- 1 | const functionTypes = [ 2 | 'FunctionDeclaration', 3 | 'FunctionExpression', 4 | 'ArrowFunctionExpression', 5 | ]; 6 | 7 | export default functionTypes; 8 | -------------------------------------------------------------------------------- /rules/ast/index.js: -------------------------------------------------------------------------------- 1 | export { 2 | isLiteral, 3 | isStringLiteral, 4 | isNumberLiteral, 5 | isBigIntLiteral, 6 | isNullLiteral, 7 | isRegexLiteral, 8 | } from './literal.js'; 9 | 10 | export { 11 | isNewExpression, 12 | isCallExpression, 13 | isCallOrNewExpression, 14 | } from './call-or-new-expression.js'; 15 | 16 | export {default as isArrowFunctionBody} from './is-arrow-function-body.js'; 17 | export {default as isDirective} from './is-directive.js'; 18 | export {default as isEmptyNode} from './is-empty-node.js'; 19 | export {default as isExpressionStatement} from './is-expression-statement.js'; 20 | export {default as isFunction} from './is-function.js'; 21 | export {default as isMemberExpression} from './is-member-expression.js'; 22 | export {default as isMethodCall} from './is-method-call.js'; 23 | export {default as isNegativeOne} from './is-negative-one.js'; 24 | export {default as isReferenceIdentifier} from './is-reference-identifier.js'; 25 | export {default as isStaticRequire} from './is-static-require.js'; 26 | export {default as isTaggedTemplateLiteral} from './is-tagged-template-literal.js'; 27 | export {default as isUndefined} from './is-undefined.js'; 28 | export {default as functionTypes} from './function-types.js'; 29 | -------------------------------------------------------------------------------- /rules/ast/is-arrow-function-body.js: -------------------------------------------------------------------------------- 1 | export default function isArrowFunctionBody(node) { 2 | return node.parent.type === 'ArrowFunctionExpression' && node.parent.body === node; 3 | } 4 | -------------------------------------------------------------------------------- /rules/ast/is-directive.js: -------------------------------------------------------------------------------- 1 | const isDirective = node => node.type === 'ExpressionStatement' 2 | && typeof node.directive === 'string'; 3 | 4 | export default isDirective; 5 | -------------------------------------------------------------------------------- /rules/ast/is-empty-node.js: -------------------------------------------------------------------------------- 1 | export default function isEmptyNode(node, additionalEmpty) { 2 | const {type} = node; 3 | 4 | if (type === 'BlockStatement') { 5 | return node.body.every(currentNode => isEmptyNode(currentNode, additionalEmpty)); 6 | } 7 | 8 | if (type === 'EmptyStatement') { 9 | return true; 10 | } 11 | 12 | if (additionalEmpty?.(node)) { 13 | return true; 14 | } 15 | 16 | return false; 17 | } 18 | -------------------------------------------------------------------------------- /rules/ast/is-expression-statement.js: -------------------------------------------------------------------------------- 1 | export default function isExpressionStatement(node) { 2 | return node.type === 'ExpressionStatement' 3 | || ( 4 | node.type === 'ChainExpression' 5 | && node.parent.type === 'ExpressionStatement' 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /rules/ast/is-function.js: -------------------------------------------------------------------------------- 1 | import functionTypes from './function-types.js'; 2 | 3 | export default function isFunction(node) { 4 | return functionTypes.includes(node.type); 5 | } 6 | -------------------------------------------------------------------------------- /rules/ast/is-negative-one.js: -------------------------------------------------------------------------------- 1 | import {isNumberLiteral} from './literal.js'; 2 | 3 | export default function isNegativeOne(node) { 4 | return node?.type === 'UnaryExpression' 5 | && node.operator === '-' 6 | && isNumberLiteral(node.argument) 7 | && node.argument.value === 1; 8 | } 9 | -------------------------------------------------------------------------------- /rules/ast/is-static-require.js: -------------------------------------------------------------------------------- 1 | import {isStringLiteral} from './literal.js'; 2 | import {isCallExpression} from './call-or-new-expression.js'; 3 | 4 | const isStaticRequire = node => isCallExpression(node, { 5 | name: 'require', 6 | argumentsLength: 1, 7 | optional: false, 8 | }) && isStringLiteral(node.arguments[0]); 9 | 10 | export default isStaticRequire; 11 | -------------------------------------------------------------------------------- /rules/ast/is-tagged-template-literal.js: -------------------------------------------------------------------------------- 1 | import {isNodeMatches} from '../utils/is-node-matches.js'; 2 | 3 | /** 4 | Check if the given node is a tagged template literal. 5 | 6 | @param {Node} node - The AST node to check. 7 | @param {string[]} tags - The object name or key paths. 8 | @returns {boolean} 9 | */ 10 | export default function isTaggedTemplateLiteral(node, tags) { 11 | if ( 12 | node.type !== 'TemplateLiteral' 13 | || node.parent.type !== 'TaggedTemplateExpression' 14 | || node.parent.quasi !== node 15 | ) { 16 | return false; 17 | } 18 | 19 | if (tags) { 20 | return isNodeMatches(node.parent.tag, tags); 21 | } 22 | 23 | return true; 24 | } 25 | -------------------------------------------------------------------------------- /rules/ast/is-undefined.js: -------------------------------------------------------------------------------- 1 | export default function isUndefined(node) { 2 | return node.type === 'Identifier' && node.name === 'undefined'; 3 | } 4 | -------------------------------------------------------------------------------- /rules/ast/literal.js: -------------------------------------------------------------------------------- 1 | export function isLiteral(node, value) { 2 | if (node?.type !== 'Literal') { 3 | return false; 4 | } 5 | 6 | if (value === null) { 7 | return node.raw === 'null'; 8 | } 9 | 10 | return node.value === value; 11 | } 12 | 13 | export const isStringLiteral = node => node?.type === 'Literal' && typeof node.value === 'string'; 14 | 15 | export const isNumberLiteral = node => node.type === 'Literal' && typeof node.value === 'number'; 16 | 17 | export const isRegexLiteral = node => node.type === 'Literal' && Boolean(node.regex); 18 | 19 | // eslint-disable-next-line unicorn/no-null 20 | export const isNullLiteral = node => isLiteral(node, null); 21 | 22 | export const isBigIntLiteral = node => node.type === 'Literal' && Boolean(node.bigint); 23 | 24 | -------------------------------------------------------------------------------- /rules/fix/add-parenthesizes-to-return-or-throw-expression.js: -------------------------------------------------------------------------------- 1 | import {isSemicolonToken} from '@eslint-community/eslint-utils'; 2 | 3 | export default function * addParenthesizesToReturnOrThrowExpression(fixer, node, sourceCode) { 4 | if (node.type !== 'ReturnStatement' && node.type !== 'ThrowStatement') { 5 | return; 6 | } 7 | 8 | const returnOrThrowToken = sourceCode.getFirstToken(node); 9 | yield fixer.insertTextAfter(returnOrThrowToken, ' ('); 10 | const lastToken = sourceCode.getLastToken(node); 11 | if (!isSemicolonToken(lastToken)) { 12 | yield fixer.insertTextAfter(node, ')'); 13 | return; 14 | } 15 | 16 | yield fixer.insertTextBefore(lastToken, ')'); 17 | } 18 | -------------------------------------------------------------------------------- /rules/fix/append-argument.js: -------------------------------------------------------------------------------- 1 | import {isCommaToken} from '@eslint-community/eslint-utils'; 2 | 3 | export default function appendArgument(fixer, node, text, sourceCode) { 4 | // This function should also work for `NewExpression` 5 | // But parentheses of `NewExpression` could be omitted, add this check to prevent accident use on it 6 | /* c8 ignore next 3 */ 7 | if (node.type !== 'CallExpression') { 8 | throw new Error(`Unexpected node "${node.type}".`); 9 | } 10 | 11 | const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2); 12 | if (node.arguments.length > 0) { 13 | text = isCommaToken(penultimateToken) ? ` ${text},` : `, ${text}`; 14 | } 15 | 16 | return fixer.insertTextBefore(lastToken, text); 17 | } 18 | -------------------------------------------------------------------------------- /rules/fix/extend-fix-range.js: -------------------------------------------------------------------------------- 1 | /** 2 | Extend fix range to prevent changes from other rules. 3 | https://github.com/eslint/eslint/pull/13748/files#diff-c692f3fde09eda7c89f1802c908511a3fb59f5d207fe95eb009cb52e46a99e84R348 4 | 5 | @param {ruleFixer} fixer - The fixer to fix. 6 | @param {int[]} range - The extended range node. 7 | */ 8 | export default function * extendFixRange(fixer, range) { 9 | yield fixer.insertTextBeforeRange(range, ''); 10 | yield fixer.insertTextAfterRange(range, ''); 11 | } 12 | -------------------------------------------------------------------------------- /rules/fix/fix-space-around-keywords.js: -------------------------------------------------------------------------------- 1 | import {getParenthesizedRange} from '../utils/parentheses.js'; 2 | 3 | const isProblematicToken = ({type, value}) => ( 4 | (type === 'Keyword' && /^[a-z]*$/.test(value)) 5 | // ForOfStatement 6 | || (type === 'Identifier' && value === 'of') 7 | // AwaitExpression 8 | || (type === 'Identifier' && value === 'await') 9 | ); 10 | 11 | export default function * fixSpaceAroundKeyword(fixer, node, sourceCode) { 12 | const range = getParenthesizedRange(node, sourceCode); 13 | const tokenBefore = sourceCode.getTokenBefore({range}, {includeComments: true}); 14 | 15 | if ( 16 | tokenBefore 17 | && range[0] === sourceCode.getRange(tokenBefore)[1] 18 | && isProblematicToken(tokenBefore) 19 | ) { 20 | yield fixer.insertTextAfter(tokenBefore, ' '); 21 | } 22 | 23 | const tokenAfter = sourceCode.getTokenAfter({range}, {includeComments: true}); 24 | 25 | if ( 26 | tokenAfter 27 | && range[1] === sourceCode.getRange(tokenAfter)[0] 28 | && isProblematicToken(tokenAfter) 29 | ) { 30 | yield fixer.insertTextBefore(tokenAfter, ' '); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rules/fix/remove-argument.js: -------------------------------------------------------------------------------- 1 | import {isCommaToken} from '@eslint-community/eslint-utils'; 2 | import {getParentheses} from '../utils/parentheses.js'; 3 | 4 | export default function removeArgument(fixer, node, sourceCode) { 5 | const callExpression = node.parent; 6 | const index = callExpression.arguments.indexOf(node); 7 | const parentheses = getParentheses(node, sourceCode); 8 | const firstToken = parentheses[0] || node; 9 | const lastToken = parentheses.at(-1) || node; 10 | 11 | let [start] = sourceCode.getRange(firstToken); 12 | let [, end] = sourceCode.getRange(lastToken); 13 | 14 | if (index !== 0) { 15 | const commaToken = sourceCode.getTokenBefore(firstToken); 16 | [start] = sourceCode.getRange(commaToken); 17 | } 18 | 19 | // If the removed argument is the only argument, the trailing comma must be removed too 20 | /* c8 ignore start */ 21 | if (callExpression.arguments.length === 1) { 22 | const tokenAfter = sourceCode.getTokenBefore(lastToken); 23 | if (isCommaToken(tokenAfter)) { 24 | [, end] = sourceCode.getRange(tokenAfter); 25 | } 26 | } 27 | /* c8 ignore end */ 28 | 29 | return fixer.removeRange([start, end]); 30 | } 31 | -------------------------------------------------------------------------------- /rules/fix/remove-member-expression-property.js: -------------------------------------------------------------------------------- 1 | import {getParenthesizedRange} from '../utils/parentheses.js'; 2 | 3 | export default function removeMemberExpressionProperty(fixer, memberExpression, sourceCode) { 4 | const [, start] = getParenthesizedRange(memberExpression.object, sourceCode); 5 | const [, end] = sourceCode.getRange(memberExpression); 6 | return fixer.removeRange([start, end]); 7 | } 8 | -------------------------------------------------------------------------------- /rules/fix/remove-method-call.js: -------------------------------------------------------------------------------- 1 | import {getParenthesizedRange} from '../utils/parentheses.js'; 2 | import removeMemberExpressionProperty from './remove-member-expression-property.js'; 3 | 4 | export default function * removeMethodCall(fixer, callExpression, sourceCode) { 5 | const memberExpression = callExpression.callee; 6 | 7 | // `(( (( foo )).bar ))()` 8 | // ^^^^ 9 | yield removeMemberExpressionProperty(fixer, memberExpression, sourceCode); 10 | 11 | // `(( (( foo )).bar ))()` 12 | // ^^ 13 | const [, start] = getParenthesizedRange(memberExpression, sourceCode); 14 | const [, end] = sourceCode.getRange(callExpression); 15 | 16 | yield fixer.removeRange([start, end]); 17 | } 18 | -------------------------------------------------------------------------------- /rules/fix/remove-parentheses.js: -------------------------------------------------------------------------------- 1 | import {getParentheses} from '../utils/parentheses.js'; 2 | 3 | export default function * removeParentheses(node, fixer, sourceCode) { 4 | const parentheses = getParentheses(node, sourceCode); 5 | for (const token of parentheses) { 6 | yield fixer.remove(token); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /rules/fix/remove-spaces-after.js: -------------------------------------------------------------------------------- 1 | export default function removeSpacesAfter(indexOrNodeOrToken, sourceCode, fixer) { 2 | let index = indexOrNodeOrToken; 3 | if (typeof indexOrNodeOrToken === 'object') { 4 | index = sourceCode.getRange(indexOrNodeOrToken)[1]; 5 | } 6 | 7 | const textAfter = sourceCode.text.slice(index); 8 | const [leadingSpaces] = textAfter.match(/^\s*/); 9 | return fixer.removeRange([index, index + leadingSpaces.length]); 10 | } 11 | -------------------------------------------------------------------------------- /rules/fix/rename-variable.js: -------------------------------------------------------------------------------- 1 | import getVariableIdentifiers from '../utils/get-variable-identifiers.js'; 2 | import replaceReferenceIdentifier from './replace-reference-identifier.js'; 3 | 4 | const renameVariable = (variable, name, fixer) => getVariableIdentifiers(variable) 5 | .map(identifier => replaceReferenceIdentifier(identifier, name, fixer)); 6 | 7 | export default renameVariable; 8 | -------------------------------------------------------------------------------- /rules/fix/replace-argument.js: -------------------------------------------------------------------------------- 1 | import {getParenthesizedRange} from '../utils/parentheses.js'; 2 | 3 | export default function replaceArgument(fixer, node, text, sourceCode) { 4 | return fixer.replaceTextRange(getParenthesizedRange(node, sourceCode), text); 5 | } 6 | -------------------------------------------------------------------------------- /rules/fix/replace-node-or-token-and-spaces-before.js: -------------------------------------------------------------------------------- 1 | import {getParentheses} from '../utils/parentheses.js'; 2 | 3 | // eslint-disable-next-line max-params 4 | export default function * replaceNodeOrTokenAndSpacesBefore(nodeOrToken, replacement, fixer, sourceCode, tokenStore = sourceCode) { 5 | const tokens = getParentheses(nodeOrToken, tokenStore); 6 | 7 | for (const token of tokens) { 8 | yield * replaceNodeOrTokenAndSpacesBefore(token, '', fixer, sourceCode, tokenStore); 9 | } 10 | 11 | let [start, end] = sourceCode.getRange(nodeOrToken); 12 | 13 | const textBefore = sourceCode.text.slice(0, start); 14 | const [trailingSpaces] = textBefore.match(/\s*$/); 15 | const [lineBreak] = trailingSpaces.match(/(?:\r?\n|\r){0,1}/); 16 | start -= trailingSpaces.length; 17 | 18 | yield fixer.replaceTextRange([start, end], `${lineBreak}${replacement}`); 19 | } 20 | -------------------------------------------------------------------------------- /rules/fix/replace-reference-identifier.js: -------------------------------------------------------------------------------- 1 | import isShorthandPropertyValue from '../utils/is-shorthand-property-value.js'; 2 | import isShorthandPropertyAssignmentPatternLeft from '../utils/is-shorthand-property-assignment-pattern-left.js'; 3 | import isShorthandImportLocal from '../utils/is-shorthand-import-local.js'; 4 | import isShorthandExportLocal from '../utils/is-shorthand-export-local.js'; 5 | 6 | export default function replaceReferenceIdentifier(identifier, replacement, fixer) { 7 | if ( 8 | isShorthandPropertyValue(identifier) 9 | || isShorthandPropertyAssignmentPatternLeft(identifier) 10 | ) { 11 | return fixer.replaceText(identifier, `${identifier.name}: ${replacement}`); 12 | } 13 | 14 | if (isShorthandImportLocal(identifier)) { 15 | return fixer.replaceText(identifier, `${identifier.name} as ${replacement}`); 16 | } 17 | 18 | if (isShorthandExportLocal(identifier)) { 19 | return fixer.replaceText(identifier, `${replacement} as ${identifier.name}`); 20 | } 21 | 22 | // `typeAnnotation` 23 | if (identifier.typeAnnotation) { 24 | return fixer.replaceTextRange( 25 | // eslint-disable-next-line internal/no-restricted-property-access 26 | [identifier.range[0], identifier.typeAnnotation.range[0]], 27 | `${replacement}${identifier.optional ? '?' : ''}`, 28 | ); 29 | } 30 | 31 | return fixer.replaceText(identifier, replacement); 32 | } 33 | -------------------------------------------------------------------------------- /rules/fix/replace-string-raw.js: -------------------------------------------------------------------------------- 1 | // Replace `StringLiteral` or `TemplateLiteral` node with raw text 2 | const replaceStringRaw = (fixer, node, raw) => 3 | fixer.replaceTextRange( 4 | // Ignore quotes and backticks 5 | [ 6 | // eslint-disable-next-line internal/no-restricted-property-access 7 | node.range[0] + 1, 8 | // eslint-disable-next-line internal/no-restricted-property-access 9 | node.range[1] - 1, 10 | ], 11 | raw, 12 | ); 13 | 14 | export default replaceStringRaw; 15 | -------------------------------------------------------------------------------- /rules/fix/replace-template-element.js: -------------------------------------------------------------------------------- 1 | const replaceTemplateElement = (fixer, node, replacement) => { 2 | // eslint-disable-next-line internal/no-restricted-property-access 3 | const {range: [start, end], tail} = node; 4 | return fixer.replaceTextRange( 5 | [start + 1, end - (tail ? 1 : 2)], 6 | replacement, 7 | ); 8 | }; 9 | 10 | export default replaceTemplateElement; 11 | -------------------------------------------------------------------------------- /rules/fix/switch-call-expression-to-new-expression.js: -------------------------------------------------------------------------------- 1 | import {isParenthesized} from '../utils/parentheses.js'; 2 | import shouldAddParenthesesToNewExpressionCallee from '../utils/should-add-parentheses-to-new-expression-callee.js'; 3 | import fixSpaceAroundKeyword from './fix-space-around-keywords.js'; 4 | 5 | export default function * switchCallExpressionToNewExpression(node, sourceCode, fixer) { 6 | yield * fixSpaceAroundKeyword(fixer, node, sourceCode); 7 | yield fixer.insertTextBefore(node, 'new '); 8 | 9 | const {callee} = node; 10 | if ( 11 | !isParenthesized(callee, sourceCode) 12 | && shouldAddParenthesesToNewExpressionCallee(callee) 13 | ) { 14 | yield fixer.insertTextBefore(callee, '('); 15 | yield fixer.insertTextAfter(callee, ')'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rules/no-document-cookie.js: -------------------------------------------------------------------------------- 1 | import {GlobalReferenceTracker} from './utils/global-reference-tracker.js'; 2 | 3 | const MESSAGE_ID = 'no-document-cookie'; 4 | const messages = { 5 | [MESSAGE_ID]: 'Do not use `document.cookie` directly.', 6 | }; 7 | 8 | const tracker = new GlobalReferenceTracker({ 9 | object: 'document.cookie', 10 | filter: ({node}) => node.parent.type === 'AssignmentExpression' && node.parent.left === node, 11 | handle: ({node}) => ({node, messageId: MESSAGE_ID}), 12 | }); 13 | 14 | /** @type {import('eslint').Rule.RuleModule} */ 15 | const config = { 16 | create: context => tracker.createListeners(context), 17 | meta: { 18 | type: 'problem', 19 | docs: { 20 | description: 'Do not use `document.cookie` directly.', 21 | recommended: true, 22 | }, 23 | messages, 24 | }, 25 | }; 26 | 27 | export default config; 28 | -------------------------------------------------------------------------------- /rules/no-empty-file.js: -------------------------------------------------------------------------------- 1 | import {isEmptyNode, isDirective} from './ast/index.js'; 2 | 3 | const MESSAGE_ID = 'no-empty-file'; 4 | const messages = { 5 | [MESSAGE_ID]: 'Empty files are not allowed.', 6 | }; 7 | 8 | const isEmpty = node => isEmptyNode(node, isDirective); 9 | 10 | const isTripleSlashDirective = node => 11 | node.type === 'Line' && node.value.startsWith('/'); 12 | 13 | const hasTripeSlashDirectives = comments => 14 | comments.some(currentNode => isTripleSlashDirective(currentNode)); 15 | 16 | /** @param {import('eslint').Rule.RuleContext} context */ 17 | const create = context => { 18 | const filename = context.physicalFilename; 19 | 20 | if (!/\.(?:js|mjs|cjs|jsx|ts|mts|cts|tsx)$/i.test(filename)) { 21 | return; 22 | } 23 | 24 | return { 25 | Program(node) { 26 | if (node.body.some(node => !isEmpty(node))) { 27 | return; 28 | } 29 | 30 | const {sourceCode} = context; 31 | const comments = sourceCode.getAllComments(); 32 | 33 | if (hasTripeSlashDirectives(comments)) { 34 | return; 35 | } 36 | 37 | return { 38 | node, 39 | messageId: MESSAGE_ID, 40 | }; 41 | }, 42 | }; 43 | }; 44 | 45 | /** @type {import('eslint').Rule.RuleModule} */ 46 | const config = { 47 | create, 48 | meta: { 49 | type: 'suggestion', 50 | docs: { 51 | description: 'Disallow empty files.', 52 | recommended: true, 53 | }, 54 | messages, 55 | }, 56 | }; 57 | 58 | export default config; 59 | -------------------------------------------------------------------------------- /rules/no-object-as-default-parameter.js: -------------------------------------------------------------------------------- 1 | import {isFunction} from './ast/index.js'; 2 | 3 | const MESSAGE_ID_IDENTIFIER = 'identifier'; 4 | const MESSAGE_ID_NON_IDENTIFIER = 'non-identifier'; 5 | const messages = { 6 | [MESSAGE_ID_IDENTIFIER]: 'Do not use an object literal as default for parameter `{{parameter}}`.', 7 | [MESSAGE_ID_NON_IDENTIFIER]: 'Do not use an object literal as default.', 8 | }; 9 | 10 | /** @param {import('eslint').Rule.RuleContext} context */ 11 | const create = () => ({ 12 | AssignmentPattern(node) { 13 | if (!( 14 | node.right.type === 'ObjectExpression' 15 | && node.right.properties.length > 0 16 | && isFunction(node.parent) 17 | && node.parent.params.includes(node) 18 | )) { 19 | return; 20 | } 21 | 22 | const {left, right} = node; 23 | 24 | if (left.type === 'Identifier') { 25 | return { 26 | node: left, 27 | messageId: MESSAGE_ID_IDENTIFIER, 28 | data: {parameter: left.name}, 29 | }; 30 | } 31 | 32 | return { 33 | node: right, 34 | messageId: MESSAGE_ID_NON_IDENTIFIER, 35 | }; 36 | }, 37 | }); 38 | 39 | /** @type {import('eslint').Rule.RuleModule} */ 40 | const config = { 41 | create, 42 | meta: { 43 | type: 'problem', 44 | docs: { 45 | description: 'Disallow the use of objects as default parameters.', 46 | recommended: true, 47 | }, 48 | messages, 49 | }, 50 | }; 51 | 52 | export default config; 53 | -------------------------------------------------------------------------------- /rules/no-this-assignment.js: -------------------------------------------------------------------------------- 1 | const MESSAGE_ID = 'no-this-assignment'; 2 | const messages = { 3 | [MESSAGE_ID]: 'Do not assign `this` to `{{name}}`.', 4 | }; 5 | 6 | function getProblem(variableNode, valueNode) { 7 | if ( 8 | variableNode.type !== 'Identifier' 9 | || valueNode?.type !== 'ThisExpression' 10 | ) { 11 | return; 12 | } 13 | 14 | return { 15 | node: valueNode.parent, 16 | data: {name: variableNode.name}, 17 | messageId: MESSAGE_ID, 18 | }; 19 | } 20 | 21 | /** @param {import('eslint').Rule.RuleContext} context */ 22 | const create = context => { 23 | context.on('VariableDeclarator', node => getProblem(node.id, node.init)); 24 | context.on('AssignmentExpression', node => getProblem(node.left, node.right)); 25 | }; 26 | 27 | /** @type {import('eslint').Rule.RuleModule} */ 28 | const config = { 29 | create, 30 | meta: { 31 | type: 'suggestion', 32 | docs: { 33 | description: 'Disallow assigning `this` to a variable.', 34 | recommended: true, 35 | }, 36 | messages, 37 | }, 38 | }; 39 | 40 | export default config; 41 | -------------------------------------------------------------------------------- /rules/no-unnecessary-array-flat-depth.js: -------------------------------------------------------------------------------- 1 | import {isMethodCall, isLiteral} from './ast/index.js'; 2 | import {removeArgument} from './fix/index.js'; 3 | import {} from './utils/index.js'; 4 | 5 | const MESSAGE_ID = 'no-unnecessary-array-flat-depth'; 6 | const messages = { 7 | [MESSAGE_ID]: 'Passing `1` as the `depth` argument is unnecessary.', 8 | }; 9 | 10 | /** @param {import('eslint').Rule.RuleContext} context */ 11 | const create = context => { 12 | context.on('CallExpression', callExpression => { 13 | if (!( 14 | isMethodCall(callExpression, { 15 | method: 'flat', 16 | argumentsLength: 1, 17 | optionalCall: false, 18 | }) 19 | && isLiteral(callExpression.arguments[0], 1) 20 | )) { 21 | return; 22 | } 23 | 24 | const [numberOne] = callExpression.arguments; 25 | 26 | return { 27 | node: numberOne, 28 | messageId: MESSAGE_ID, 29 | /** @param {import('eslint').Rule.RuleFixer} fixer */ 30 | fix: fixer => removeArgument(fixer, numberOne, context.sourceCode), 31 | }; 32 | }); 33 | }; 34 | 35 | /** @type {import('eslint').Rule.RuleModule} */ 36 | const config = { 37 | create, 38 | meta: { 39 | type: 'suggestion', 40 | docs: { 41 | description: 'Disallow using `1` as the `depth` argument of `Array#flat()`.', 42 | recommended: true, 43 | }, 44 | fixable: 'code', 45 | 46 | messages, 47 | }, 48 | }; 49 | 50 | export default config; 51 | -------------------------------------------------------------------------------- /rules/no-unnecessary-array-splice-count.js: -------------------------------------------------------------------------------- 1 | import {listen} from './shared/no-unnecessary-length-or-infinity-rule.js'; 2 | 3 | const MESSAGE_ID = 'no-unnecessary-array-splice-count'; 4 | const messages = { 5 | [MESSAGE_ID]: 'Passing `{{description}}` as the `{{argumentName}}` argument is unnecessary.', 6 | }; 7 | 8 | /** @type {import('eslint').Rule.RuleModule} */ 9 | const config = { 10 | create: context => listen(context, {methods: ['splice', 'toSpliced'], messageId: MESSAGE_ID}), 11 | meta: { 12 | type: 'suggestion', 13 | docs: { 14 | description: 'Disallow using `.length` or `Infinity` as the `deleteCount` or `skipCount` argument of `Array#{splice,toSpliced}()`.', 15 | recommended: true, 16 | }, 17 | fixable: 'code', 18 | 19 | messages, 20 | }, 21 | }; 22 | 23 | export default config; 24 | -------------------------------------------------------------------------------- /rules/no-unnecessary-slice-end.js: -------------------------------------------------------------------------------- 1 | import {listen} from './shared/no-unnecessary-length-or-infinity-rule.js'; 2 | 3 | const MESSAGE_ID = 'no-unnecessary-slice-end'; 4 | const messages = { 5 | [MESSAGE_ID]: 'Passing `{{description}}` as the `end` argument is unnecessary.', 6 | }; 7 | 8 | /** @type {import('eslint').Rule.RuleModule} */ 9 | const config = { 10 | create: context => listen(context, {methods: ['slice'], messageId: MESSAGE_ID}), 11 | meta: { 12 | type: 'suggestion', 13 | docs: { 14 | description: 'Disallow using `.length` or `Infinity` as the `end` argument of `{Array,String,TypedArray}#slice()`.', 15 | recommended: true, 16 | }, 17 | fixable: 'code', 18 | messages, 19 | }, 20 | }; 21 | 22 | export default config; 23 | -------------------------------------------------------------------------------- /rules/no-unreadable-iife.js: -------------------------------------------------------------------------------- 1 | import {isParenthesized, getParenthesizedRange, toLocation} from './utils/index.js'; 2 | 3 | const MESSAGE_ID_ERROR = 'no-unreadable-iife'; 4 | const messages = { 5 | [MESSAGE_ID_ERROR]: 'IIFE with parenthesized arrow function body is considered unreadable.', 6 | }; 7 | 8 | /** @param {import('eslint').Rule.RuleContext} context */ 9 | const create = context => ({ 10 | CallExpression(callExpression) { 11 | const {sourceCode} = context; 12 | 13 | if ( 14 | callExpression.callee.type !== 'ArrowFunctionExpression' 15 | || callExpression.callee.body.type === 'BlockStatement' 16 | || !isParenthesized(callExpression.callee.body, sourceCode) 17 | ) { 18 | return; 19 | } 20 | 21 | return { 22 | node: callExpression, 23 | loc: toLocation(getParenthesizedRange(callExpression.callee.body, sourceCode), sourceCode), 24 | messageId: MESSAGE_ID_ERROR, 25 | }; 26 | }, 27 | }); 28 | 29 | /** @type {import('eslint').Rule.RuleModule} */ 30 | const config = { 31 | create, 32 | meta: { 33 | type: 'suggestion', 34 | docs: { 35 | description: 'Disallow unreadable IIFEs.', 36 | recommended: true, 37 | }, 38 | hasSuggestions: false, 39 | messages, 40 | }, 41 | }; 42 | 43 | export default config; 44 | -------------------------------------------------------------------------------- /rules/prefer-array-index-of.js: -------------------------------------------------------------------------------- 1 | import simpleArraySearchRule from './shared/simple-array-search-rule.js'; 2 | 3 | const indexOfOverFindIndexRule = simpleArraySearchRule({ 4 | method: 'findIndex', 5 | replacement: 'indexOf', 6 | }); 7 | 8 | const lastIndexOfOverFindLastIndexRule = simpleArraySearchRule({ 9 | method: 'findLastIndex', 10 | replacement: 'lastIndexOf', 11 | }); 12 | 13 | /** @type {import('eslint').Rule.RuleModule} */ 14 | const config = { 15 | create(context) { 16 | indexOfOverFindIndexRule.listen(context); 17 | lastIndexOfOverFindLastIndexRule.listen(context); 18 | }, 19 | meta: { 20 | type: 'suggestion', 21 | docs: { 22 | description: 'Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item.', 23 | recommended: true, 24 | }, 25 | fixable: 'code', 26 | hasSuggestions: true, 27 | messages: { 28 | ...indexOfOverFindIndexRule.messages, 29 | ...lastIndexOfOverFindLastIndexRule.messages, 30 | }, 31 | }, 32 | }; 33 | 34 | export default config; 35 | -------------------------------------------------------------------------------- /rules/prefer-blob-reading-methods.js: -------------------------------------------------------------------------------- 1 | import {isMethodCall} from './ast/index.js'; 2 | 3 | const MESSAGE_ID = 'error'; 4 | const messages = { 5 | [MESSAGE_ID]: 'Prefer `Blob#{{replacement}}()` over `FileReader#{{method}}(blob)`.', 6 | }; 7 | 8 | /** @param {import('eslint').Rule.RuleContext} context */ 9 | const create = () => ({ 10 | CallExpression(node) { 11 | if (!isMethodCall(node, { 12 | methods: ['readAsText', 'readAsArrayBuffer'], 13 | argumentsLength: 1, 14 | optionalCall: false, 15 | optionalMember: false, 16 | })) { 17 | return; 18 | } 19 | 20 | const method = node.callee.property; 21 | const methodName = method.name; 22 | 23 | return { 24 | node: method, 25 | messageId: MESSAGE_ID, 26 | data: { 27 | method: methodName, 28 | replacement: methodName === 'readAsArrayBuffer' ? 'arrayBuffer' : 'text', 29 | }, 30 | }; 31 | }, 32 | }); 33 | 34 | /** @type {import('eslint').Rule.RuleModule} */ 35 | const config = { 36 | create, 37 | meta: { 38 | type: 'suggestion', 39 | docs: { 40 | description: 'Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`.', 41 | recommended: true, 42 | }, 43 | messages, 44 | }, 45 | }; 46 | 47 | export default config; 48 | -------------------------------------------------------------------------------- /rules/prefer-dom-node-append.js: -------------------------------------------------------------------------------- 1 | import {isMethodCall} from './ast/index.js'; 2 | import {isNodeValueNotDomNode, isValueNotUsable} from './utils/index.js'; 3 | 4 | const MESSAGE_ID = 'prefer-dom-node-append'; 5 | const messages = { 6 | [MESSAGE_ID]: 'Prefer `Node#append()` over `Node#appendChild()`.', 7 | }; 8 | 9 | /** @param {import('eslint').Rule.RuleContext} context */ 10 | const create = () => ({ 11 | CallExpression(node) { 12 | if ( 13 | !isMethodCall(node, { 14 | method: 'appendChild', 15 | argumentsLength: 1, 16 | optionalCall: false, 17 | }) 18 | || isNodeValueNotDomNode(node.callee.object) 19 | || isNodeValueNotDomNode(node.arguments[0]) 20 | ) { 21 | return; 22 | } 23 | 24 | const fix = isValueNotUsable(node) 25 | ? fixer => fixer.replaceText(node.callee.property, 'append') 26 | : undefined; 27 | 28 | return { 29 | node, 30 | messageId: MESSAGE_ID, 31 | fix, 32 | }; 33 | }, 34 | }); 35 | 36 | /** @type {import('eslint').Rule.RuleModule} */ 37 | const config = { 38 | create, 39 | meta: { 40 | type: 'suggestion', 41 | docs: { 42 | description: 'Prefer `Node#append()` over `Node#appendChild()`.', 43 | recommended: true, 44 | }, 45 | fixable: 'code', 46 | messages, 47 | }, 48 | }; 49 | 50 | export default config; 51 | -------------------------------------------------------------------------------- /rules/prefer-string-trim-start-end.js: -------------------------------------------------------------------------------- 1 | import {isMethodCall} from './ast/index.js'; 2 | 3 | const MESSAGE_ID = 'prefer-string-trim-start-end'; 4 | const messages = { 5 | [MESSAGE_ID]: 'Prefer `String#{{replacement}}()` over `String#{{method}}()`.', 6 | }; 7 | 8 | /** @param {import('eslint').Rule.RuleContext} context */ 9 | const create = () => ({ 10 | CallExpression(callExpression) { 11 | if (!isMethodCall(callExpression, { 12 | methods: ['trimLeft', 'trimRight'], 13 | argumentsLength: 0, 14 | optionalCall: false, 15 | })) { 16 | return; 17 | } 18 | 19 | const node = callExpression.callee.property; 20 | const method = node.name; 21 | const replacement = method === 'trimLeft' ? 'trimStart' : 'trimEnd'; 22 | 23 | return { 24 | node, 25 | messageId: MESSAGE_ID, 26 | data: {method, replacement}, 27 | fix: fixer => fixer.replaceText(node, replacement), 28 | }; 29 | }, 30 | }); 31 | 32 | /** @type {import('eslint').Rule.RuleModule} */ 33 | const config = { 34 | create, 35 | meta: { 36 | type: 'suggestion', 37 | docs: { 38 | description: 'Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`.', 39 | recommended: true, 40 | }, 41 | fixable: 'code', 42 | messages, 43 | }, 44 | }; 45 | 46 | export default config; 47 | -------------------------------------------------------------------------------- /rules/shared/builtin-errors.js: -------------------------------------------------------------------------------- 1 | const builtinErrors = [ 2 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error 3 | 'Error', 4 | 'EvalError', 5 | 'RangeError', 6 | 'ReferenceError', 7 | 'SyntaxError', 8 | 'TypeError', 9 | 'URIError', 10 | 'InternalError', 11 | 'AggregateError', 12 | 'SuppressedError', 13 | ]; 14 | 15 | export default builtinErrors; 16 | -------------------------------------------------------------------------------- /rules/shared/event-keys.js: -------------------------------------------------------------------------------- 1 | /* eslint sort-keys: ["error", "asc", {natural: true}] */ 2 | 3 | // https://github.com/facebook/react/blob/b87aabd/packages/react-dom/src/events/getEventKey.js#L36 4 | // Only meta characters which can't be deciphered from `String.fromCharCode()` 5 | const eventKeys = { 6 | 8: 'Backspace', 7 | 9: 'Tab', 8 | 12: 'Clear', 9 | 13: 'Enter', 10 | 16: 'Shift', 11 | 17: 'Control', 12 | 18: 'Alt', 13 | 19: 'Pause', 14 | 20: 'CapsLock', 15 | 27: 'Escape', 16 | 32: ' ', 17 | 33: 'PageUp', 18 | 34: 'PageDown', 19 | 35: 'End', 20 | 36: 'Home', 21 | 37: 'ArrowLeft', 22 | 38: 'ArrowUp', 23 | 39: 'ArrowRight', 24 | 40: 'ArrowDown', 25 | 45: 'Insert', 26 | 46: 'Delete', 27 | 112: 'F1', 28 | 113: 'F2', 29 | 114: 'F3', 30 | 115: 'F4', 31 | 116: 'F5', 32 | 117: 'F6', 33 | 118: 'F7', 34 | 119: 'F8', 35 | 120: 'F9', 36 | 121: 'F10', 37 | 122: 'F11', 38 | 123: 'F12', 39 | 144: 'NumLock', 40 | 145: 'ScrollLock', 41 | 186: ';', 42 | 187: '=', 43 | 188: ',', 44 | 189: '-', 45 | 190: '.', 46 | 191: '/', 47 | 219: '[', 48 | 220: '\\', 49 | 221: ']', 50 | 222: '\'', 51 | 224: 'Meta', 52 | }; 53 | 54 | export default eventKeys; 55 | -------------------------------------------------------------------------------- /rules/shared/negative-index.js: -------------------------------------------------------------------------------- 1 | import isSameReference from '../utils/is-same-reference.js'; 2 | import {getParenthesizedRange} from '../utils/parentheses.js'; 3 | import {isNumberLiteral} from '../ast/index.js'; 4 | 5 | const isLengthMemberExpression = node => 6 | node.type === 'MemberExpression' 7 | && !node.computed 8 | && !node.optional 9 | && node.property.type === 'Identifier' 10 | && node.property.name === 'length'; 11 | 12 | const isLiteralPositiveNumber = node => 13 | isNumberLiteral(node) 14 | && node.value > 0; 15 | 16 | export function getNegativeIndexLengthNode(node, objectNode) { 17 | if (!node) { 18 | return; 19 | } 20 | 21 | const {type, operator, left, right} = node; 22 | 23 | if (type !== 'BinaryExpression' || operator !== '-' || !isLiteralPositiveNumber(right)) { 24 | return; 25 | } 26 | 27 | if (isLengthMemberExpression(left) && isSameReference(left.object, objectNode)) { 28 | return left; 29 | } 30 | 31 | // Nested BinaryExpression 32 | return getNegativeIndexLengthNode(left, objectNode); 33 | } 34 | 35 | export function removeLengthNode(node, fixer, sourceCode) { 36 | const [start, end] = getParenthesizedRange(node, sourceCode); 37 | return fixer.removeRange([ 38 | start, 39 | end + sourceCode.text.slice(end).match(/\S|$/).index, 40 | ]); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /rules/shared/package-json.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import {findUpSync} from 'find-up-simple'; 3 | 4 | const directoryCache = new Map(); 5 | const dataCache = new Map(); 6 | 7 | /** 8 | Finds the closest package.json file to the given directory and returns its path and contents. 9 | 10 | Caches the result for future lookups. 11 | 12 | @param dirname {string} 13 | @return {{ path: string, packageJson: Record } | undefined} 14 | */ 15 | export function readPackageJson(dirname) { 16 | let packageJsonPath; 17 | if (directoryCache.has(dirname)) { 18 | packageJsonPath = directoryCache.get(dirname); 19 | } else { 20 | packageJsonPath = findUpSync('package.json', {cwd: dirname, type: 'file'}); 21 | directoryCache.set(dirname, packageJsonPath); 22 | } 23 | 24 | if (!packageJsonPath) { 25 | return; 26 | } 27 | 28 | let packageJson; 29 | if (dataCache.has(packageJsonPath)) { 30 | packageJson = dataCache.get(packageJsonPath); 31 | } else { 32 | try { 33 | packageJson = JSON.parse(fs.readFileSync(packageJsonPath)); 34 | dataCache.set(packageJsonPath, packageJson); 35 | } catch { 36 | // This can happen if package.json files have comments in them etc. 37 | return; 38 | } 39 | } 40 | 41 | return {path: packageJsonPath, packageJson}; 42 | } 43 | -------------------------------------------------------------------------------- /rules/shared/typed-array.js: -------------------------------------------------------------------------------- 1 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description 2 | const typedArrayTypes = [ 3 | 'Int8Array', 4 | 'Uint8Array', 5 | 'Uint8ClampedArray', 6 | 'Int16Array', 7 | 'Uint16Array', 8 | 'Int32Array', 9 | 'Uint32Array', 10 | 'Float16Array', 11 | 'Float32Array', 12 | 'Float64Array', 13 | 'BigInt64Array', 14 | 'BigUint64Array', 15 | ]; 16 | 17 | export default typedArrayTypes; 18 | -------------------------------------------------------------------------------- /rules/throw-new-error.js: -------------------------------------------------------------------------------- 1 | import {switchCallExpressionToNewExpression} from './fix/index.js'; 2 | 3 | const messageId = 'throw-new-error'; 4 | const messages = { 5 | [messageId]: 'Use `new` when creating an error.', 6 | }; 7 | 8 | const customError = /^(?:[A-Z][\da-z]*)*Error$/; 9 | 10 | /** @param {import('eslint').Rule.RuleContext} context */ 11 | const create = context => ({ 12 | CallExpression(node) { 13 | const {callee} = node; 14 | if (!( 15 | (callee.type === 'Identifier' && customError.test(callee.name)) 16 | || ( 17 | callee.type === 'MemberExpression' 18 | && !callee.computed 19 | && callee.property.type === 'Identifier' 20 | && customError.test(callee.property.name) 21 | ) 22 | )) { 23 | return; 24 | } 25 | 26 | return { 27 | node, 28 | messageId, 29 | fix: fixer => switchCallExpressionToNewExpression(node, context.sourceCode, fixer), 30 | }; 31 | }, 32 | }); 33 | 34 | /** @type {import('eslint').Rule.RuleModule} */ 35 | const config = { 36 | create, 37 | meta: { 38 | type: 'suggestion', 39 | docs: { 40 | description: 'Require `new` when creating an error.', 41 | recommended: true, 42 | }, 43 | fixable: 'code', 44 | messages, 45 | }, 46 | }; 47 | 48 | export default config; 49 | -------------------------------------------------------------------------------- /rules/utils/array-or-object-prototype-property.js: -------------------------------------------------------------------------------- 1 | import {isMemberExpression} from '../ast/index.js'; 2 | 3 | /** 4 | @param { 5 | { 6 | object?: string, 7 | method?: string, 8 | methods?: string[], 9 | } 10 | } [options] 11 | @returns {string} 12 | */ 13 | function isPrototypeProperty(node, options) { 14 | const { 15 | object, 16 | property, 17 | properties, 18 | } = { 19 | property: '', 20 | properties: [], 21 | ...options, 22 | }; 23 | 24 | if (!isMemberExpression(node, { 25 | property, 26 | properties, 27 | optional: false, 28 | })) { 29 | return; 30 | } 31 | 32 | const objectNode = node.object; 33 | 34 | return ( 35 | // `Object.prototype.method` or `Array.prototype.method` 36 | isMemberExpression(objectNode, { 37 | object, 38 | property: 'prototype', 39 | optional: false, 40 | }) 41 | // `[].method` 42 | || ( 43 | object === 'Array' 44 | && objectNode.type === 'ArrayExpression' 45 | && objectNode.elements.length === 0 46 | ) 47 | // `{}.method` 48 | || ( 49 | object === 'Object' 50 | && objectNode.type === 'ObjectExpression' 51 | && objectNode.properties.length === 0 52 | ) 53 | ); 54 | } 55 | 56 | export const isArrayPrototypeProperty = (node, options) => isPrototypeProperty(node, {...options, object: 'Array'}); 57 | export const isObjectPrototypeProperty = (node, options) => isPrototypeProperty(node, {...options, object: 'Object'}); 58 | -------------------------------------------------------------------------------- /rules/utils/assert-token.js: -------------------------------------------------------------------------------- 1 | const ISSUE_LINK_PREFIX = 'https://github.com/sindresorhus/eslint-plugin-unicorn/issues/new?'; 2 | 3 | export default function assertToken(token, {test, expected, ruleId}) { 4 | if (test?.(token)) { 5 | return; 6 | } 7 | 8 | expected = Array.isArray(expected) ? expected : [expected]; 9 | expected = expected.map(expectedToken => typeof expectedToken === 'string' ? {value: expectedToken} : expectedToken); 10 | 11 | if ( 12 | !test 13 | && expected.some( 14 | expectedToken => 15 | Object.entries(expectedToken) 16 | .every(([key, value]) => token[key] === value), 17 | ) 18 | ) { 19 | return; 20 | } 21 | 22 | const actual = `'${JSON.stringify({value: token.value, type: token.type})}'`; 23 | expected = expected.map(expectedToken => `'${JSON.stringify(expectedToken)}'`).join(' or '); 24 | const title = `\`${ruleId}\`: Unexpected token ${actual}`; 25 | const issueLink = `${ISSUE_LINK_PREFIX}title=${encodeURIComponent(title)}`; 26 | const message = `Expected token ${expected}, got ${actual}.\nPlease open an issue at ${issueLink}.`; 27 | 28 | throw new Error(message); 29 | } 30 | -------------------------------------------------------------------------------- /rules/utils/builtins.js: -------------------------------------------------------------------------------- 1 | import typedArray from '../shared/typed-array.js'; 2 | 3 | export const enforceNew = [ 4 | 'Object', 5 | 'Array', 6 | 'ArrayBuffer', 7 | 'DataView', 8 | 'Date', 9 | 'Error', 10 | 'Function', 11 | 'Map', 12 | 'WeakMap', 13 | 'Set', 14 | 'WeakSet', 15 | 'Promise', 16 | 'RegExp', 17 | 'SharedArrayBuffer', 18 | 'Proxy', 19 | 'WeakRef', 20 | 'FinalizationRegistry', 21 | ...typedArray, 22 | ]; 23 | 24 | export const disallowNew = [ 25 | 'BigInt', 26 | 'Boolean', 27 | 'Number', 28 | 'String', 29 | 'Symbol', 30 | ]; 31 | -------------------------------------------------------------------------------- /rules/utils/cartesian-product-samples.js: -------------------------------------------------------------------------------- 1 | export default function cartesianProductSamples(combinations, length = Number.POSITIVE_INFINITY) { 2 | const total = combinations.reduce((total, {length}) => total * length, 1); 3 | 4 | const samples = Array.from({length: Math.min(total, length)}, (_, sampleIndex) => { 5 | let indexRemaining = sampleIndex; 6 | const combination = []; 7 | for (let combinationIndex = combinations.length - 1; combinationIndex >= 0; combinationIndex--) { 8 | const items = combinations[combinationIndex]; 9 | const {length} = items; 10 | const index = indexRemaining % length; 11 | indexRemaining = (indexRemaining - index) / length; 12 | combination.unshift(items[index]); 13 | } 14 | 15 | return combination; 16 | }); 17 | 18 | return { 19 | total, 20 | samples, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /rules/utils/create-deprecated-rules.js: -------------------------------------------------------------------------------- 1 | import packageJson from '../../package.json' with {type: 'json'}; 2 | 3 | const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn'; 4 | 5 | /** @returns {{ [ruleName: string]: import('eslint').Rule.RuleModule }} */ 6 | export default function createDeprecatedRules(rules) { 7 | return Object.fromEntries( 8 | Object.entries(rules).map(([ruleId, deprecatedInfo]) => { 9 | const url = `${repoUrl}/blob/v${packageJson.version}/docs/deprecated-rules.md#${ruleId}`; 10 | return [ 11 | ruleId, 12 | { 13 | create: () => ({}), 14 | meta: { 15 | docs: { 16 | description: deprecatedInfo.message, 17 | url, 18 | }, 19 | deprecated: { 20 | message: deprecatedInfo.message, 21 | url, 22 | replacedBy: deprecatedInfo.replacedBy, 23 | }, 24 | }, 25 | }, 26 | ]; 27 | }), 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /rules/utils/escape-string.js: -------------------------------------------------------------------------------- 1 | import jsesc from 'jsesc'; 2 | 3 | /** 4 | Escape string and wrap the result in quotes. 5 | 6 | @param {string} string - The string to be quoted. 7 | @param {string} [quote] - The quote character. 8 | @returns {string} - The quoted and escaped string. 9 | */ 10 | export default function escapeString(string, quote = '\'') { 11 | /* c8 ignore start */ 12 | if (typeof string !== 'string') { 13 | throw new TypeError('Unexpected string.'); 14 | } 15 | /* c8 ignore end */ 16 | 17 | return jsesc(string, { 18 | quotes: quote === '"' ? 'double' : 'single', 19 | wrap: true, 20 | es6: true, 21 | minimal: true, 22 | lowercaseHex: false, 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /rules/utils/escape-template-element-raw.js: -------------------------------------------------------------------------------- 1 | const escapeTemplateElementRaw = string => string.replaceAll( 2 | /(?<=(?:^|[^\\])(?:\\\\)*)(?(?:`|\$(?={)))/g, 3 | String.raw`\$`, 4 | ); 5 | 6 | export default escapeTemplateElementRaw; 7 | -------------------------------------------------------------------------------- /rules/utils/get-ancestor.js: -------------------------------------------------------------------------------- 1 | // TODO: Support more types 2 | function getPredicate(options) { 3 | if (typeof options === 'string') { 4 | return node => node.type === options; 5 | } 6 | } 7 | 8 | export default function getAncestor(node, options) { 9 | const predicate = getPredicate(options); 10 | for (; node.parent; node = node.parent) { 11 | if (predicate(node)) { 12 | return node; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rules/utils/get-builtin-rule.js: -------------------------------------------------------------------------------- 1 | import {builtinRules} from 'eslint/use-at-your-own-risk'; 2 | 3 | export default function getBuiltinRule(id) { 4 | return builtinRules.get(id); 5 | } 6 | -------------------------------------------------------------------------------- /rules/utils/get-call-expression-arguments-text.js: -------------------------------------------------------------------------------- 1 | import getCallExpressionTokens from './get-call-expression-tokens.js'; 2 | 3 | /** @typedef {import('estree').CallExpression} CallExpression */ 4 | 5 | /** 6 | Get the text of the arguments list of `CallExpression`. 7 | 8 | @param {import('eslint').SourceCode} sourceCode - The source code object. 9 | @param {CallExpression} callExpression - The `CallExpression` node. 10 | @param {SourceCode} sourceCode - The source code object. 11 | @returns {string} 12 | */ 13 | export default function getCallExpressionArgumentsText(sourceCode, callExpression) { 14 | const { 15 | openingParenthesisToken, 16 | closingParenthesisToken, 17 | } = getCallExpressionTokens(sourceCode, callExpression); 18 | 19 | const [, start] = sourceCode.getRange(openingParenthesisToken); 20 | const [end] = sourceCode.getRange(closingParenthesisToken); 21 | 22 | return sourceCode.text.slice(start, end); 23 | } 24 | -------------------------------------------------------------------------------- /rules/utils/get-call-expression-tokens.js: -------------------------------------------------------------------------------- 1 | import {isOpeningParenToken, isCommaToken} from '@eslint-community/eslint-utils'; 2 | 3 | /** @typedef {import('estree').CallExpression} CallExpression */ 4 | /** @typedef {import('eslint').AST.Token} Token */ 5 | 6 | /** 7 | Get the `openingParenthesisToken`, `closingParenthesisToken`, and `trailingCommaToken` of `CallExpression`. 8 | 9 | @param {import('eslint').SourceCode} sourceCode - The source code object. 10 | @param {CallExpression} callExpression - The `CallExpression` node. 11 | @returns {{ 12 | openingParenthesisToken: Token, 13 | closingParenthesisToken: Token, 14 | trailingCommaToken: Token | undefined, 15 | }} 16 | */ 17 | export default function getCallExpressionTokens(sourceCode, callExpression) { 18 | const openingParenthesisToken = sourceCode.getTokenAfter(callExpression.callee, isOpeningParenToken); 19 | const [ 20 | penultimateToken, 21 | closingParenthesisToken, 22 | ] = sourceCode.getLastTokens(callExpression, 2); 23 | const trailingCommaToken = isCommaToken(penultimateToken) ? penultimateToken : undefined; 24 | 25 | return { 26 | openingParenthesisToken, 27 | closingParenthesisToken, 28 | trailingCommaToken, 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /rules/utils/get-class-head-location.js: -------------------------------------------------------------------------------- 1 | /** 2 | @typedef {line: number, column: number} Position 3 | 4 | Get the location of the given class node for reporting. 5 | 6 | @param {Node} node - The class node to get. 7 | @param {SourceCode} sourceCode - The source code object to get tokens. 8 | @returns {{start: Position, end: Position}} The location of the class node for reporting. 9 | */ 10 | export default function getClassHeadLocation(node, sourceCode) { 11 | const {body} = node; 12 | const tokenBeforeBody = sourceCode.getTokenBefore(body); 13 | 14 | const {start} = sourceCode.getLoc(node); 15 | const {end} = sourceCode.getLoc(tokenBeforeBody); 16 | 17 | return {start, end}; 18 | } 19 | -------------------------------------------------------------------------------- /rules/utils/get-documentation-url.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import packageJson from '../../package.json' with {type: 'json'}; 3 | 4 | const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn'; 5 | 6 | export default function getDocumentationUrl(filename) { 7 | const ruleName = path.basename(filename, '.js'); 8 | return `${repoUrl}/blob/v${packageJson.version}/docs/rules/${ruleName}.md`; 9 | } 10 | -------------------------------------------------------------------------------- /rules/utils/get-indent-string.js: -------------------------------------------------------------------------------- 1 | export default function getIndentString(node, sourceCode) { 2 | const {start: {line, column}} = sourceCode.getLoc(node); 3 | const lines = sourceCode.getLines(); 4 | const before = lines[line - 1].slice(0, column); 5 | 6 | return before.match(/\s*$/)[0]; 7 | } 8 | -------------------------------------------------------------------------------- /rules/utils/get-previous-node.js: -------------------------------------------------------------------------------- 1 | export default function getPreviousNode(node, sourceCode) { 2 | const {parent} = node; 3 | const visitorKeys = sourceCode.visitorKeys[parent.type] || Object.keys(parent); 4 | 5 | for (const property of visitorKeys) { 6 | const value = parent[property]; 7 | 8 | if (value === node) { 9 | return; 10 | } 11 | 12 | if (Array.isArray(value)) { 13 | const index = value.indexOf(node); 14 | 15 | if (index !== -1) { 16 | return value[index - 1]; 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /rules/utils/get-references.js: -------------------------------------------------------------------------------- 1 | import getScopes from './get-scopes.js'; 2 | 3 | const getReferences = scope => [...new Set(getScopes(scope).flatMap(({references}) => references))]; 4 | 5 | export default getReferences; 6 | -------------------------------------------------------------------------------- /rules/utils/get-scopes.js: -------------------------------------------------------------------------------- 1 | /** 2 | Gather a list of all Scopes starting recursively from the input Scope. 3 | 4 | @param {Scope} scope - The Scope to start checking from. 5 | @returns {Scope[]} - The resulting Scopes. 6 | */ 7 | const getScopes = scope => [ 8 | scope, 9 | ...scope.childScopes.flatMap(scope => getScopes(scope)), 10 | ]; 11 | 12 | export default getScopes; 13 | -------------------------------------------------------------------------------- /rules/utils/get-switch-case-head-location.js: -------------------------------------------------------------------------------- 1 | import {isColonToken} from '@eslint-community/eslint-utils'; 2 | 3 | /** 4 | @typedef {line: number, column: number} Position 5 | 6 | Get the location of the given `SwitchCase` node for reporting. 7 | 8 | @param {Node} node - The `SwitchCase` node to get. 9 | @param {SourceCode} sourceCode - The source code object to get tokens from. 10 | @returns {{start: Position, end: Position}} The location of the class node for reporting. 11 | */ 12 | export default function getSwitchCaseHeadLocation(node, sourceCode) { 13 | const startToken = node.test || sourceCode.getFirstToken(node); 14 | const colonToken = sourceCode.getTokenAfter(startToken, isColonToken); 15 | return {start: sourceCode.getLoc(node).start, end: sourceCode.getLoc(colonToken).end}; 16 | } 17 | -------------------------------------------------------------------------------- /rules/utils/get-variable-identifiers.js: -------------------------------------------------------------------------------- 1 | // Get identifiers of given variable 2 | const getVariableIdentifiers = ({identifiers, references}) => [...new Set([ 3 | ...identifiers, 4 | ...references.map(({identifier}) => identifier), 5 | ])]; 6 | 7 | export default getVariableIdentifiers; 8 | -------------------------------------------------------------------------------- /rules/utils/has-optional-chain-element.js: -------------------------------------------------------------------------------- 1 | const isChainElement = node => node.type === 'MemberExpression' || node.type === 'CallExpression'; 2 | 3 | export default function hasOptionalChainElement(node) { 4 | if (!isChainElement(node)) { 5 | return false; 6 | } 7 | 8 | if (node.optional) { 9 | return true; 10 | } 11 | 12 | if (node.type === 'MemberExpression') { 13 | return hasOptionalChainElement(node.object); 14 | } 15 | 16 | return false; 17 | } 18 | -------------------------------------------------------------------------------- /rules/utils/has-same-range.js: -------------------------------------------------------------------------------- 1 | const hasSameRange = (node1, node2) => 2 | node1 3 | && node2 4 | // eslint-disable-next-line internal/no-restricted-property-access 5 | && node1.range[0] === node2.range[0] 6 | // eslint-disable-next-line internal/no-restricted-property-access 7 | && node1.range[1] === node2.range[1]; 8 | 9 | export default hasSameRange; 10 | -------------------------------------------------------------------------------- /rules/utils/is-function-self-used-inside.js: -------------------------------------------------------------------------------- 1 | import {findVariable} from '@eslint-community/eslint-utils'; 2 | 3 | const getReferences = (scope, nodeOrName) => { 4 | const {references = []} = findVariable(scope, nodeOrName) || {}; 5 | return references; 6 | }; 7 | 8 | /** 9 | Check if `this`, `arguments`, or the function name is used inside of itself. 10 | 11 | @param {Node} functionNode - The function node. 12 | @param {Scope} functionScope - The scope of the function node. 13 | @returns {boolean} 14 | */ 15 | export default function isFunctionSelfUsedInside(functionNode, functionScope) { 16 | /* c8 ignore next 3 */ 17 | if (functionScope.block !== functionNode) { 18 | throw new Error('"functionScope" should be the scope of "functionNode".'); 19 | } 20 | 21 | const {type, id} = functionNode; 22 | if (type === 'ArrowFunctionExpression') { 23 | return false; 24 | } 25 | 26 | if (functionScope.thisFound) { 27 | return true; 28 | } 29 | 30 | if (getReferences(functionScope, 'arguments').some(({from}) => from === functionScope)) { 31 | return true; 32 | } 33 | 34 | if (id && getReferences(functionScope, id).length > 0) { 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | -------------------------------------------------------------------------------- /rules/utils/is-left-hand-side.js: -------------------------------------------------------------------------------- 1 | const isLeftHandSide = node => 2 | ( 3 | (node.parent.type === 'AssignmentExpression' || node.parent.type === 'AssignmentPattern') 4 | && node.parent.left === node 5 | ) 6 | || (node.parent.type === 'UpdateExpression' && node.parent.argument === node) 7 | || (node.parent.type === 'ArrayPattern' && node.parent.elements.includes(node)) 8 | || ( 9 | node.parent.type === 'Property' 10 | && node.parent.value === node 11 | && node.parent.parent.type === 'ObjectPattern' 12 | && node.parent.parent.properties.includes(node.parent) 13 | ) 14 | || ( 15 | node.parent.type === 'UnaryExpression' 16 | && node.parent.operator === 'delete' 17 | && node.parent.argument === node 18 | ); 19 | 20 | export default isLeftHandSide; 21 | -------------------------------------------------------------------------------- /rules/utils/is-logical-expression.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if the given node is a true logical expression or not. 3 | 4 | The three binary expressions logical-or (`||`), logical-and (`&&`), and coalesce (`??`) are known as `ShortCircuitExpression`, but ESTree represents these by the `LogicalExpression` node type. This function rejects coalesce expressions of `LogicalExpression` node type. 5 | 6 | @param {Node} node - The node to check. 7 | @returns {boolean} `true` if the node is `&&` or `||`. 8 | @see https://tc39.es/ecma262/#prod-ShortCircuitExpression 9 | */ 10 | const isLogicalExpression = node => 11 | node?.type === 'LogicalExpression' 12 | && (node.operator === '&&' || node.operator === '||'); 13 | 14 | export default isLogicalExpression; 15 | -------------------------------------------------------------------------------- /rules/utils/is-method-named.js: -------------------------------------------------------------------------------- 1 | const isMethodNamed = (node, name) => 2 | node.type === 'CallExpression' 3 | && node.callee.type === 'MemberExpression' 4 | && node.callee.property.type === 'Identifier' 5 | && node.callee.property.name === name; 6 | 7 | export default isMethodNamed; 8 | -------------------------------------------------------------------------------- /rules/utils/is-new-expression-with-parentheses.js: -------------------------------------------------------------------------------- 1 | import {isOpeningParenToken, isClosingParenToken} from '@eslint-community/eslint-utils'; 2 | 3 | /** 4 | Determine if a constructor function is newed-up with parens. 5 | 6 | @param {Node} node - The `NewExpression` node to be checked. 7 | @param {SourceCode} sourceCode - The source code object. 8 | @returns {boolean} True if the constructor is called with parens. 9 | 10 | Copied from https://github.com/eslint/eslint/blob/cc4871369645c3409dc56ded7a555af8a9f63d51/lib/rules/no-extra-parens.js#L252 11 | */ 12 | export default function isNewExpressionWithParentheses(node, sourceCode) { 13 | if (node.arguments.length > 0) { 14 | return true; 15 | } 16 | 17 | const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2); 18 | // The expression should end with its own parens, for example, `new new Foo()` is not a new expression with parens. 19 | return isOpeningParenToken(penultimateToken) 20 | && isClosingParenToken(lastToken) 21 | && sourceCode.getRange(node.callee)[1] < sourceCode.getRange(node)[1]; 22 | } 23 | -------------------------------------------------------------------------------- /rules/utils/is-node-matches.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if node matches object name or key path. 3 | 4 | @param {Node} node - The AST node to check. 5 | @param {string} nameOrPath - The object name or key path. 6 | @returns {boolean} 7 | */ 8 | export function isNodeMatchesNameOrPath(node, nameOrPath) { 9 | const names = nameOrPath.trim().split('.'); 10 | for (let index = names.length - 1; index >= 0; index--) { 11 | const name = names[index]; 12 | if (!name) { 13 | return false; 14 | } 15 | 16 | if (index === 0) { 17 | return ( 18 | (node.type === 'Identifier' && node.name === name) 19 | || (name === 'this' && node.type === 'ThisExpression') 20 | ); 21 | } 22 | 23 | if ( 24 | node.type !== 'MemberExpression' 25 | || node.optional 26 | || node.computed 27 | || node.property.type !== 'Identifier' 28 | || node.property.name !== name 29 | ) { 30 | return false; 31 | } 32 | 33 | node = node.object; 34 | } 35 | } 36 | 37 | /** 38 | Check if node matches any object name or key path. 39 | 40 | @param {Node} node - The AST node to check. 41 | @param {string[]} nameOrPaths - The object name or key paths. 42 | @returns {boolean} 43 | */ 44 | export function isNodeMatches(node, nameOrPaths) { 45 | return nameOrPaths.some(nameOrPath => isNodeMatchesNameOrPath(node, nameOrPath)); 46 | } 47 | -------------------------------------------------------------------------------- /rules/utils/is-node-value-not-dom-node.js: -------------------------------------------------------------------------------- 1 | import {isUndefined} from '../ast/index.js'; 2 | 3 | // AST Types: 4 | // https://github.com/eslint/espree/blob/master/lib/ast-node-types.js#L18 5 | // Only types possible to be `callee` or `argument` are listed 6 | const impossibleNodeTypes = new Set([ 7 | 'ArrayExpression', 8 | 'ArrowFunctionExpression', 9 | 'ClassExpression', 10 | 'FunctionExpression', 11 | 'Literal', 12 | 'ObjectExpression', 13 | 'TemplateLiteral', 14 | ]); 15 | 16 | const isNodeValueNotDomNode = node => 17 | impossibleNodeTypes.has(node.type) 18 | || isUndefined(node); 19 | 20 | export default isNodeValueNotDomNode; 21 | -------------------------------------------------------------------------------- /rules/utils/is-node-value-not-function.js: -------------------------------------------------------------------------------- 1 | import {isUndefined, isCallExpression, isMethodCall} from '../ast/index.js'; 2 | 3 | // AST Types: 4 | // https://github.com/eslint/espree/blob/master/lib/ast-node-types.js#L18 5 | // Only types possible to be `argument` are listed 6 | const impossibleNodeTypes = new Set([ 7 | 'ArrayExpression', 8 | 'BinaryExpression', 9 | 'ClassExpression', 10 | 'Literal', 11 | 'ObjectExpression', 12 | 'TemplateLiteral', 13 | 'UnaryExpression', 14 | 'UpdateExpression', 15 | ]); 16 | 17 | // Technically these nodes could be a function, but most likely not 18 | const mostLikelyNotNodeTypes = new Set([ 19 | 'AssignmentExpression', 20 | 'AwaitExpression', 21 | 'NewExpression', 22 | 'TaggedTemplateExpression', 23 | 'ThisExpression', 24 | ]); 25 | 26 | const isNodeValueNotFunction = node => ( 27 | impossibleNodeTypes.has(node.type) 28 | || mostLikelyNotNodeTypes.has(node.type) 29 | || isUndefined(node) 30 | || ( 31 | isCallExpression(node) 32 | && !(isMethodCall(node, { 33 | method: 'bind', 34 | optionalCall: false, 35 | optionalMember: false, 36 | })) 37 | ) 38 | ); 39 | 40 | export default isNodeValueNotFunction; 41 | -------------------------------------------------------------------------------- /rules/utils/is-object-method.js: -------------------------------------------------------------------------------- 1 | export default function isObjectMethod(node, object, method) { 2 | const {callee} = node; 3 | return ( 4 | callee.type === 'MemberExpression' 5 | && callee.object.type === 'Identifier' 6 | && callee.object.name === object 7 | && callee.property.type === 'Identifier' 8 | && callee.property.name === method 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /rules/utils/is-on-same-line.js: -------------------------------------------------------------------------------- 1 | export default function isOnSameLine(nodeOrTokenA, nodeOrTokenB) { 2 | // eslint-disable-next-line internal/no-restricted-property-access -- Need fix 3 | return nodeOrTokenA.loc.start.line === nodeOrTokenB.loc.start.line; 4 | } 5 | -------------------------------------------------------------------------------- /rules/utils/is-same-identifier.js: -------------------------------------------------------------------------------- 1 | const isSameIdentifier = (nodeA, nodeB) => nodeA.type === 'Identifier' 2 | && nodeB.type === 'Identifier' 3 | && nodeA.name === nodeB.name; 4 | 5 | export default isSameIdentifier; 6 | -------------------------------------------------------------------------------- /rules/utils/is-shadowed.js: -------------------------------------------------------------------------------- 1 | /** 2 | Finds the eslint-scope reference in the given scope. 3 | 4 | @param {Object} scope The scope to search. 5 | @param {ASTNode} node The identifier node. 6 | @returns {Reference|undefined} Returns the found reference or null if none were found. 7 | */ 8 | function findReference(scope, node) { 9 | const references = scope.references 10 | .filter(reference => reference.identifier === node); 11 | 12 | if (references.length === 1) { 13 | return references[0]; 14 | } 15 | } 16 | 17 | /** 18 | Checks if the given identifier node is shadowed in the given scope. 19 | 20 | @param {Object} scope The current scope. 21 | @param {string} node The identifier node to check 22 | @returns {boolean} Whether or not the name is shadowed. 23 | */ 24 | export default function isShadowed(scope, node) { 25 | const reference = findReference(scope, node); 26 | 27 | return ( 28 | Boolean(reference?.resolved) 29 | && reference.resolved.defs.length > 0 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /rules/utils/is-shorthand-export-local.js: -------------------------------------------------------------------------------- 1 | import hasSameRange from './has-same-range.js'; 2 | 3 | const isShorthandExportLocal = node => { 4 | const {type, local, exported} = node.parent; 5 | return type === 'ExportSpecifier' && hasSameRange(local, exported) && local === node; 6 | }; 7 | 8 | export default isShorthandExportLocal; 9 | -------------------------------------------------------------------------------- /rules/utils/is-shorthand-import-local.js: -------------------------------------------------------------------------------- 1 | import hasSameRange from './has-same-range.js'; 2 | 3 | const isShorthandImportLocal = node => { 4 | const {type, local, imported} = node.parent; 5 | return type === 'ImportSpecifier' && hasSameRange(local, imported) && local === node; 6 | }; 7 | 8 | export default isShorthandImportLocal; 9 | -------------------------------------------------------------------------------- /rules/utils/is-shorthand-property-assignment-pattern-left.js: -------------------------------------------------------------------------------- 1 | import isShorthandPropertyValue from './is-shorthand-property-value.js'; 2 | 3 | const isShorthandPropertyAssignmentPatternLeft = identifier => 4 | identifier.parent.type === 'AssignmentPattern' 5 | && identifier.parent.left === identifier 6 | && isShorthandPropertyValue(identifier.parent); 7 | 8 | export default isShorthandPropertyAssignmentPatternLeft; 9 | -------------------------------------------------------------------------------- /rules/utils/is-shorthand-property-value.js: -------------------------------------------------------------------------------- 1 | const isShorthandPropertyValue = identifier => 2 | identifier.parent.type === 'Property' 3 | && identifier.parent.shorthand 4 | && identifier === identifier.parent.value; 5 | 6 | export default isShorthandPropertyValue; 7 | -------------------------------------------------------------------------------- /rules/utils/is-value-not-usable.js: -------------------------------------------------------------------------------- 1 | import {isExpressionStatement} from '../ast/index.js'; 2 | 3 | const isValueNotUsable = node => isExpressionStatement(node.parent); 4 | 5 | export default isValueNotUsable; 6 | -------------------------------------------------------------------------------- /rules/utils/resolve-variable-name.js: -------------------------------------------------------------------------------- 1 | /** 2 | Finds a variable named `name` in the scope `scope` (or it's parents). 3 | 4 | @param {string} name - The variable name to be resolve. 5 | @param {import('eslint').Scope.Scope} scope - The scope to look for the variable in. 6 | @returns {import('eslint').Scope.Variable | void} - The found variable, if any. 7 | */ 8 | export default function resolveVariableName(name, scope) { 9 | while (scope) { 10 | const variable = scope.set.get(name); 11 | 12 | if (variable) { 13 | return variable; 14 | } 15 | 16 | scope = scope.upper; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-await-expression-argument.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if parentheses should be added to a `node` when it's used as `argument` of `AwaitExpression`. 3 | 4 | @param {Node} node - The AST node to check. 5 | @returns {boolean} 6 | */ 7 | export default function shouldAddParenthesesToAwaitExpressionArgument(node) { 8 | return ( 9 | node.type === 'SequenceExpression' 10 | || node.type === 'YieldExpression' 11 | || node.type === 'ArrowFunctionExpression' 12 | || node.type === 'ConditionalExpression' 13 | || node.type === 'AssignmentExpression' 14 | || node.type === 'LogicalExpression' 15 | || node.type === 'BinaryExpression' 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-call-expression-callee.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if parentheses should be added to a `node` when it's used as `callee` of `CallExpression`. 3 | 4 | @param {Node} node - The AST node to check. 5 | @returns {boolean} 6 | */ 7 | export default function shouldAddParenthesesToCallExpressionCallee(node) { 8 | return node.type === 'SequenceExpression' 9 | || node.type === 'YieldExpression' 10 | || node.type === 'ArrowFunctionExpression' 11 | || node.type === 'ConditionalExpression' 12 | || node.type === 'AssignmentExpression' 13 | || node.type === 'LogicalExpression' 14 | || node.type === 'BinaryExpression' 15 | || node.type === 'UnaryExpression' 16 | || node.type === 'UpdateExpression' 17 | || node.type === 'NewExpression'; 18 | } 19 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-conditional-expression-child.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if parentheses should be added to a `node` when it's used as child of `ConditionalExpression`. 3 | 4 | @param {Node} node - The AST node to check. 5 | @returns {boolean} 6 | */ 7 | export default function shouldAddParenthesesToConditionalExpressionChild(node) { 8 | return node.type === 'AwaitExpression' 9 | // Lower precedence, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 10 | || node.type === 'AssignmentExpression' 11 | || node.type === 'YieldExpression' 12 | || node.type === 'SequenceExpression'; 13 | } 14 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-expression-statement-expression.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if parentheses should to be added to a `node` when it's used as an `expression` of `ExpressionStatement`. 3 | 4 | @param {Node} node - The AST node to check. 5 | @param {SourceCode} sourceCode - The source code object. 6 | @returns {boolean} 7 | */ 8 | export default function shouldAddParenthesesToExpressionStatementExpression(node) { 9 | switch (node.type) { 10 | case 'ObjectExpression': { 11 | return true; 12 | } 13 | 14 | case 'AssignmentExpression': { 15 | return node.left.type === 'ObjectPattern' || node.left.type === 'ArrayPattern'; 16 | } 17 | 18 | default: { 19 | return false; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-logical-expression-child.js: -------------------------------------------------------------------------------- 1 | /** 2 | Check if parentheses should be added to a `node` when it's used as child of `LogicalExpression`. 3 | @param {Node} node - The AST node to check. 4 | @param {{operator: string, property: string}} options - Options 5 | @returns {boolean} 6 | */ 7 | export default function shouldAddParenthesesToLogicalExpressionChild(node, {operator, property}) { 8 | // We are not using this, but we can improve this function with it 9 | /* c8 ignore next 3 */ 10 | if (!property) { 11 | throw new Error('`property` is required.'); 12 | } 13 | 14 | if ( 15 | node.type === 'LogicalExpression' 16 | && node.operator === operator 17 | ) { 18 | return false; 19 | } 20 | 21 | // Not really needed, but more readable 22 | if ( 23 | node.type === 'AwaitExpression' 24 | || node.type === 'BinaryExpression' 25 | ) { 26 | return true; 27 | } 28 | 29 | // Lower precedence than `LogicalExpression` 30 | // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 31 | if ( 32 | node.type === 'LogicalExpression' 33 | || node.type === 'ConditionalExpression' 34 | || node.type === 'AssignmentExpression' 35 | || node.type === 'ArrowFunctionExpression' 36 | || node.type === 'YieldExpression' 37 | || node.type === 'SequenceExpression' 38 | ) { 39 | return true; 40 | } 41 | 42 | return false; 43 | } 44 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-member-expression-object.js: -------------------------------------------------------------------------------- 1 | import isNewExpressionWithParentheses from './is-new-expression-with-parentheses.js'; 2 | import {isDecimalIntegerNode} from './numeric.js'; 3 | 4 | /** 5 | Check if parentheses should to be added to a `node` when it's used as an `object` of `MemberExpression`. 6 | 7 | @param {Node} node - The AST node to check. 8 | @param {SourceCode} sourceCode - The source code object. 9 | @returns {boolean} 10 | */ 11 | export default function shouldAddParenthesesToMemberExpressionObject(node, sourceCode) { 12 | switch (node.type) { 13 | // This is not a full list. Some other nodes like `FunctionDeclaration` don't need parentheses, 14 | // but it's not possible to be in the place we are checking at this point. 15 | case 'Identifier': 16 | case 'MemberExpression': 17 | case 'CallExpression': 18 | case 'ChainExpression': 19 | case 'TemplateLiteral': 20 | case 'ThisExpression': 21 | case 'ArrayExpression': 22 | case 'FunctionExpression': { 23 | return false; 24 | } 25 | 26 | case 'NewExpression': { 27 | return !isNewExpressionWithParentheses(node, sourceCode); 28 | } 29 | 30 | case 'Literal': { 31 | /* c8 ignore next */ 32 | if (isDecimalIntegerNode(node)) { 33 | return true; 34 | } 35 | 36 | return false; 37 | } 38 | 39 | default: { 40 | return true; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rules/utils/should-add-parentheses-to-new-expression-callee.js: -------------------------------------------------------------------------------- 1 | // Copied from https://github.com/eslint/eslint/blob/aa87329d919f569404ca573b439934552006572f/lib/rules/no-extra-parens.js#L448 2 | /** 3 | Check if a member expression contains a call expression. 4 | 5 | @param {ASTNode} node - The `MemberExpression` node to evaluate. 6 | @returns {boolean} true if found, false if not. 7 | */ 8 | function doesMemberExpressionContainCallExpression(node) { 9 | let currentNode = node.object; 10 | let currentNodeType = node.object.type; 11 | 12 | while (currentNodeType === 'MemberExpression') { 13 | currentNode = currentNode.object; 14 | currentNodeType = currentNode.type; 15 | } 16 | 17 | return currentNodeType === 'CallExpression'; 18 | } 19 | 20 | /** 21 | Check if parentheses should be added to a `node` when it's used as `callee` of `NewExpression`. 22 | 23 | @param {Node} node - The AST node to check. 24 | @returns {boolean} 25 | */ 26 | export default function shouldAddParenthesesToNewExpressionCallee(node) { 27 | return node.type === 'MemberExpression' && doesMemberExpressionContainCallExpression(node); 28 | } 29 | -------------------------------------------------------------------------------- /rules/utils/singular.js: -------------------------------------------------------------------------------- 1 | import pluralize_ from 'pluralize'; 2 | 3 | /** 4 | Singularizes a word/name, i.e. `items` to `item`. 5 | 6 | @param {string} original - The word/name to singularize. 7 | @returns {string|undefined} - The singularized result, or `undefined` if attempting singularization resulted in no change. 8 | */ 9 | const singular = original => { 10 | const singularized = pluralize_.singular(original); 11 | if (singularized !== original) { 12 | return singularized; 13 | } 14 | }; 15 | 16 | export default singular; 17 | -------------------------------------------------------------------------------- /rules/utils/string-cases.js: -------------------------------------------------------------------------------- 1 | export const upperFirst = string => string.charAt(0).toUpperCase() + string.slice(1); 2 | export const lowerFirst = string => string.charAt(0).toLowerCase() + string.slice(1); 3 | -------------------------------------------------------------------------------- /rules/utils/to-location.js: -------------------------------------------------------------------------------- 1 | /** 2 | Get location info for the given node or range. 3 | 4 | @param {import('estree').Node | number[]} nodeOrRange - The AST node or range to get the location for. 5 | @param {import('eslint').SourceCode} sourceCode - The source code object. 6 | @param {int} [startOffset] - Start position offset. 7 | @param {int} [endOffset] - End position offset. 8 | @returns {import('estree').SourceLocation} 9 | */ 10 | function toLocation(nodeOrRange, sourceCode, startOffset = 0, endOffset = 0) { 11 | const [start, end] = Array.isArray(nodeOrRange) ? nodeOrRange : sourceCode.getRange(nodeOrRange); 12 | 13 | return { 14 | start: sourceCode.getLocFromIndex(start + startOffset), 15 | end: sourceCode.getLocFromIndex(end + endOffset), 16 | }; 17 | } 18 | 19 | export default toLocation; 20 | -------------------------------------------------------------------------------- /scripts/create-rules-index-file.js: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs'; 2 | import path from 'node:path'; 3 | 4 | const DIRECTORY = new URL('../rules/', import.meta.url); 5 | 6 | const files = fs.readdirSync(DIRECTORY, {withFileTypes: true}) 7 | .filter(file => file.isFile() && file.name.endsWith('.js') && file.name !== 'index.js') 8 | .map(file => file.name) 9 | .sort(); 10 | 11 | const content = files 12 | .map(file => `export {default as '${path.basename(file, '.js')}'} from './${file}';`) 13 | .join('\n'); 14 | 15 | fs.writeFileSync( 16 | new URL('index.js', DIRECTORY), 17 | '// Generated file, DO NOT edit\n\n' + content + '\n', 18 | ); 19 | -------------------------------------------------------------------------------- /scripts/internal-rules/prefer-fixer-remove-range.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import {fileURLToPath} from 'node:url'; 3 | import {isMethodCall, isLiteral} from '../../rules/ast/index.js'; 4 | import {removeArgument} from '../../rules/fix/index.js'; 5 | 6 | const messageId = path.basename(fileURLToPath(import.meta.url), '.js'); 7 | 8 | const config = { 9 | create(context) { 10 | return { 11 | CallExpression(callExpression) { 12 | const [, emptyString] = callExpression.arguments; 13 | 14 | if (!( 15 | isMethodCall(callExpression, { 16 | object: 'fixer', 17 | method: 'replaceTextRange', 18 | argumentsLength: 2, 19 | optionalCall: false, 20 | optionalMember: false, 21 | }) 22 | && isLiteral(emptyString, '') 23 | )) { 24 | return; 25 | } 26 | 27 | const {property} = callExpression.callee; 28 | context.report({ 29 | node: property, 30 | messageId, 31 | * fix(fixer) { 32 | yield removeArgument(fixer, emptyString, context.sourceCode); 33 | yield fixer.replaceText(property, 'removeRange'); 34 | }, 35 | }); 36 | }, 37 | }; 38 | }, 39 | meta: { 40 | fixable: 'code', 41 | messages: { 42 | [messageId]: 'Prefer `fixer.removeRange(…)` over `fixer.replaceTextRange(…, \'\')`.', 43 | }, 44 | }, 45 | }; 46 | 47 | export default config; 48 | -------------------------------------------------------------------------------- /scripts/internal-rules/prefer-negative-boolean-attribute.js: -------------------------------------------------------------------------------- 1 | import path from 'node:path'; 2 | import {fileURLToPath} from 'node:url'; 3 | 4 | const messageId = path.basename(fileURLToPath(import.meta.url), '.js'); 5 | 6 | const shouldReport = (string, value) => { 7 | const index = string.indexOf(`=${value}]`); 8 | 9 | if (index === -1) { 10 | return false; 11 | } 12 | 13 | return string[index - 1] !== '!'; 14 | }; 15 | 16 | const config = { 17 | create(context) { 18 | return { 19 | 'TemplateElement, Literal'(node) { 20 | const string = node.value; 21 | if (typeof string !== 'string') { 22 | return; 23 | } 24 | 25 | for (const value of [true, false]) { 26 | if (shouldReport(string, value)) { 27 | context.report({ 28 | node, 29 | messageId, 30 | data: { 31 | preferred: String(!value), 32 | }, 33 | }); 34 | } 35 | } 36 | }, 37 | }; 38 | }, 39 | meta: { 40 | messages: { 41 | [messageId]: 'Prefer use `[…!={{preferred}}]` in esquery selector.', 42 | }, 43 | }, 44 | }; 45 | 46 | export default config; 47 | -------------------------------------------------------------------------------- /scripts/template/documentation.md.jst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ## Examples 7 | 8 | ```js 9 | // ❌ 10 | const foo = 'unicorn'; 11 | 12 | // ✅ 13 | const foo = '🦄'; 14 | ``` 15 | 16 | ```js 17 | // ❌ 18 | function foo() { 19 | var replace = 'me'; 20 | return replace; 21 | } 22 | 23 | // ✅ 24 | function foo() { 25 | return 'me'; 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /scripts/template/test.js.jst: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'const foo = "🦄";', 9 | ], 10 | invalid: [ 11 | 'const foo = "unicorn";', 12 | ], 13 | }); 14 | -------------------------------------------------------------------------------- /test/consistent-date-clone.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'new Date(date)', 9 | 'date.getTime()', 10 | 'new Date(...date.getTime())', 11 | 'new Date(getTime())', 12 | 'new Date(date.getTime(), extraArgument)', 13 | 'new Date(date.not_getTime())', 14 | 'new Date(date?.getTime())', 15 | 'new NotDate(date.getTime())', 16 | 'new Date(date[getTime]())', 17 | 'new Date(date.getTime(extraArgument))', 18 | 'Date(date.getTime())', 19 | // We may support these cases in future, https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2437 20 | outdent` 21 | new Date( 22 | date.getFullYear(), 23 | date.getMonth(), 24 | date.getDate(), 25 | date.getHours(), 26 | date.getMinutes(), 27 | date.getSeconds(), 28 | date.getMilliseconds(), 29 | ); 30 | `, 31 | outdent` 32 | new Date( 33 | date.getFullYear(), 34 | date.getMonth(), 35 | date.getDate(), 36 | date.getHours(), 37 | date.getMinutes(), 38 | date.getSeconds(), 39 | ); 40 | `, 41 | ], 42 | invalid: [ 43 | 'new Date(date.getTime())', 44 | 'new Date(date.getTime(),)', 45 | 'new Date((0, date).getTime())', 46 | 'new Date(date.getTime(/* comment */))', 47 | 'new Date(date./* comment */getTime())', 48 | ], 49 | }); 50 | -------------------------------------------------------------------------------- /test/consistent-empty-array-spread.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | '[,,,]', 9 | '[...(test ? [] : [a, b])]', 10 | '[...(test ? [a, b] : [])]', 11 | '[...(test ? "" : "ab")]', 12 | '[...(test ? "ab" : "")]', 13 | '[...(test ? "" : unknown)]', 14 | '[...(test ? unknown : "")]', 15 | '[...(test ? [] : unknown)]', 16 | '[...(test ? unknown : [])]', 17 | '_ = {...(test ? "" : [a, b])}', 18 | '_ = {...(test ? [] : "ab")}', 19 | 'call(...(test ? "" : [a, b]))', 20 | 'call(...(test ? [] : "ab"))', 21 | '[...(test ? "ab" : [a, b])]', 22 | // Not checking 23 | 'const EMPTY_STRING = ""; [...(test ? EMPTY_STRING : [a, b])]', 24 | ], 25 | invalid: [ 26 | outdent` 27 | [ 28 | ...(test ? [] : "ab"), 29 | ...(test ? "ab" : []), 30 | ]; 31 | `, 32 | outdent` 33 | const STRING = "ab"; 34 | [ 35 | ...(test ? [] : STRING), 36 | ...(test ? STRING : []), 37 | ]; 38 | `, 39 | outdent` 40 | [ 41 | ...(test ? "" : [a, b]), 42 | ...(test ? [a, b] : ""), 43 | ]; 44 | `, 45 | outdent` 46 | const ARRAY = ["a", "b"]; 47 | [ 48 | /* hole */, 49 | ...(test ? "" : ARRAY), 50 | /* hole */, 51 | ...(test ? ARRAY : ""), 52 | /* hole */, 53 | ]; 54 | `, 55 | '[...(foo ? "" : [])]', 56 | ], 57 | }); 58 | -------------------------------------------------------------------------------- /test/integration/fixtures-local/conflicts-no-array-for-each-and-prevent-abbreviations.js: -------------------------------------------------------------------------------- 1 | const btn = bar; 2 | foo.forEach(btn => click(btn)) 3 | -------------------------------------------------------------------------------- /test/integration/fixtures-local/error-name-conflicts.js: -------------------------------------------------------------------------------- 1 | function foo() { 2 | try { 3 | } catch (err) { 4 | console.log(err); 5 | 6 | if (test) { 7 | throw a; 8 | } else { 9 | throw b; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/integration/readme.md: -------------------------------------------------------------------------------- 1 | # Integration tests 2 | 3 | To run the integration tests, go to the project root, and run `$ npm run integration`. 4 | 5 | To run tests on specific projects, run `$ npm run integration projectName1 projectName2 … projectNameN`. The project names can be found in [`projects.js`](projects.js). 6 | -------------------------------------------------------------------------------- /test/no-document-cookie.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'document.cookie', 9 | 'const foo = document.cookie', 10 | 'foo = document.cookie', 11 | 'foo = document?.cookie', 12 | 'foo = document.cookie + ";foo=bar"', 13 | 'delete document.cookie', 14 | 'if (document.cookie.includes("foo")){}', 15 | 'Object.assign(document, {cookie: "foo=bar"})', 16 | 'document[CONSTANTS_COOKIE] = "foo=bar"', 17 | 'document[cookie] = "foo=bar"', 18 | outdent` 19 | const CONSTANTS_COOKIE = "cookie"; 20 | document[CONSTANTS_COOKIE] = "foo=bar"; 21 | `, 22 | ], 23 | invalid: [ 24 | 'document.cookie = "foo=bar"', 25 | 'document.cookie += ";foo=bar"', 26 | 'document.cookie = document.cookie + ";foo=bar"', 27 | 'document.cookie &&= true', 28 | 'document["coo" + "kie"] = "foo=bar"', 29 | 'foo = document.cookie = "foo=bar"', 30 | 'var doc = document; doc.cookie = "foo=bar"', 31 | 'let doc = document; doc.cookie = "foo=bar"', 32 | 'const doc = globalThis.document; doc.cookie = "foo=bar"', 33 | 'window.document.cookie = "foo=bar"', 34 | ], 35 | }); 36 | -------------------------------------------------------------------------------- /test/no-magic-array-flat-depth.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | 'array.flat(1)', 8 | 'array.flat(1.0)', 9 | 'array.flat(0x01)', 10 | 'array.flat(unknown)', 11 | 'array.flat(Number.POSITIVE_INFINITY)', 12 | 'array.flat(Infinity)', 13 | 'array.flat(/* explanation */2)', 14 | 'array.flat(2/* explanation */)', 15 | 'array.flat()', 16 | 'array.flat(2, extraArgument)', 17 | 'new array.flat(2)', 18 | 'array.flat?.(2)', 19 | 'array.notFlat(2)', 20 | 'flat(2)', 21 | ], 22 | invalid: [ 23 | 'array.flat(2)', 24 | 'array?.flat(2)', 25 | 'array.flat(99,)', 26 | 'array.flat(0b10,)', 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /test/no-negation-in-equality-check.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | '!foo instanceof bar', 9 | '+foo === bar', 10 | '!(foo === bar)', 11 | '!!foo === bar', 12 | '!!!foo === bar', 13 | // We are not checking right side 14 | 'foo === !bar', 15 | ], 16 | invalid: [ 17 | '!foo === bar', 18 | '!foo !== bar', 19 | '!foo == bar', 20 | '!foo != bar', 21 | outdent` 22 | function x() { 23 | return!foo === bar; 24 | } 25 | `, 26 | outdent` 27 | function x() { 28 | return! 29 | foo === bar; 30 | throw! 31 | foo === bar; 32 | } 33 | `, 34 | outdent` 35 | foo 36 | !(a) === b 37 | `, 38 | outdent` 39 | foo 40 | ![a, b].join('') === c 41 | `, 42 | outdent` 43 | foo 44 | ! [a, b].join('') === c 45 | `, 46 | outdent` 47 | foo 48 | !/* comment */[a, b].join('') === c 49 | `, 50 | ], 51 | }); 52 | -------------------------------------------------------------------------------- /test/no-this-assignment.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'const {property} = this;', 9 | 'const property = this.property;', 10 | 'const [element] = this;', 11 | 'const element = this[0];', 12 | '([element] = this);', 13 | 'element = this[0];', 14 | 'property = this.property;', 15 | 'const [element] = [this];', 16 | '([element] = [this]);', 17 | 'const {property} = {property: this};', 18 | '({property} = {property: this});', 19 | 'const self = true && this;', 20 | 'const self = false || this;', 21 | 'const self = false ?? this;', 22 | 'foo.bar = this;', 23 | 'function foo(a = this) {}', 24 | 'function foo({a = this}) {}', 25 | 'function foo([a = this]) {}', 26 | ], 27 | invalid: [ 28 | 'const foo = this;', 29 | 'let foo;foo = this;', 30 | 'var foo = bar, baz = this;', 31 | ], 32 | }); 33 | 34 | test.babel({ 35 | valid: [ 36 | outdent` 37 | class A { 38 | foo = this; 39 | } 40 | `, 41 | outdent` 42 | class A { 43 | static foo = this; 44 | } 45 | `, 46 | ], 47 | invalid: [], 48 | }); 49 | -------------------------------------------------------------------------------- /test/no-unnecessary-array-flat-depth.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | 'foo.flat()', 8 | 'foo.flat?.(1)', 9 | 'foo?.flat()', 10 | 'foo.flat(1, extra)', 11 | 'flat(1)', 12 | 'new foo.flat(1)', 13 | 'const ONE = 1; foo.flat(ONE)', 14 | 'foo.notFlat(1)', 15 | ], 16 | invalid: [ 17 | 'foo.flat(1)', 18 | 'foo.flat(1.0)', 19 | 'foo.flat(0b01)', 20 | 'foo?.flat(1)', 21 | ], 22 | }); 23 | -------------------------------------------------------------------------------- /test/no-unnecessary-array-splice-count.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | import {createFixtures} from './shared/no-unnecessary-length-or-infinity-rule-tests.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot(createFixtures('splice')); 7 | test.snapshot(createFixtures('toSpliced')); 8 | -------------------------------------------------------------------------------- /test/no-unnecessary-slice-end.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | import {createFixtures} from './shared/no-unnecessary-length-or-infinity-rule-tests.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot(createFixtures('slice')); 7 | -------------------------------------------------------------------------------- /test/no-unreadable-iife.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'const foo = (bar => bar)();', 9 | outdent` 10 | const foo = (() => { 11 | return a ? b : c 12 | })(); 13 | `, 14 | ], 15 | invalid: [ 16 | 'const foo = (() => (a ? b : c))();', 17 | outdent` 18 | const foo = (() => ( 19 | a ? b : c 20 | ))(); 21 | `, 22 | outdent` 23 | const foo = ( 24 | () => ( 25 | a ? b : c 26 | ) 27 | )(); 28 | `, 29 | outdent` 30 | const foo = (() => ( 31 | a, b 32 | ))(); 33 | `, 34 | outdent` 35 | const foo = (() => ({ 36 | a: b, 37 | }))(); 38 | `, 39 | 'const foo = (bar => (bar))();', 40 | outdent` 41 | (async () => ({ 42 | bar, 43 | }))(); 44 | `, 45 | outdent` 46 | const foo = (async (bar) => ({ 47 | bar: await baz(), 48 | }))(); 49 | `, 50 | '(async () => (( {bar} )))();', 51 | ], 52 | }); 53 | -------------------------------------------------------------------------------- /test/prefer-array-index-of.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | import createSimpleArraySearchRuleTestFixtures from './shared/simple-array-search-rule-tests.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | const indexOfOverFindIndexFixtures = createSimpleArraySearchRuleTestFixtures({ 7 | method: 'findIndex', 8 | replacement: 'indexOf', 9 | }); 10 | 11 | test.snapshot(indexOfOverFindIndexFixtures.snapshot); 12 | test.typescript(indexOfOverFindIndexFixtures.typescript); 13 | 14 | const lastIndexOfOverFindLastIndexFixtures = createSimpleArraySearchRuleTestFixtures({ 15 | method: 'findLastIndex', 16 | replacement: 'lastIndexOf', 17 | }); 18 | 19 | test.snapshot(lastIndexOfOverFindLastIndexFixtures.snapshot); 20 | test.typescript(lastIndexOfOverFindLastIndexFixtures.typescript); 21 | -------------------------------------------------------------------------------- /test/prefer-blob-reading-methods.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | 'blob.arrayBuffer()', 8 | 'blob.text()', 9 | 'new Response(blob).arrayBuffer()', 10 | 'new Response(blob).text()', 11 | 'fileReader.readAsDataURL(blob)', 12 | 'fileReader.readAsBinaryString(blob)', 13 | 'fileReader.readAsText(blob, "ascii")', 14 | ], 15 | invalid: [ 16 | 'fileReader.readAsArrayBuffer(blob)', 17 | 'fileReader.readAsText(blob)', 18 | ], 19 | }); 20 | -------------------------------------------------------------------------------- /test/prefer-code-point.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | '"🦄".codePointAt(0)', 8 | 'foo.charCodeAt', 9 | 'new foo.charCodeAt', 10 | 'charCodeAt(0)', 11 | 'foo.charCodeAt?.(0)', 12 | 'foo?.charCodeAt(0)', 13 | 'foo[charCodeAt](0)', 14 | 'foo["charCodeAt"](0)', 15 | 'foo.notCharCodeAt(0)', 16 | 17 | 'String.fromCodePoint(0x1f984)', 18 | 'String.fromCodePoint', 19 | 'new String.fromCodePoint', 20 | 'fromCodePoint(foo)', 21 | 'String.fromCodePoint?.(foo)', 22 | 'String?.fromCodePoint(foo)', 23 | 'window.String.fromCodePoint(foo)', 24 | 'String[fromCodePoint](foo)', 25 | 'String["fromCodePoint"](foo)', 26 | 'String.notFromCodePoint(foo)', 27 | 'NotString.fromCodePoint(foo)', 28 | ], 29 | invalid: [ 30 | 'string.charCodeAt(index)', 31 | '(( (( string )).charCodeAt( ((index)), )))', 32 | 'String.fromCharCode( code )', 33 | '(( (( String )).fromCharCode( ((code)), ) ))', 34 | ], 35 | }); 36 | -------------------------------------------------------------------------------- /test/prefer-dom-node-text-content.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | 'innerText;', 8 | 'node.textContent;', 9 | 'node[innerText];', 10 | 'innerText = true;', 11 | 'node[\'innerText\'];', 12 | 'innerText.textContent', 13 | 'const [innerText] = node;', 14 | '[innerText] = node;', 15 | 'const {[innerText]: text} = node;', 16 | '({[innerText]: text} = node);', 17 | 'const foo = {innerText}', 18 | 'const foo = {innerText: text}', 19 | ], 20 | invalid: [ 21 | 'node.innerText;', 22 | 'node?.innerText;', 23 | 'node.innerText = \'foo\';', 24 | 'innerText.innerText;', 25 | 'const {innerText} = node;', 26 | 'const {innerText,} = node;', 27 | 'const {innerText: text} = node;', 28 | 'const {innerText = "default text"} = node;', 29 | 'const {innerText: text = "default text"} = node;', 30 | '({innerText} = node);', 31 | '({innerText: text} = node);', 32 | '({innerText = "default text"} = node);', 33 | '({innerText: text = "default text"} = node);', 34 | 'function foo({innerText}) {return innerText}', 35 | 'for (const [{innerText}] of elements);', 36 | ], 37 | }); 38 | -------------------------------------------------------------------------------- /test/prefer-logical-operator-over-ternary.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'foo ? foo1 : bar;', 9 | 'foo.bar ? foo.bar1 : foo.baz', 10 | 'foo.bar ? foo1.bar : foo.baz', 11 | '++foo ? ++foo : bar;', 12 | 13 | // Not checking 14 | '!!bar ? foo : bar;', 15 | ], 16 | invalid: [ 17 | 'foo ? foo : bar;', 18 | 'foo.bar ? foo.bar : foo.baz', 19 | 'foo?.bar ? foo.bar : baz', 20 | '!bar ? foo : bar;', 21 | '!!bar ? foo : !bar;', 22 | 23 | 'foo() ? foo() : bar', 24 | 25 | // Children parentheses 26 | 'foo ? foo : a && b', 27 | 'foo ? foo : a || b', 28 | 'foo ? foo : a ?? b', 29 | 'a && b ? a && b : bar', 30 | 'a || b ? a || b : bar', 31 | 'a ?? b ? a ?? b : bar', 32 | 'foo ? foo : await a', 33 | 'await a ? await a : foo', 34 | 35 | // ASI 36 | outdent` 37 | const foo = [] 38 | !+a ? b : +a 39 | `, 40 | outdent` 41 | const foo = [] 42 | a && b ? a && b : 1 43 | `, 44 | ], 45 | }); 46 | -------------------------------------------------------------------------------- /test/prefer-string-trim-start-end.js: -------------------------------------------------------------------------------- 1 | import outdent from 'outdent'; 2 | import {getTester} from './utils/test.js'; 3 | 4 | const {test} = getTester(import.meta); 5 | 6 | test.snapshot({ 7 | valid: [ 8 | 'foo.trimStart()', 9 | 'foo.trimStart?.()', 10 | 'foo.trimEnd()', 11 | // Not `CallExpression` 12 | 'new foo.trimLeft();', 13 | // Not `MemberExpression` 14 | 'trimLeft();', 15 | // `callee.property` is not a `Identifier` 16 | 'foo[\'trimLeft\']();', 17 | // Computed 18 | 'foo[trimLeft]();', 19 | // Not `trimLeft`/`trimRight` 20 | 'foo.bar();', 21 | // More argument(s) 22 | 'foo.trimLeft(extra);', 23 | 'foo.trimLeft(...argumentsArray)', 24 | // `trimLeft` is in argument 25 | 'foo.bar(trimLeft)', 26 | 'foo.bar(foo.trimLeft)', 27 | // `trimLeft` is in `MemberExpression.object` 28 | 'trimLeft.foo()', 29 | 'foo.trimLeft.bar()', 30 | ], 31 | invalid: [ 32 | 'foo.trimLeft()', 33 | 'foo.trimRight()', 34 | 'trimLeft.trimRight()', 35 | 'foo.trimLeft.trimRight()', 36 | '"foo".trimLeft()', 37 | outdent` 38 | foo 39 | // comment 40 | .trimRight/* comment */( 41 | /* comment */ 42 | ) 43 | `, 44 | 'foo?.trimLeft()', 45 | ], 46 | }); 47 | -------------------------------------------------------------------------------- /test/require-number-to-fixed-digits-argument.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | 'number.toFixed(0)', 8 | 'number.toFixed(...[])', 9 | 'number.toFixed(2)', 10 | 'number.toFixed(1,2,3)', 11 | 'number[toFixed]()', 12 | 'number["toFixed"]()', 13 | 'number?.toFixed()', 14 | 'number.toFixed?.()', 15 | 'number.notToFixed();', 16 | 17 | // `callee` is a `NewExpression` 18 | 'new BigNumber(1).toFixed()', 19 | 'new Number(1).toFixed()', 20 | ], 21 | invalid: [ 22 | 'const string = number.toFixed();', 23 | 'const string = number.toFixed( /* comment */ );', 24 | 'Number(1).toFixed()', 25 | 26 | // False positive cases 27 | 'const bigNumber = new BigNumber(1); const string = bigNumber.toFixed();', 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /test/require-post-message-target-origin.js: -------------------------------------------------------------------------------- 1 | import {getTester} from './utils/test.js'; 2 | 3 | const {test} = getTester(import.meta); 4 | 5 | test.snapshot({ 6 | valid: [ 7 | 'window.postMessage(message, targetOrigin)', 8 | 'postMessage(message)', 9 | 'window.postMessage', 10 | 'window.postMessage()', 11 | 'window.postMessage(message, targetOrigin, transfer)', 12 | 'window.postMessage(...message)', 13 | 'window[postMessage](message)', 14 | 'window["postMessage"](message)', 15 | 'window.notPostMessage(message)', 16 | 'window.postMessage?.(message)', 17 | 'window?.postMessage(message)', 18 | ], 19 | invalid: [ 20 | 'window.postMessage(message)', 21 | 'self.postMessage(message)', 22 | 'globalThis.postMessage(message)', 23 | 'foo.postMessage(message )', 24 | 'foo.postMessage( ((message)) )', 25 | 'foo.postMessage(message,)', 26 | 'foo.postMessage(message , )', 27 | 'foo.window.postMessage(message)', 28 | 'document.defaultView.postMessage(message)', 29 | 'getWindow().postMessage(message)', 30 | ], 31 | }); 32 | -------------------------------------------------------------------------------- /test/snapshots/better-regex.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/better-regex.js` 2 | 3 | The actual snapshot is saved in `better-regex.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): /(?!a)+/g 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | /(?!a)+/g␊ 13 | ` 14 | 15 | > Error 1/1 16 | 17 | `␊ 18 | > 1 | /(?!a)+/g␊ 19 | | ^^^^^^^^^ Problem parsing /(?!a)+/g: ␊ 20 | ␊ 21 | /(?!a)+/g␊ 22 | ^␊ 23 | Unexpected token: "+" at 1:6.␊ 24 | ` 25 | -------------------------------------------------------------------------------- /test/snapshots/better-regex.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/better-regex.js.snap -------------------------------------------------------------------------------- /test/snapshots/consistent-assert.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/consistent-assert.js.snap -------------------------------------------------------------------------------- /test/snapshots/consistent-date-clone.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/consistent-date-clone.js.snap -------------------------------------------------------------------------------- /test/snapshots/consistent-empty-array-spread.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/consistent-empty-array-spread.js.snap -------------------------------------------------------------------------------- /test/snapshots/consistent-existence-index-check.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/consistent-existence-index-check.js.snap -------------------------------------------------------------------------------- /test/snapshots/consistent-function-scoping.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/consistent-function-scoping.js.snap -------------------------------------------------------------------------------- /test/snapshots/empty-brace-spaces.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/empty-brace-spaces.js` 2 | 3 | The actual snapshot is saved in `empty-brace-spaces.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): try { foo(); } catch (error) { } 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | try {␊ 13 | 2 | foo();␊ 14 | 3 | } catch (error) {␊ 15 | 4 | ␊ 16 | 5 | }␊ 17 | ` 18 | 19 | > Output 20 | 21 | `␊ 22 | 1 | try {␊ 23 | 2 | foo();␊ 24 | 3 | } catch (error) {}␊ 25 | ` 26 | 27 | > Error 1/1 28 | 29 | `␊ 30 | 1 | try {␊ 31 | 2 | foo();␊ 32 | > 3 | } catch (error) {␊ 33 | | ^␊ 34 | > 4 | ␊ 35 | | ^^^^^^^^␊ 36 | > 5 | }␊ 37 | | ^ Do not add spaces between braces.␊ 38 | ` 39 | -------------------------------------------------------------------------------- /test/snapshots/empty-brace-spaces.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/empty-brace-spaces.js.snap -------------------------------------------------------------------------------- /test/snapshots/error-message.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/error-message.js.snap -------------------------------------------------------------------------------- /test/snapshots/explicit-length-check.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/explicit-length-check.js.snap -------------------------------------------------------------------------------- /test/snapshots/filename-case.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/filename-case.js.snap -------------------------------------------------------------------------------- /test/snapshots/import-style.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/import-style.js.snap -------------------------------------------------------------------------------- /test/snapshots/new-for-builtins.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/new-for-builtins.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-abusive-eslint-disable.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-abusive-eslint-disable.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-accessor-recursion.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-accessor-recursion.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-anonymous-default-export.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-anonymous-default-export.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-array-callback-reference.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-array-callback-reference.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-array-for-each.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-array-for-each.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-array-method-this-argument.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-array-method-this-argument.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-await-expression-member.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-await-expression-member.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-await-in-promise-methods.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-await-in-promise-methods.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-console-spaces.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-console-spaces.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-document-cookie.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-document-cookie.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-empty-file.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-empty-file.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-for-loop.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-for-loop.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-hex-escape.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/no-hex-escape.js` 2 | 3 | The actual snapshot is saved in `no-hex-escape.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): const foo = "\xb1" 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | const foo = "\\xb1"␊ 13 | ` 14 | 15 | > Output 16 | 17 | `␊ 18 | 1 | const foo = "\\u00b1"␊ 19 | ` 20 | 21 | > Error 1/1 22 | 23 | `␊ 24 | > 1 | const foo = "\\xb1"␊ 25 | | ^^^^^^ Use Unicode escapes instead of hexadecimal escapes.␊ 26 | ` 27 | -------------------------------------------------------------------------------- /test/snapshots/no-hex-escape.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-hex-escape.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-instanceof-builtins.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-instanceof-builtins.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-invalid-fetch-options.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-invalid-fetch-options.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-invalid-remove-event-listener.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-invalid-remove-event-listener.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-lonely-if.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-lonely-if.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-magic-array-flat-depth.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/no-magic-array-flat-depth.js` 2 | 3 | The actual snapshot is saved in `no-magic-array-flat-depth.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): array.flat(2) 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | array.flat(2)␊ 13 | ` 14 | 15 | > Error 1/1 16 | 17 | `␊ 18 | > 1 | array.flat(2)␊ 19 | | ^ Magic number as depth is not allowed.␊ 20 | ` 21 | 22 | ## invalid(2): array?.flat(2) 23 | 24 | > Input 25 | 26 | `␊ 27 | 1 | array?.flat(2)␊ 28 | ` 29 | 30 | > Error 1/1 31 | 32 | `␊ 33 | > 1 | array?.flat(2)␊ 34 | | ^ Magic number as depth is not allowed.␊ 35 | ` 36 | 37 | ## invalid(3): array.flat(99,) 38 | 39 | > Input 40 | 41 | `␊ 42 | 1 | array.flat(99,)␊ 43 | ` 44 | 45 | > Error 1/1 46 | 47 | `␊ 48 | > 1 | array.flat(99,)␊ 49 | | ^^ Magic number as depth is not allowed.␊ 50 | ` 51 | 52 | ## invalid(4): array.flat(0b10,) 53 | 54 | > Input 55 | 56 | `␊ 57 | 1 | array.flat(0b10,)␊ 58 | ` 59 | 60 | > Error 1/1 61 | 62 | `␊ 63 | > 1 | array.flat(0b10,)␊ 64 | | ^^^^ Magic number as depth is not allowed.␊ 65 | ` 66 | -------------------------------------------------------------------------------- /test/snapshots/no-magic-array-flat-depth.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-magic-array-flat-depth.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-named-default.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-named-default.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-negated-condition.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-negated-condition.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-negation-in-equality-check.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-negation-in-equality-check.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-nested-ternary.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-nested-ternary.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-new-array.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-new-array.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-new-buffer.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-new-buffer.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-null.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-null.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-object-as-default-parameter.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-object-as-default-parameter.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-process-exit.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/no-process-exit.js` 2 | 3 | The actual snapshot is saved in `no-process-exit.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): process.exit(1); 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | process.exit(1);␊ 13 | ` 14 | 15 | > Error 1/1 16 | 17 | `␊ 18 | > 1 | process.exit(1);␊ 19 | | ^^^^^^^^^^^^^^^ Only use \`process.exit()\` in CLI apps. Throw an error instead.␊ 20 | ` 21 | -------------------------------------------------------------------------------- /test/snapshots/no-process-exit.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-process-exit.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-single-promise-in-promise-methods.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-single-promise-in-promise-methods.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-static-only-class.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-static-only-class.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-thenable.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-thenable.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-this-assignment.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/no-this-assignment.js` 2 | 3 | The actual snapshot is saved in `no-this-assignment.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): const foo = this; 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | const foo = this;␊ 13 | ` 14 | 15 | > Error 1/1 16 | 17 | `␊ 18 | > 1 | const foo = this;␊ 19 | | ^^^^^^^^^^ Do not assign \`this\` to \`foo\`.␊ 20 | ` 21 | 22 | ## invalid(2): let foo;foo = this; 23 | 24 | > Input 25 | 26 | `␊ 27 | 1 | let foo;foo = this;␊ 28 | ` 29 | 30 | > Error 1/1 31 | 32 | `␊ 33 | > 1 | let foo;foo = this;␊ 34 | | ^^^^^^^^^^ Do not assign \`this\` to \`foo\`.␊ 35 | ` 36 | 37 | ## invalid(3): var foo = bar, baz = this; 38 | 39 | > Input 40 | 41 | `␊ 42 | 1 | var foo = bar, baz = this;␊ 43 | ` 44 | 45 | > Error 1/1 46 | 47 | `␊ 48 | > 1 | var foo = bar, baz = this;␊ 49 | | ^^^^^^^^^^ Do not assign \`this\` to \`baz\`.␊ 50 | ` 51 | -------------------------------------------------------------------------------- /test/snapshots/no-this-assignment.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-this-assignment.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-typeof-undefined.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-typeof-undefined.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unnecessary-array-flat-depth.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unnecessary-array-flat-depth.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unnecessary-array-splice-count.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unnecessary-array-splice-count.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unnecessary-await.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unnecessary-await.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unnecessary-slice-end.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unnecessary-slice-end.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unreadable-array-destructuring.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unreadable-array-destructuring.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unreadable-iife.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unreadable-iife.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-unused-properties.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/no-unused-properties.js` 2 | 3 | The actual snapshot is saved in `no-unused-properties.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): function foo() { const bar = { b: 2, u: 3 }; console.log(bar.b); } 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | function foo() {␊ 13 | 2 | const bar = {␊ 14 | 3 | b: 2,␊ 15 | 4 | u: 3␊ 16 | 5 | };␊ 17 | 6 | console.log(bar.b);␊ 18 | 7 | }␊ 19 | ` 20 | 21 | > Error 1/1 22 | 23 | `␊ 24 | 1 | function foo() {␊ 25 | 2 | const bar = {␊ 26 | 3 | b: 2,␊ 27 | > 4 | u: 3␊ 28 | | ^^^^ Property \`u\` is defined but never used.␊ 29 | 5 | };␊ 30 | 6 | console.log(bar.b);␊ 31 | 7 | }␊ 32 | ` 33 | -------------------------------------------------------------------------------- /test/snapshots/no-unused-properties.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-unused-properties.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-useless-fallback-in-spread.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-useless-fallback-in-spread.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-useless-length-check.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-useless-length-check.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-useless-spread.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-useless-spread.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-useless-switch-case.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-useless-switch-case.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-useless-undefined.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-useless-undefined.js.snap -------------------------------------------------------------------------------- /test/snapshots/no-zero-fractions.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/no-zero-fractions.js.snap -------------------------------------------------------------------------------- /test/snapshots/number-literal-case.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/number-literal-case.js.snap -------------------------------------------------------------------------------- /test/snapshots/numeric-separators-style.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/numeric-separators-style.js` 2 | 3 | The actual snapshot is saved in `numeric-separators-style.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): console.log(0XdeEdBeeFn) 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | console.log(0XdeEdBeeFn)␊ 13 | ` 14 | 15 | > Output 16 | 17 | `␊ 18 | 1 | console.log(0Xde_Ed_Be_eFn)␊ 19 | ` 20 | 21 | > Error 1/1 22 | 23 | `␊ 24 | > 1 | console.log(0XdeEdBeeFn)␊ 25 | | ^^^^^^^^^^^ Invalid group length in numeric value.␊ 26 | ` 27 | 28 | ## invalid(2): const foo = 12345678..toString() 29 | 30 | > Input 31 | 32 | `␊ 33 | 1 | const foo = 12345678..toString()␊ 34 | ` 35 | 36 | > Output 37 | 38 | `␊ 39 | 1 | const foo = 12_345_678..toString()␊ 40 | ` 41 | 42 | > Error 1/1 43 | 44 | `␊ 45 | > 1 | const foo = 12345678..toString()␊ 46 | | ^^^^^^^^^ Invalid group length in numeric value.␊ 47 | ` 48 | -------------------------------------------------------------------------------- /test/snapshots/numeric-separators-style.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/numeric-separators-style.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-add-event-listener.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-add-event-listener.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-array-flat-map.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-array-flat-map.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-array-flat.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-array-flat.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-array-index-of.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-array-index-of.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-array-some.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-array-some.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-at.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-at.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-blob-reading-methods.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/prefer-blob-reading-methods.js` 2 | 3 | The actual snapshot is saved in `prefer-blob-reading-methods.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): fileReader.readAsArrayBuffer(blob) 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | fileReader.readAsArrayBuffer(blob)␊ 13 | ` 14 | 15 | > Error 1/1 16 | 17 | `␊ 18 | > 1 | fileReader.readAsArrayBuffer(blob)␊ 19 | | ^^^^^^^^^^^^^^^^^ Prefer \`Blob#arrayBuffer()\` over \`FileReader#readAsArrayBuffer(blob)\`.␊ 20 | ` 21 | 22 | ## invalid(2): fileReader.readAsText(blob) 23 | 24 | > Input 25 | 26 | `␊ 27 | 1 | fileReader.readAsText(blob)␊ 28 | ` 29 | 30 | > Error 1/1 31 | 32 | `␊ 33 | > 1 | fileReader.readAsText(blob)␊ 34 | | ^^^^^^^^^^ Prefer \`Blob#text()\` over \`FileReader#readAsText(blob)\`.␊ 35 | ` 36 | -------------------------------------------------------------------------------- /test/snapshots/prefer-blob-reading-methods.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-blob-reading-methods.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-code-point.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-code-point.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-date-now.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-date-now.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-dom-node-dataset.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-dom-node-dataset.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-dom-node-remove.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-dom-node-remove.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-dom-node-text-content.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-dom-node-text-content.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-event-target.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-event-target.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-export-from.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-export-from.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-global-this.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-global-this.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-import-meta-properties.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-import-meta-properties.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-includes.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-includes.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-json-parse-buffer.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-json-parse-buffer.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-keyboard-event-key.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-keyboard-event-key.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-logical-operator-over-ternary.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-logical-operator-over-ternary.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-math-min-max.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-math-min-max.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-math-trunc.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-math-trunc.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-modern-math-apis.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-modern-math-apis.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-module.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-module.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-native-coercion-functions.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-native-coercion-functions.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-negative-index.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-negative-index.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-node-protocol.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-node-protocol.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-number-properties.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-number-properties.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-object-from-entries.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-object-from-entries.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-optional-catch-binding.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-optional-catch-binding.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-prototype-methods.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-prototype-methods.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-query-selector.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-query-selector.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-regexp-test.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-regexp-test.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-set-has.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-set-has.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-set-size.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-set-size.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-single-call.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-single-call.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-spread.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-spread.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-string-raw.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-string-raw.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-string-replace-all.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-string-replace-all.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-string-slice.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-string-slice.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-string-starts-ends-with.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-string-starts-ends-with.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-string-trim-start-end.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-string-trim-start-end.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-structured-clone.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-structured-clone.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-switch.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-switch.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-top-level-await.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-top-level-await.js.snap -------------------------------------------------------------------------------- /test/snapshots/prefer-type-error.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/prefer-type-error.js` 2 | 3 | The actual snapshot is saved in `prefer-type-error.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): if (!isFinite(foo)) { throw new Error(); } 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | if (!isFinite(foo)) {␊ 13 | 2 | throw new Error();␊ 14 | 3 | }␊ 15 | ` 16 | 17 | > Output 18 | 19 | `␊ 20 | 1 | if (!isFinite(foo)) {␊ 21 | 2 | throw new TypeError();␊ 22 | 3 | }␊ 23 | ` 24 | 25 | > Error 1/1 26 | 27 | `␊ 28 | 1 | if (!isFinite(foo)) {␊ 29 | > 2 | throw new Error();␊ 30 | | ^^^^^ \`new Error()\` is too unspecific for a type check. Use \`new TypeError()\` instead.␊ 31 | 3 | }␊ 32 | ` 33 | -------------------------------------------------------------------------------- /test/snapshots/prefer-type-error.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/prefer-type-error.js.snap -------------------------------------------------------------------------------- /test/snapshots/relative-url-style.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/relative-url-style.js.snap -------------------------------------------------------------------------------- /test/snapshots/require-array-join-separator.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/require-array-join-separator.js.snap -------------------------------------------------------------------------------- /test/snapshots/require-number-to-fixed-digits-argument.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/require-number-to-fixed-digits-argument.js.snap -------------------------------------------------------------------------------- /test/snapshots/require-post-message-target-origin.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/require-post-message-target-origin.js.snap -------------------------------------------------------------------------------- /test/snapshots/switch-case-braces.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/switch-case-braces.js.snap -------------------------------------------------------------------------------- /test/snapshots/template-indent.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/template-indent.js` 2 | 3 | The actual snapshot is saved in `template-indent.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## invalid(1): expect(foo).toMatchInlineSnapshot(` one three ` ) 8 | 9 | > Input 10 | 11 | `␊ 12 | 1 | expect(foo).toMatchInlineSnapshot(\`␊ 13 | 2 | one␊ 14 | 3 | three␊ 15 | 4 | \`␊ 16 | 5 | )␊ 17 | ` 18 | 19 | > Output 20 | 21 | `␊ 22 | 1 | expect(foo).toMatchInlineSnapshot(\`␊ 23 | 2 | one␊ 24 | 3 | three␊ 25 | 4 | \`␊ 26 | 5 | )␊ 27 | ` 28 | 29 | > Error 1/1 30 | 31 | `␊ 32 | > 1 | expect(foo).toMatchInlineSnapshot(\`␊ 33 | | ^␊ 34 | > 2 | one␊ 35 | | ^^^^^^^␊ 36 | > 3 | three␊ 37 | | ^^^^^^^␊ 38 | > 4 | \`␊ 39 | | ^^^^^^^^ Templates should be properly indented.␊ 40 | 5 | )␊ 41 | ` 42 | -------------------------------------------------------------------------------- /test/snapshots/template-indent.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/template-indent.js.snap -------------------------------------------------------------------------------- /test/snapshots/text-encoding-identifier-case.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/text-encoding-identifier-case.js.snap -------------------------------------------------------------------------------- /test/snapshots/throw-new-error.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/snapshots/throw-new-error.js.snap -------------------------------------------------------------------------------- /test/unit/get-documentation-url.js: -------------------------------------------------------------------------------- 1 | import url from 'node:url'; 2 | import test from 'ava'; 3 | import getDocumentationUrl from '../../rules/utils/get-documentation-url.js'; 4 | import packageJson from '../../package.json' with {type: 'json'}; 5 | 6 | const filename = url.fileURLToPath(import.meta.url).replace(/\.js$/, '.js'); 7 | 8 | test('returns the URL of the a named rule\'s documentation', t => { 9 | const url = `https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v${packageJson.version}/docs/rules/foo.md`; 10 | t.is(getDocumentationUrl('foo.js'), url); 11 | }); 12 | 13 | test('determines the rule name from the file', t => { 14 | const url = `https://github.com/sindresorhus/eslint-plugin-unicorn/blob/v${packageJson.version}/docs/rules/get-documentation-url.md`; 15 | t.is(getDocumentationUrl(filename), url); 16 | }); 17 | -------------------------------------------------------------------------------- /test/unit/snapshots/assert-token.js.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/unit/assert-token.js` 2 | 3 | The actual snapshot is saved in `assert-token.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## Error message 8 | 9 | > Snapshot 1 10 | 11 | Error { 12 | message: `Expected token '{"value":"expectedValue"}' or '{"type":"expectedType"}', got '{"value":"b","type":"a"}'.␊ 13 | Please open an issue at https://github.com/sindresorhus/eslint-plugin-unicorn/issues/new?title=%60test-rule%60%3A%20Unexpected%20token%20'%7B%22value%22%3A%22b%22%2C%22type%22%3A%22a%22%7D'.`, 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/snapshots/assert-token.js.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/unit/snapshots/assert-token.js.snap -------------------------------------------------------------------------------- /test/unit/snapshots/assert-token.mjs.md: -------------------------------------------------------------------------------- 1 | # Snapshot report for `test/unit/assert-token.js` 2 | 3 | The actual snapshot is saved in `assert-token.js.snap`. 4 | 5 | Generated by [AVA](https://avajs.dev). 6 | 7 | ## Error message 8 | 9 | > Snapshot 1 10 | 11 | Error { 12 | message: `Expected token '{"value":"expectedValue"}' or '{"type":"expectedType"}', got '{"value":"b","type":"a"}'.␊ 13 | Please open an issue at https://github.com/sindresorhus/eslint-plugin-unicorn/issues/new?title=%60test-rule%60%3A%20Unexpected%20token%20'%7B%22value%22%3A%22b%22%2C%22type%22%3A%22a%22%7D'.`, 14 | } 15 | -------------------------------------------------------------------------------- /test/unit/snapshots/assert-token.mjs.snap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sindresorhus/eslint-plugin-unicorn/bc4dd3fe65ab411b8b7b53dd3d9c06d91c3c3cc3/test/unit/snapshots/assert-token.mjs.snap -------------------------------------------------------------------------------- /test/utils/default-options.js: -------------------------------------------------------------------------------- 1 | const defaultOptions = { 2 | languageOptions: { 3 | sourceType: 'module', 4 | }, 5 | }; 6 | 7 | export default defaultOptions; 8 | -------------------------------------------------------------------------------- /test/utils/not-dom-node-types.js: -------------------------------------------------------------------------------- 1 | const notDomNodeTypes = [ 2 | // ArrayExpression 3 | '[]', 4 | '[element]', 5 | '[...elements]', 6 | // ArrowFunctionExpression 7 | '() => {}', 8 | // ClassExpression 9 | 'class Node {}', 10 | // FunctionExpression 11 | 'function() {}', 12 | // Literal 13 | '0', 14 | '1', 15 | '0.1', 16 | '""', 17 | '"string"', 18 | '/regex/', 19 | 'null', 20 | '0n', 21 | '1n', 22 | 'true', 23 | 'false', 24 | // ObjectExpression 25 | '{}', 26 | // TemplateLiteral 27 | '`templateLiteral`', 28 | // Undefined 29 | 'undefined', 30 | ]; 31 | 32 | export default notDomNodeTypes; 33 | -------------------------------------------------------------------------------- /test/utils/not-function-types.js: -------------------------------------------------------------------------------- 1 | const notFunctionTypes = [ 2 | // ArrayExpression 3 | '[]', 4 | '[element]', 5 | '[...elements]', 6 | // BinaryExpression 7 | '1 + fn', 8 | '"length" in fn', 9 | 'fn instanceof Function', 10 | // ClassExpression 11 | 'class ClassCantUseAsFunction {}', 12 | // Literal 13 | '0', 14 | '1', 15 | '0.1', 16 | '""', 17 | '"string"', 18 | '/regex/', 19 | 'null', 20 | '0n', 21 | '1n', 22 | 'true', 23 | 'false', 24 | // ObjectExpression 25 | '{}', 26 | // TemplateLiteral 27 | '`templateLiteral`', 28 | // Undefined 29 | 'undefined', 30 | // UnaryExpression 31 | '- fn', 32 | '+ fn', 33 | '~ fn', 34 | 'typeof fn', 35 | 'void fn', 36 | 'delete foo.fn', 37 | // UpdateExpression 38 | '++ fn', 39 | '-- fn', 40 | 41 | // Following are not safe 42 | 'a = fn', // Could be a function 43 | // 'await fn', // This requires async function to test, ignore for now 44 | 'fn()', // Could be a factory returns a function 45 | 'new ClassReturnsFunction()', // `class` constructor could return a function 46 | 'new Function()', // `function` 47 | 'fn``', // Same as `CallExpression` 48 | 'this', // Could be a function 49 | ]; 50 | 51 | export default notFunctionTypes; 52 | --------------------------------------------------------------------------------