]> git.proxmox.com Git - pve-eslint.git/commitdiff
import 8.4.0 source
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 6 Dec 2021 13:02:55 +0000 (14:02 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 6 Dec 2021 13:02:55 +0000 (14:02 +0100)
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
393 files changed:
Makefile
eslint/.github/PULL_REQUEST_TEMPLATE.md
eslint/.github/workflows/ci.yml
eslint/.markdownlint.yml
eslint/.markdownlintignore
eslint/CHANGELOG.md
eslint/CONTRIBUTING.md
eslint/Makefile.js
eslint/README.md
eslint/conf/globals.js [new file with mode: 0644]
eslint/docs/developer-guide/code-path-analysis.md
eslint/docs/developer-guide/contributing/pull-requests.md
eslint/docs/developer-guide/development-environment.md
eslint/docs/developer-guide/nodejs-api.md
eslint/docs/developer-guide/shareable-configs.md
eslint/docs/developer-guide/working-with-custom-formatters.md
eslint/docs/developer-guide/working-with-rules.md
eslint/docs/rules/accessor-pairs.md
eslint/docs/rules/array-bracket-newline.md
eslint/docs/rules/array-callback-return.md
eslint/docs/rules/arrow-parens.md
eslint/docs/rules/callback-return.md
eslint/docs/rules/class-methods-use-this.md
eslint/docs/rules/comma-spacing.md
eslint/docs/rules/comma-style.md
eslint/docs/rules/function-call-argument-newline.md
eslint/docs/rules/getter-return.md
eslint/docs/rules/indent.md
eslint/docs/rules/line-comment-position.md
eslint/docs/rules/linebreak-style.md
eslint/docs/rules/lines-around-comment.md
eslint/docs/rules/max-lines-per-function.md
eslint/docs/rules/no-compare-neg-zero.md
eslint/docs/rules/no-constant-condition.md
eslint/docs/rules/no-empty-function.md
eslint/docs/rules/no-empty-label.md
eslint/docs/rules/no-implied-eval.md
eslint/docs/rules/no-loop-func.md
eslint/docs/rules/no-mixed-operators.md
eslint/docs/rules/no-mixed-spaces-and-tabs.md
eslint/docs/rules/no-multiple-empty-lines.md
eslint/docs/rules/no-param-reassign.md
eslint/docs/rules/no-process-env.md
eslint/docs/rules/no-restricted-imports.md
eslint/docs/rules/no-restricted-modules.md
eslint/docs/rules/no-restricted-properties.md
eslint/docs/rules/no-template-curly-in-string.md
eslint/docs/rules/no-undef-init.md
eslint/docs/rules/no-undefined.md
eslint/docs/rules/no-unused-vars.md
eslint/docs/rules/no-void.md
eslint/docs/rules/no-wrap-func.md
eslint/docs/rules/object-shorthand.md
eslint/docs/rules/prefer-destructuring.md
eslint/docs/rules/prefer-named-capture-group.md
eslint/docs/rules/prefer-promise-reject-errors.md
eslint/docs/rules/prefer-reflect.md
eslint/docs/rules/radix.md
eslint/docs/rules/require-await.md
eslint/docs/rules/sort-imports.md
eslint/docs/rules/space-after-function-name.md
eslint/docs/rules/space-in-brackets.md
eslint/docs/rules/spaced-comment.md
eslint/docs/rules/spaced-line-comment.md
eslint/docs/rules/switch-colon-spacing.md
eslint/docs/rules/symbol-description.md
eslint/docs/user-guide/command-line-interface.md
eslint/docs/user-guide/configuring/configuration-files.md
eslint/docs/user-guide/configuring/ignoring-code.md
eslint/docs/user-guide/configuring/language-options.md
eslint/docs/user-guide/configuring/plugins.md
eslint/docs/user-guide/configuring/rules.md
eslint/docs/user-guide/getting-started.md
eslint/docs/user-guide/integrations.md
eslint/docs/user-guide/migrating-from-jscs.md
eslint/docs/user-guide/migrating-to-2.0.0.md
eslint/docs/user-guide/migrating-to-4.0.0.md
eslint/docs/user-guide/migrating-to-5.0.0.md
eslint/docs/user-guide/migrating-to-6.0.0.md
eslint/docs/user-guide/migrating-to-8.0.0.md
eslint/karma.conf.js
eslint/lib/cli.js
eslint/lib/config/default-config.js
eslint/lib/config/flat-config-array.js
eslint/lib/config/flat-config-helpers.js [new file with mode: 0644]
eslint/lib/config/flat-config-schema.js
eslint/lib/config/rule-validator.js
eslint/lib/eslint/eslint.js
eslint/lib/linter/linter.js
eslint/lib/options.js
eslint/lib/rules/accessor-pairs.js
eslint/lib/rules/array-bracket-newline.js
eslint/lib/rules/array-bracket-spacing.js
eslint/lib/rules/array-callback-return.js
eslint/lib/rules/array-element-newline.js
eslint/lib/rules/arrow-body-style.js
eslint/lib/rules/arrow-parens.js
eslint/lib/rules/arrow-spacing.js
eslint/lib/rules/block-scoped-var.js
eslint/lib/rules/block-spacing.js
eslint/lib/rules/brace-style.js
eslint/lib/rules/callback-return.js
eslint/lib/rules/camelcase.js
eslint/lib/rules/capitalized-comments.js
eslint/lib/rules/class-methods-use-this.js
eslint/lib/rules/comma-dangle.js
eslint/lib/rules/comma-spacing.js
eslint/lib/rules/comma-style.js
eslint/lib/rules/complexity.js
eslint/lib/rules/computed-property-spacing.js
eslint/lib/rules/consistent-return.js
eslint/lib/rules/consistent-this.js
eslint/lib/rules/constructor-super.js
eslint/lib/rules/curly.js
eslint/lib/rules/default-case-last.js
eslint/lib/rules/default-case.js
eslint/lib/rules/default-param-last.js
eslint/lib/rules/dot-location.js
eslint/lib/rules/dot-notation.js
eslint/lib/rules/eol-last.js
eslint/lib/rules/eqeqeq.js
eslint/lib/rules/for-direction.js
eslint/lib/rules/func-call-spacing.js
eslint/lib/rules/func-name-matching.js
eslint/lib/rules/func-names.js
eslint/lib/rules/func-style.js
eslint/lib/rules/function-call-argument-newline.js
eslint/lib/rules/function-paren-newline.js
eslint/lib/rules/generator-star-spacing.js
eslint/lib/rules/getter-return.js
eslint/lib/rules/global-require.js
eslint/lib/rules/grouped-accessor-pairs.js
eslint/lib/rules/guard-for-in.js
eslint/lib/rules/handle-callback-err.js
eslint/lib/rules/id-blacklist.js
eslint/lib/rules/id-denylist.js
eslint/lib/rules/id-length.js
eslint/lib/rules/id-match.js
eslint/lib/rules/implicit-arrow-linebreak.js
eslint/lib/rules/indent-legacy.js
eslint/lib/rules/indent.js
eslint/lib/rules/init-declarations.js
eslint/lib/rules/jsx-quotes.js
eslint/lib/rules/key-spacing.js
eslint/lib/rules/keyword-spacing.js
eslint/lib/rules/line-comment-position.js
eslint/lib/rules/linebreak-style.js
eslint/lib/rules/lines-around-comment.js
eslint/lib/rules/lines-around-directive.js
eslint/lib/rules/lines-between-class-members.js
eslint/lib/rules/max-classes-per-file.js
eslint/lib/rules/max-depth.js
eslint/lib/rules/max-len.js
eslint/lib/rules/max-lines-per-function.js
eslint/lib/rules/max-lines.js
eslint/lib/rules/max-nested-callbacks.js
eslint/lib/rules/max-params.js
eslint/lib/rules/max-statements-per-line.js
eslint/lib/rules/max-statements.js
eslint/lib/rules/multiline-comment-style.js
eslint/lib/rules/multiline-ternary.js
eslint/lib/rules/new-cap.js
eslint/lib/rules/new-parens.js
eslint/lib/rules/newline-after-var.js
eslint/lib/rules/newline-before-return.js
eslint/lib/rules/newline-per-chained-call.js
eslint/lib/rules/no-alert.js
eslint/lib/rules/no-array-constructor.js
eslint/lib/rules/no-async-promise-executor.js
eslint/lib/rules/no-await-in-loop.js
eslint/lib/rules/no-bitwise.js
eslint/lib/rules/no-buffer-constructor.js
eslint/lib/rules/no-caller.js
eslint/lib/rules/no-case-declarations.js
eslint/lib/rules/no-catch-shadow.js
eslint/lib/rules/no-class-assign.js
eslint/lib/rules/no-compare-neg-zero.js
eslint/lib/rules/no-cond-assign.js
eslint/lib/rules/no-confusing-arrow.js
eslint/lib/rules/no-console.js
eslint/lib/rules/no-const-assign.js
eslint/lib/rules/no-constant-condition.js
eslint/lib/rules/no-constructor-return.js
eslint/lib/rules/no-continue.js
eslint/lib/rules/no-control-regex.js
eslint/lib/rules/no-debugger.js
eslint/lib/rules/no-delete-var.js
eslint/lib/rules/no-div-regex.js
eslint/lib/rules/no-dupe-args.js
eslint/lib/rules/no-dupe-class-members.js
eslint/lib/rules/no-dupe-else-if.js
eslint/lib/rules/no-dupe-keys.js
eslint/lib/rules/no-duplicate-case.js
eslint/lib/rules/no-duplicate-imports.js
eslint/lib/rules/no-else-return.js
eslint/lib/rules/no-empty-character-class.js
eslint/lib/rules/no-empty-function.js
eslint/lib/rules/no-empty-pattern.js
eslint/lib/rules/no-empty.js
eslint/lib/rules/no-eq-null.js
eslint/lib/rules/no-eval.js
eslint/lib/rules/no-ex-assign.js
eslint/lib/rules/no-extend-native.js
eslint/lib/rules/no-extra-bind.js
eslint/lib/rules/no-extra-boolean-cast.js
eslint/lib/rules/no-extra-label.js
eslint/lib/rules/no-extra-parens.js
eslint/lib/rules/no-extra-semi.js
eslint/lib/rules/no-fallthrough.js
eslint/lib/rules/no-floating-decimal.js
eslint/lib/rules/no-func-assign.js
eslint/lib/rules/no-global-assign.js
eslint/lib/rules/no-implicit-coercion.js
eslint/lib/rules/no-implicit-globals.js
eslint/lib/rules/no-implied-eval.js
eslint/lib/rules/no-import-assign.js
eslint/lib/rules/no-inline-comments.js
eslint/lib/rules/no-inner-declarations.js
eslint/lib/rules/no-invalid-regexp.js
eslint/lib/rules/no-invalid-this.js
eslint/lib/rules/no-irregular-whitespace.js
eslint/lib/rules/no-iterator.js
eslint/lib/rules/no-label-var.js
eslint/lib/rules/no-labels.js
eslint/lib/rules/no-lone-blocks.js
eslint/lib/rules/no-lonely-if.js
eslint/lib/rules/no-loop-func.js
eslint/lib/rules/no-loss-of-precision.js
eslint/lib/rules/no-magic-numbers.js
eslint/lib/rules/no-misleading-character-class.js
eslint/lib/rules/no-mixed-operators.js
eslint/lib/rules/no-mixed-requires.js
eslint/lib/rules/no-mixed-spaces-and-tabs.js
eslint/lib/rules/no-multi-assign.js
eslint/lib/rules/no-multi-spaces.js
eslint/lib/rules/no-multi-str.js
eslint/lib/rules/no-multiple-empty-lines.js
eslint/lib/rules/no-native-reassign.js
eslint/lib/rules/no-negated-condition.js
eslint/lib/rules/no-negated-in-lhs.js
eslint/lib/rules/no-nested-ternary.js
eslint/lib/rules/no-new-func.js
eslint/lib/rules/no-new-object.js
eslint/lib/rules/no-new-require.js
eslint/lib/rules/no-new-symbol.js
eslint/lib/rules/no-new-wrappers.js
eslint/lib/rules/no-new.js
eslint/lib/rules/no-nonoctal-decimal-escape.js
eslint/lib/rules/no-obj-calls.js
eslint/lib/rules/no-octal-escape.js
eslint/lib/rules/no-octal.js
eslint/lib/rules/no-param-reassign.js
eslint/lib/rules/no-path-concat.js
eslint/lib/rules/no-plusplus.js
eslint/lib/rules/no-process-env.js
eslint/lib/rules/no-process-exit.js
eslint/lib/rules/no-promise-executor-return.js
eslint/lib/rules/no-proto.js
eslint/lib/rules/no-prototype-builtins.js
eslint/lib/rules/no-redeclare.js
eslint/lib/rules/no-regex-spaces.js
eslint/lib/rules/no-restricted-exports.js
eslint/lib/rules/no-restricted-globals.js
eslint/lib/rules/no-restricted-imports.js
eslint/lib/rules/no-restricted-modules.js
eslint/lib/rules/no-restricted-properties.js
eslint/lib/rules/no-restricted-syntax.js
eslint/lib/rules/no-return-assign.js
eslint/lib/rules/no-return-await.js
eslint/lib/rules/no-script-url.js
eslint/lib/rules/no-self-assign.js
eslint/lib/rules/no-self-compare.js
eslint/lib/rules/no-sequences.js
eslint/lib/rules/no-setter-return.js
eslint/lib/rules/no-shadow-restricted-names.js
eslint/lib/rules/no-shadow.js
eslint/lib/rules/no-spaced-func.js
eslint/lib/rules/no-sparse-arrays.js
eslint/lib/rules/no-sync.js
eslint/lib/rules/no-tabs.js
eslint/lib/rules/no-template-curly-in-string.js
eslint/lib/rules/no-ternary.js
eslint/lib/rules/no-this-before-super.js
eslint/lib/rules/no-throw-literal.js
eslint/lib/rules/no-trailing-spaces.js
eslint/lib/rules/no-undef-init.js
eslint/lib/rules/no-undef.js
eslint/lib/rules/no-undefined.js
eslint/lib/rules/no-underscore-dangle.js
eslint/lib/rules/no-unexpected-multiline.js
eslint/lib/rules/no-unmodified-loop-condition.js
eslint/lib/rules/no-unneeded-ternary.js
eslint/lib/rules/no-unreachable-loop.js
eslint/lib/rules/no-unreachable.js
eslint/lib/rules/no-unsafe-finally.js
eslint/lib/rules/no-unsafe-negation.js
eslint/lib/rules/no-unsafe-optional-chaining.js
eslint/lib/rules/no-unused-expressions.js
eslint/lib/rules/no-unused-labels.js
eslint/lib/rules/no-unused-private-class-members.js
eslint/lib/rules/no-unused-vars.js
eslint/lib/rules/no-use-before-define.js
eslint/lib/rules/no-useless-backreference.js
eslint/lib/rules/no-useless-call.js
eslint/lib/rules/no-useless-catch.js
eslint/lib/rules/no-useless-computed-key.js
eslint/lib/rules/no-useless-concat.js
eslint/lib/rules/no-useless-constructor.js
eslint/lib/rules/no-useless-escape.js
eslint/lib/rules/no-useless-rename.js
eslint/lib/rules/no-useless-return.js
eslint/lib/rules/no-var.js
eslint/lib/rules/no-void.js
eslint/lib/rules/no-warning-comments.js
eslint/lib/rules/no-whitespace-before-property.js
eslint/lib/rules/no-with.js
eslint/lib/rules/nonblock-statement-body-position.js
eslint/lib/rules/object-curly-newline.js
eslint/lib/rules/object-curly-spacing.js
eslint/lib/rules/object-property-newline.js
eslint/lib/rules/object-shorthand.js
eslint/lib/rules/one-var-declaration-per-line.js
eslint/lib/rules/one-var.js
eslint/lib/rules/operator-assignment.js
eslint/lib/rules/operator-linebreak.js
eslint/lib/rules/padded-blocks.js
eslint/lib/rules/padding-line-between-statements.js
eslint/lib/rules/prefer-arrow-callback.js
eslint/lib/rules/prefer-const.js
eslint/lib/rules/prefer-destructuring.js
eslint/lib/rules/prefer-exponentiation-operator.js
eslint/lib/rules/prefer-named-capture-group.js
eslint/lib/rules/prefer-numeric-literals.js
eslint/lib/rules/prefer-object-spread.js
eslint/lib/rules/prefer-promise-reject-errors.js
eslint/lib/rules/prefer-reflect.js
eslint/lib/rules/prefer-regex-literals.js
eslint/lib/rules/prefer-rest-params.js
eslint/lib/rules/prefer-spread.js
eslint/lib/rules/prefer-template.js
eslint/lib/rules/quote-props.js
eslint/lib/rules/quotes.js
eslint/lib/rules/radix.js
eslint/lib/rules/require-atomic-updates.js
eslint/lib/rules/require-await.js
eslint/lib/rules/require-jsdoc.js
eslint/lib/rules/require-unicode-regexp.js
eslint/lib/rules/require-yield.js
eslint/lib/rules/rest-spread-spacing.js
eslint/lib/rules/semi-spacing.js
eslint/lib/rules/semi-style.js
eslint/lib/rules/semi.js
eslint/lib/rules/sort-imports.js
eslint/lib/rules/sort-keys.js
eslint/lib/rules/sort-vars.js
eslint/lib/rules/space-before-blocks.js
eslint/lib/rules/space-before-function-paren.js
eslint/lib/rules/space-in-parens.js
eslint/lib/rules/space-infix-ops.js
eslint/lib/rules/space-unary-ops.js
eslint/lib/rules/spaced-comment.js
eslint/lib/rules/strict.js
eslint/lib/rules/switch-colon-spacing.js
eslint/lib/rules/symbol-description.js
eslint/lib/rules/template-curly-spacing.js
eslint/lib/rules/template-tag-spacing.js
eslint/lib/rules/unicode-bom.js
eslint/lib/rules/use-isnan.js
eslint/lib/rules/valid-jsdoc.js
eslint/lib/rules/valid-typeof.js
eslint/lib/rules/vars-on-top.js
eslint/lib/rules/wrap-iife.js
eslint/lib/rules/wrap-regex.js
eslint/lib/rules/yield-star-spacing.js
eslint/lib/rules/yoda.js
eslint/lib/shared/types.js
eslint/package.json
eslint/templates/blogpost.md.ejs
eslint/templates/bug-report.md
eslint/templates/rule-change-proposal.md
eslint/templates/rule-proposal.md
eslint/tests/fixtures/formatters/async.js [new file with mode: 0644]
eslint/tests/fixtures/formatters/cwd.js [new file with mode: 0644]
eslint/tests/fixtures/parsers/throws-with-options.js
eslint/tests/lib/cli-engine/cli-engine.js
eslint/tests/lib/cli.js
eslint/tests/lib/config/flat-config-array.js
eslint/tests/lib/eslint/eslint.js
eslint/tests/lib/linter/linter.js
eslint/tests/lib/rule-tester/rule-tester.js
eslint/tests/lib/rules/max-lines-per-function.js
eslint/tests/lib/rules/no-constant-condition.js
eslint/tools/update-readme.js

index de67eb03d1222307acc0af83cc626d547a2f4797..789a3f556c92c5cfaffb945a6ee8498d8c67ae45 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ DSC=${PACKAGE}_${DEB_VERSION_UPSTREAM_REVISION}.dsc
 
 SRCDIR=src
 UPSTREAM=eslint
-UPSTREAMTAG=v8.3.0
+UPSTREAMTAG=v8.4.0
 BUILDSRC=${UPSTREAM}-${UPSTREAMTAG}
 
 all: ${DEB}
index e15677eada1047dc68ff50c6ddd4a57b552c0ab1..e2d756628cb853ab08aaa9d8e91971bfe89d19d8 100644 (file)
@@ -19,7 +19,7 @@
 [ ] Bug fix ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/bug-report.md))
 [ ] New rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-proposal.md))
 [ ] Changes an existing rule ([template](https://raw.githubusercontent.com/eslint/eslint/HEAD/templates/rule-change-proposal.md))
-[ ] Add autofixing to a rule
+[ ] Add autofix to a rule
 [ ] Add a CLI option
 [ ] Add something to the core
 [ ] Other, please explain:
index d6baaa97036dcaad34f90eabc1fa53effaf0408d..1087ab4e4debe038b1579d3fd177a781272ea3bc 100644 (file)
@@ -13,7 +13,7 @@ jobs:
     - uses: actions/checkout@v2
     - uses: actions/setup-node@v2
       with:
-        node-version: '14.x'
+        node-version: '16.x'
     - name: Install Packages
       run: npm install
     - name: Lint Files
index 975106df0fdc4517e38958c749f8b9db51750959..c37cf77fbbc98db194e3a3b38cec183b8f094b20 100644 (file)
@@ -1,11 +1,9 @@
 default: true
 
 # Exclusions for deliberate/widespread violations
-MD001: false     # Header levels should only increment by one level at a time
 MD002: false     # First header should be a h1 header
 MD007:           # Unordered list indentation
     indent: 4
-MD012: false     # Multiple consecutive blank lines
 MD013: false     # Line length
 MD014: false     # Dollar signs used before commands without showing output
 MD019: false     # Multiple spaces after hash on atx style header
@@ -15,7 +13,5 @@ MD026: false     # Trailing punctuation in header
 MD029: false     # Ordered list item prefix
 MD030: false     # Spaces after list markers
 MD033: false     # Allow inline HTML
-MD034: false     # Bare URL used
-MD040: false     # Fenced code blocks should have a language specified
 MD041: false     # First line in file should be a top level header
 MD046: false     # Code block style
index 1b763b1bae0d0061ad60e8847714df98e68f7eac..251c083e056680c74fc80d8a1094e8282a57aea3 100644 (file)
@@ -1 +1,3 @@
 CHANGELOG.md
+node_modules
+tmp
index abcfbb41ca4150582c0771f0bcf8e0c03aa7acd9..3b78599132d8a835dca955dd13a0ea526b30f4c7 100644 (file)
@@ -1,3 +1,23 @@
+v8.4.0 - December 3, 2021
+
+* [`efede90`](https://github.com/eslint/eslint/commit/efede90d59edc5cca9cd739df7e98f1ff00ca37d) chore: upgrade @eslint/eslintrc@1.0.5 (#15389) (Milos Djermanovic)
+* [`5771663`](https://github.com/eslint/eslint/commit/5771663e8d3e86fec9454ee0af439c6989506bf3) feat: add `allowReserved` parser option (#15387) (Milos Djermanovic)
+* [`32ac37a`](https://github.com/eslint/eslint/commit/32ac37a76b2e009a8f106229bc7732671d358189) feat: Flat config support in Linter (refs #13481) (#15185) (Nicholas C. Zakas)
+* [`54deec5`](https://github.com/eslint/eslint/commit/54deec56bc25d516becaf767769ee7543f491d62) docs: update integrations.md (#15380) (Vlad Sholokhov)
+* [`d041f34`](https://github.com/eslint/eslint/commit/d041f345cdf0306f15faa2f305fe1d21ef137eb1) feat: Treat Class/New Expressions as truthy in no-constant-condition (#15326) (Jordan Eldredge)
+* [`8f44cf5`](https://github.com/eslint/eslint/commit/8f44cf505765b663e371412ab57f0f1dbbe78513) feat: report only lines that exceed the limit in max-lines-per-function (#15140) (Sneh Khatri)
+* [`fa0423a`](https://github.com/eslint/eslint/commit/fa0423af7f8453f6c97b915b3b026f258b76a600) docs: fix typo in PR template (#15365) (Nitin Kumar)
+* [`0b8c846`](https://github.com/eslint/eslint/commit/0b8c846c77234125fbb211980bc1e62dc8791513) chore: fix update-readme to avoid multiple consecutive blank lines (#15375) (Milos Djermanovic)
+* [`808ad35`](https://github.com/eslint/eslint/commit/808ad35f204c838cd5eb8d766807dc43692f42f9) feat: pass cwd to formatters (refs eslint/rfcs#57) (#13392) (Toru Nagashima)
+* [`94b2a8b`](https://github.com/eslint/eslint/commit/94b2a8b3d1f7d139dd6b06216a64727b7d5f009b) chore: Use default Chromium binary in M1 Mac tests (#15371) (Brandon Mills)
+* [`4940cc5`](https://github.com/eslint/eslint/commit/4940cc5c4903a691fe51d409137dd573c4c7706e) fix: mark --rulesdir option as deprecated in CLI docs (#15310) (Kevin Partington)
+* [`e233920`](https://github.com/eslint/eslint/commit/e233920857e282ba22116ad5f1dcc6dfabc8ef5b) docs: enable a few more markdownlint rules and fix violations (#15368) (Bryan Mishkin)
+* [`ba58d94`](https://github.com/eslint/eslint/commit/ba58d94cb51d4d2644c024446d5750eaf4853129) ci: use node `v16` for Verify Files (#15364) (Nitin Kumar)
+* [`632176d`](https://github.com/eslint/eslint/commit/632176dc43180ea4e7f99da429fee3ee3814a04d) docs: Dedent needlessly indented example in getter-return docs (#15363) (Jordan Eldredge)
+* [`4497e88`](https://github.com/eslint/eslint/commit/4497e880248c24dc19eea8a5466555b847c0c7eb) docs: Update release notes blog post template (#15285) (Nicholas C. Zakas)
+* [`f1b7499`](https://github.com/eslint/eslint/commit/f1b7499a5162d3be918328ce496eb80692353a5a) feat: support async formatters (#15243) (MO)
+* [`1e32ee5`](https://github.com/eslint/eslint/commit/1e32ee591e978188b121604d0af9cbc04a50a3b5) chore: add jsdoc type annotation to rules (#15291) (Bryan Mishkin)
+
 v8.3.0 - November 21, 2021
 
 * [`60b0a29`](https://github.com/eslint/eslint/commit/60b0a292efd1b9cdc318b1e88a0cb7bbf14860b1) feat: add `allowProperties` option to require-atomic-updates (#15238) (Milos Djermanovic)
index 9260dfefa5e0c11451ae5a22d422c065405b84c2..8f2246f3b4e3205751b9698189c82f77759e974e 100644 (file)
@@ -24,4 +24,4 @@ Please sign our [Contributor License Agreement](https://cla.js.foundation/eslint
 ## Full Documentation
 
 Our full contribution guidelines can be found at:
-https://eslint.org/docs/developer-guide/contributing/
+<https://eslint.org/docs/developer-guide/contributing/>
index 0a0846b9270dbe75877b6a6420d21e94926f6b9b..3730e9b8db2aee0f2bae6b0ce666446deb8f8f7e 100644 (file)
@@ -789,6 +789,8 @@ target.checkRuleFiles = function() {
     RULE_FILES.forEach(filename => {
         const basename = path.basename(filename, ".js");
         const docFilename = `docs/rules/${basename}.md`;
+        const docText = cat(docFilename);
+        const ruleCode = cat(filename);
 
         /**
          * Check if basename is present in rule-types.json file.
@@ -806,7 +808,6 @@ target.checkRuleFiles = function() {
          * @private
          */
         function hasIdInTitle(id) {
-            const docText = cat(docFilename);
             const idOldAtEndOfTitleRegExp = new RegExp(`^# (.*?) \\(${id}\\)`, "u"); // original format
             const idNewAtBeginningOfTitleRegExp = new RegExp(`^# ${id}: `, "u"); // new format is same as rules index
             /*
@@ -824,14 +825,23 @@ target.checkRuleFiles = function() {
          * @private
          */
         function hasDeprecatedInfo() {
-            const ruleCode = cat(filename);
             const deprecatedTagRegExp = /@deprecated in ESLint/u;
-            const docText = cat(docFilename);
             const deprecatedInfoRegExp = /This rule was .+deprecated.+in ESLint/u;
 
             return deprecatedTagRegExp.test(ruleCode) && deprecatedInfoRegExp.test(docText);
         }
 
+        /**
+         * Check if the rule code has the jsdoc comment with the rule type annotation.
+         * @returns {boolean} true if present
+         * @private
+         */
+        function hasRuleTypeJSDocComment() {
+            const comment = "/** @type {import('../shared/types').Rule} */";
+
+            return ruleCode.includes(comment);
+        }
+
         // check for docs
         if (!test("-f", docFilename)) {
             console.error("Missing documentation for rule %s", basename);
@@ -880,6 +890,11 @@ target.checkRuleFiles = function() {
                     errors++;
                 }
             }
+
+            if (!hasRuleTypeJSDocComment()) {
+                console.error(`Missing rule type JSDoc comment from ${basename} rule code.`);
+                errors++;
+            }
         }
 
         // check for tests
index bbc74b7ce4d25e1770b5d240f1ded0cf626cbd15..e8b005d7de39cddab18b7086bd0933035504ef4c 100644 (file)
@@ -47,19 +47,19 @@ Prerequisites: [Node.js](https://nodejs.org/) (`^12.22.0`, `^14.17.0`, or `>=16.
 
 You can install ESLint using npm:
 
-```
+```sh
 $ npm install eslint --save-dev
 ```
 
 You should then set up a configuration file:
 
-```
+```sh
 $ ./node_modules/.bin/eslint --init
 ```
 
 After that, you can run ESLint on any file or directory like this:
 
-```
+```sh
 $ ./node_modules/.bin/eslint yourfile.js
 ```
 
@@ -207,8 +207,6 @@ These folks keep the project moving and are resources for help.
 
 <!-- NOTE: This section is autogenerated. Do not manually edit.-->
 
-
-
 <!--teamstart-->
 
 ### Technical Steering Committee (TSC)
@@ -232,7 +230,6 @@ Milos Djermanovic
 </a>
 </td></tr></tbody></table>
 
-
 ### Reviewers
 
 The people who review and implement new features.
@@ -249,9 +246,6 @@ Toru Nagashima
 </a>
 </td></tr></tbody></table>
 
-
-
-
 ### Committers
 
 The people who review and fix bugs and help triage issues.
@@ -288,12 +282,8 @@ Nitin Kumar
 </a>
 </td></tr></tbody></table>
 
-
 <!--teamend-->
 
-
-
-
 ## <a name="sponsors"></a>Sponsors
 
 The following companies, organizations, and individuals support ESLint's ongoing maintenance and development. [Become a Sponsor](https://opencollective.com/eslint) to get your logo on our README and website.
@@ -301,10 +291,10 @@ The following companies, organizations, and individuals support ESLint's ongoing
 <!-- NOTE: This section is autogenerated. Do not manually edit.-->
 <!--sponsorsstart-->
 <h3>Platinum Sponsors</h3>
-<p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
-<p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://coinbase.com"><img src="https://avatars.githubusercontent.com/u/1885080?v=4" alt="Coinbase" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
+<p><a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
+<p><a href="https://contra.com"><img src="https://images.opencollective.com/contra1/c70f93f/logo.png" alt="Contra" height="96"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://coinbase.com"><img src="https://avatars.githubusercontent.com/u/1885080?v=4" alt="Coinbase" height="96"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
 <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
-<p><a href="https://launchdarkly.com"><img src="https://images.opencollective.com/launchdarkly/574bb9e/logo.png" alt="launchdarkly" height="32"></a> <a href="https://troypoint.com"><img src="https://images.opencollective.com/troypoint/080f96f/avatar.png" alt="TROYPOINT" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
+<p><a href="https://sumatosoft.com/"><img src="https://images.opencollective.com/sumatosoft1/cab6013/logo.png" alt="SumatoSoft" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://www.practiceignition.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Practice Ignition" height="32"></a></p>
 <!--sponsorsend-->
 
 ## <a name="technology-sponsors"></a>Technology Sponsors
diff --git a/eslint/conf/globals.js b/eslint/conf/globals.js
new file mode 100644 (file)
index 0000000..076ffb2
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * @fileoverview Globals for ecmaVersion/sourceType
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//-----------------------------------------------------------------------------
+// Globals
+//-----------------------------------------------------------------------------
+
+const commonjs = {
+    exports: true,
+    global: false,
+    module: false,
+    require: false
+};
+
+const es3 = {
+    Array: false,
+    Boolean: false,
+    constructor: false,
+    Date: false,
+    decodeURI: false,
+    decodeURIComponent: false,
+    encodeURI: false,
+    encodeURIComponent: false,
+    Error: false,
+    escape: false,
+    eval: false,
+    EvalError: false,
+    Function: false,
+    hasOwnProperty: false,
+    Infinity: false,
+    isFinite: false,
+    isNaN: false,
+    isPrototypeOf: false,
+    Math: false,
+    NaN: false,
+    Number: false,
+    Object: false,
+    parseFloat: false,
+    parseInt: false,
+    propertyIsEnumerable: false,
+    RangeError: false,
+    ReferenceError: false,
+    RegExp: false,
+    String: false,
+    SyntaxError: false,
+    toLocaleString: false,
+    toString: false,
+    TypeError: false,
+    undefined: false,
+    unescape: false,
+    URIError: false,
+    valueOf: false
+};
+
+const es5 = {
+    ...es3,
+    JSON: false
+};
+
+const es2015 = {
+    ...es5,
+    ArrayBuffer: false,
+    DataView: false,
+    Float32Array: false,
+    Float64Array: false,
+    Int16Array: false,
+    Int32Array: false,
+    Int8Array: false,
+    Map: false,
+    Promise: false,
+    Proxy: false,
+    Reflect: false,
+    Set: false,
+    Symbol: false,
+    Uint16Array: false,
+    Uint32Array: false,
+    Uint8Array: false,
+    Uint8ClampedArray: false,
+    WeakMap: false,
+    WeakSet: false
+};
+
+// no new globals in ES2016
+const es2016 = {
+    ...es2015
+};
+
+const es2017 = {
+    ...es2016,
+    Atomics: false,
+    SharedArrayBuffer: false
+};
+
+// no new globals in ES2018
+const es2018 = {
+    ...es2017
+};
+
+// no new globals in ES2019
+const es2019 = {
+    ...es2018
+};
+
+const es2020 = {
+    ...es2019,
+    BigInt: false,
+    BigInt64Array: false,
+    BigUint64Array: false,
+    globalThis: false
+};
+
+const es2021 = {
+    ...es2020,
+    AggregateError: false,
+    FinalizationRegistry: false,
+    WeakRef: false
+};
+
+const es2022 = {
+    ...es2021
+};
+
+
+//-----------------------------------------------------------------------------
+// Exports
+//-----------------------------------------------------------------------------
+
+module.exports = {
+    commonjs,
+    es3,
+    es5,
+    es2015,
+    es2016,
+    es2017,
+    es2018,
+    es2019,
+    es2020,
+    es2021,
+    es2022
+};
index f22eb8f3497499b404c7f5da520de9e85130356c..2b01bc77e813496937fc78868fddd38bc8983e2c 100644 (file)
@@ -189,8 +189,6 @@ bar();
 
    ![Loop Event's Example 5](./code-path-analysis/loop-event-example-for-5.svg)
 
-
-
 ## Usage Examples
 
 ### To check whether or not this is reachable
index dde1c31446f193204f8320f13ce0e775b2703aa0..58fe6f9c02a27ad2408230ef2a2669677526b98e 100644 (file)
@@ -30,7 +30,7 @@ Details about each step are found below.
 
 The first step to sending a pull request is to create a new branch in your ESLint fork. Give the branch a descriptive name that describes what it is you're fixing, such as:
 
-```
+```sh
 $ git checkout -b issue1234
 ```
 
@@ -42,14 +42,14 @@ You should do all of your development for the issue in this branch.
 
 Make the changes to the code and tests, following the [code conventions](../code-conventions.md) as you go. Once you have finished, commit the changes to your branch:
 
-```
+```sh
 $ git add -A
 $ git commit
 ```
 
 All ESLint projects follow [Conventional Commits](https://www.conventionalcommits.org/) for our commit messages. Here's an example commit message:
 
-```
+```pt
 tag: Short description of what you did
 
 Longer description here if necessary
@@ -79,7 +79,7 @@ The message summary should be a one-sentence description of the change, and it m
 
 Here are some good commit message summary examples:
 
-```
+```pt
 build: Update Travis to only test Node 0.10
 fix: Semi rule incorrectly flagging extra semicolon
 chore: Upgrade Esprima to 1.2, switch to using comment attachment
@@ -91,7 +91,7 @@ The commit message format is important because these messages are used to create
 
 Before you send the pull request, be sure to rebase onto the upstream source. This ensures your code is running on the latest available code.
 
-```
+```sh
 git fetch upstream
 git rebase upstream/main
 ```
@@ -100,7 +100,7 @@ git rebase upstream/main
 
 After rebasing, be sure to run all of the tests once again to make sure nothing broke:
 
-```
+```sh
 npm test
 ```
 
@@ -123,13 +123,13 @@ With your code ready to go, this is a good time to double-check your submission
 
 Next, push your changes to your clone:
 
-```
+```sh
 git push origin issue1234
 ```
 
 If you are unable to push because some references are old, do a forced push instead:
 
-```
+```sh
 git push -f origin issue1234
 ```
 
@@ -149,13 +149,13 @@ Once your pull request is sent, it's time for the team to review it. As such, pl
 
 If your commit message is in the incorrect format, you'll be asked to update it. You can do so via:
 
-```
+```sh
 $ git commit --amend
 ```
 
 This will open up your editor so you can make changes. After that, you'll need to do a forced push to your branch:
 
-```
+```sh
 $ git push origin issue1234 -f
 ```
 
@@ -163,7 +163,7 @@ $ git push origin issue1234 -f
 
 If we ask you to make code changes, there's no need to close the pull request and create a new one. Just go back to the branch on your fork and make your changes. Then, when you're ready, you can add your changes into the branch:
 
-```
+```sh
 $ git add -A
 $ git commit
 $ git push origin issue1234
@@ -177,13 +177,13 @@ The commit messages in subsequent commits do not need to be in any specific form
 
 If your code is out-of-date, we might ask you to rebase. That means we want you to apply your changes on top of the latest upstream code. Make sure you have set up a [development environment](../development-environment.md) and then you can rebase using these commands:
 
-```
+```sh
 $ git fetch upstream
 $ git rebase upstream/main
 ```
 
 You might find that there are merge conflicts when you attempt to rebase. Please [resolve the conflicts](https://help.github.com/articles/resolving-merge-conflicts-after-a-git-rebase/) and then do a forced push to your branch:
 
-```
+```sh
 $ git push origin issue1234 -f
 ```
index 7981c66e685e1bc8db16a209f45fa73ddecd1539..4828476aac83b8e8fb66683ae7eb4e3ebb498087 100644 (file)
@@ -14,7 +14,7 @@ Go to <https://github.com/eslint/eslint> and click the "Fork" button. Follow the
 
 Once you've cloned the repository, run `npm install` to get all the necessary dependencies:
 
-```
+```sh
 $ cd eslint
 $ npm install
 ```
@@ -27,7 +27,7 @@ The *upstream source* is the main ESLint repository where active development hap
 
 To add the upstream source for ESLint, run the following in your repository:
 
-```
+```sh
 git remote add upstream git@github.com:eslint/eslint.git
 ```
 
@@ -49,7 +49,7 @@ Please see the [generator documentation](https://github.com/eslint/generator-esl
 
 Running the tests is the best way to ensure you have correctly set up your development environment. Make sure you're in the `eslint` directory and run:
 
-```
+```sh
 npm test
 ```
 
index 378b9c16b8da0be410d3695385c94f562489a37c..ca07415cd2bfc69bb7d7b92f4cd8f08dfd9717ba 100644 (file)
@@ -404,7 +404,7 @@ This edit information means replacing the range of the `range` property by the `
 
 The `Formatter` value is the object to convert the [LintResult] objects to text. The [eslint.loadFormatter()][eslint-loadformatter] method returns it. It has the following method:
 
-* `format` (`(results: LintResult[]) => string`)<br>
+* `format` (`(results: LintResult[]) => string | Promise<string>`)<br>
   The method to convert the [LintResult] objects to text.
 
 ---
@@ -473,7 +473,7 @@ const linter2 = new Linter();
 ```
 
 In this example, rules run on `linter1` will get `path/to/project` when calling `context.getCwd()`.
-Those run on `linter2` will get `process.cwd()` if the global `process` object is defined or `undefined` otherwise (e.g. on the browser https://eslint.org/demo).
+Those run on `linter2` will get `process.cwd()` if the global `process` object is defined or `undefined` otherwise (e.g. on the browser <https://eslint.org/demo>).
 
 ### Linter#verify
 
@@ -783,7 +783,7 @@ Any additional properties of a test case will be passed directly to the linter a
 
 If a valid test case only uses the `code` property, it can optionally be provided as a string containing the code, rather than an object with a `code` key.
 
-#### Testing errors with `messageId`
+### Testing errors with `messageId`
 
 If the rule under test uses `messageId`s, you can use `messageId` property in a test case to assert reported error's `messageId` instead of its `message`.
 
@@ -805,7 +805,7 @@ For messages with placeholders, a test case can also use `data` property to addi
 
 Please note that `data` in a test case does not assert `data` passed to `context.report`. Instead, it is used to form the expected message text which is then compared with the received `message`.
 
-#### Testing Suggestions
+### Testing Suggestions
 
 Suggestions can be tested by defining a `suggestions` key on an errors object. The options to check for the suggestions are the following (all are optional):
 
index 7b57f3fbf284f0f8d2ea1ce6f0e923727e1f1aec..15032d9e7a0d39d7bd21ccfb228648125a343a47 100644 (file)
@@ -32,9 +32,11 @@ Once your shareable config is ready, you can [publish to npm](https://docs.npmjs
 
 You should declare your dependency on ESLint in `package.json` using the [peerDependencies](https://docs.npmjs.com/files/package.json#peerdependencies) field. The recommended way to declare a dependency for future proof compatibility is with the ">=" range syntax, using the lowest required ESLint version. For example:
 
-```
-"peerDependencies": {
-    "eslint": ">= 3"
+```json
+{
+    "peerDependencies": {
+        "eslint": ">= 3"
+    }
 }
 ```
 
@@ -76,7 +78,6 @@ You can also omit the `eslint-config-` and it will be automatically assumed by E
 
 npm [scoped modules](https://docs.npmjs.com/misc/scope) are also supported in a number of ways.
 
-
 By using the module name:
 
 ```json
index a5e9ade81bfba4e235516fddb5ab0b2d5c949316..54db6632847c8ad4b8985949c79e72eef2c38a1d 100644 (file)
@@ -6,11 +6,21 @@ Each formatter is just a function that receives a `results` object and returns a
 
 ```js
 //my-awesome-formatter.js
-module.exports = function(results) {
+module.exports = function(results, context) {
     return JSON.stringify(results, null, 2);
 };
 ```
 
+Formatter can also be an async function (from ESLint v8.4.0), the following shows a simple example:
+
+```js
+//my-awesome-formatter.js
+module.exports = async function(results) {
+    const formatted = await asyncTask();
+    return formatted;
+};
+```
+
 To run ESLint with this formatter, you can use the `-f` (or `--format`) command line flag:
 
 ```bash
@@ -19,35 +29,6 @@ eslint -f ./my-awesome-formatter.js src/
 
 In order to use a local file as a custom formatter, you must begin the filename with a dot (such as `./my-awesome-formatter.js` or `../formatters/my-awesome-formatter.js`).
 
-### The `data` Argument
-
-The exported function receives an optional second argument named `data`. The `data` object provides extended information related to the analysis results. Currently, the `data` object consists of a single property named `rulesMeta`. This property is a dictionary of rule metadata, keyed with `ruleId`. The value for each entry is the `meta` property from the corresponding rule object. The dictionary contains an entry for each rule that was run during the analysis.
-
-Here's what the `data` object would look like if one rule, `no-extra-semi`, had been run:
-
-```js
-{
-    rulesMeta: {
-        "no-extra-semi": {
-            type: "suggestion",
-            docs: {
-                description: "disallow unnecessary semicolons",
-                category: "Possible Errors",
-                recommended: true,
-                url: "https://eslint.org/docs/rules/no-extra-semi"
-            },
-            fixable: "code",
-            schema: [],
-            messages: {
-                unexpected: "Unnecessary semicolon."
-            }
-        }
-    }
-}
-```
-
-The [Using Rule metadata](#using-rule-metadata) example shows how to use the `data` object in a custom formatter. See the [Working with Rules](https://eslint.org/docs/developer-guide/working-with-rules) page for more information about rules.
-
 ## Packaging the Custom Formatter
 
 Custom formatters can also be distributed through npm packages. To do so, create an npm package with a name in the format of `eslint-formatter-*`, where `*` is the name of your formatter (such as `eslint-formatter-awesome`). Projects should then install the package and can use the custom formatter with the `-f` (or `--format`) flag like this:
@@ -68,14 +49,14 @@ Tips for `package.json`:
 
 See all [formatters on npm](https://www.npmjs.com/search?q=eslint-formatter);
 
-## The `results` Object
+## The `results` Argument
 
 The `results` object passed into a formatter is an array of objects containing the lint results for individual files. Here's some example output:
 
 ```js
 [
     {
-        filePath: "path/to/file.js",
+        filePath: "/path/to/a/file.js",
         messages: [
             {
                 ruleId: "curly",
@@ -102,7 +83,7 @@ The `results` object passed into a formatter is an array of objects containing t
             "var err = doStuff();\nif (err) console.log('failed tests: ' + err);\nprocess.exit(1);\n"
     },
     {
-        filePath: "Gruntfile.js",
+        filePath: "/path/to/Gruntfile.js",
         messages: [],
         errorCount: 0,
         warningCount: 0,
@@ -137,6 +118,38 @@ Each `message` object contains information about the ESLint rule that was trigge
 *   **column**: the column where the issue is located.
 *   **nodeType**: the type of the node in the [AST](https://github.com/estree/estree/blob/master/spec.md#node-objects)
 
+## The `context` Argument
+
+The formatter function receives an object as the second argument. The object has two properties:
+
+* `cwd` ... The current working directory. This value comes from the `cwd` constructor option of the [ESLint](nodejs-api.md#-new-eslintoptions) class.
+* `rulesMeta` ... The `meta` property values of rules. See the [Working with Rules](working-with-rules.md) page for more information about rules.
+
+For example, here's what the object would look like if one rule, `no-extra-semi`, had been run:
+
+```js
+{
+    cwd: "/path/to/cwd",
+    rulesMeta: {
+        "no-extra-semi": {
+            type: "suggestion",
+            docs: {
+                description: "disallow unnecessary semicolons",
+                recommended: true,
+                url: "https://eslint.org/docs/rules/no-extra-semi"
+            },
+            fixable: "code",
+            schema: [],
+            messages: {
+                unexpected: "Unnecessary semicolon."
+            }
+        }
+    }
+}
+```
+
+**Note:** if a linting is executed by deprecated `CLIEngine` class, the `context` argument may be a different value because it is up to the API users. Please check whether the `context` argument is an expected value or not if you want to support legacy environments.
+
 ## Examples
 
 ### Summary formatter
@@ -144,7 +157,7 @@ Each `message` object contains information about the ESLint rule that was trigge
 A formatter that only cares about the total count of errors and warnings will look like this:
 
 ```javascript
-module.exports = function(results) {
+module.exports = function(results, context) {
     // accumulate the errors and warnings
     var summary = results.reduce(
         function(seq, current) {
@@ -186,7 +199,7 @@ Errors: 2, Warnings: 4
 A more complex report will look something like this:
 
 ```javascript
-module.exports = function(results, data) {
+module.exports = function(results, context) {
     var results = results || [];
 
     var summary = results.reduce(
@@ -195,7 +208,7 @@ module.exports = function(results, data) {
                 var logMessage = {
                     filePath: current.filePath,
                     ruleId: msg.ruleId,
-                    ruleUrl: data.rulesMeta[msg.ruleId].docs.url,
+                    ruleUrl: context.rulesMeta[msg.ruleId].docs.url,
                     message: msg.message,
                     line: msg.line,
                     column: msg.column
@@ -348,7 +361,6 @@ error semi
   src/configs/bundler.js:6:10
 ```
 
-
 ### Complex Argument Passing
 
 If you find the custom formatter pattern doesn't provide enough options for the way you'd like to format ESLint results, the best option is to use ESLint's built-in [JSON formatter](https://eslint.org/docs/user-guide/formatters/) and pipe the output to a second program. For example:
index ee5a5606fac4e6d36e483999c4d7b8dc7e1eba99..697b7ed8bff1d451b75772d7f7ca403f2aad4d17 100644 (file)
@@ -24,9 +24,7 @@ Here is the basic format of the source file for a rule:
 // Rule Definition
 //------------------------------------------------------------------------------
 
-/**
- * @type {import('eslint').Rule.RuleModule}
- */
+/** @type {import('eslint').Rule.RuleModule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 25028d9ef73121718c7a0eb89faf55e6c752f469..22cf28ab982f7750c180c075da97720ff248f9eb 100644 (file)
@@ -232,7 +232,6 @@ const Quux = class {
 }
 ```
 
-
 ## Known Limitations
 
 Due to the limits of static analysis, this rule does not account for possible side effects and in certain cases
index eed32295f439dc5d29249f833f9fda9dd6948872..bb990c75bf8f761301767f9988ff4a97683564a5 100644 (file)
@@ -267,7 +267,6 @@ var e = [
 ];
 ```
 
-
 ## When Not To Use It
 
 If you don't want to enforce line breaks after opening and before closing array brackets, don't enable this rule.
index 84bf0e7710d556f5133ae1bdb079a2a99afff91e..568e014cd745ec0ae62ca9f260412dc112cc2c06 100644 (file)
@@ -144,7 +144,6 @@ myArray.forEach(item => {
 });
 ```
 
-
 ## Known Limitations
 
 This rule checks callback functions of methods with the given names, *even if* the object which has the method is *not* an array.
index 144ebdf071035db463a2274d471a3ba433ab2d11..8a133cdf452d006dbf5c4e6da06216d45d8ca2e2 100644 (file)
@@ -20,7 +20,6 @@ a => {}
 Following this style will help you find arrow functions (`=>`) which may be mistakenly included in a condition
 when a comparison such as `>=` was the intent.
 
-
 ```js
 /*eslint-env es6*/
 
index f425ccd3f257e5348c4166d16dfff874bb140469..c4e7277c45715888b8d6fbac5efb6356e58dcc1f 100644 (file)
@@ -165,7 +165,6 @@ There are some cases where you might want to call a callback function more than
  may lead to incorrect behavior. In those cases you may want to reserve a special name for those callbacks and
  not include that in the list of callbacks that trigger warnings.
 
-
 ## Further Reading
 
 * [The Art Of Node: Callbacks](https://github.com/maxogden/art-of-node#callbacks)
index 73efc9dba5482b4840e38bba402e4f36ddf70b66..7e25b069a8b206f9ea798e14a565a29f8e5cbb84 100644 (file)
@@ -99,7 +99,7 @@ This rule has two options:
 
 ### exceptMethods
 
-```
+```js
 "class-methods-use-this": [<enabled>, { "exceptMethods": [<...exceptions>] }]
 ```
 
@@ -131,7 +131,7 @@ class A {
 
 ## enforceForClassFields
 
-```
+```js
 "class-methods-use-this": [<enabled>, { "enforceForClassFields": true | false }]
 ```
 
index 23107719a32522453f8cf5db29d7a5ce1603533b..3160f86a8f5f671869bf6089cda8edff06ebb311 100644 (file)
@@ -110,13 +110,11 @@ var arr = [,2 ,3]
 
 If your project will not be following a consistent comma-spacing pattern, turn this rule off.
 
-
 ## Further Reading
 
 * [JavaScript](http://javascript.crockford.com/code.html)
 * [Dojo Style Guide](https://dojotoolkit.org/reference-guide/1.9/developer/styleguide.html)
 
-
 ## Related Rules
 
 * [array-bracket-spacing](array-bracket-spacing.md)
index 24b5515743d3b14394f2dce425f0428145212d06..f71e3105aa8ccabdf7d1f65cae96ad16013c45a8 100644 (file)
@@ -157,7 +157,6 @@ var o = {fst:1,
 
 This rule can safely be turned off if your project does not care about enforcing a consistent comma style.
 
-
 ## Further Reading
 
 For more information on the Comma First style:
@@ -165,7 +164,6 @@ For more information on the Comma First style:
 * [A better coding convention for lists and object literals in JavaScript by isaacs](https://gist.github.com/isaacs/357981)
 * [npm coding style guideline](https://docs.npmjs.com/misc/coding-style)
 
-
 ## Related Rules
 
 * [operator-linebreak](operator-linebreak.md)
index 01c1ff42604d2112f7c2a1a51264034c740b9d0b..abe0d495651ab70b75f008583e3c3f657273ea06 100644 (file)
@@ -14,7 +14,6 @@ This rule has a string option:
 * `"never"` disallows line breaks between arguments
 * `"consistent"` requires consistent usage of line breaks between arguments
 
-
 ### always
 
 Examples of **incorrect** code for this rule with the default `"always"` option:
@@ -69,7 +68,6 @@ baz(
 );
 ```
 
-
 ### never
 
 Examples of **incorrect** code for this rule with the `"never"` option:
@@ -189,7 +187,6 @@ baz(
 );
 ```
 
-
 ## When Not To Use It
 
 If you don't want to enforce line breaks between arguments, don't enable this rule.
index c49f39dd29664b684c8a3e767262cc046d0d67c1..631de805966590a59d98fa20beadb2c588a661c0 100644 (file)
@@ -3,17 +3,17 @@
 The get syntax binds an object property to a function that will be called when that property is looked up. It was first introduced in ECMAScript 5:
 
 ```js
-    var p = {
-        get name(){
-            return "nicholas";
-        }
-    };
-
-    Object.defineProperty(p, "age", {
-        get: function (){
-            return 17;
-        }
-    });
+var p = {
+    get name(){
+        return "nicholas";
+    }
+};
+
+Object.defineProperty(p, "age", {
+    get: function (){
+        return 17;
+    }
+});
 ```
 
 Note that every `getter` is expected to return a value.
index 74fb0e7e2acd839065ca21bf178974476ee0d354..bd4e86ea945909dc1bab4610924a42ec10ba0c65 100644 (file)
@@ -842,7 +842,6 @@ if (foo) {
 }
 ```
 
-
 ## Compatibility
 
 * **JSHint**: `indent`
index 734453411c943a20047df1e130bcefb3e69aba25..2e0eef8530ae4ba87c441c97ccb39d5ed19f778d 100644 (file)
@@ -11,7 +11,6 @@ var foo = "bar";  // beside comment
 
 This rule enforces consistent position of line comments. Block comments are not affected by this rule. By default, this rule ignores comments starting with the following words: `eslint`, `jshint`, `jslint`, `istanbul`, `global`, `exported`, `jscs`, `falls through`.
 
-
 ## Options
 
 This rule takes one argument, which can be a string or an object. The string settings are the same as those of the `position` property (explained below). The object option has the following properties:
@@ -33,7 +32,6 @@ Examples of **correct** code for the `{ "position": "above" }` option:
 1 + 1;
 ```
 
-
 Examples of **incorrect** code for the `{ "position": "above" }` option:
 
 ```js
@@ -50,7 +48,6 @@ Examples of **correct** code for the `{ "position": "beside" }` option:
 1 + 1; // valid comment
 ```
 
-
 Examples of **incorrect** code for the `{ "position": "beside" }` option:
 
 ```js
index d2aa5a1aa8e9c1d8f4aed65a67ee29ec591986f8..a4eb620acc37c4ab584ef2379d701d88e52d5327 100644 (file)
@@ -19,7 +19,6 @@ This rule has a string option:
 * `"unix"` (default) enforces the usage of Unix line endings: `\n` for LF.
 * `"windows"` enforces the usage of Windows line endings: `\r\n` for CRLF.
 
-
 ### unix
 
 Examples of **incorrect** code for this rule with the default `"unix"` option:
@@ -73,7 +72,7 @@ Version control systems sometimes have special behavior for linebreaks. To make
 
 For example, the default behavior of [git](https://git-scm.com/) on Windows systems is to convert LF linebreaks to CRLF when checking out files, but to store the linebreaks as LF when committing a change. This will cause the `linebreak-style` rule to report errors if configured with the `"unix"` setting, because the files that ESLint sees will have CRLF linebreaks. If you use git, you may want to add a line to your [`.gitattributes` file](https://git-scm.com/docs/gitattributes) to prevent git from converting linebreaks in `.js` files:
 
-```
+```pt
 *.js text eol=lf
 ```
 
index fb0161102727c1c1cdfc3cc67333067ffcd899b0..b13d525326aaed9164d70a63055d092e1ecbf1ad 100644 (file)
@@ -26,7 +26,6 @@ This rule has an object option:
 * `"applyDefaultIgnorePatterns"` enables or disables the default comment patterns to be ignored by the rule
 * `"ignorePattern"` custom patterns to be ignored by the rule
 
-
 ### beforeBlockComment
 
 Examples of **incorrect** code for this rule with the default `{ "beforeBlockComment": true }` option:
@@ -515,7 +514,6 @@ const [
 ] = ["great", "not great"];
 ```
 
-
 ### ignorePattern
 
 By default this rule ignores comments starting with the following words: `eslint`, `jshint`, `jslint`, `istanbul`, `global`, `exported`, `jscs`. To ignore more comments in addition to the defaults, set the `ignorePattern` option to a string pattern that will be passed to the [`RegExp` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp).
@@ -568,7 +566,6 @@ foo();
 
 ```
 
-
 ## When Not To Use It
 
 Many people enjoy a terser code style and don't mind comments bumping up against code. If you fall into that category this rule is not for you.
index d3b13615b42f28ed770b0e0fe25ff2eef8611e10..f2af93b8d48c51237f44faaf88c21f0534cda4a8 100644 (file)
@@ -10,7 +10,7 @@ This rule enforces a maximum number of lines per function, in order to aid in ma
 
 Nested long method chains like the below example are often broken onto separate lines for readability:
 
-```
+```js
 function() {
     return m("div", [
         m("table", {className: "table table-striped latest-data"}, [
index e9de786e8cd390fc14a490e30134126cf7b01164..cfbe545e28583ee5d7e0f2bb2e474973f6eda65b 100644 (file)
@@ -31,5 +31,3 @@ if (Object.is(x, -0)) {
     // doSomething()...
 }
 ```
-
-
index 036bbb786b9240ab288f57aa080ab3d5c63ab4b6..8de5e69f3f8feb495c801ea5c7876fc5d48f8489 100644 (file)
@@ -32,6 +32,14 @@ if (x &&= false) {
     doSomethingNever();
 }
 
+if (class {}) {
+    doSomethingAlways();
+}
+
+if (new Boolean(x)) {
+    doSomethingAlways();
+}
+
 if (x ||= true) {
     doSomethingAlways();
 }
index 0f8691c82d3b1243289c13753b96288c06eaa35b..19110312a64aaedd6bb91fb7379246ac1d57fdc5 100644 (file)
@@ -180,7 +180,7 @@ This rule has an option to allow specific kinds of functions to be empty.
     * `"asyncFunctions"` - Async functions.
     * `"asyncMethods"` - Async class methods and method shorthands of object literals.
 
-#### allow: functions
+### allow: functions
 
 Examples of **correct** code for the `{ "allow": ["functions"] }` option:
 
@@ -196,7 +196,7 @@ var obj = {
 };
 ```
 
-#### allow: arrowFunctions
+### allow: arrowFunctions
 
 Examples of **correct** code for the `{ "allow": ["arrowFunctions"] }` option:
 
@@ -207,7 +207,7 @@ Examples of **correct** code for the `{ "allow": ["arrowFunctions"] }` option:
 var foo = () => {};
 ```
 
-#### allow: generatorFunctions
+### allow: generatorFunctions
 
 Examples of **correct** code for the `{ "allow": ["generatorFunctions"] }` option:
 
@@ -224,7 +224,7 @@ var obj = {
 };
 ```
 
-#### allow: methods
+### allow: methods
 
 Examples of **correct** code for the `{ "allow": ["methods"] }` option:
 
@@ -242,7 +242,7 @@ class A {
 }
 ```
 
-#### allow: generatorMethods
+### allow: generatorMethods
 
 Examples of **correct** code for the `{ "allow": ["generatorMethods"] }` option:
 
@@ -260,7 +260,7 @@ class A {
 }
 ```
 
-#### allow: getters
+### allow: getters
 
 Examples of **correct** code for the `{ "allow": ["getters"] }` option:
 
@@ -278,7 +278,7 @@ class A {
 }
 ```
 
-#### allow: setters
+### allow: setters
 
 Examples of **correct** code for the `{ "allow": ["setters"] }` option:
 
@@ -296,7 +296,7 @@ class A {
 }
 ```
 
-#### allow: constructors
+### allow: constructors
 
 Examples of **correct** code for the `{ "allow": ["constructors"] }` option:
 
@@ -309,7 +309,7 @@ class A {
 }
 ```
 
-#### allow: asyncFunctions
+### allow: asyncFunctions
 
 Examples of **correct** code for the `{ "allow": ["asyncFunctions"] }` options:
 
@@ -320,7 +320,7 @@ Examples of **correct** code for the `{ "allow": ["asyncFunctions"] }` options:
 async function a(){}
 ```
 
-#### allow: asyncMethods
+### allow: asyncMethods
 
 Examples of **correct** code for the `{ "allow": ["asyncMethods"] }` options:
 
index 3f8850199b76d94db4b4c5ce4cab26b7a1eb0f83..b887c87a59077c137386526e6b7eef12334db756 100644 (file)
@@ -4,7 +4,6 @@
 
 Labeled statements are only used in conjunction with labeled break and continue statements. ECMAScript has no goto statement.
 
-
 ## Rule Details
 
 This error occurs when a label is used to mark a statement that is not an iteration or switch
index d300ff61d3fd48187f72d999e0bb690bc95551e3..cbf7c67c2b8eef79e55b47e86be10fb277586eb6 100644 (file)
@@ -19,7 +19,6 @@ setTimeout(function() {
 
 The best practice is to always use a function for the first argument of `setTimeout()` and `setInterval()` (and avoid `execScript()`).
 
-
 ## Rule Details
 
 This rule aims to eliminate implied `eval()` through the use of `setTimeout()`, `setInterval()` or `execScript()`. As such, it will warn when either function is used with a string as the first argument.
index 65c7532781561e2c504d3457e732a4eb79c5c04d..f39b868e5e370d9be62155771915129e5ea08135 100644 (file)
@@ -26,7 +26,6 @@ for (let i = 0; i < 10; i++) {
 
 In this case, each function created within the loop returns a different number as expected.
 
-
 ## Rule Details
 
 This error is raised to highlight a piece of code that may not work as you expect it to and could also indicate a misunderstanding of how the language works. Your code may run without any problems if you do not fix this error, but in some situations it could behave unexpectedly.
index 33ce7f658313bc5fc2b1940f13fac8222ae488d4..1dca581e81cf29b397c53c05e26f9c35b34197b8 100644 (file)
@@ -36,7 +36,6 @@ will generate
 1:18  Unexpected mix of '&&' and '?:'. (no-mixed-operators)
 ```
 
-
 ## Rule Details
 
 This rule checks `BinaryExpression`, `LogicalExpression` and `ConditionalExpression`.
index ba34dbe49294cb755d25ec927ff0f4cb93eff945..9f156bb2b3f28b0d2f8fef6c6d2b9918fffd29b1 100644 (file)
@@ -59,7 +59,6 @@ function main() {
 }
 ```
 
-
 ## Further Reading
 
 * [Smart Tabs](https://www.emacswiki.org/emacs/SmartTabs)
index aff6c2e6f1b7545fe5cf15c220fbc1ec509f0c82..1a04841825c16b1b097b50b01414f80d06f6c8aa 100644 (file)
@@ -69,7 +69,7 @@ var bar = 3;
 
 **Incorrect**:
 
-```
+```js
 1    /*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎
 2    ⏎
 3    var foo = 5;⏎
@@ -82,7 +82,7 @@ var bar = 3;
 
 **Correct**:
 
-```
+```js
 1    /*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎
 2    ⏎
 3    var foo = 5;⏎
index 47a7af3cbe926526a32f1589cd1d3076491f7f34..29952c370eafb3030a3336d24d7168963c2927a1 100644 (file)
@@ -150,7 +150,6 @@ function foo(barBaz) {
 }
 ```
 
-
 ## When Not To Use It
 
 If you want to allow assignment to function parameters, then you can safely disable this rule.
index 83bfa6d02acb5cc28332ea471f35ded1ae005881..4655e965ef7433bbc04ecd0db93c965aed55b7db 100644 (file)
@@ -4,7 +4,6 @@ This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule
 
 The `process.env` object in Node.js is used to store deployment/configuration parameters. Littering it through out a project could lead to maintenance issues as it's another kind of global dependency. As such, it could lead to merge conflicts in a multi-user setup and deployment issues in a multi-server setup. Instead, one of the best practices is to define all those parameters in a single configuration/settings file which could be accessed throughout the project.
 
-
 ## Rule Details
 
 This rule is aimed at discouraging use of `process.env` to avoid global dependencies. As such, it will warn whenever `process.env` is used.
index f1577d7d89d6ffd79a4923eac01bffd39f6f7989..d8e06101b4116445f5b9aa944b0470d206ce1928 100644 (file)
@@ -91,7 +91,7 @@ or like this if you want to apply a custom message to pattern matches:
 
 The custom message will be appended to the default error message.
 
-To restrict the use of all Node.js core imports (via https://github.com/nodejs/node/tree/master/lib):
+To restrict the use of all Node.js core imports (via <https://github.com/nodejs/node/tree/master/lib>):
 
 ```json
     "no-restricted-imports": ["error",
index 3fc412fe5d66f83d2d99e7ec0612d0eb07514d50..3bce058049e470ae11407ce1362b3db27c673586 100644 (file)
@@ -57,8 +57,7 @@ or like this:
 
 The custom message will be appended to the default error message. Please note that you may not specify custom error messages for restricted patterns as a particular module may match more than one pattern.
 
-
-To restrict the use of all Node.js core modules (via https://github.com/nodejs/node/tree/master/lib):
+To restrict the use of all Node.js core modules (via <https://github.com/nodejs/node/tree/master/lib>):
 
 ```json
 {
index e1824d5792546a9962a1a3ad0146fef0e4771744..468d0b36a1b38c170f8fed4337e1750765cbd68d 100644 (file)
@@ -2,7 +2,6 @@
 
 Certain properties on objects may be disallowed in a codebase. This is useful for deprecating an API or restricting usage of a module's methods. For example, you may want to disallow using `describe.only` when using Mocha or telling people to use `Object.assign` instead of `_.extend`.
 
-
 ## Rule Details
 
 This rule looks for accessing a given property key on a given object name, either when reading the property's value or invoking it as a function. You may specify an optional message to indicate an alternative API or a reason for the restriction.
index 9c03b67a61237c68c90213397bcd279c8732c63a..68a237de9887f91e237eb8cf82932096614a93ff 100644 (file)
@@ -2,7 +2,6 @@
 
 ECMAScript 6 allows programmers to create strings containing variable or expressions using template literals, instead of string concatenation, by writing expressions like `${variable}` between two backtick quotes (\`). It can be easy to use the wrong quotes when wanting to use template literals, by writing `"${variable}"`, and end up with the literal value `"${variable}"` instead of a string containing the value of the injected expressions.
 
-
 ## Rule Details
 
 This rule aims to warn when a regular string contains what looks like a template literal placeholder. It will warn when it finds a string containing the template literal placeholder (`${something}`) that uses either `"` or `'` for the quotes.
index 0cf99c192961e4972c671e4098fa719bf43a3acd..10bde7769bc5880d1c1bed33ded9ac41d0960e70 100644 (file)
@@ -16,7 +16,6 @@ var foo = undefined;
 
 It's considered a best practice to avoid initializing variables to `undefined`.
 
-
 ## Rule Details
 
 This rule aims to eliminate `var` and `let` variable declarations that initialize to `undefined`.
index 0e183f266d53f51728ca4001676286ded9de6372..0e67c21fd86a00b8dce2967cb04e4fb2daa35c59 100644 (file)
@@ -22,7 +22,6 @@ Because `undefined` can be overwritten or shadowed, reading `undefined` can give
 
 As an alternative, you can use the [no-global-assign](no-global-assign.md) and [no-shadow-restricted-names](no-shadow-restricted-names.md) rules to prevent `undefined` from being shadowed or assigned a different value. This ensures that `undefined` will always hold its original, expected value.
 
-
 ## Rule Details
 
 This rule aims to eliminate the use of `undefined`, and as such, generates a warning whenever it is used.
index 30647031eb1513d4440ad9da1b959cedc05e47e5..24eb337c637f370dff68d08c216884239619d579 100644 (file)
@@ -293,7 +293,6 @@ try {
 }
 ```
 
-
 ## When Not To Use It
 
 If you don't want to be notified about unused variables or function arguments, you can safely turn this rule off.
index 6b7774805dbe48dc11b726dad991259d9139bd14..3f7837622b85904d5fd6dce79d9ddf9af5149752 100644 (file)
@@ -38,7 +38,7 @@ void function(){ foo = 1; }() // will assign foo a value of 1
 +function(){ foo = 1; }() // same as above
 ```
 
-```
+```js
 function(){ foo = 1; }() // will throw SyntaxError
 ```
 
index 6732c92423f2f8252d98083bf7b4f1a406e05689..5193d79ec2c11ae222b592fbd717a6d09982162a 100644 (file)
@@ -2,7 +2,6 @@
 
 (removed) This rule was **removed** in ESLint v1.0 and **replaced** by the [no-extra-parens](no-extra-parens.md) rule. The `"functions"` option in the new rule is equivalent to the removed rule.
 
-
 Although it's possible to wrap functions in parentheses, this can be confusing when the code also contains immediately-invoked function expressions (IIFEs) since parentheses are often used to make this distinction. For example:
 
 ```js
index 79e76655c5dc8769870036aceb7b62cb52a60c12..fee0e62f4ffefebc0d91b0b3a42514ca9bb41b74 100644 (file)
@@ -43,7 +43,6 @@ properties defined where the key name matches name of the assigned variable.
 
 Each of the following properties would warn:
 
-
 ```js
 /*eslint object-shorthand: "error"*/
 /*eslint-env es6*/
index 64e914fcee4931f694e375c5f592a580177a3180..b0f887c13a945f0ce7e51afeb6abab07b91a1b28 100644 (file)
@@ -179,7 +179,6 @@ var foo = $('body')[0];
 var [bar] = $('body'); // fails with a TypeError
 ```
 
-
 ## Further Reading
 
 If you want to learn more about destructuring, check out the links below:
index 2caf9518eabd65718fe85b0f1aa29f5fa757171d..f48ec8003fc8f30c60c2538b9d26f2ebff779a27 100644 (file)
@@ -1,6 +1,5 @@
 # Suggest using named capture group in regular expression (prefer-named-capture-group)
 
-
 ## Rule Details
 
 With the landing of ECMAScript 2018, named capture groups can be used in regular expressions, which can improve their readability.
index ac0a227d1e62e77bd5d5c3bf80b6e4191bbd6f11..9740bc97546f649192d678b1485388c9e0846b6d 100644 (file)
@@ -2,7 +2,6 @@
 
 It is considered good practice to only pass instances of the built-in `Error` object to the `reject()` function for user-defined errors in Promises. `Error` objects automatically store a stack trace, which can be used to debug an error by determining where it came from. If a Promise is rejected with a non-`Error` value, it can be difficult to determine where the rejection occurred.
 
-
 ## Rule Details
 
 This rule aims to ensure that Promises are only rejected with `Error` objects.
index 55bc1bbbe778558df55dced38ead8a84a70a18cb..af0838efba9dbd27932aecde742facd93ce62308 100644 (file)
@@ -19,7 +19,7 @@ The prefer-reflect rule will flag usage of any older method, suggesting to inste
 
 ### Exceptions
 
-```
+```js
 "prefer-reflect": [<enabled>, { "exceptions": [<...exceptions>] }]
 ```
 
index da3196c85f0071938eab5d6bd6e72bc0bb40d483..4453a648f38b95117073b2464819d50cd19ffe25 100644 (file)
@@ -29,7 +29,6 @@ There are two options for this rule:
 * `"always"` enforces providing a radix (default)
 * `"as-needed"` disallows providing the `10` radix
 
-
 ### always
 
 Examples of **incorrect** code for the default `"always"` option:
index 595d0acbf002e54e634a69e189aa0c669539105a..9c84d439360cee41255f744dcb69a7580e8f7fc2 100644 (file)
@@ -81,7 +81,6 @@ In this case, the `fail()` function throws an error that is intended to be caugh
 
 If you are throwing an error inside of an asynchronous function for this purpose, then you may want to disable this rule.
 
-
 ## Related Rules
 
 * [require-yield](require-yield.md)
index 637c9fcf3f383b9641806436abf00e174b6cddc5..08c2cf366847314b3b26efd61b05b6a5e9fde8c3 100644 (file)
@@ -22,7 +22,6 @@ import "my-module.js"
 
 When declaring multiple imports, a sorted list of import declarations make it easier for developers to read the code and find necessary imports later. This rule is purely a matter of style.
 
-
 ## Rule Details
 
 This rule checks all import declarations and verifies that all imports are first sorted by the used member syntax and then alphabetically by the first member or alias name.
index 4607ff4a16856ce6c31201d4b4d0e6fd967df72d..6cceaab12f4092712b68260e8ab3a8659f95ba5a 100644 (file)
@@ -20,7 +20,6 @@ Some style guides may require a consistent spacing for function names.
 
 This rule aims to enforce a consistent spacing after function names. It takes one argument. If it is `"always"` then all function names must be followed by at least one space. If `"never"` then there should be no spaces between the name and the parameter list. The default is `"never"`.
 
-
 Examples of **incorrect** code for this rule:
 
 ```js
index 9bb247727c4fd18555d6dacb89a7feee2e0632f1..330609acd25d7e684f204075b81c513588c55080 100644 (file)
@@ -232,7 +232,6 @@ var arr = [ {
 
 Examples of **correct** code when `"objectsInArrays"` is set to `false`:
 
-
 ```js
 var arr = [{ 'foo': 'bar' }];
 var arr = [{
index 5a885f9821b9503285182d40ca8fd5f1f730f379..66f8f708667142f122e46de30e8ec10d678678fe 100644 (file)
@@ -24,7 +24,7 @@ The rule takes two options.
     * The `"exceptions"` value is an array of string patterns which are considered exceptions to the rule. The rule will not warn when the pattern starts from the beginning of the comment and repeats until the end of the line or `*/` if the comment is a single line comment.
     Please note that exceptions are ignored if the first argument is `"never"`.
 
-    ```
+    ```js
     "spaced-comment": ["error", "always", { "exceptions": ["-", "+"] }]
     ```
 
@@ -32,7 +32,7 @@ The rule takes two options.
     such as an additional `/`, used to denote documentation read by doxygen, vsdoc, etc. which must have additional characters.
     The `"markers"` array will apply regardless of the value of the first argument, e.g. `"always"` or `"never"`.
 
-    ```
+    ```js
     "spaced-comment": ["error", "always", { "markers": ["/"] }]
     ```
 
@@ -281,7 +281,6 @@ subsequent lines are ignored
 /*global ABC*/
 ```
 
-
 ## Related Rules
 
 * [spaced-line-comment](spaced-line-comment.md)
index b50404b74f31a374a336ca006c9bc6812bbed7c1..aaaa27a181fb31ef744fa6e5b6074d5822403c18 100644 (file)
@@ -6,7 +6,6 @@ Some style guides require or disallow a whitespace immediately after the initial
 Whitespace after the `//` makes it easier to read text in comments.
 On the other hand, commenting out code is easier without having to put a whitespace right after the `//`.
 
-
 ## Rule Details
 
 This rule will enforce consistency of spacing after the start of a line comment `//`.
index bd469ea779100d1a4c7a4845f8576082232abe61..b9872c2ad5b20ae55d92404afe0159ff65078cb2 100644 (file)
@@ -20,7 +20,6 @@ This rule has 2 options that are boolean value.
 - `"before": true` requires one or more spaces before colons.
 - `"before": false` (Default) disallows before colons.
 
-
 Examples of **incorrect** code for this rule:
 
 ```js
index 61be8767ed5765a86b7d26a679bf77ca0a236bc0..7743867d29078e7c712d896a8c04fdc7a3d60238 100644 (file)
@@ -9,7 +9,6 @@ var someString = "some description";
 var bar = Symbol(someString);
 ```
 
-
 Using `description` promotes easier debugging: when a symbol is logged the description is used:
 
 ```js
@@ -21,12 +20,10 @@ var foo = Symbol("some description");
 
 It may facilitate identifying symbols when one is observed during debugging.
 
-
 ## Rule Details
 
 This rules requires a description when creating symbols.
 
-
 ## Examples
 
 Examples of **incorrect** code for this rule:
@@ -50,7 +47,6 @@ var someString = "some description";
 var bar = Symbol(someString);
 ```
 
-
 ## When Not To Use It
 
 This rule should not be used in ES3/5 environments.
index ad84c37b6be770978c644402598768498a0b2822..6f350d48597c5703cd81bf768bc3709d26c534b1 100644 (file)
@@ -1,6 +1,6 @@
 # Command Line Interface
 
-To run ESLint on Node.js, you must have npm installed. If npm is not installed, follow the instructions here: https://www.npmjs.com/
+To run ESLint on Node.js, you must have npm installed. If npm is not installed, follow the instructions here: <https://www.npmjs.com/>
 
 Once npm is installed, run the following
 
@@ -30,62 +30,62 @@ The command line utility has several options. You can view the options by runnin
 eslint [options] file.js [file.js] [dir]
 
 Basic configuration:
-  --no-eslintrc                  Disable use of configuration from .eslintrc.*
-  -c, --config path::String      Use this configuration, overriding .eslintrc.* config options if present
-  --env [String]                 Specify environments
-  --ext [String]                 Specify JavaScript file extensions - default: .js
-  --global [String]              Define global variables
-  --parser String                Specify the parser to be used
-  --parser-options Object        Specify parser options
+  --no-eslintrc                   Disable use of configuration from .eslintrc.*
+  -c, --config path::String       Use this configuration, overriding .eslintrc.* config options if present
+  --env [String]                  Specify environments
+  --ext [String]                  Specify JavaScript file extensions
+  --global [String]               Define global variables
+  --parser String                 Specify the parser to be used
+  --parser-options Object         Specify parser options
   --resolve-plugins-relative-to path::String  A folder where plugins should be resolved from, CWD by default
 
 Specifying rules and plugins:
-  --rulesdir [path::String]      Use additional rules from this directory
-  --plugin [String]              Specify plugins
-  --rule Object                  Specify rules
+  --plugin [String]               Specify plugins
+  --rule Object                   Specify rules
+  --rulesdir [path::String]       Load additional rules from this directory. Deprecated: Use rules from plugins
 
 Fixing problems:
-  --fix                          Automatically fix problems
-  --fix-dry-run                  Automatically fix problems without saving the changes to the file system
-  --fix-type Array               Specify the types of fixes to apply (directive, problem, suggestion, layout)
+  --fix                           Automatically fix problems
+  --fix-dry-run                   Automatically fix problems without saving the changes to the file system
+  --fix-type Array                Specify the types of fixes to apply (directive, problem, suggestion, layout)
 
 Ignoring files:
-  --ignore-path path::String     Specify path of ignore file
-  --no-ignore                    Disable use of ignore files and patterns
-  --ignore-pattern [String]      Pattern of files to ignore (in addition to those in .eslintignore)
+  --ignore-path path::String      Specify path of ignore file
+  --no-ignore                     Disable use of ignore files and patterns
+  --ignore-pattern [String]       Pattern of files to ignore (in addition to those in .eslintignore)
 
 Using stdin:
-  --stdin                        Lint code provided on <STDIN> - default: false
-  --stdin-filename String        Specify filename to process STDIN as
+  --stdin                         Lint code provided on <STDIN> - default: false
+  --stdin-filename String         Specify filename to process STDIN as
 
 Handling warnings:
-  --quiet                        Report errors only - default: false
-  --max-warnings Int             Number of warnings to trigger nonzero exit code - default: -1
+  --quiet                         Report errors only - default: false
+  --max-warnings Int              Number of warnings to trigger nonzero exit code - default: -1
 
 Output:
   -o, --output-file path::String  Specify file to write report to
-  -f, --format String            Use a specific output format - default: stylish
-  --color, --no-color            Force enabling/disabling of color
+  -f, --format String             Use a specific output format - default: stylish
+  --color, --no-color             Force enabling/disabling of color
 
 Inline configuration comments:
-  --no-inline-config             Prevent comments from changing config or rules
+  --no-inline-config              Prevent comments from changing config or rules
   --report-unused-disable-directives  Adds reported errors for unused eslint-disable directives
 
 Caching:
-  --cache                        Only check changed files - default: false
-  --cache-file path::String      Path to the cache file. Deprecated: use --cache-location - default: .eslintcache
-  --cache-location path::String  Path to the cache file or directory
-  --cache-strategy String        Strategy to use for detecting changed files - either: metadata or content - default: metadata
+  --cache                         Only check changed files - default: false
+  --cache-file path::String       Path to the cache file. Deprecated: use --cache-location - default: .eslintcache
+  --cache-location path::String   Path to the cache file or directory
+  --cache-strategy String         Strategy to use for detecting changed files in the cache - either: metadata or content - default: metadata
 
 Miscellaneous:
-  --init                         Run config initialization wizard - default: false
-  --env-info                     Output execution environment information - default: false
-  --no-error-on-unmatched-pattern  Prevent errors when pattern is unmatched - default: false
-  --exit-on-fatal-error          Exit with exit code 2 in case of fatal error - default: false
-  --debug                        Output debugging information
-  -h, --help                     Show help
-  -v, --version                  Output the version number
-  --print-config path::String    Print the configuration for the given file
+  --init                          Run config initialization wizard - default: false
+  --env-info                      Output execution environment information - default: false
+  --no-error-on-unmatched-pattern  Prevent errors when pattern is unmatched
+  --exit-on-fatal-error           Exit with exit code 2 in case of fatal error - default: false
+  --debug                         Output debugging information
+  -h, --help                      Show help
+  -v, --version                   Output the version number
+  --print-config path::String     Print the configuration for the given file
 ```
 
 Options that accept array values can be specified by repeating the option or with a comma-delimited list (other than `--ignore-pattern` which does not allow the second style).
@@ -178,20 +178,6 @@ Changes the folder where plugins are resolved from. By default, plugins are reso
 
 ### Specifying rules and plugins
 
-#### `--rulesdir`
-
-This option allows you to specify another directory from which to load rules files. This allows you to dynamically load new rules at run time. This is useful when you have custom rules that aren't suitable for being bundled with ESLint.
-
-Example:
-
-    eslint --rulesdir my-rules/ file.js
-
-The rules in your custom rules directory must follow the same format as bundled rules to work properly. You can also specify multiple locations for custom rules by including multiple `--rulesdir` options:
-
-    eslint --rulesdir my-rules/ --rulesdir my-other-rules/ file.js
-
-Note that, as with core rules and plugin rules, you still need to enable the rules in configuration or via the `--rule` CLI option in order to actually run those rules during linting. Specifying a rules directory with `--rulesdir` does not automatically enable the rules within that directory.
-
 #### `--plugin`
 
 This option specifies a plugin to load. You can omit the prefix `eslint-plugin-` from the plugin name.
@@ -215,6 +201,22 @@ Examples:
     eslint --rule 'guard-for-in: error' --rule 'brace-style: [error, 1tbs]'
     eslint --rule 'jquery/dollar-sign: error'
 
+#### `--rulesdir`
+
+**Deprecated**: Use rules from plugins instead.
+
+This option allows you to specify another directory from which to load rules files. This allows you to dynamically load new rules at run time. This is useful when you have custom rules that aren't suitable for being bundled with ESLint.
+
+Example:
+
+    eslint --rulesdir my-rules/ file.js
+
+The rules in your custom rules directory must follow the same format as bundled rules to work properly. You can also specify multiple locations for custom rules by including multiple `--rulesdir` options:
+
+    eslint --rulesdir my-rules/ --rulesdir my-other-rules/ file.js
+
+Note that, as with core rules and plugin rules, you still need to enable the rules in configuration or via the `--rule` CLI option in order to actually run those rules during linting. Specifying a rules directory with `--rulesdir` does not automatically enable the rules within that directory.
+
 ### Fixing problems
 
 #### `--fix`
@@ -232,7 +234,7 @@ This option has the same effect as `--fix` with one difference: the fixes are no
 
 Because the default formatter does not output the fixed code, you'll have to use another one (e.g. `json`) to get the fixes. Here's an example of this pattern:
 
-```
+```sh
 getSomeText | eslint --stdin --fix-dry-run --format=json
 ```
 
@@ -249,7 +251,7 @@ This option allows you to specify the type of fixes to apply when using either `
 
 You can specify one or more fix type on the command line. Here are some examples:
 
-```
+```sh
 eslint --fix --fix-type suggestion .
 eslint --fix --fix-type suggestion --fix-type problem .
 eslint --fix --fix-type suggestion,layout .
@@ -473,7 +475,7 @@ This option causes ESLint to exit with exit code 2 if one or more fatal parsing
 
 #### `--debug`
 
-This option outputs debugging information to the console. This information is useful when you're seeing a problem and having a hard time pinpointing it. The ESLint team may ask for this debugging information to help solve bugs.  
+This option outputs debugging information to the console. This information is useful when you're seeing a problem and having a hard time pinpointing it. The ESLint team may ask for this debugging information to help solve bugs.
 Add this flag to an ESLint command line invocation in order to get extra debug information as the command is run (e.g. `eslint --debug test.js` and `eslint test.js --debug` are equivalent)
 
 #### `-h`, `--help`
index 091d043b9e40477892fbd58abb715a29b1a10cd3..b1fded2a36c4a80b80a661870f7a3faff04f24e8 100644 (file)
@@ -392,7 +392,7 @@ Here is how overrides work in a configuration file:
 
 ### Relative glob patterns
 
-```
+```pt
 project-root
 ├── app
 │   ├── lib
index d7b3cfd27c8fdef1b02604686b92f1ccdacfcafd..35c2d25dd3f723a76604c1d7e14b71143b42e019 100644 (file)
@@ -1,6 +1,5 @@
 # Ignoring Code
 
-
 * [`ignorePatterns` in Config Files](#ignorepatterns-in-config-files)
 * [The `.eslintignore` File](#the-eslintignore-file)
 * [Using an Alternate File](#using-an-alternate-file)
index 1ee3f2d19bee5a6a5f3c3f0b5cf266cd61cb59da..d44959df2bbc19474f9ecb17ebe5505d03a9297e 100644 (file)
@@ -1,6 +1,5 @@
 # Language Options
 
-
 * [Specifying Environments](#specifying-environments)
 * [Specifying Globals](#specifying-globals)
 * [Specifying Parser Options](#specifying-parser-options)
@@ -174,7 +173,6 @@ Globals can be disabled with the string `"off"`. For example, in an environment
 
 For historical reasons, the boolean value `false` and the string value `"readable"` are equivalent to `"readonly"`. Similarly, the boolean value `true` and the string value `"writeable"` are equivalent to `"writable"`. However, the use of older values is deprecated.
 
-
 ## Specifying Parser Options
 
 ESLint allows you to specify the JavaScript language options you want to support. By default, ESLint expects ECMAScript 5 syntax. You can override that setting to enable support for other ECMAScript versions as well as JSX by using parser options.
@@ -189,6 +187,7 @@ Parser options are set in your `.eslintrc.*` file by using the `parserOptions` p
 
 * `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, 10, 11, 12, or 13 to specify the version of ECMAScript syntax you want to use. You can also set to 2015 (same as 6), 2016 (same as 7), 2017 (same as 8), 2018 (same as 9), 2019 (same as 10), 2020 (same as 11), 2021 (same as 12), or 2022 (same as 13) to use the year-based naming. You can also set "latest" to use the most recently supported version.
 * `sourceType` - set to `"script"` (default) or `"module"` if your code is in ECMAScript modules.
+* `allowReserved` - allow the use of reserved words as identifiers (if `ecmaVersion` is 3).
 * `ecmaFeatures` - an object indicating which additional language features you'd like to use:
     * `globalReturn` - allow `return` statements in the global scope
     * `impliedStrict` - enable global [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) (if `ecmaVersion` is 5 or greater)
index 0235586c98080976a5dacf9fc431886b684a5707..9d2c9294c4c8ebdac359a3037cb6dcb26343a7f2 100644 (file)
@@ -1,6 +1,5 @@
 # Plugins
 
-
 * [Specifying Parser](#specifying-parser)
 * [Specifying Processor](#specifying-processor)
 * [Configuring Plugins](#configuring-plugins)
index 0191f6348862f340152999566a6bc9bbe42ec6e2..4f45b4a876a530b23f44fbbea9c0e768e44cbe84 100644 (file)
@@ -1,6 +1,5 @@
 # Rules
 
-
 * [Configuring Rules](#configuring-rules)
 * [Disabling Rules](#disabling-rules)
 
index 3c9633bb31553ecf8e0d923f9d886d16fb950377..cf808ddc022c21874f6ba225363038a9ef5995f4 100644 (file)
@@ -12,7 +12,7 @@ Prerequisites: [Node.js](https://nodejs.org/en/) (`^12.22.0`, `^14.17.0`, or `>=
 
 You can install ESLint using npm or yarn:
 
-```
+```sh
 npm install eslint --save-dev
 
 # or
@@ -22,7 +22,7 @@ yarn add eslint --dev
 
 You should then set up a configuration file, and the easiest way to do that is to use the `--init` flag:
 
-```
+```sh
 $ npx eslint --init
 
 # or
@@ -34,7 +34,7 @@ $ yarn run eslint --init
 
 After that, you can run ESLint on any file or directory like this:
 
-```
+```sh
 $ npx eslint yourfile.js
 
 # or
index c919c2d0d42eec53533f4070e5d961e91998259d..f7680be4021c3cb2506baf5fd284af89ecaae5bc 100644 (file)
@@ -15,7 +15,7 @@
     * [eslint.tmbundle](https://github.com/ryanfitzer/eslint.tmbundle)
     * [javascript-eslint.tmbundle](https://github.com/natesilva/javascript-eslint.tmbundle)
 * Atom: [linter-eslint](https://atom.io/packages/linter-eslint)
-* IntelliJ IDEA, RubyMine, WebStorm, PhpStorm, PyCharm, AppCode, Android Studio, 0xDBE: [ESLint Plugin](https://plugins.jetbrains.com/plugin/7494-eslint)
+* IntelliJ IDEA, WebStorm, PhpStorm, PyCharm, RubyMine, and other JetBrains IDEs: [How to use ESLint](https://www.jetbrains.com/help/webstorm/eslint.html)
 * Visual Studio Code: [ESLint Extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
 * Brackets: Included and [Brackets ESLint](https://github.com/brackets-userland/brackets-eslint)
 
index c5ac5f2352337c4fc0e0d91c16a1360d7784f88b..e05ee70d6251b8dab9b27298757f312e98777653 100644 (file)
@@ -15,7 +15,7 @@ Before beginning the process of migrating to ESLint, it's helpful to understand
 
 To install Polyjuice:
 
-```
+```sh
 $ npm install -g polyjuice
 ```
 
@@ -23,7 +23,7 @@ Polyjuice works with JSON configuration files, so if you're using a JavaScript o
 
 To convert your configuration file, pass in the location of your `.jscs.json` file using the `--jscs` flag:
 
-```
+```sh
 $ polyjuice --jscs .jscsrc.json > .eslintrc.json
 ```
 
@@ -31,7 +31,7 @@ This creates a `.eslintrc.json` with the equivalent rules from `.jscsrc.json`.
 
 If you have multiple `.jscsrc.json` files, you can pass them all and Polyjuice will combine them into one `.eslintrc.json` file:
 
-```
+```sh
 $ polyjuice --jscs .jscsrc.json ./foo/.jscsrc.json > .eslintrc.json
 ```
 
@@ -41,7 +41,7 @@ $ polyjuice --jscs .jscsrc.json ./foo/.jscsrc.json > .eslintrc.json
 
 If you don't want to convert your JSCS configuration directly into an ESLint configuration, then you can use ESLint's built-in wizard to get you started. Just run:
 
-```
+```sh
 $ eslint --init
 ```
 
@@ -74,7 +74,7 @@ As an example, suppose that you are using the `airbnb` preset, so your `.jscsrc`
 
 In order to get the same functionality in ESLint, you would first need to install the `eslint-config-airbnb` shareable config package:
 
-```
+```sh
 $ npm install eslint-config-airbnb-base --save-dev
 ```
 
@@ -110,13 +110,13 @@ Both JSCS and ESLint have command line arguments corresponding to many of their
 
 JSCS uses the `--fix` option to apply automatic fixes to code:
 
-```
+```sh
 $ jscs --fix file.js
 ```
 
 ESLint has the same option:
 
-```
+```sh
 $ eslint --fix file.js
 ```
 
@@ -124,13 +124,13 @@ $ eslint --fix file.js
 
 The JSCS `--auto-configure` option created a configuration based on what it found in a given file:
 
-```
+```sh
 $ jscs --auto-configure file.js
 ```
 
 In ESLint, there's a similar option when you use `--init`. Just select "Inspect your JavaScript file(s)":
 
-```
+```sh
 $ eslint --init
 ? How would you like to configure ESLint? (Use arrow keys)
 > Answer questions about your style
@@ -142,30 +142,28 @@ $ eslint --init
 
 JSCS allows you to specify a configuration file to use on the command line using either `--config` or `-c`, such as:
 
-```
+```sh
 $ jscs --config myconfig.json file.js
 $ jscs -c myconfig.json file.js
 ```
 
 Both flags are also supported by ESLint:
 
-```
+```sh
 $ eslint --config myconfig.json file.js
 $ eslint -c myconfig.json file.js
 ```
 
-
-
 ## Piping Code Into ESLint
 
 In JSCS, you can pipe code in like this:
 
-```
+```sh
 $ cat file.js | jscs
 ```
 
 In ESLint, you can also pipe in code, but you need to use the `--stdin` flag:
 
-```
+```sh
 $ cat file.js | eslint --stdin
 ```
index 95a3a1774e9c0176123774fe2114ba55ea672bfe..c5f50b3a1d04e6dcfdd47a6814f7e2ac2e03a42e 100644 (file)
@@ -285,7 +285,7 @@ if (variable) {
 }
 ```
 
-Further Reading: https://estools.github.io/escope/
+Further Reading: <https://estools.github.io/escope/>
 
 ## Default Changes When Using `eslint:recommended`
 
index b62ef053c09cad39f65882e061aa6d81747e8bf0..8f78291d5cdbf972dd93cea392b3dcd360ef10ab 100644 (file)
@@ -4,7 +4,7 @@ ESLint v4.0.0 is the fourth major version release. We have made several breaking
 
 The lists below are ordered roughly by the number of users each change is expected to affect, where the first items are expected to affect the most users.
 
-### Breaking changes for users
+## Breaking changes for users
 
 1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
 1. [The `indent` rule is more strict](#indent-rewrite)
@@ -15,14 +15,14 @@ The lists below are ordered roughly by the number of users each change is expect
 1. [The `no-multi-spaces` rule is more strict by default](#no-multi-spaces-eol-comments)
 1. [References to scoped plugins in config files are now required to include the scope](#scoped-plugin-resolution)
 
-### Breaking changes for plugin/custom rule developers
+## Breaking changes for plugin/custom rule developers
 
 1. [`RuleTester` now validates properties of test cases](#rule-tester-validation)
 1. [AST nodes no longer have comment properties](#comment-attachment)
 1. [`LineComment` and `BlockComment` events will no longer be emitted during AST traversal](#event-comments)
 1. [Shebangs are now returned from comment APIs](#shebangs)
 
-### Breaking changes for integration developers
+## Breaking changes for integration developers
 
 1. [The `global` property in the `linter.verify()` API is no longer supported](#global-property)
 1. [More report messages now have full location ranges](#report-locations)
@@ -186,7 +186,7 @@ Starting in 4.0, `LineComment` and `BlockComments` events will not be emitted du
 
 **To address:** Instead of relying on `LineComment` and `BlockComment`, rules can now use `sourceCode.getAllComments()` to get all comments in a file. To check all comments of a specific type, rules can use the following pattern:
 
-```
+```js
 sourceCode.getAllComments().filter(comment => comment.type === "Line");
 sourceCode.getAllComments().filter(comment => comment.type === "Block");
 ```
@@ -199,7 +199,7 @@ In 4.0, shebang comments are treated as comment tokens of type `Shebang` and wil
 
 **To address:** If you have a custom rule that performs operations on comments, some additional logic might be required to ensure that shebang comments are correctly handled or filtered out:
 
-```
+```js
 sourceCode.getAllComments().filter(comment => comment.type !== "Shebang");
 ```
 
index da5c435aa8a76b360dea6039d4b2f24cddb8ae0c..372963163cd01829b7a173a4ceff1999a0c27938 100644 (file)
@@ -4,7 +4,7 @@ ESLint v5.0.0 is the fifth major version release. We have made a few breaking ch
 
 The lists below are ordered roughly by the number of users each change is expected to affect, where the first items are expected to affect the most users.
 
-### Breaking changes for users
+## Breaking changes for users
 
 1. [Node.js 4 is no longer supported](#drop-node-4)
 1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
@@ -16,7 +16,7 @@ The lists below are ordered roughly by the number of users each change is expect
 1. [Plugins in scoped packages are now resolvable in configs](#scoped-plugins)
 1. [Multi-line `eslint-disable-line` directives are now reported as problems](#multiline-directives)
 
-### Breaking changes for plugin/custom rule developers
+## Breaking changes for plugin/custom rule developers
 
 1. [The `parent` property of AST nodes is now set before rules start running](#parent-before-rules)
 1. [When using the default parser, spread operators now have type `SpreadElement`](#spread-operators)
@@ -27,7 +27,7 @@ The lists below are ordered roughly by the number of users each change is expect
 1. [`RuleTester` now uses strict equality checks in its assertions](#rule-tester-equality)
 1. [Rules are now required to provide messages along with reports](#required-report-messages)
 
-### Breaking changes for integration developers
+## Breaking changes for integration developers
 
 1. [The `source` property is no longer available on individual linting messages](#source-property)
 1. [Fatal errors now result in an exit code of 2](#exit-code-two)
index 3baec19d95c6fe732ecf44f338f44988ac4c2d49..225cc4c0e3bdf06308d70779a255352a95eee8dc 100644 (file)
@@ -4,7 +4,7 @@ ESLint v6.0.0 is a major release of ESLint. We have made a few breaking changes
 
 The lists below are ordered roughly by the number of users each change is expected to affect, where the first items are expected to affect the most users.
 
-### Breaking changes for users
+## Breaking changes for users
 
 1. [Node.js 6 is no longer supported](#drop-node-6)
 1. [`eslint:recommended` has been updated](#eslint-recommended-changes)
@@ -20,14 +20,14 @@ The lists below are ordered roughly by the number of users each change is expect
 1. [The deprecated `experimentalObjectRestSpread` option has been removed](#experimental-object-rest-spread)
 1. [User-provided regular expressions in rule options are parsed with the unicode flag](#unicode-regexes)
 
-### Breaking changes for plugin/custom rule developers
+## Breaking changes for plugin/custom rule developers
 
 1. [Plugin authors may need to update installation instructions](#plugin-documentation)
 1. [`RuleTester` now validates against invalid `default` keywords in rule schemas](#rule-tester-defaults)
 1. [`RuleTester` now requires an absolute path on `parser` option](#rule-tester-parser)
 1. [The `eslintExplicitGlobalComment` scope analysis property has been removed](#eslintExplicitGlobalComment)
 
-### Breaking changes for integration developers
+## Breaking changes for integration developers
 
 1. [Plugins and shareable configs are no longer affected by ESLint's location](#package-loading-simplification)
 1. [`Linter` no longer tries to load missing parsers from the filesystem](#linter-parsers)
index 351309cc00fa1ce94715f1f19b06df8818516bb1..444ac124c4cd0925de336827af60b6f047eb7f54 100644 (file)
@@ -51,7 +51,6 @@ ESLint v8.0.0 has removed the `codeframe` and `table` formatters from the core.
 
 **Related issue(s):** [#14277](https://github.com/eslint/eslint/issues/14277), [#14316](https://github.com/eslint/eslint/pull/14316)
 
-
 ## <a name="comma-dangle"></a> `comma-dangle` rule schema is stricter
 
 In ESLint v7.0.0, the `comma-dangle` rule could be configured like this without error:
@@ -105,7 +104,6 @@ Four new rules have been enabled in the `eslint:recommended` preset.
 
 **Related issue(s):** [#14673](https://github.com/eslint/eslint/issues/14673)
 
-
 ## <a name="suggestions"></a> Rules require `meta.hasSuggestions` to provide suggestions
 
 In ESLint v7.0.0, rules that [provided suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions) did not need to let ESLint know. In v8.0.0, rules providing suggestions need to set their `meta.hasSuggestions` to `true`. This informs ESLint that the rule intends to provide suggestions. Without this property, any attempt to provide a suggestion will result in an error.
@@ -219,7 +217,6 @@ In ESLint v8.0.0 (via Acorn v8.0.0), the key and value are now separate objects
 
 **Related issue(s):** [#14591](https://github.com/eslint/eslint/pull/14591#issuecomment-887733070)
 
-
 ## <a name="remove-cliengine"></a> The `CLIEngine` class has been removed
 
 The `CLIEngine` class has been removed and replaced by the [`ESLint` class](https://eslint.org/docs/developer-guide/nodejs-api#eslint-class).
index 05f1a1ceb6eea550115e56439d916d028c0a7391..606d13f88f62124ce16ade2aa10d48e04c349ab9 100644 (file)
@@ -2,7 +2,7 @@
 const os = require("os");
 const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
 
-if (os.arch() === "arm64") {
+if (os.platform === "linux" && os.arch() === "arm64") {
 
     // For arm64 architecture, install chromium-browser using "apt-get install chromium-browser"
     process.env.CHROME_BIN = "/usr/bin/chromium-browser";
@@ -16,6 +16,15 @@ module.exports = function(config) {
         // base path that will be used to resolve all patterns (eg. files, exclude)
         basePath: "",
 
+        // next three sections allow console.log to work
+        client: {
+            captureConsole: true
+        },
+
+        browserConsoleLogOptions: {
+            terminal: true,
+            level: "log"
+        },
 
         /*
          * frameworks to use
index 477310da5850e7c488adcc998c1e3d7985fd215e..f09d143d2557851d307047875fe9862616f2a12b 100644 (file)
@@ -178,7 +178,7 @@ async function printResults(engine, results, format, outputFile) {
         return false;
     }
 
-    const output = formatter.format(results);
+    const output = await formatter.format(results);
 
     if (output) {
         if (outputFile) {
index cb6f403380dfe111d0195fc6b11d26eddf99fa88..a655a6d83ca08ba019091279bc1b61e634725569 100644 (file)
@@ -26,7 +26,7 @@ exports.defaultConfig = [
 
                 /*
                  * Because we try to delay loading rules until absolutely
-                 * necessary, a proxy  allows us to hook into the lazy-loading
+                 * necessary, a proxy allows us to hook into the lazy-loading
                  * aspect of the rules map while still keeping all of the
                  * relevant configuration inside of the config array.
                  */
@@ -46,7 +46,16 @@ exports.defaultConfig = [
             ".git/**"
         ],
         languageOptions: {
-            parser: "@/espree"
+            ecmaVersion: "latest",
+            sourceType: "module",
+            parser: "@/espree",
+            parserOptions: {}
+        }
+    },
+    {
+        files: ["**/*.cjs"],
+        languageOptions: {
+            sourceType: "commonjs"
         }
     }
 ];
index ef9cb33ca287a5933ef764e421edb050317cb3c9..c06fd92a383809cf8faacd980c83f1c63b639796 100644 (file)
@@ -52,13 +52,13 @@ class FlatConfigArray extends ConfigArray {
      * @param {{basePath: string, baseConfig: FlatConfig}} options The options
      *      to use for the config array instance.
      */
-    constructor(configs, { basePath, baseConfig = defaultConfig }) {
+    constructor(configs, { basePath, baseConfig = defaultConfig } = {}) {
         super(configs, {
             basePath,
             schema: flatConfigSchema
         });
 
-        this.unshift(baseConfig);
+        this.unshift(...baseConfig);
     }
 
     /* eslint-disable class-methods-use-this -- Desired as instance method */
diff --git a/eslint/lib/config/flat-config-helpers.js b/eslint/lib/config/flat-config-helpers.js
new file mode 100644 (file)
index 0000000..778f129
--- /dev/null
@@ -0,0 +1,67 @@
+/**
+ * @fileoverview Shared functions to work with configs.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//-----------------------------------------------------------------------------
+// Functions
+//-----------------------------------------------------------------------------
+
+/**
+ * Parses a ruleId into its plugin and rule parts.
+ * @param {string} ruleId The rule ID to parse.
+ * @returns {{pluginName:string,ruleName:string}} The plugin and rule
+ *      parts of the ruleId;
+ */
+function parseRuleId(ruleId) {
+    let pluginName, ruleName;
+
+    // distinguish between core rules and plugin rules
+    if (ruleId.includes("/")) {
+        pluginName = ruleId.slice(0, ruleId.lastIndexOf("/"));
+        ruleName = ruleId.slice(pluginName.length + 1);
+    } else {
+        pluginName = "@";
+        ruleName = ruleId;
+    }
+
+    return {
+        pluginName,
+        ruleName
+    };
+}
+
+/**
+ * Retrieves a rule instance from a given config based on the ruleId.
+ * @param {string} ruleId The rule ID to look for.
+ * @param {FlatConfig} config The config to search.
+ * @returns {import("../shared/types").Rule|undefined} The rule if found
+ *      or undefined if not.
+ */
+function getRuleFromConfig(ruleId, config) {
+
+    const { pluginName, ruleName } = parseRuleId(ruleId);
+
+    const plugin = config.plugins && config.plugins[pluginName];
+    let rule = plugin && plugin.rules && plugin.rules[ruleName];
+
+    // normalize function rules into objects
+    if (rule && typeof rule === "function") {
+        rule = {
+            create: rule
+        };
+    }
+
+    return rule;
+}
+
+//-----------------------------------------------------------------------------
+// Exports
+//-----------------------------------------------------------------------------
+
+module.exports = {
+    parseRuleId,
+    getRuleFromConfig
+};
index c8cc711494090bfc932791836e1c9e227ea88ab7..cb8e7961add509f5c4e698f5850d75e7bcd30ddf 100644 (file)
@@ -195,13 +195,6 @@ function assertIsObjectOrString(value) {
 // Low-Level Schemas
 //-----------------------------------------------------------------------------
 
-
-/** @type {ObjectPropertySchema} */
-const numberSchema = {
-    merge: "replace",
-    validate: "number"
-};
-
 /** @type {ObjectPropertySchema} */
 const booleanSchema = {
     merge: "replace",
@@ -415,6 +408,18 @@ const rulesSchema = {
     }
 };
 
+/** @type {ObjectPropertySchema} */
+const ecmaVersionSchema = {
+    merge: "replace",
+    validate(value) {
+        if (typeof value === "number" || value === "latest") {
+            return;
+        }
+
+        throw new TypeError("Expected a number or \"latest\".");
+    }
+};
+
 /** @type {ObjectPropertySchema} */
 const sourceTypeSchema = {
     merge: "replace",
@@ -439,7 +444,7 @@ exports.flatConfigSchema = {
     },
     languageOptions: {
         schema: {
-            ecmaVersion: numberSchema,
+            ecmaVersion: ecmaVersionSchema,
             sourceType: sourceTypeSchema,
             globals: globalsSchema,
             parser: parserSchema,
index 527a56e1799c8fe8f7b469cdd93446bfa792c84d..9172f93568812cccc56af9a679bda4b5710f13a1 100644 (file)
 //-----------------------------------------------------------------------------
 
 const ajv = require("../shared/ajv")();
+const { parseRuleId, getRuleFromConfig } = require("./flat-config-helpers");
+const ruleReplacements = require("../../conf/replacements.json");
 
 //-----------------------------------------------------------------------------
 // Helpers
 //-----------------------------------------------------------------------------
 
 /**
- * Finds a rule with the given ID in the given config.
- * @param {string} ruleId The ID of the rule to find.
+ * Throws a helpful error when a rule cannot be found.
+ * @param {Object} ruleId The rule identifier.
+ * @param {string} ruleId.pluginName The ID of the rule to find.
+ * @param {string} ruleId.ruleName The ID of the rule to find.
  * @param {Object} config The config to search in.
  * @throws {TypeError} For missing plugin or rule.
- * @returns {{create: Function, schema: (Array|null)}} THe rule object.
+ * @returns {void}
  */
-function findRuleDefinition(ruleId, config) {
-    const ruleIdParts = ruleId.split("/");
-    let pluginName, ruleName;
-
-    // built-in rule
-    if (ruleIdParts.length === 1) {
-        pluginName = "@";
-        ruleName = ruleIdParts[0];
-    } else {
-        ruleName = ruleIdParts.pop();
-        pluginName = ruleIdParts.join("/");
-    }
+function throwRuleNotFoundError({ pluginName, ruleName }, config) {
+
+    const ruleId = pluginName === "@" ? ruleName : `${pluginName}/${ruleName}`;
 
     const errorMessageHeader = `Key "rules": Key "${ruleId}"`;
     let errorMessage = `${errorMessageHeader}: Could not find plugin "${pluginName}".`;
 
     // if the plugin exists then we need to check if the rule exists
     if (config.plugins && config.plugins[pluginName]) {
+        const replacementRuleName = ruleReplacements.rules[ruleName];
 
-        const plugin = config.plugins[pluginName];
+        if (pluginName === "@" && replacementRuleName) {
 
-        // first check for exact rule match
-        if (plugin.rules && plugin.rules[ruleName]) {
-            return config.plugins[pluginName].rules[ruleName];
-        }
+            errorMessage = `${errorMessageHeader}: Rule "${ruleName}" was removed and replaced by "${replacementRuleName}".`;
+
+        } else {
 
-        errorMessage = `${errorMessageHeader}: Could not find "${ruleName}" in plugin "${pluginName}".`;
+            errorMessage = `${errorMessageHeader}: Could not find "${ruleName}" in plugin "${pluginName}".`;
 
-        // otherwise, let's see if we can find the rule name elsewhere
-        for (const [otherPluginName, otherPlugin] of Object.entries(config.plugins)) {
-            if (otherPlugin.rules && otherPlugin.rules[ruleName]) {
-                errorMessage += ` Did you mean "${otherPluginName}/${ruleName}"?`;
-                break;
+            // otherwise, let's see if we can find the rule name elsewhere
+            for (const [otherPluginName, otherPlugin] of Object.entries(config.plugins)) {
+                if (otherPlugin.rules && otherPlugin.rules[ruleName]) {
+                    errorMessage += ` Did you mean "${otherPluginName}/${ruleName}"?`;
+                    break;
+                }
             }
+
         }
 
         // falls through to throw error
@@ -154,7 +151,11 @@ class RuleValidator {
                 continue;
             }
 
-            const rule = findRuleDefinition(ruleId, config);
+            const rule = getRuleFromConfig(ruleId, config);
+
+            if (!rule) {
+                throwRuleNotFoundError(parseRuleId(ruleId), config);
+            }
 
             // Precompile and cache validator the first time
             if (!this.validators.has(rule)) {
index 8886d45ab43480d4bbec8480aa0b1eda3730cced..6274772ad856a4adb4c7046212b01abe0ddfc622 100644 (file)
@@ -34,7 +34,12 @@ const { version } = require("../../package.json");
 /** @typedef {import("../shared/types").LintMessage} LintMessage */
 /** @typedef {import("../shared/types").Plugin} Plugin */
 /** @typedef {import("../shared/types").Rule} Rule */
-/** @typedef {import("./load-formatter").Formatter} Formatter */
+
+/**
+ * The main formatter object.
+ * @typedef Formatter
+ * @property {function(LintResult[]): string | Promise<string>} format format function.
+ */
 
 /**
  * The options with which to configure the ESLint instance.
@@ -617,7 +622,7 @@ class ESLint {
             throw new Error("'name' must be a string");
         }
 
-        const { cliEngine } = privateMembersMap.get(this);
+        const { cliEngine, options } = privateMembersMap.get(this);
         const formatter = cliEngine.getFormatter(name);
 
         if (typeof formatter !== "function") {
@@ -629,7 +634,7 @@ class ESLint {
             /**
              * The main formatter method.
              * @param {LintResults[]} results The lint results to format.
-             * @returns {string} The formatted lint results.
+             * @returns {string | Promise<string>} The formatted lint results.
              */
             format(results) {
                 let rulesMeta = null;
@@ -637,6 +642,9 @@ class ESLint {
                 results.sort(compareResultsByFilePath);
 
                 return formatter(results, {
+                    get cwd() {
+                        return options.cwd;
+                    },
                     get rulesMeta() {
                         if (!rulesMeta) {
                             rulesMeta = createRulesMeta(cliEngine.getRules());
index 4e07a25751e114102711d94e30d5ac1367ac8a56..f897b8ddb8c011e53885d6e9a272cf54b3b3e77a 100644 (file)
@@ -37,6 +37,8 @@ const
     SourceCodeFixer = require("./source-code-fixer"),
     timing = require("./timing"),
     ruleReplacements = require("../../conf/replacements.json");
+const { getRuleFromConfig } = require("../config/flat-config-helpers");
+const { FlatConfigArray } = require("../config/flat-config-array");
 
 const debug = require("debug")("eslint:linter");
 const MAX_AUTOFIX_PASSES = 10;
@@ -45,6 +47,7 @@ const DEFAULT_ECMA_VERSION = 5;
 const commentParser = new ConfigCommentParser();
 const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };
 const parserSymbol = Symbol.for("eslint.RuleTester.parser");
+const globals = require("../../conf/globals");
 
 //------------------------------------------------------------------------------
 // Typedefs
@@ -57,6 +60,7 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
 /** @typedef {import("../shared/types").GlobalConf} GlobalConf */
 /** @typedef {import("../shared/types").LintMessage} LintMessage */
 /** @typedef {import("../shared/types").ParserOptions} ParserOptions */
+/** @typedef {import("../shared/types").LanguageOptions} LanguageOptions */
 /** @typedef {import("../shared/types").Processor} Processor */
 /** @typedef {import("../shared/types").Rule} Rule */
 
@@ -126,6 +130,38 @@ const parserSymbol = Symbol.for("eslint.RuleTester.parser");
 // Helpers
 //------------------------------------------------------------------------------
 
+/**
+ * Determines if a given object is Espree.
+ * @param {Object} parser The parser to check.
+ * @returns {boolean} True if the parser is Espree or false if not.
+ */
+function isEspree(parser) {
+    return !!(parser === espree || parser[parserSymbol] === espree);
+}
+
+/**
+ * Retrieves globals for the given ecmaVersion.
+ * @param {number} ecmaVersion The version to retrieve globals for.
+ * @returns {Object} The globals for the given ecmaVersion.
+ */
+function getGlobalsForEcmaVersion(ecmaVersion) {
+
+    switch (ecmaVersion) {
+        case 3:
+            return globals.es3;
+
+        case 5:
+            return globals.es5;
+
+        default:
+            if (ecmaVersion < 2015) {
+                return globals[`es${ecmaVersion + 2009}`];
+            }
+
+            return globals[`es${ecmaVersion}`];
+    }
+}
+
 /**
  * Ensures that variables representing built-in properties of the Global Object,
  * and any globals declared by special block comments, are present in the global
@@ -268,7 +304,7 @@ function createDisableDirectives(options) {
     for (const ruleId of directiveRules) {
 
         // push to directives, if the rule is defined(including null, e.g. /*eslint enable*/)
-        if (ruleId === null || ruleMapper(ruleId) !== null) {
+        if (ruleId === null || !!ruleMapper(ruleId)) {
             result.directives.push({ parentComment, type, line: commentToken.loc.start.line, column: commentToken.loc.start.column + 1, ruleId });
         } else {
             result.directiveProblems.push(createLintingProblem({ ruleId, loc: commentToken.loc }));
@@ -400,7 +436,7 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {
                         const rule = ruleMapper(name);
                         const ruleValue = parseResult.config[name];
 
-                        if (rule === null) {
+                        if (!rule) {
                             problems.push(createLintingProblem({ ruleId: name, loc: comment.loc }));
                             return;
                         }
@@ -447,7 +483,8 @@ function getDirectiveComments(filename, ast, ruleMapper, warnInlineConfig) {
  * @returns {number} normalized ECMAScript version
  */
 function normalizeEcmaVersion(parser, ecmaVersion) {
-    if ((parser[parserSymbol] || parser) === espree) {
+
+    if (isEspree(parser)) {
         if (ecmaVersion === "latest") {
             return espree.latestEcmaVersion;
         }
@@ -460,6 +497,38 @@ function normalizeEcmaVersion(parser, ecmaVersion) {
     return ecmaVersion >= 2015 ? ecmaVersion - 2009 : ecmaVersion;
 }
 
+/**
+ * Normalize ECMAScript version from the initial config into languageOptions (year)
+ * format.
+ * @param {any} [ecmaVersion] ECMAScript version from the initial config
+ * @returns {number} normalized ECMAScript version
+ */
+function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
+
+    switch (ecmaVersion) {
+        case 3:
+            return 3;
+
+        // void 0 = no ecmaVersion specified so use the default
+        case 5:
+        case void 0:
+            return 5;
+
+        default:
+            if (typeof ecmaVersion === "number") {
+                return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
+            }
+    }
+
+    /*
+     * We default to the latest supported ecmaVersion for everything else.
+     * Remember, this is for languageOptions.ecmaVersion, which sets the version
+     * that is used for a number of processes inside of ESLint. It's normally
+     * safe to assume people want the latest unless otherwise specified.
+     */
+    return espree.latestEcmaVersion + 2009;
+}
+
 const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)(?:\*\/|$)/gsu;
 
 /**
@@ -511,7 +580,11 @@ function normalizeFilename(filename) {
  * @returns {Required<VerifyOptions> & InternalOptions} Normalized options
  */
 function normalizeVerifyOptions(providedOptions, config) {
-    const disableInlineConfig = config.noInlineConfig === true;
+
+    const linterOptions = config.linterOptions || config;
+
+    // .noInlineConfig for eslintrc, .linterOptions.noInlineConfig for flat
+    const disableInlineConfig = linterOptions.noInlineConfig === true;
     const ignoreInlineConfig = providedOptions.allowInlineConfig === false;
     const configNameOfNoInlineConfig = config.configNameOfNoInlineConfig
         ? ` (${config.configNameOfNoInlineConfig})`
@@ -523,7 +596,9 @@ function normalizeVerifyOptions(providedOptions, config) {
         reportUnusedDisableDirectives = reportUnusedDisableDirectives ? "error" : "off";
     }
     if (typeof reportUnusedDisableDirectives !== "string") {
-        reportUnusedDisableDirectives = config.reportUnusedDisableDirectives ? "warn" : "off";
+        reportUnusedDisableDirectives =
+            linterOptions.reportUnusedDisableDirectives
+                ? "warn" : "off";
     }
 
     return {
@@ -566,6 +641,30 @@ function resolveParserOptions(parser, providedOptions, enabledEnvironments) {
     return mergedParserOptions;
 }
 
+/**
+ * Converts parserOptions to languageOptions for backwards compatibility with eslintrc.
+ * @param {ConfigData} config Config object.
+ * @param {Object} config.globals Global variable definitions.
+ * @param {Parser} config.parser The parser to use.
+ * @param {ParserOptions} config.parserOptions The parserOptions to use.
+ * @returns {LanguageOptions} The languageOptions equivalent.
+ */
+function createLanguageOptions({ globals: configuredGlobals, parser, parserOptions }) {
+
+    const {
+        ecmaVersion,
+        sourceType
+    } = parserOptions;
+
+    return {
+        globals: configuredGlobals,
+        ecmaVersion: normalizeEcmaVersionForLanguageOptions(ecmaVersion),
+        sourceType,
+        parser,
+        parserOptions
+    };
+}
+
 /**
  * Combines the provided globals object with the globals from environments
  * @param {Record<string, GlobalConf>} providedGlobals The 'globals' key in a config
@@ -614,20 +713,21 @@ function getRuleOptions(ruleConfig) {
 /**
  * Analyze scope of the given AST.
  * @param {ASTNode} ast The `Program` node to analyze.
- * @param {ParserOptions} parserOptions The parser options.
+ * @param {LanguageOptions} languageOptions The parser options.
  * @param {Record<string, string[]>} visitorKeys The visitor keys.
  * @returns {ScopeManager} The analysis result.
  */
-function analyzeScope(ast, parserOptions, visitorKeys) {
+function analyzeScope(ast, languageOptions, visitorKeys) {
+    const parserOptions = languageOptions.parserOptions;
     const ecmaFeatures = parserOptions.ecmaFeatures || {};
-    const ecmaVersion = parserOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
+    const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
 
     return eslintScope.analyze(ast, {
         ignoreEval: true,
         nodejsScope: ecmaFeatures.globalReturn,
         impliedStrict: ecmaFeatures.impliedStrict,
         ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
-        sourceType: parserOptions.sourceType || "script",
+        sourceType: languageOptions.sourceType || "script",
         childVisitorKeys: visitorKeys || evk.KEYS,
         fallback: Traverser.getKeys
     });
@@ -638,25 +738,29 @@ function analyzeScope(ast, parserOptions, visitorKeys) {
  * optimization of functions, so it's best to keep the try-catch as isolated
  * as possible
  * @param {string} text The text to parse.
- * @param {Parser} parser The parser to parse.
- * @param {ParserOptions} providedParserOptions Options to pass to the parser
+ * @param {LanguageOptions} languageOptions Options to pass to the parser
  * @param {string} filePath The path to the file being parsed.
  * @returns {{success: false, error: Problem}|{success: true, sourceCode: SourceCode}}
  * An object containing the AST and parser services if parsing was successful, or the error if parsing failed
  * @private
  */
-function parse(text, parser, providedParserOptions, filePath) {
+function parse(text, languageOptions, filePath) {
     const textToParse = stripUnicodeBOM(text).replace(astUtils.shebangPattern, (match, captured) => `//${captured}`);
-    const parserOptions = Object.assign({}, providedParserOptions, {
-        loc: true,
-        range: true,
-        raw: true,
-        tokens: true,
-        comment: true,
-        eslintVisitorKeys: true,
-        eslintScopeManager: true,
-        filePath
-    });
+    const { ecmaVersion, sourceType, parser } = languageOptions;
+    const parserOptions = Object.assign(
+        { ecmaVersion, sourceType },
+        languageOptions.parserOptions,
+        {
+            loc: true,
+            range: true,
+            raw: true,
+            tokens: true,
+            comment: true,
+            eslintVisitorKeys: true,
+            eslintScopeManager: true,
+            filePath
+        }
+    );
 
     /*
      * Check for parsing errors first. If there's a parsing error, nothing
@@ -671,7 +775,7 @@ function parse(text, parser, providedParserOptions, filePath) {
         const ast = parseResult.ast;
         const parserServices = parseResult.services || {};
         const visitorKeys = parseResult.visitorKeys || evk.KEYS;
-        const scopeManager = parseResult.scopeManager || analyzeScope(ast, parserOptions, visitorKeys);
+        const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
 
         return {
             success: true,
@@ -740,13 +844,17 @@ function getScope(scopeManager, currentNode) {
  * Marks a variable as used in the current scope
  * @param {ScopeManager} scopeManager The scope manager for this AST. The scope may be mutated by this function.
  * @param {ASTNode} currentNode The node currently being traversed
- * @param {Object} parserOptions The options used to parse this text
+ * @param {LanguageOptions} languageOptions The options used to parse this text
  * @param {string} name The name of the variable that should be marked as used.
  * @returns {boolean} True if the variable was found and marked as used, false if not.
  */
-function markVariableAsUsed(scopeManager, currentNode, parserOptions, name) {
-    const hasGlobalReturn = parserOptions.ecmaFeatures && parserOptions.ecmaFeatures.globalReturn;
-    const specialScope = hasGlobalReturn || parserOptions.sourceType === "module";
+function markVariableAsUsed(scopeManager, currentNode, languageOptions, name) {
+    const parserOptions = languageOptions.parserOptions;
+    const sourceType = languageOptions.sourceType;
+    const hasGlobalReturn =
+        (parserOptions.ecmaFeatures && parserOptions.ecmaFeatures.globalReturn) ||
+        sourceType === "commonjs";
+    const specialScope = hasGlobalReturn || sourceType === "module";
     const currentScope = getScope(scopeManager, currentNode);
 
     // Special Node.js scope means we need to start one level deeper
@@ -837,8 +945,8 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
  * @param {SourceCode} sourceCode A SourceCode object for the given text
  * @param {Object} configuredRules The rules configuration
  * @param {function(string): Rule} ruleMapper A mapper function from rule names to rules
- * @param {Object} parserOptions The options that were passed to the parser
- * @param {string} parserName The name of the parser in the config
+ * @param {string | undefined} parserName The name of the parser in the config
+ * @param {LanguageOptions} languageOptions The options for parsing the code.
  * @param {Object} settings The settings that were enabled in the config
  * @param {string} filename The reported filename of the code
  * @param {boolean} disableFixes If true, it doesn't make `fix` properties.
@@ -846,7 +954,7 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
  * @param {string} physicalFilename The full path of the file on disk without any code block information
  * @returns {Problem[]} An array of reported problems
  */
-function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename, disableFixes, cwd, physicalFilename) {
+function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename) {
     const emitter = createEmitter();
     const nodeQueue = [];
     let currentNode = sourceCode.ast;
@@ -878,16 +986,18 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
                 getPhysicalFilename: () => physicalFilename || filename,
                 getScope: () => getScope(sourceCode.scopeManager, currentNode),
                 getSourceCode: () => sourceCode,
-                markVariableAsUsed: name => markVariableAsUsed(sourceCode.scopeManager, currentNode, parserOptions, name),
-                parserOptions,
+                markVariableAsUsed: name => markVariableAsUsed(sourceCode.scopeManager, currentNode, languageOptions, name),
+                parserOptions: {
+                    ...languageOptions.parserOptions
+                },
                 parserPath: parserName,
+                languageOptions,
                 parserServices: sourceCode.parserServices,
                 settings
             }
         )
     );
 
-
     const lintingProblems = [];
 
     Object.keys(configuredRules).forEach(ruleId => {
@@ -900,7 +1010,7 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
 
         const rule = ruleMapper(ruleId);
 
-        if (rule === null) {
+        if (!rule) {
             lintingProblems.push(createLintingProblem({ ruleId }));
             return;
         }
@@ -1074,13 +1184,28 @@ function normalizeCwd(cwd) {
  */
 const internalSlotsMap = new WeakMap();
 
+/**
+ * Throws an error when the given linter is in flat config mode.
+ * @param {Linter} linter The linter to check.
+ * @returns {void}
+ * @throws {Error} If the linter is in flat config mode.
+ */
+function assertEslintrcConfig(linter) {
+    const { configType } = internalSlotsMap.get(linter);
+
+    if (configType === "flat") {
+        throw new Error("This method cannot be used with flat config. Add your entries directly into the config array.");
+    }
+}
+
+
 //------------------------------------------------------------------------------
 // Public Interface
 //------------------------------------------------------------------------------
 
 /**
  * Object that is responsible for verifying JavaScript text
- * @name eslint
+ * @name Linter
  */
 class Linter {
 
@@ -1088,12 +1213,14 @@ class Linter {
      * Initialize the Linter.
      * @param {Object} [config] the config object
      * @param {string} [config.cwd] path to a directory that should be considered as the current working directory, can be undefined.
+     * @param {"flat"|"eslintrc"} [config.configType="eslintrc"] the type of config used.
      */
-    constructor({ cwd } = {}) {
+    constructor({ cwd, configType } = {}) {
         internalSlotsMap.set(this, {
             cwd: normalizeCwd(cwd),
             lastConfigArray: null,
             lastSourceCode: null,
+            configType, // TODO: Remove after flat config conversion
             parserMap: new Map([["espree", espree]]),
             ruleMap: new Rules()
         });
@@ -1168,12 +1295,16 @@ class Linter {
         const parserOptions = resolveParserOptions(parser, config.parserOptions || {}, enabledEnvs);
         const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
         const settings = config.settings || {};
+        const languageOptions = createLanguageOptions({
+            globals: config.globals,
+            parser,
+            parserOptions
+        });
 
         if (!slots.lastSourceCode) {
             const parseResult = parse(
                 text,
-                parser,
-                parserOptions,
+                languageOptions,
                 options.filename
             );
 
@@ -1194,7 +1325,7 @@ class Linter {
                     ast: slots.lastSourceCode.ast,
                     parserServices: slots.lastSourceCode.parserServices,
                     visitorKeys: slots.lastSourceCode.visitorKeys,
-                    scopeManager: analyzeScope(slots.lastSourceCode.ast, parserOptions)
+                    scopeManager: analyzeScope(slots.lastSourceCode.ast, languageOptions)
                 });
             }
         }
@@ -1220,8 +1351,8 @@ class Linter {
                 sourceCode,
                 configuredRules,
                 ruleId => getRule(slots, ruleId),
-                parserOptions,
                 parserName,
+                languageOptions,
                 settings,
                 options.filename,
                 options.disableFixes,
@@ -1270,15 +1401,43 @@ class Linter {
      */
     verify(textOrSourceCode, config, filenameOrOptions) {
         debug("Verify");
+
+        const { configType } = internalSlotsMap.get(this);
+
         const options = typeof filenameOrOptions === "string"
             ? { filename: filenameOrOptions }
             : filenameOrOptions || {};
 
-        // CLIEngine passes a `ConfigArray` object.
-        if (config && typeof config.extractConfig === "function") {
-            return this._verifyWithConfigArray(textOrSourceCode, config, options);
+        if (config) {
+            if (configType === "flat") {
+
+                /*
+                 * Because of how Webpack packages up the files, we can't
+                 * compare directly to `FlatConfigArray` using `instanceof`
+                 * because it's not the same `FlatConfigArray` as in the tests.
+                 * So, we work around it by assuming an array is, in fact, a
+                 * `FlatConfigArray` if it has a `getConfig()` method.
+                 */
+                let configArray = config;
+
+                if (!Array.isArray(config) || typeof config.getConfig !== "function") {
+                    configArray = new FlatConfigArray(config);
+                    configArray.normalizeSync();
+                }
+
+                return this._verifyWithFlatConfigArray(textOrSourceCode, configArray, options, true);
+            }
+
+            if (typeof config.extractConfig === "function") {
+                return this._verifyWithConfigArray(textOrSourceCode, config, options);
+            }
         }
 
+        /*
+         * If we get to here, it means `config` is just an object rather
+         * than a config array so we can go right into linting.
+         */
+
         /*
          * `Linter` doesn't support `overrides` property in configuration.
          * So we cannot apply multiple processors.
@@ -1289,6 +1448,214 @@ class Linter {
         return this._verifyWithoutProcessors(textOrSourceCode, config, options);
     }
 
+    /**
+     * Verify with a processor.
+     * @param {string|SourceCode} textOrSourceCode The source code.
+     * @param {FlatConfig} config The config array.
+     * @param {VerifyOptions&ProcessorOptions} options The options.
+     * @param {FlatConfigArray} [configForRecursive] The `ConfigArray` object to apply multiple processors recursively.
+     * @returns {LintMessage[]} The found problems.
+     */
+    _verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options, configForRecursive) {
+        const filename = options.filename || "<input>";
+        const filenameToExpose = normalizeFilename(filename);
+        const physicalFilename = options.physicalFilename || filenameToExpose;
+        const text = ensureText(textOrSourceCode);
+        const preprocess = options.preprocess || (rawText => [rawText]);
+        const postprocess = options.postprocess || (messagesList => messagesList.flat());
+        const filterCodeBlock =
+            options.filterCodeBlock ||
+            (blockFilename => blockFilename.endsWith(".js"));
+        const originalExtname = path.extname(filename);
+        const messageLists = preprocess(text, filenameToExpose).map((block, i) => {
+            debug("A code block was found: %o", block.filename || "(unnamed)");
+
+            // Keep the legacy behavior.
+            if (typeof block === "string") {
+                return this._verifyWithFlatConfigArrayAndWithoutProcessors(block, config, options);
+            }
+
+            const blockText = block.text;
+            const blockName = path.join(filename, `${i}_${block.filename}`);
+
+            // Skip this block if filtered.
+            if (!filterCodeBlock(blockName, blockText)) {
+                debug("This code block was skipped.");
+                return [];
+            }
+
+            // Resolve configuration again if the file content or extension was changed.
+            if (configForRecursive && (text !== blockText || path.extname(blockName) !== originalExtname)) {
+                debug("Resolving configuration again because the file content or extension was changed.");
+                return this._verifyWithFlatConfigArray(
+                    blockText,
+                    configForRecursive,
+                    { ...options, filename: blockName, physicalFilename }
+                );
+            }
+
+            // Does lint.
+            return this._verifyWithFlatConfigArrayAndWithoutProcessors(
+                blockText,
+                config,
+                { ...options, filename: blockName, physicalFilename }
+            );
+        });
+
+        return postprocess(messageLists, filenameToExpose);
+    }
+
+    /**
+     * Same as linter.verify, except without support for processors.
+     * @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
+     * @param {FlatConfig} providedConfig An ESLintConfig instance to configure everything.
+     * @param {VerifyOptions} [providedOptions] The optional filename of the file being checked.
+     * @throws {Error} If during rule execution.
+     * @returns {LintMessage[]} The results as an array of messages or an empty array if no messages.
+     */
+    _verifyWithFlatConfigArrayAndWithoutProcessors(textOrSourceCode, providedConfig, providedOptions) {
+        const slots = internalSlotsMap.get(this);
+        const config = providedConfig || {};
+        const options = normalizeVerifyOptions(providedOptions, config);
+        let text;
+
+        // evaluate arguments
+        if (typeof textOrSourceCode === "string") {
+            slots.lastSourceCode = null;
+            text = textOrSourceCode;
+        } else {
+            slots.lastSourceCode = textOrSourceCode;
+            text = textOrSourceCode.text;
+        }
+
+        const languageOptions = config.languageOptions;
+
+        languageOptions.ecmaVersion = normalizeEcmaVersionForLanguageOptions(
+            languageOptions.ecmaVersion
+        );
+
+        // add configured globals and language globals
+        const configuredGlobals = {
+            ...(getGlobalsForEcmaVersion(languageOptions.ecmaVersion)),
+            ...(languageOptions.sourceType === "commonjs" ? globals.commonjs : void 0),
+            ...languageOptions.globals
+        };
+
+        // Espree expects this information to be passed in
+        if (isEspree(languageOptions.parser)) {
+            const parserOptions = languageOptions.parserOptions;
+
+            if (languageOptions.sourceType) {
+
+                parserOptions.sourceType = languageOptions.sourceType;
+
+                if (
+                    parserOptions.sourceType === "module" &&
+                    parserOptions.ecmaFeatures &&
+                    parserOptions.ecmaFeatures.globalReturn
+                ) {
+                    parserOptions.ecmaFeatures.globalReturn = false;
+                }
+            }
+        }
+
+        const settings = config.settings || {};
+
+        if (!slots.lastSourceCode) {
+            const parseResult = parse(
+                text,
+                languageOptions,
+                options.filename
+            );
+
+            if (!parseResult.success) {
+                return [parseResult.error];
+            }
+
+            slots.lastSourceCode = parseResult.sourceCode;
+        } else {
+
+            /*
+             * If the given source code object as the first argument does not have scopeManager, analyze the scope.
+             * This is for backward compatibility (SourceCode is frozen so it cannot rebind).
+             */
+            if (!slots.lastSourceCode.scopeManager) {
+                slots.lastSourceCode = new SourceCode({
+                    text: slots.lastSourceCode.text,
+                    ast: slots.lastSourceCode.ast,
+                    parserServices: slots.lastSourceCode.parserServices,
+                    visitorKeys: slots.lastSourceCode.visitorKeys,
+                    scopeManager: analyzeScope(slots.lastSourceCode.ast, languageOptions)
+                });
+            }
+        }
+
+        const sourceCode = slots.lastSourceCode;
+        const commentDirectives = options.allowInlineConfig
+            ? getDirectiveComments(
+                options.filename,
+                sourceCode.ast,
+                ruleId => getRuleFromConfig(ruleId, config),
+                options.warnInlineConfig
+            )
+            : { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
+
+        // augment global scope with declared global variables
+        addDeclaredGlobals(
+            sourceCode.scopeManager.scopes[0],
+            configuredGlobals,
+            { exportedVariables: commentDirectives.exportedVariables, enabledGlobals: commentDirectives.enabledGlobals }
+        );
+
+        const configuredRules = Object.assign({}, config.rules, commentDirectives.configuredRules);
+
+        let lintingProblems;
+
+        try {
+            lintingProblems = runRules(
+                sourceCode,
+                configuredRules,
+                ruleId => getRuleFromConfig(ruleId, config),
+                void 0,
+                languageOptions,
+                settings,
+                options.filename,
+                options.disableFixes,
+                slots.cwd,
+                providedOptions.physicalFilename
+            );
+        } catch (err) {
+            err.message += `\nOccurred while linting ${options.filename}`;
+            debug("An error occurred while traversing");
+            debug("Filename:", options.filename);
+            if (err.currentNode) {
+                const { line } = err.currentNode.loc.start;
+
+                debug("Line:", line);
+                err.message += `:${line}`;
+            }
+            debug("Parser Options:", languageOptions.parserOptions);
+
+            // debug("Parser Path:", parserName);
+            debug("Settings:", settings);
+
+            if (err.ruleId) {
+                err.message += `\nRule: "${err.ruleId}"`;
+            }
+
+            throw err;
+        }
+
+        return applyDisableDirectives({
+            directives: commentDirectives.disableDirectives,
+            disableFixes: options.disableFixes,
+            problems: lintingProblems
+                .concat(commentDirectives.problems)
+                .sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
+            reportUnusedDisableDirectives: options.reportUnusedDisableDirectives
+        });
+    }
+
     /**
      * Verify a given code with `ConfigArray`.
      * @param {string|SourceCode} textOrSourceCode The source code.
@@ -1324,6 +1691,47 @@ class Linter {
         return this._verifyWithoutProcessors(textOrSourceCode, config, options);
     }
 
+    /**
+     * Verify a given code with a flat config.
+     * @param {string|SourceCode} textOrSourceCode The source code.
+     * @param {FlatConfigArray} configArray The config array.
+     * @param {VerifyOptions&ProcessorOptions} options The options.
+     * @param {boolean} [firstCall=false] Indicates if this is being called directly
+     *      from verify(). (TODO: Remove once eslintrc is removed.)
+     * @returns {LintMessage[]} The found problems.
+     */
+    _verifyWithFlatConfigArray(textOrSourceCode, configArray, options, firstCall = false) {
+        debug("With flat config: %s", options.filename);
+
+        // we need a filename to match configs against
+        const filename = options.filename || "<input>";
+
+        // Store the config array in order to get plugin envs and rules later.
+        internalSlotsMap.get(this).lastConfigArray = configArray;
+        const config = configArray.getConfig(filename);
+
+        // Verify.
+        if (config.processor) {
+            debug("Apply the processor: %o", config.processor);
+            const { preprocess, postprocess, supportsAutofix } = config.processor;
+            const disableFixes = options.disableFixes || !supportsAutofix;
+
+            return this._verifyWithFlatConfigArrayAndProcessor(
+                textOrSourceCode,
+                config,
+                { ...options, filename, disableFixes, postprocess, preprocess },
+                configArray
+            );
+        }
+
+        // check for options-based processing
+        if (firstCall && (options.preprocess || options.postprocess)) {
+            return this._verifyWithFlatConfigArrayAndProcessor(textOrSourceCode, config, options);
+        }
+
+        return this._verifyWithFlatConfigArrayAndWithoutProcessors(textOrSourceCode, config, options);
+    }
+
     /**
      * Verify with a processor.
      * @param {string|SourceCode} textOrSourceCode The source code.
@@ -1397,6 +1805,7 @@ class Linter {
      * @returns {void}
      */
     defineRule(ruleId, ruleModule) {
+        assertEslintrcConfig(this);
         internalSlotsMap.get(this).ruleMap.define(ruleId, ruleModule);
     }
 
@@ -1406,6 +1815,7 @@ class Linter {
      * @returns {void}
      */
     defineRules(rulesToDefine) {
+        assertEslintrcConfig(this);
         Object.getOwnPropertyNames(rulesToDefine).forEach(ruleId => {
             this.defineRule(ruleId, rulesToDefine[ruleId]);
         });
@@ -1416,6 +1826,7 @@ class Linter {
      * @returns {Map<string, Rule>} All loaded rules
      */
     getRules() {
+        assertEslintrcConfig(this);
         const { lastConfigArray, ruleMap } = internalSlotsMap.get(this);
 
         return new Map(function *() {
@@ -1434,6 +1845,7 @@ class Linter {
      * @returns {void}
      */
     defineParser(parserId, parserModule) {
+        assertEslintrcConfig(this);
         internalSlotsMap.get(this).parserMap.set(parserId, parserModule);
     }
 
@@ -1441,7 +1853,7 @@ class Linter {
      * Performs multiple autofix passes over the text until as many fixes as possible
      * have been applied.
      * @param {string} text The source text to apply fixes to.
-     * @param {ConfigData|ConfigArray} config The ESLint config object to use.
+     * @param {ConfigData|ConfigArray|FlatConfigArray} config The ESLint config object to use.
      * @param {VerifyOptions&ProcessorOptions&FixOptions} options The ESLint options object to use.
      * @returns {{fixed:boolean,messages:LintMessage[],output:string}} The result of the fix operation as returned from the
      *      SourceCodeFixer.
index 2dd186de3e82a432ff99c977a02d298825dc7265..6d06e3ddce1d500859f3437d0995e7d32f8c3875 100644 (file)
@@ -50,7 +50,7 @@ const optionator = require("optionator");
  * @property {boolean | undefined} reportUnusedDisableDirectives Adds reported errors for unused eslint-disable directives
  * @property {string} [resolvePluginsRelativeTo] A folder where plugins should be resolved from, CWD by default
  * @property {Object} [rule] Specify rules
- * @property {string[]} [rulesdir] Use additional rules from this directory
+ * @property {string[]} [rulesdir] Load additional rules from this directory. Deprecated: Use rules from plugins
  * @property {boolean} stdin Lint code provided on <STDIN>
  * @property {string} [stdinFilename] Specify filename to process STDIN as
  * @property {boolean} quiet Report errors only
@@ -118,11 +118,6 @@ module.exports = optionator({
         {
             heading: "Specifying rules and plugins"
         },
-        {
-            option: "rulesdir",
-            type: "[path::String]",
-            description: "Use additional rules from this directory"
-        },
         {
             option: "plugin",
             type: "[String]",
@@ -133,6 +128,11 @@ module.exports = optionator({
             type: "Object",
             description: "Specify rules"
         },
+        {
+            option: "rulesdir",
+            type: "[path::String]",
+            description: "Load additional rules from this directory. Deprecated: Use rules from plugins"
+        },
         {
             heading: "Fixing problems"
         },
index f047252668000e2ad6c29ef34cb19614e8d665c1..2fcf1535290352c61952c1d332f5aef34f402dea 100644 (file)
@@ -134,6 +134,7 @@ function isPropertyDescriptor(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 28a05b3504308809154b3d238ba1e3fa14a49cfc..0beb138c4e2e79d846285842de00fe467b24ecf1 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 1eea99c14ca1fba3d20ba6854fe369ec7335cedd..e4912ec17a1a1289854693e2493695fbebf104bd 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index d13ecd717906f0171b17369e977355c8d875c980..fba414c1ef4f50f4ea56c1591af18517c67be08f 100644 (file)
@@ -133,6 +133,7 @@ function getArrayMethodName(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 535fa2155a204266db50572502a37a43940a1e7a..77f5fc9e9ce72f73167ac8d089250964ad1c4dbd 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 3a3f544444e99c69ced5af94a9e368f28d470c5e..7a141b0d788a15d0bc49107711bdfcb203736088 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 4f4dea0e23735f402b145cc06b7da7a731850ad1..779ab6fe9c9c2aaf081f3a4c63e3359a1cb58897 100644 (file)
@@ -27,6 +27,7 @@ function hasBlockBody(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 9e1ed71d4bd22376e195601fd5b5d18b2f035072..9fdcdd58ba70ad397f16f1c7ed7d4a7a7a93a7b5 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index d98250b062bcb22a2ef9aeec78e62eed7e6255a5..3a277863ef2e708d73cc6797e5f58102aff6a484 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 990b441e34dd8a7636b9d32c1bb245c8cd35e9bc..53303a9b0041cb145f07a9f65abca5e0ffefb5ec 100644 (file)
@@ -11,6 +11,7 @@ const util = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 89f9ba559538d83ae6333dc9653a217964e218ac..f4adb9490ebdf69a2837a6ce8ac94cb90ff13c14 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 449b9a96227363a7ef9574f1f257e13a1509f8a3..532faee45187ca005cbf22f9295f8a9e66301260 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 7e8fc68da6319e04ea89922e0c7a4e4094387021..61dd062edea4ecb31ddb29d7fad4437c09b0f284 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index e5f429356b2951ad6b07e8cd929e5f8cc04798aa..6ea87a70a814edfc3dd079b93767dbc53052ab30 100644 (file)
@@ -99,6 +99,7 @@ function createRegExpForIgnorePatterns(normalizedOptions) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index beb742d93a793824b88ef23f3299c06adaff680b..1af6084ed8be783c4b8a638fcafb670ac02cab0f 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index e97a59886e3ac92edd1f891619f9000f44d508e4..232b27cb39cf7d9394e2157aace9d84720d76fb0 100644 (file)
@@ -70,6 +70,7 @@ function normalizeOptions(optionValue, ecmaVersion) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index d30a5ef320dea55736000f0bc8466713de414ad2..23a517528149833b48d0fce1820c328b446ffbf2 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 1d62fcf1c4d70317feeedf4ed9218e1b9e8184fa..cbcbe3ae15b0b16eabfeda9bb78c95f628980d44 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index a247039760e9a056de2155e2ad8f45e15362045f..b2355556af9d24f824bd82de5211fa317c61675f 100644 (file)
@@ -17,6 +17,7 @@ const { upperCaseFirst } = require("../shared/string-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c8d8834ea9233d5ea6df1ebaa6056a4f21e92f61..4850a8b651ffe99b2a4c24123abf8cc45e87a6f4 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index b509c36564fb03948251579a34b58b5ca735a25a..fffb4357b65b7ad72c52c06afc99780e90622021 100644 (file)
@@ -40,6 +40,7 @@ function isClassConstructor(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 025f3d0a3402911803c7c6adfaf01a95d0232192..a613f992d7a22287ef1990d43bf04ec10a4c7d8c 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 38eb489327d597634ffdc3b05c5d4156afb28e97..defdb91d69dba34dd558f63d9fb21c5c2243ca89 100644 (file)
@@ -116,6 +116,7 @@ function isPossibleConstructor(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 57c2e72e4e4d9e886618c32bdf8b6f3cd7a5fd13..29e73953da6f4694156d0fadcc983bf429a469e5 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1eeadd1e71637e9b72d479ba0a4fa125c9341c1a..34be2894e410473eeb0c949ab9b54807e5a75ad6 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index b839aa2013313938b1e8f0f0f93e1b11a20b9344..6ce238529d069fabe6f6b368097f5f05bdddc688 100644 (file)
@@ -10,6 +10,7 @@ const DEFAULT_COMMENT_PATTERN = /^no default$/iu;
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 8382d46e760fe2fecd496369e588378f2a70706f..ea12a2a558a05b8a9e759919b72446814def9f36 100644 (file)
@@ -5,6 +5,7 @@
 
 "use strict";
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index d80f87090a73f3ee497d4bea1b06853c0fe7d6dc..9dea4f25cf78249b702ac185612068573f07a716 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 1cd908f7a2c25ef1ebedb29bfa07a6b9b53c6957..6f6b5166f76438f3f733d733affff0a89f0292d8 100644 (file)
@@ -20,6 +20,7 @@ const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/u;
 // `null` literal must be handled separately.
 const literalTypesToCheck = new Set(["string", "boolean"]);
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index f8b922c25037614a596ee88ca80ed421e7cc2f4a..393b934125ea8cbc51c51551fa98db893e527451 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index d3e6b5af0b6cd69e632dbae360decda716c3240c..b5d784dad6e61b001a0837b4535f7eba871aca47 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index abe4ad3c6b8c2bc3891b7523d6fb49924739c332..d3d825a5766132ab643d1fcdc56ced0a4452b15f 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index a6ebde4ac0bdd4027b5319b114486c0fdba0ef32..0391d99c76323e088980dda34621c5af8cde31e9 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 122cfd8d33c62d47cc339a7a6fc2f80efcf94a1f..9cee5fe019ac0c6a4c7b964d79ce0eb0feeefe6e 100644 (file)
@@ -68,6 +68,7 @@ const optionsObject = {
     additionalProperties: false
 };
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 589903c96a50d6b415af4983358c80ef22c0d428..c7b2072e177d34169f28bfb931feb1e5f9347ef9 100644 (file)
@@ -24,6 +24,7 @@ function isFunctionName(variable) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0921ff54cd4d462ee1fdd108c07e277a02adabed..f71574890c8916fa048471f6f48cb707478eeae6 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index ed4e296fd6e90f03fdca8968fe0cc02b511a09d4..f3cfeee703aa530ceb6ff8fa9f3d31cbf3f21843 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 18435b7897823c59c6ba2ae50a330e9ffab0a9ad..ed94fad460cefa524c5603223b5bfeb593a72775 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index c50445c9c9bf9e1d77cbe7b773dc130dd6c053ee..28e81013fcb95ef11db343deeb51c7ab37d81e75 100644 (file)
@@ -25,6 +25,7 @@ const OVERRIDE_SCHEMA = {
     ]
 };
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 8bb42536e8c06752ae8202fdaf44c893546a0374..03cfce2cf1abc918d9b785579a359862d019a75c 100644 (file)
@@ -29,6 +29,7 @@ function isReachable(segment) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index f2d29d1df5aa5d6378bfabb377cde007ba611b56..f00ca9bf6dd6d83c1980ad57af5e18e6abeda638 100644 (file)
@@ -48,6 +48,7 @@ function isShadowed(scope, node) {
     return reference && reference.resolved && reference.resolved.defs.length > 0;
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index cc4a4b522a14e072b6d5ab4fcef149ba14c5bc35..0fe6f91e4db0fac4e8359671a01402c4225ad8f9 100644 (file)
@@ -90,6 +90,7 @@ function isAccessorKind(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 6f877bab9588b020ffefe9604faaa7d615177869..1c52af7d4cde20a8c7bfb80f65401e96678e611e 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index cdb3a7642ea3c90f3537b883c08ce2578c2695e3..f370407743a502d2d54ff79aac7a16d583f7e316 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 77deac707085ca6875e6d95c396a53f00e344d24..f7e04ae73765f9913d60b8ee8448677716f02814 100644 (file)
@@ -110,6 +110,7 @@ function isShorthandPropertyDefinition(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 2b3463554234540a4eb53fc55eacdab2bbef5e35..a0b1f416f46db46055928e4c40f8dfa5e565ada1 100644 (file)
@@ -93,6 +93,7 @@ function isPropertyNameInDestructuring(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index ac6385f59c045222b148fc63ba15b78afff1847d..3701c66e347a7287321da25d25d743ca7ff9305f 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 7a6cd058f2ec41948e5b2fb833e156bbefa89f47..bcc07a8e372e675601391607c0b7c2f799f593e6 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 2d09552440b2007bffc6de43d59caab4cc38d37a..71b2437eef83bc7e71fd21dfe0f77b0575bafbe3 100644 (file)
@@ -9,6 +9,7 @@ const { isCommentToken, isNotOpeningParenToken } = require("./utils/ast-utils");
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 54ca9ddd138e98a57cea8a516ca3d34fac4d8947..bd61f6f843121bfe5a919657a5c37fcff4261fe3 100644 (file)
@@ -20,6 +20,7 @@ const astUtils = require("./utils/ast-utils");
 //------------------------------------------------------------------------------
 
 /* istanbul ignore next: this rule has known coverage issues, but it's deprecated and shouldn't be updated in the future anyway. */
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index f4dbfff27b41cb40c89381149b906253868d4614..6152bc561f9a818971b7d357efd566bdca272e34 100644 (file)
@@ -494,6 +494,7 @@ const ELEMENT_LIST_SCHEMA = {
     ]
 };
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index d994bbc1ea0590ea54d780dc14e8d84425c262c2..d952b8925ed33504c2bd0c0264a8056a317fcc8e 100644 (file)
@@ -42,6 +42,7 @@ function isInitialized(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index cbadc19d5ed5632567538b41d40f1b61b72aead5..a0cdfaa62bedb89038a2d8e0ed76095cd6317625 100644 (file)
@@ -36,6 +36,7 @@ const QUOTE_SETTINGS = {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index c09cebb513ae3dd141a4e73699d8515c0a923214..ce8bad5bb354901bd022caab83176b75bd37848d 100644 (file)
@@ -133,6 +133,7 @@ function initOptions(toOptions, fromOptions) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 44222e1a493f68ce3bae6570cbcde386e6c23380..956fc42656d17662383553819a4e1cc25bbdc91d 100644 (file)
@@ -61,6 +61,7 @@ function isCloseParenOfTemplate(token) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index ad109a4f795a5a481cb9ee17f4f3207646528eea..9ce2831dec6d620a30d096ceffac86e723e0d6c8 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 92996ebd33189d2f122805e8a696af9c39d1ba21..483788aa6ef3de7e6c61822032c14c33de42b576 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 513d196224e10a4a4e0e9fa50969b14e3e5679ff..74df09b01bd2b4838d9d7e9bb072b3d9755b42b4 100644 (file)
@@ -49,6 +49,7 @@ function getCommentLineNums(comments) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index c0c70e1a61ff39e7210eeda782d0b8eb9680e8bf..21884f162e8031d20209a415757f990b39e3e559 100644 (file)
@@ -12,6 +12,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index e4c05f3050c0379bfc3fe67ed0a0eec8416ff751..1d6b7e7693eadc49a73c4bee3e66cdfc0de15146 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 3d26108a71504ace6b7ff9e1a76a05cec95a6d11..2157bebe4a9add3553024a8612960aace5a24eb5 100644 (file)
@@ -13,6 +13,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index bdacc66afb13052e6babb789fdd80bce82371fcb..8006ffdef75634af55af5015865a45a7cf453888 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 8c7985d3e16b452263a0c232f1e2df249943d982..d05559e5baf2efb2606e7e9a88c1ea86da69d17d 100644 (file)
@@ -63,6 +63,7 @@ const OPTIONS_OR_INTEGER_SCHEMA = {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index b2130ca260b4dcd31ccebbfbf90b834ddc0889d8..c1b945ca11abeb2926b0240d5e841810a8efc6a1 100644 (file)
@@ -65,6 +65,7 @@ function getCommentLineNumbers(comments) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
@@ -79,7 +80,7 @@ module.exports = {
             OPTIONS_OR_INTEGER_SCHEMA
         ],
         messages: {
-            exceed: "{{name}} has too many lines ({{lineCount}}). Maximum allowed is {{maxLines}}."
+            exceed: "{{name}} has exceeded the limit of lines allowed by {{linesExceed}}. Maximum allowed number of lines per function is {{maxLines}}."
         }
     },
 
@@ -169,18 +170,26 @@ module.exports = {
                 return;
             }
             let lineCount = 0;
+            let comments = 0;
+            let blankLines = 0;
 
             for (let i = node.loc.start.line - 1; i < node.loc.end.line; ++i) {
                 const line = lines[i];
 
                 if (skipComments) {
                     if (commentLineNumbers.has(i + 1) && isFullLineComment(line, i + 1, commentLineNumbers.get(i + 1))) {
+                        if (lineCount <= maxLines) {
+                            comments++;
+                        }
                         continue;
                     }
                 }
 
                 if (skipBlankLines) {
                     if (line.match(/^\s*$/u)) {
+                        if (lineCount <= maxLines) {
+                            blankLines++;
+                        }
                         continue;
                     }
                 }
@@ -190,11 +199,21 @@ module.exports = {
 
             if (lineCount > maxLines) {
                 const name = upperCaseFirst(astUtils.getFunctionNameWithKind(funcNode));
+                const linesExceed = lineCount - maxLines;
+
+                const loc = {
+                    start: {
+                        line: node.loc.start.line + maxLines + (comments + blankLines),
+                        column: 0
+                    },
+                    end: node.loc.end
+                };
 
                 context.report({
                     node,
+                    loc,
                     messageId: "exceed",
-                    data: { name, lineCount, maxLines }
+                    data: { name, linesExceed, maxLines }
                 });
             }
         }
index 291d7d9c1a89cbb9e9df294bdd0b408ae41543b3..31fc657a63c16e273f6fc4d8a5bd3df8ba040f76 100644 (file)
@@ -28,6 +28,7 @@ function range(start, end) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index df24a96da583954eafe907366a328ab347096cb2..0d43050779068c457e908aa0aafae9114f6b95c6 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c8be60e57745fd19d1e2abecb4db2acbc1051642..72379d217d69c976d2d06f0bfcb63324c7d617e8 100644 (file)
@@ -16,6 +16,7 @@ const { upperCaseFirst } = require("../shared/string-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 7c743292bd662f461701bd308ddd1e5f8e0f18d4..61b508cf6cde2611ce7f3afddf80fa910b6ce728 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 969e40bbd855c55ce1bf29f364f858c659026f94..ac117e92e725930b452350872d26f52bef9091db 100644 (file)
@@ -16,6 +16,7 @@ const { upperCaseFirst } = require("../shared/string-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index da5ee50df4a6e539058c98a896e73922fc97f0af..7985bc86270b8d757b9695338ea2fa2dfc14ef50 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 6f468c828c04a57c5e67e5e27dadea94b56ec18e..91aa5a1003116ff0b67f518630fce400bc94a77c 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 9abf3379b8a7d9be465a42536ffbad04db265265..466cfd4c58590926bebc8bc8046aa20229324f58 100644 (file)
@@ -76,6 +76,7 @@ function calculateCapIsNewExceptions(config) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 786300dba7d61002dd069f307e203b3fc6fb2102..8ee4a2e1d19361a51a3971862c4cbb40da67f975 100644 (file)
@@ -19,6 +19,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 3eea1b1f7328e21b14434478c15e8d1e9f0719a8..e519a3afb6becb882d6e5c2e80db1a1ab1a4ba06 100644 (file)
@@ -16,6 +16,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index fd6341e67c0d667ba91ecaa125b309f61029c440..f4aa5166f0e8d19d5b5b6ea6ddd284f76bdf99d8 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 8de9a6a239801a1c5866e7dc2ecaafe118f0fb31..818bf703d2b7454f7303ed8defa4144a653ae0f2 100644 (file)
@@ -12,6 +12,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 918b98489a7e72a57df0c1560aad8ebb888fa9f7..c6f7ddf38db1a3f50e86671a601bbd94ae00a77d 100644 (file)
@@ -82,6 +82,7 @@ function isGlobalThisReferenceOrGlobalWindow(scope, node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0904fa6d8f0cd9a79beb62046d64c92fb50c9053..02e6114dadc8f37e69833e73725d177a14224e23 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 27116f1da788e78ab6705c11759a59022cc1c221..f940f152e3cecdb877870655dda09d98a670cbdc 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 38af8b56c1a8a118277af598c1242fcf0af56728..3aea39a16b9f3eecd0509dec36ea6ae36c993553 100644 (file)
@@ -53,6 +53,7 @@ function isLooped(node, parent) {
     }
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 10bf24a29977a3debeb5bc7bd0f8e88702b31fca..1de1619bffa8a01883fa85aea4e4ebadd3aa04a3 100644 (file)
@@ -20,6 +20,7 @@ const BITWISE_OPERATORS = [
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index cc5906e78a353f6198e83d58b3761c55c313c319..678d7032ab447bca31463a3656477f3e4d72fb2c 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index dbb527906f257077cad540262eedb09c6732a5e1..a6ad94f2fe6a6667095b6070bdc1b8286db02234 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a132f0370fa60068a415c2eafcb1297e3076dee9..d722f0cf58422f6ad153fddb05fc735e9af89650 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0cbeedf90b6ed2dc2b87b2620276537abe91adcc..d09c91349680cf7c1c272757998c9deb9206d2c2 100644 (file)
@@ -16,6 +16,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 839ad03e292d1be273a0fd06ca52ff2cfd023c25..f679d4263e860e5d0cd8d84aebf22fedd7361fce 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index e8fdaa0cc6949335c55419d5e3a96efb50b6edf8..fb56b99c58b3db4e011cfdaae66aae7fed75c643 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 42f75af7d0c7d2857cddfb5e45e331f4694326ff..30d5b3bdaee9600aeca91d23738394953a637ced 100644 (file)
@@ -28,6 +28,7 @@ const NODE_DESCRIPTIONS = {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index fa87f4012e8561ba7bc465c2893cccddaf9ff8a2..7b736c1972821d75dee1dff327c92acd2567588d 100644 (file)
@@ -25,6 +25,7 @@ function isConditional(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a5937cbddb20eaf11148affcc8abbfc2f4250d2b..c0802e23dc7240cf76b86aedfb7b015ece63949d 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 6ca1b6107a86bd4edab1851cab6e99e01d5b2f65..b5f7c37a98f6df25da0322cb2635d165dc975b97 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 7a7030a9a46cb0cccb5873aee2ce1c02370f1d64..0bcb31931e4205bbd695cb46bb4512b32a42b428 100644 (file)
@@ -13,6 +13,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
@@ -138,6 +139,7 @@ module.exports = {
                 case "ArrowFunctionExpression":
                 case "FunctionExpression":
                 case "ObjectExpression":
+                case "ClassExpression":
                     return true;
                 case "TemplateLiteral":
                     return (inBooleanPosition && node.quasis.some(quasi => quasi.value.cooked.length)) ||
@@ -179,7 +181,8 @@ module.exports = {
                         isLeftShortCircuit ||
                         isRightShortCircuit;
                 }
-
+                case "NewExpression":
+                    return inBooleanPosition;
                 case "AssignmentExpression":
                     if (node.operator === "=") {
                         return isConstant(node.right, inBooleanPosition);
index b4b5baf743c28c130139fa2218228c2d7f90fe66..f8a717c75e5261fe384bf6d94719fd7087786e36 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index e72e862df596f6554058d2d8338b50479bda86ad..8658a7984bb6bb9e77f6160e33bb4894e64a1dbf 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 908d61ae449ba1f3cc1f8aad82c7b8dfa7557fc5..04f3449fb1931e0e140a6734c20ccd8ff0eae967 100644 (file)
@@ -46,6 +46,7 @@ const collector = new (class {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 46dd57639cf41599d217d7c9e18e74f74a1342b1..e62db1b7393b1afef75ae675ffecf8bf04bfafdd 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 1438ebc33bd51f091f0d3717ca0335cae6053e0a..1d1c710b0982008e7b89bb2a1cb0ee7a6a6a1bde 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 40388c366e266f976d73aec5794c22b2208da1fe..175f6c20104d3ad2e794370cf84244e0bdd68d94 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0880b9c812476bb353cb056d4d965def7682872a..13090e19a87e28068c10b41ba315508152a64ac1 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index f74865b82a8862f1e1cfec42802c2e1c99690b75..ae61f164ca9218a2d7a9dd49c391c0e4fb43b9c2 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 0d8b17cc0ab4c9ca17bedba70de42dad93f5726c..1e1d549185d72b575d5d3e4b8bfde6d7c143dccb 100644 (file)
@@ -46,6 +46,7 @@ const splitByAnd = splitByLogicalOperator.bind(null, "&&");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ecec022185fd686858afd5e76cfa4f9aada7e76d..dac13cf9e098c28353a14bc6459829738d46d03c 100644 (file)
@@ -82,6 +82,7 @@ class ObjectInfo {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4669dcee1baa50be4e52e8ac98b3d7e6969a0709..a0c0b31308b0e891d70484e25926472fd48256f8 100644 (file)
@@ -16,6 +16,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 2663698dc96c4292ffd78883230032615828d86d..947bb30c2e175a887f38ab7feae5ad2518183257 100644 (file)
@@ -227,6 +227,7 @@ function handleImportsExports(
     };
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4c981ae159293ddad3dbf74aa8b20ca622241650..3662fc8c6e727da69fa4cdec22c3b2433691a420 100644 (file)
@@ -16,6 +16,7 @@ const FixTracker = require("./utils/fix-tracker");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 85e8ef767912ef5282523a5ade0be8f9956840c3..f75f59191aae40820394b1c5a52177059ffe6683 100644 (file)
@@ -24,6 +24,7 @@ const regex = /^([^\\[]|\\.|\[([^\\\]]|\\.)+\])*$/u;
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 8b1073a59d86444d89bf1cb16b0a274507a3fb6f..6e73d63b98a4fc5f027c3e71eecc33aca4e85d9c 100644 (file)
@@ -89,6 +89,7 @@ function getKind(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 99ea3a7905b6a8cfda72f8f999be2719c702999a..2de575fcf0849f26c58f83526bc579bff7220151 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4ed3c5c5458b1da059ebbbf82feb400f65ff5da5..f04ee2cb3209cc7b7088bf699f6215b7199ce47c 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index dae922840b825eb1ccf7ccb8064f996d16e67ee8..b693737126d62c20511062f7880314704b5a4f16 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 96b85a07120ef5fcd325eefbf54da56d500e5535..ae6d71b80c99e3460f6ac61eefa21b57d7934514 100644 (file)
@@ -37,6 +37,7 @@ function isMember(node, name) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index cd56c94af7587cb39d1e95a9558e239832ffb07a..3db14206b0b3fefccb269b761a8eca49f1671a7f 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4d5accbae632978e53ea89585aaa98bad9deea7e..771200f26f7579c01570ad3d54c5bcc292a5e70c 100644 (file)
@@ -16,6 +16,7 @@ const globals = require("globals");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 6fd3be1d601818f7fe0b299f537df6e1a3229909..561cb1a33f8591226f0712f83a24d5d527432b7c 100644 (file)
@@ -20,6 +20,7 @@ const SIDE_EFFECT_FREE_NODE_TYPES = new Set(["Literal", "Identifier", "ThisExpre
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index cb061dac5d543c08eafad776ab8fd5b471d7664c..f45ac616ed907721201a57eb4f1851595e6f80b2 100644 (file)
@@ -18,6 +18,7 @@ const precedence = astUtils.getPrecedence;
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index bbb2413b2c76b329058c29462db935e2bf8419af..9186a9faca127f4405fcf8b7c055e2fe63ede4b0 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0756d2fb2c7bfcd79798ccd0b314990a05909355..5b54ae26fe3e50d12054898337c301d0d55f2502 100644 (file)
@@ -11,6 +11,7 @@
 const { isParenthesized: isParenthesizedRaw } = require("eslint-utils");
 const astUtils = require("./utils/ast-utils.js");
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 0e2bcaf077891b54f47774d7048d0a92c597ae4a..89d9fce57f05760521108d0c7e2d9764abaa4a82 100644 (file)
@@ -16,6 +16,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index bf2c82514bb2d1b376a41f58cf8008416eb819e1..f3b7c8554ad7b232d3805dba4877b25c7977d2f1 100644 (file)
@@ -58,6 +58,7 @@ function hasBlankLinesBetween(node, token) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 92ac2326b9fd7be12bc4e7740a6ada8aa462df2b..8831bb824d07ce092ce57b65e2b355397bb45426 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index aa04f337ae0c43f79f064ee66e724f315656ab62..04a7dd370551a502f01b6fb95e9042db972be3fc 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 85aac7cdc0f280c55979c9a052cb62405bd2870a..340c6c798c39fb13e905badc43bcd56b523395fd 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1d11e10d597ced793874da1c33096af31afd3fde..f646093f55581b7450dca85a5d5f97d42bcaba8c 100644 (file)
@@ -167,6 +167,7 @@ function getNonEmptyOperand(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 8740cd8053194a61978800dcf693055e7ecb5b45..5dd6aa71acd86231dccc465ee2c9247b2c17c055 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 2432e68b6120d382465b50a5c699a2c9fd7729ef..38de5b31ccc377c0be7b5f22bc1f88eae93c5e0d 100644 (file)
@@ -16,6 +16,7 @@ const { getStaticValue } = require("eslint-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index fbe63d0539f4941398ecdaf541c06d3650752fca..385386e9a4379072e10e72cc77c835fde08a9f32 100644 (file)
@@ -174,6 +174,7 @@ function getWriteNode(id) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 8a955a6130e298b6dfc2115bae0ff444dbc508d4..2ed7feb46b839d84c8ad3cfb4922894edf2cf028 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 49b5114a2099bcc2c94c7fe717a97a2774702a51..3b0feb71a3faa45718431394eff5ab2b1bfdd46c 100644 (file)
@@ -42,6 +42,7 @@ function getAllowedBodyDescription(node) {
     return "program";
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ee19932896609934ccae25fe9a697889c860f53e..92ac5125e60a29b9295523b47b935ddef89b8307 100644 (file)
@@ -17,6 +17,7 @@ const undefined1 = void 0;
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index e1d7cbcf553860307412256e47aa17c936a40c0f..5f9b9f871ecf6b9d1b0d3518e00906b58924655b 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c160971539471bb635d6f6cb0d3d96a25c650f29..65c4d67285cb1b2959175c7d56cd5208719dcf3f 100644 (file)
@@ -25,6 +25,7 @@ const LINE_BREAK = astUtils.createGlobalLinebreakMatcher();
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4117f6211c7614d2162152eed4852e4fc021bd87..d11267286c808cfbe73e91002cbeb36640222ab1 100644 (file)
@@ -15,6 +15,7 @@ const { getStaticPropertyName } = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 4532527c6e84b65f607f305821b6d3663ac9f13a..50211811ac80f12ddde0a8010a593c8d536a909f 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 5dd15be092e32a8b34548633d191d09185100e96..2e79f378a9bf1e39d189c4a6083e4e068bd6a3dc 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 33d4706a946646fac6f8264dc8f68b9007f2b6e2..f9fe9514dd7f64d07f4afd33e7162d150d8236f8 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index e44f000141bf25f7099af306d213f7820a6b52d1..9abd4650b561984457c4779a87a0ae9985a716b0 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index d1a7868072a48019f3e6e3f624fe97936c8e31ca..c5460616dc13cc9e1090d496528d3e943730d58e 100644 (file)
@@ -148,6 +148,7 @@ function isSafe(loopNode, reference) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 417616dd231c93d73cfbb69141b818ed3de02e5d..fefc7b768fe9bca5d5d7a8a1684bc4ab7b2efa60 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index a2c678e710080f72e9110817b60c9842a05a279b..dfcd593ecbef51df46605332ac4ee0546cc8ab65 100644 (file)
@@ -26,6 +26,7 @@ function normalizeIgnoreValue(x) {
     return x;
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 70e31e604f4abd556a53f96e7d5018fa0ffcb838..94b28784a1032f2a0ea8851544ca1b90224c4d05 100644 (file)
@@ -98,6 +98,7 @@ const kinds = Object.keys(hasCharacterSequence);
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ed37a90b1c6a40840ce6505e59bc1d4a45f93a39..c75d01147c9030d81f3085ea848f0f63b709493b 100644 (file)
@@ -82,6 +82,7 @@ function getChildNode(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index f7c2d11ee4f74ed9722442bf0a82ccff08741832..5e05cf7a72adcb86595444b19ada95bb9b47b1de 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index ac73cddda3b4c32bbeefe8c2cad1b2d72a747122..f82a352caa4f33caecba9721b3b3b0f1caf57c12 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 8d7bd32c7dd99310e2e7ef085c062f403bee1d3b..be4d41f33d6a30919308c88d69779808a0cf3d18 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0134dd279b587c6ea4142554fa8e2cb98922f577..e37aae0a16e9e1656c3b2c3cc44b8117fe095ce2 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 848f8d405a869b9a4c5999344cfcdd6e6837dd89..6a17d581b98fa1060ba3d803e6c4f8f5f09788d4 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 33ac76f60378941e2d0da22fd9fd929d232322c9..d012303cc33a1a3917371a85d2b2fc9040cde89f 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 80ba0948cbce650a110bc6f57f9f9af7e2383a76..1814a5b3c5b6ccbd11b74a9e8d6db6ae014c3b2b 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index b5cbadca50f908dcd0541ae71c13b9d557e55071..a2870137f57ef551e2032a103c583633a101e080 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0f9c84be6c918da38de5c1d0402386f99c6d13f8..95ab58a080f598f59482f9cf0d6b8daa362fb79b 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 2d3359d38f144955199712d079bece9c319efdf1..c87875e40400f72b9988804ca821d189003157ad 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index ddf61024dac54b529c05b0fcbfeedda49667e50f..3b5994335194eb8bffaf8967a6c5fdfbdba6a9d8 100644 (file)
@@ -21,6 +21,7 @@ const callMethods = new Set(["apply", "bind", "call"]);
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 17dfd344476fe9aedab9cd65981096d17c02f3b1..1a5784df24d6a7bd895e0fee05ed90d204a2df4d 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 7973f8f2a27beb7d72441c05890a78fbce58e94c..5dadf6c2538e9563f5ee5119814d246179335a6d 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 391527df90cd694f381950d9079255fa9192e5bd..6acfca94358c4fd287a6837b7b5fcccd34941d04 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index b697d8d7951f7cb16e4e3593886812688b04865d..4667d581f654472d8fa91dd590b9f654af0c356d 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1b37f077d5c4b697393a61ac55524ed799ee5121..5b0976534d6e3d411f2905abf0b2d84c12a61636 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index da61f61d02f2a69116eae48f525bbf3c424887ae..3edd269faeb33deb1c263296dbcb631ecba06de9 100644 (file)
@@ -24,6 +24,7 @@ function getUnicodeEscape(character) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index d62c1f0b4be852ccbeba27d4c8cc0533bc67fe4d..667ba69d80310996f6e1782762e36348249c6c01 100644 (file)
@@ -37,6 +37,7 @@ function getReportNodeName(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4513a83861d259491d96d7ff0c079cb678c21b69..9ac56ab7bea8a52e10f562b98bb96e88d2a24039 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 5ee6895f623cbccd0c11165874ccd3e4af5546a8..44df45fdacda79b115ad562a201fe01d2f2d34dd 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index b758b9d97fccbec91dfc2e0fa59399f08af8c2e8..87a6b70238247ec21be78cbd78662f77217cf7b7 100644 (file)
@@ -10,6 +10,7 @@
 
 const stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Program)$/u;
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 184c9182b4d536f82d39093ed84f0e51306e5881..8d570a3778f3d318cbd24576b619b0b49248fe49 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index d7b6c730562670deae186004537f2e0f9e86cc54..2565da43231a254c1182c4b48aa040f5fe6a347b 100644 (file)
@@ -45,6 +45,7 @@ function isForLoopAfterthought(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c61b5572314a42866d6ebd7be38d91e95b4b6a62..f7c2c718fd04cb7d546bfd225a1802e92448ef99 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 73310a9e4e6364379cd65b186a3fb3c20be74495..251044b31c91c57d3696fd013f7d1537fc451b66 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 42652416f8fac461f61efb0a5115ed470d645efd..e40d4bcb3f52bd30828eb9e14e0d6718a1c62f63 100644 (file)
@@ -63,6 +63,7 @@ function isPromiseExecutor(node, scope) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 0c2490f7b421e0a4d8b21e238c060eaff8b38125..e6659e59c6bc274288b9b51c5d9940e348ce5606 100644 (file)
@@ -15,6 +15,7 @@ const { getStaticPropertyName } = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1f837b960403d8800a1485edbc33b102f4dbc619..ae736981e71865edf16ad053e184e842d31ecddb 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 3de4397b1b0e15fdbd4290340d92f62fe8795dc0..cc71a61234954fdbdcb8f02a87febddbb21cf2c8 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1d6b121ba80e759565e2aa6bdd36dd1982db260b..400c72b5027a8aeb6761ba6e77979b154b032f9f 100644 (file)
@@ -33,6 +33,7 @@ function isString(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index f568fdc6850245e108b67b28918ec97dc35e1632..775e505d846c213223b152a5c550bcbf919dddcb 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index efbcd755b1f607aa7a234a8f3271aea3c00bf6f4..09d347890ca89fc391a9212558543b30c53c175f 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index eda63407ff2d48626ec812d955a0329d4ebc1ab3..6813037f13a4ca901163521eb799b005b27696fb 100644 (file)
@@ -73,6 +73,7 @@ const arrayOfStringsOrObjectPatterns = {
     ]
 };
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 66e6fe49e3183e63245a4c7dd02b9a620585e901..26e75ef81a21d35f80426c09f2f7bc6b8b4c80a0 100644 (file)
@@ -39,6 +39,7 @@ const arrayOfStringsOrObjects = {
     uniqueItems: true
 };
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 3671d88eb600b9d7e0bed9d29847c0d0638caa29..1e8c7a89aedae70c2140efc0e8fb57daea65d65b 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0ff6b91bc69448612e83a7feeec39990d8193730..713d1157c4d692ebead1cad978ebde16d0f72825 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index ecb789ea269926d4f75529646c75fa492026996d..4fd7a3ddba587fc96cd16f7d4243012f867d9fbb 100644 (file)
@@ -20,6 +20,7 @@ const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionE
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 7ec808f50a3280ab17d87bc0a9ce900ae5af8466..191bf42dcf98eeac3e2e69f0697b369aa076c570 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 12451ad9a9eb3f4f39ac4e8306424d6114f91696..0eef25418402c02b0e62e3a52d4bffaf00959e0b 100644 (file)
@@ -12,6 +12,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 813771e700a2435fcb3515607f824093fd4ef23f..d9e261dfaae0c302d42361bec4d4a67de8a3867b 100644 (file)
@@ -124,6 +124,7 @@ function eachSelfAssignment(left, right, props, report) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ee77ff08b202e84239da6c5d49eba62f794687d4..c3512895e13474e421909daa2d4c55a4d40c12b6 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index b8941256e6f1a5a7c3f95b6a937e47af220f9046..376aec3798805af89417c716db3449ad5a222b0d 100644 (file)
@@ -23,6 +23,7 @@ const DEFAULT_OPTIONS = {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 67114ade8215311970d50b907c29139e959fda4b..7204e5c0c4d5c457fed566baea2b75aabe93e193 100644 (file)
@@ -136,6 +136,7 @@ function getOuterScope(scope) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 7d4174a104e3a99be2bcedc78ab9e068ccbf5b16..52620e58d1c1c1ec804e9c457e4371f042084c01 100644 (file)
@@ -21,6 +21,7 @@ function safelyShadowsUndefined(variable) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 4ec357620b6436f46533cdee788e3ecc54ed97af..bd619235ab9c59d4682066a95079e8c920c90c24 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 8f51d5446d844b987bbe1739f17d9b52f8b7d826..1d2994333e125e13c578c1eef655e5f23131d35d 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 56ce5dcc871b1ef99f704718ca18a6c28f6b52b9..c95bc203c4a96ca895506f2a77c7c6233f5ea8ce 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ea40df12933b5c994953e484b8db63b4887981ba..3536d9f2a39a9b70bffeced6739ce71e570fc22e 100644 (file)
@@ -10,6 +10,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         deprecated: true,
index 1f3921a9a70fd620e614c409335b0071ec244301..9758b850be161ab3cae8257210f30f104e8c2630 100644 (file)
@@ -16,6 +16,7 @@ const anyNonWhitespaceRegex = /\S/u;
 // Public Interface
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index e71480fc0131ab7d51f3254c3d09b8bab8e071ed..1901460f3d22631d6da74c616b3b719c1387cfeb 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 8b2e10a34a4e5c40b1c538d0eefd90091c636bb5..b0dc626832bc2e3a7d83ad1271d0d75e7be21c41 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 9cc85ebbe21064c4fc349b34a193ca04f8a0404b..929eded2443324755b16c6d0e07364e85bd0244a 100644 (file)
@@ -34,6 +34,7 @@ function isConstructorFunction(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 311e6d4f079daec7d29d6da6c5afbbc56e114f09..c670ed9e5e1cbbbef97ebfc627fbbc6a4078d999 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1930098bea00404a393a14b8936ed3ef2f9864fa..9e720ad32e8f2d624540b228a6836ad265cfbdd7 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 7298d3449417cd7ef8ffe184750ce37aa42d79f4..2c2204cf0fe2d27ca7932f932ce5566d0de28fc1 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index ee611f9c866df1085e155511e4d8687b98518b97..f65903245c8d6c54ed0fd8c9e9a83848863038c7 100644 (file)
@@ -23,6 +23,7 @@ function hasTypeOfOperator(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ad302255420acbb5124332197087b1826f2dd47f..de396d889c0e27901004e670689ab3a388d2d496 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 916b8c01baa1bd60b19028f347bcdee33dedb384..0ab41feb03c22f2677f50db056cc6cec46bb6f5d 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 4447959ed9a17636d08668fb40df6a107fcfe79c..60d8f3164cd9f0e2f7c573dd446ff698f0f60f1c 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ba321d2c6ed33198e1dff8bfbcbb17a7515f77c5..5b8da26f2d21cdcbf6145356c678df4e50ab0af3 100644 (file)
@@ -156,6 +156,7 @@ function updateModifiedFlag(conditions, modifiers) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index e12240d03e0d767c7ebf7b2547ac1f541770928a..e00d5270a2aa05d02da3b2a54a73380052b9ae01 100644 (file)
@@ -23,6 +23,7 @@ const OR_PRECEDENCE = astUtils.getPrecedence({ type: "LogicalExpression", operat
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 5cbfac46d318f18d9016036be1d2b57d63a328ec..f100263308fad66c4d61e9276cce5070f109dab3 100644 (file)
@@ -53,6 +53,7 @@ function getDifference(arrA, arrB) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ce17a5966a7eccae48cb3ac0976fadebf3c20936..4dda51f11b9a9a0949cde786740bd845c5173b11 100644 (file)
@@ -105,6 +105,7 @@ class ConsecutiveRange {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 4bb7f7fec4f2c3de1cd4b1f7cfce04446fcc2911..26c05eab8b08250fb72f50ad9ec10c91c4305c3e 100644 (file)
@@ -18,6 +18,7 @@ const SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaratio
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index c681986941ae0e16567f34f89a62122aeed1704e..057b1742acc05812ddb72e7289f52baaf54c81cd 100644 (file)
@@ -46,6 +46,7 @@ function isNegation(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index cc15c9988138f66c8084bc94320954c38c7034de..8556ccbd79dc2cce53fa1afc26cf72f134e35120 100644 (file)
@@ -18,6 +18,7 @@ function isDestructuringPattern(node) {
     return node.type === "ObjectPattern" || node.type === "ArrayPattern";
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 2081a518b30ce06603e268731cb8adae1b416604..68a7ebd5e00cea045e8ff53b4091102b9ab4c608 100644 (file)
@@ -24,6 +24,7 @@ function alwaysFalse() {
     return false;
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index f0b09614e09ce40863607e2178143a231f7748e0..f309dd12b1253ccd11540fb04ef2be4c9bacecd6 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 74cf6ab694a4609b4c4195cef5e93ebd2ae0b1e0..754c36002eb94a1a966ce6cf376768c6fe8269dc 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 847e21baf5f46201a2d4b5643a5e105a4f6e3537..eaf7a8b912e427b6a8d248ced9ff64b533eec602 100644 (file)
@@ -27,6 +27,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 7f904f46bd540466f14880263b2dbf17c92cc0be..07d035c431ff1255039b401841afadd1ff642016 100644 (file)
@@ -218,6 +218,7 @@ function isEvaluatedDuringInitialization(reference) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index ae491471282458793e8b7396c822f439d4d16388..1a09988b80956e2dac4ec416aa1a464eaa4f7134 100644 (file)
@@ -58,6 +58,7 @@ function isNegativeLookaround(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 89350665fe37723d8e745beae1f65714984c5d78..8c57cd5cc9a8769388060087605a7205e95ac116 100644 (file)
@@ -49,6 +49,7 @@ function isValidThisArg(expectedThis, thisArg, sourceCode) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 280ba55336727962ccf51b176fe597f0fc50e5e0..325a2e58117188573dd06f2d7f93a0bdffe95398 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a8769214f5478a126a76f8529550ac55cf52cbcd..7ebbe09de26bb70b5f00cc7c6f8e3d5ba47acd25 100644 (file)
@@ -85,6 +85,7 @@ function hasUselessComputedKey(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a0176a7e9db47314f5d3d0c17cd721e3fd48f526..36ca84f90cbacfd1242b36ea697c5a8f74a89e75 100644 (file)
@@ -64,6 +64,7 @@ function getRight(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 13ec6755015adc59bf774090920ac99cf67c0edb..6512c8b1fefbf980886517cf7cb5140a003df688 100644 (file)
@@ -132,6 +132,7 @@ function isRedundantSuperCall(body, ctorParams) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a780a7a84a670623da9d3743a07cffefe53019e4..123bc5b8a0169c419948ee083262d4b1be79e97a 100644 (file)
@@ -78,6 +78,7 @@ function parseRegExp(regExpText) {
     return charList;
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c0d27e600a8aab80c0d8d9f2372080f39193a270..616ec2a43cc631ef13040d7dcb317578567ff849 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 87f05892a943e22a080879a0f2157388c8389505..0baa6b2942d1721f261d7ebea0835b2bf77e4b8d 100644 (file)
@@ -61,6 +61,7 @@ function isInFinally(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a821c38a36e0edd2dd412771ec41af9c7d7c9973..83a1f62eb6f952aeae489c482ad38654b4277a88 100644 (file)
@@ -179,6 +179,7 @@ function hasNameDisallowedForLetDeclarations(variable) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index dba4932385d720d46265cba691cf09125b0c4013..8631caf70cf96e27b80e2df03b6e5de97b73f9d3 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 23e3da35e146726b4bbd2249aacc7f442ea4cc4c..5f3ea21d7d0e867e285a3d0e7fc5cf77b9fa9098 100644 (file)
@@ -14,6 +14,7 @@ const CHAR_LIMIT = 40;
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 9a492997d765806bc55433b005132ddbc18404be..95e920f27ea9bc7c777d83a3acdccf9a2c86a5a7 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 219a68094cb5bf78db440130a7f0d2d82746df8d..fc93f199f87ac036038454710f2c246b6d67a257 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 7ed541b3802750a4f9f093569dbaeb3945fddc4e..c177cf34cee880c4c8aa6c6942088f2bc8052924 100644 (file)
@@ -10,6 +10,7 @@
 
 const POSITION_SCHEMA = { enum: ["beside", "below", "any"] };
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index e16099135826b98c4be1fb14489af3d0d78d4b37..e052cd86493f3840f93e3f40a81a0c373c6c3656 100644 (file)
@@ -144,6 +144,7 @@ function areLineBreaksRequired(node, options, first, last) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index b18ef57404599fa563fcbf46de97208c72166c31..9122da3ef3dbfca28f46cd02d74bc1d64f27003f 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 7cca23ff31ffa98687b559dbde43d441638dc641..dac084c3f651d17d4b5f719a50fbabe6e9124d39 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 10bb07bbb0cb0159ab4546df75b339a3ae0b8182..aa03450d0719095a6f523c330aeea10806eaea10 100644 (file)
@@ -22,6 +22,7 @@ const astUtils = require("./utils/ast-utils");
 //------------------------------------------------------------------------------
 // Rule Definition
 //------------------------------------------------------------------------------
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c0ad70004e6716fbc4f8f3fc747b7c747e8e5d08..440146b92c1c65abef4d0a102793045f8a4fc193 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index daff2d22b15254870362e940b7a58116842047c0..1818c02e6e14156a5c42460fe7488299406e9277 100644 (file)
@@ -28,6 +28,7 @@ function isInStatementList(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 34bdb861f46bee416a4917c2c3de77bcca84c731..d200811634c65e6e26744cedaba0b508c7ab7855 100644 (file)
@@ -57,6 +57,7 @@ function canBeFixed(node) {
     );
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 6eab0cccbb4e1ed0f61e45b08c5ab2bdf3c267e5..a04f85bdea96ba16690ebb08cad6f79204bb17b9 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index de75e8d2d51b06d88a8985bb281a6d6e1547b862..336adac9a02f199c6fbd79737e30e1c55ef4712b 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 42859dd38b0b8fa12307c664d77f321c4cf728eb..fe5d304dd5b6130a09d28a0336f70c8e22ba2bfb 100644 (file)
@@ -425,6 +425,7 @@ const StatementTypes = {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 518bf4b2da3bda40438c3ce9ab09b247846a8686..55a098a60979ce2c8086e3d21e8a590cbc0b9d76 100644 (file)
@@ -145,6 +145,7 @@ function hasDuplicateParams(paramsList) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 38ec973fcdb592920098b80823da74ecce5d3924..190860019d8e8f78d7bd83d7b8f7a6a0050136ec 100644 (file)
@@ -326,6 +326,7 @@ function findUp(node, type, shouldStop) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 46986d237df3dc05f35f9fb0ca60a65ed7c99528..1f68313d6b178d0ee02ceaa6abbbd2decc2fb24c 100644 (file)
@@ -20,6 +20,7 @@ const PRECEDENCE_OF_ASSIGNMENT_EXPR = astUtils.getPrecedence({ type: "Assignment
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index de802ce1e11cb89df8e2c7e4c92bc3f1207e50cc..a291e8dec151648333588b279081237d9f7bbc70 100644 (file)
@@ -84,6 +84,7 @@ function parenthesizeIfShould(text, shouldParenthesize) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 41aa549327d96923f9b6176ead7b21225df0774b..cff2d8f45d270a70fa95da5439f54a22d9151c7c 100644 (file)
@@ -27,6 +27,7 @@ const parser = new regexpp.RegExpParser();
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 91bb26724eb13c4fc49849a86ef1f7655aa19430..53a515368960fc74765491661b25c49d19b8402a 100644 (file)
@@ -39,6 +39,7 @@ function isParseInt(calleeNode) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 3958a51b30e4601c1edcb258f736707150ab538d..b63474ef2bd376de77ba9b7ca46bc1be4f1d7000 100644 (file)
@@ -240,6 +240,7 @@ function defineFixer(node, sourceCode) {
     };
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index bdc1fef4d7c18a79778d8a84ad89b0797d9a7ebb..60e72f451019f8e2f439e006ee5a105622fadd17 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index fea88c67827afbd4638383744bf75dac1b8d29d8..1367a1848df9e27cbe249d7b21c81f0d9fcecc7f 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index fbfeb5636d754a2b1138219f9a0b087751a606f5..afd6a01398e72d3cffaeec4e7566e9e5d5076eca 100644 (file)
@@ -48,6 +48,7 @@ function isStaticTemplateLiteral(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 157f0bbd61a84e65e4fc76cac169073d9fd1a05b..371a28964f2739e5d560771ce40a192684e4715e 100644 (file)
@@ -59,6 +59,7 @@ function isNotNormalMemberAccess(reference) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 3944fedb126cacd34ca4a6b83655ca0cd6499d03..c5f9e1e6cbf674b665e4bb95746d5407429aa931 100644 (file)
@@ -43,6 +43,7 @@ function isValidThisArg(expectedThis, thisArg, context) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 564dd555f8e9b843d639eeddad349660fefa67e1..953155d8f982470c4f2d6f78dc18353a7ecfe348 100644 (file)
@@ -122,6 +122,7 @@ function endsWithTemplateCurly(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index ce277cdcc9d897c9c1853f1567ac77f01c0affa9..e57ad6eea294f719f317d32afa66a473a09aea6b 100644 (file)
@@ -16,6 +16,7 @@ const keywords = require("./utils/keywords");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index d7959c0d1f02653112c18b20a6dba6cf6e2dfb54..a9960961edf242060ae22ab63b2eab8ca337d228 100644 (file)
@@ -74,6 +74,7 @@ const AVOID_ESCAPE = "avoid-escape";
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 0c6c6ffb1a60bb4f12ab0b51ed2257bca53e2312..f83c762c11d39788c390a4d277f45a75ca0b8492 100644 (file)
@@ -74,6 +74,7 @@ function isDefaultRadix(radix) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 248b0eb11d00d59a1a49438e477a9a8bf2408721..4dbd48dfc585a4d1f4ae24c3b1d6f4221dbef82c 100644 (file)
@@ -165,6 +165,7 @@ class SegmentInfo {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 8ec6f547ae9403db1b4979106902f62a6d4a635a..1b17de0e197556440199552cf23fdbfe8fb4a0de 100644 (file)
@@ -28,6 +28,7 @@ function capitalizeFirstLetter(text) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 1d76e3d222b0e7bf3f11f8f08f08780e3493de84..169b6f524139cb4cfa819e658c3bd94a6067f5dd 100644 (file)
@@ -5,6 +5,7 @@
  */
 "use strict";
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a332b48da669aebe74002ef7ac4c78a48a8f5af0..577ae6cf8271d114f6b005bd5692e62ea1544864 100644 (file)
@@ -20,6 +20,7 @@ const {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index f5b5d530396a0041c55c965e01023e58811f9e0f..aba06140672d6a6058e776c45b4733ebb309155d 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a636defdcd9046e17e2da37ce6b97ac2326aba18..ace1ec521415ab031cd8c1e636b3a68884d13610 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index e5e2ae25cc7365f125d3850fdc3cf7ca0438da0b..4f0afbb11a3db4f030348db6096f02c21b9e921c 100644 (file)
@@ -11,6 +11,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 2d17d028c2fb06b6cc2d824b0f338bba2e89e686..7952a9adff1632ca279d4db40ca089dea3b94388 100644 (file)
@@ -67,6 +67,7 @@ function isLastChild(node) {
     return nodeList !== null && nodeList[nodeList.length - 1] === node; // before `}` or etc.
 }
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index c29029cedfe153750ff49fffc6118934e5f8d8e6..86ff8d74ee12d7aa2a6003da738e5f9c923c49a4 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index dd43daddf05b6d97ede27cdb9f995f4ef45c5c19..13cb63681cb8a66de1b84b4a775dab56dc706129 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 65a99142279c8d181c527aab07d14a5394e67a57..2fc19635271759f83446c6dd359af2cb3922e2c3 100644 (file)
@@ -75,6 +75,7 @@ const isValidOrders = {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 0616c44ac621bb2f2fdf77c3b15c35f723928c0f..8246558c5478f7d94ba296be412a2497d95f5b01 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 87d5b27aace7baab25c0251c5526a3d0067f0470..5cc7266654f5fc75a64fba44d303264fd0ba7dc9 100644 (file)
@@ -34,6 +34,7 @@ function isFunctionBody(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index b60bee0409720a91411233e54e3b7c6e609b806c..fdd45be241d4645f6d73c4e9e26fba5dfae32456 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 24378b89f046614cc2c321cfdf3eaa01b82fda63..1509d600f1d58dbce096504505398b3924b8ba44 100644 (file)
@@ -10,6 +10,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 8065b5240b9ffac0e43c5e882de0bc86e4bb9db2..c526b7e2b0a40669a3f01768b581fa6b72af47b8 100644 (file)
@@ -10,6 +10,7 @@ const { isEqToken } = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index de9018f9b69e0de7840c18ae8a4891a07ad7c72c..04487c49e0d8c62bba7f80a765a10c9ca3057cf2 100644 (file)
@@ -14,6 +14,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 6f0b432b765ac5812d1103ac99741439fc11f43d..674c13cf3807ec6378544ec3324bd85589fe9885 100644 (file)
@@ -146,6 +146,7 @@ function createNeverStylePattern(markers) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 24af39dabee3889504a3e7d4856ad81b1d2c35ca..0ea1da5677ed6daaa8e2790e0fa9e0895a7a8327 100644 (file)
@@ -63,6 +63,7 @@ function isSimpleParameterList(params) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index a4f3ba213eb52141d6af65476e8d2597f3ee9bd5..cd2ca7018d284f9747e5b0ff833011aaca7981b1 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 9f5d9358f00253a40fe2db201ef093b61f700637..07bb8cd27355fe60aca7d32a0c7c71e72254f0a0 100644 (file)
@@ -16,6 +16,7 @@ const astUtils = require("./utils/ast-utils");
 //------------------------------------------------------------------------------
 
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 5133a54539cb32e5dded906757d5c3565a328d99..c842b76a41f38bacc35e24b42322566459c64fef 100644 (file)
@@ -15,6 +15,7 @@ const astUtils = require("./utils/ast-utils");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 45b66068a83f3d3d79090070c663d15e78a22fef..fa1a613b8949057fd9a2a6175cc99f3b96792735 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index e80497d19ca029bf302a8d479d00cb94c221cc87..d480f1bcdc8575406f61589ed81eb5a900825431 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index cd8331f932e3edd75fa47708db5d34aa0d15127c..92903500c183366e6326d4a23e9498e7343b23c5 100644 (file)
@@ -31,6 +31,7 @@ function isNaNIdentifier(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 824410b33704d892efbf6fde88a579353e401b30..c118e033dd875a3d739b825a49d71978876922b3 100644 (file)
@@ -15,6 +15,7 @@ const doctrine = require("doctrine");
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 33b64f56cc3857c16b2b815acd91dcd5994032f8..6046358123351355da518fa820634f40ad5fd8f2 100644 (file)
@@ -8,6 +8,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "problem",
index 0f95d58dbc670e55a07f5caf2b230945fdd652c2..09e9932b4ca5a8aa808be129615bac856185f0ad 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index 498d7bd2842e2928594886db40e80e2ae353410a..8523796722a18730c1c622777f0a83c33c41069c 100644 (file)
@@ -37,6 +37,7 @@ function isCalleeOfNewExpression(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 945eb5ecea1ff076f12cf59d4865fe0dabc82b9e..b10f2ec53bd8d87eb0606355cab05570606cbf1c 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 8c3eefa4acd71030796f115f0fbde85a5c32b5d9..884a3a4ed01601da4ad3070d5da590e984073a64 100644 (file)
@@ -9,6 +9,7 @@
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "layout",
index 2d018dc3df1253f1c6351e90e028dd0a3d1bddb3..f491f756d5463d2e6da49f1af4a56ca4273c31c7 100644 (file)
@@ -115,6 +115,7 @@ function getNormalizedLiteral(node) {
 // Rule Definition
 //------------------------------------------------------------------------------
 
+/** @type {import('../shared/types').Rule} */
 module.exports = {
     meta: {
         type: "suggestion",
index c497f783be5c464ecc5c9e5d904843d1215f9f39..ab59207a6b116432a2d86e036e0737b3ce8817ba 100644 (file)
@@ -23,6 +23,16 @@ module.exports = {};
  * @property {EcmaFeatures} [ecmaFeatures] The optional features.
  * @property {3|5|6|7|8|9|10|11|12|13|2015|2016|2017|2018|2019|2020|2021|2022} [ecmaVersion] The ECMAScript version (or revision number).
  * @property {"script"|"module"} [sourceType] The source code type.
+ * @property {boolean} [allowReserved] Allowing the use of reserved words as identifiers in ES3.
+ */
+
+/**
+ * @typedef {Object} LanguageOptions
+ * @property {number|"latest"} [ecmaVersion] The ECMAScript version (or revision number).
+ * @property {Record<string, GlobalConf>} [globals] The global variable settings.
+ * @property {"script"|"module"|"commonjs"} [sourceType] The source code type.
+ * @property {string|Object} [parser] The parser to use.
+ * @property {Object} [parserOptions] The parser options to use.
  */
 
 /**
index c3dfa1bb3703e4822482219ae28792d97ec63c17..82cc50e84eee4eaa99086862fd646aa129f98f2d 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "eslint",
-  "version": "8.3.0",
+  "version": "8.4.0",
   "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
   "description": "An AST-based pattern checker for JavaScript.",
   "bin": {
@@ -47,8 +47,8 @@
   "homepage": "https://eslint.org",
   "bugs": "https://github.com/eslint/eslint/issues/",
   "dependencies": {
-    "@eslint/eslintrc": "^1.0.4",
-    "@humanwhocodes/config-array": "^0.6.0",
+    "@eslint/eslintrc": "^1.0.5",
+    "@humanwhocodes/config-array": "^0.9.2",
     "ajv": "^6.10.0",
     "chalk": "^4.0.0",
     "cross-spawn": "^7.0.2",
@@ -59,7 +59,7 @@
     "eslint-scope": "^7.1.0",
     "eslint-utils": "^3.0.0",
     "eslint-visitor-keys": "^3.1.0",
-    "espree": "^9.1.0",
+    "espree": "^9.2.0",
     "esquery": "^1.4.0",
     "esutils": "^2.0.2",
     "fast-deep-equal": "^3.1.3",
     "karma-webpack": "^5.0.0",
     "lint-staged": "^11.0.0",
     "load-perf": "^0.2.0",
-    "markdownlint": "^0.23.1",
-    "markdownlint-cli": "^0.28.1",
+    "markdownlint": "^0.24.0",
+    "markdownlint-cli": "^0.30.0",
     "memfs": "^3.0.1",
     "mocha": "^8.3.2",
     "mocha-junit-reporter": "^2.0.0",
index 71e1973b2e7d16b0d7c330760929a428e22db1dd..37be7ec5eb11950425ea6290cf3654e57c564fa2 100644 (file)
@@ -1,13 +1,14 @@
 ---
 layout: post
 title: ESLint v<%- version %> released
+teaser: "We just pushed ESLint v<%- version %>, which is a <%- type %> release upgrade of ESLint. This release <% if (type !== "patch") { %>adds some new features and <% } %>fixes several bugs found in the previous release.<% if (type === "major") { %> This release also has some breaking changes, so please read the following closely.<% } %>"
+categories:
+  - Release Notes
 tags:
   - release
   - <%- type %>
 ---
 
-We just pushed ESLint v<%- version %>, which is a <%- type %> release upgrade of ESLint. This release <% if (type !== "patch") { %>adds some new features and <% } %>fixes several bugs found in the previous release.<% if (type === "major") { %> This release also has some breaking changes, so please read the following closely.<% } %>
-
 <%
 const RULE_REGEX = new RegExp(`\`?\\b(${ruleList.join("|")})\\b\`?`, "g");
 
index bd3035b540eda0c920defb725fba246804020335..c8c552d306d47e720f6faac46bcaedc2ad4e8cba 100644 (file)
@@ -1,4 +1,4 @@
-**Tell us about your environment**
+**Tell us about your environment:**
 
 * **ESLint Version:**
 * **Node Version:**
@@ -23,4 +23,3 @@
 **What did you expect to happen?**
 
 **What actually happened? Please include the actual, raw output from ESLint.**
-
index ee100011bc4fd31959036c2f8e517ed214fa4528..a4a8e17cbd51ac9edb64a36165e6406d6958b140 100644 (file)
@@ -1,12 +1,9 @@
 **What rule do you want to change?**
 
-
 **Does this change cause the rule to produce more or fewer warnings?**
 
-
 **How will the change be implemented? (New option, new default behavior, etc.)?**
 
-
 **Please provide some example code that this change will affect:**
 
 ```js
@@ -15,6 +12,4 @@
 
 **What does the rule currently do for this code?**
 
-
 **What will the rule do after it's changed?**
-
index 383b1b4819c13fe1dc8579ab84a2f869bf83e301..2adf9317613bc6783f605af577300526682167ac 100644 (file)
@@ -1,7 +1,6 @@
 **Please describe what the rule should do:**
 
-
-**What category of rule is this? (place an "X" next to just one item)**
+**What category of rule is this (place an "X" next to just one item)?**
 
 [ ] Enforces code style
 [ ] Warns about a potential error
@@ -15,4 +14,3 @@
 ```
 
 **Why should this rule be included in ESLint (instead of a plugin)?**
-
diff --git a/eslint/tests/fixtures/formatters/async.js b/eslint/tests/fixtures/formatters/async.js
new file mode 100644 (file)
index 0000000..b5651a6
--- /dev/null
@@ -0,0 +1,4 @@
+/*global module*/
+module.exports = function(results) {
+  return Promise.resolve('from async formatter');
+};
diff --git a/eslint/tests/fixtures/formatters/cwd.js b/eslint/tests/fixtures/formatters/cwd.js
new file mode 100644 (file)
index 0000000..b9c4966
--- /dev/null
@@ -0,0 +1,4 @@
+/*global module*/
+module.exports = function(results, context) {
+    return context.cwd;
+};
index 95857751a755a5d55a8aa6d1f5b5e6dc5730f332..0c701edbbe2652432ba2502c1a9e596ee4d4e51c 100644 (file)
@@ -4,7 +4,7 @@ const espree = require("espree");
 
 exports.parse = (sourceText, options) => {
     if (options.ecmaVersion) {
-        throw new Error("Expected no parserOptions to be used");
+        throw new Error("Expected no parserOptions.ecmaVersion to be used");
     }
     return espree.parse(sourceText, options);
 };
index 31f59bf51b4b78213d934b1821e855da735d9bb7..2ba4839baf60b6c2b2b6713615cf1a0b8cd04ed6 100644 (file)
@@ -1158,28 +1158,44 @@ describe("CLIEngine", () => {
                 configFile: getFixturePath("configurations", "semi-error.json")
             });
 
-            const report = engine.executeOnFiles([getFixturePath("formatters")]);
+            const fixturePath = getFixturePath("formatters");
+            const report = engine.executeOnFiles([fixturePath]);
 
-            assert.strictEqual(report.results.length, 3);
             assert.strictEqual(report.errorCount, 0);
             assert.strictEqual(report.warningCount, 0);
             assert.strictEqual(report.fixableErrorCount, 0);
             assert.strictEqual(report.fixableWarningCount, 0);
-            assert.strictEqual(report.results[0].messages.length, 0);
-            assert.strictEqual(report.results[1].messages.length, 0);
-            assert.strictEqual(report.results[2].messages.length, 0);
+            assert.strictEqual(report.results.length, 5);
+            assert.strictEqual(path.relative(fixturePath, report.results[0].filePath), "async.js");
             assert.strictEqual(report.results[0].errorCount, 0);
             assert.strictEqual(report.results[0].warningCount, 0);
             assert.strictEqual(report.results[0].fixableErrorCount, 0);
             assert.strictEqual(report.results[0].fixableWarningCount, 0);
+            assert.strictEqual(report.results[0].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, report.results[1].filePath), "broken.js");
             assert.strictEqual(report.results[1].errorCount, 0);
             assert.strictEqual(report.results[1].warningCount, 0);
             assert.strictEqual(report.results[1].fixableErrorCount, 0);
             assert.strictEqual(report.results[1].fixableWarningCount, 0);
+            assert.strictEqual(report.results[1].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, report.results[2].filePath), "cwd.js");
             assert.strictEqual(report.results[2].errorCount, 0);
             assert.strictEqual(report.results[2].warningCount, 0);
             assert.strictEqual(report.results[2].fixableErrorCount, 0);
             assert.strictEqual(report.results[2].fixableWarningCount, 0);
+            assert.strictEqual(report.results[2].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, report.results[3].filePath), "simple.js");
+            assert.strictEqual(report.results[3].errorCount, 0);
+            assert.strictEqual(report.results[3].warningCount, 0);
+            assert.strictEqual(report.results[3].fixableErrorCount, 0);
+            assert.strictEqual(report.results[3].fixableWarningCount, 0);
+            assert.strictEqual(report.results[3].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, report.results[4].filePath), path.join("test", "simple.js"));
+            assert.strictEqual(report.results[4].errorCount, 0);
+            assert.strictEqual(report.results[4].warningCount, 0);
+            assert.strictEqual(report.results[4].fixableErrorCount, 0);
+            assert.strictEqual(report.results[4].fixableWarningCount, 0);
+            assert.strictEqual(report.results[4].messages.length, 0);
         });
 
 
@@ -1190,24 +1206,39 @@ describe("CLIEngine", () => {
                 configFile: getFixturePath("configurations", "single-quotes-error.json")
             });
 
-            const report = engine.executeOnFiles([getFixturePath("formatters")]);
+            const fixturePath = getFixturePath("formatters");
+            const report = engine.executeOnFiles([fixturePath]);
 
             assert.strictEqual(report.errorCount, 6);
             assert.strictEqual(report.warningCount, 0);
             assert.strictEqual(report.fixableErrorCount, 6);
             assert.strictEqual(report.fixableWarningCount, 0);
+            assert.strictEqual(report.results.length, 5);
+            assert.strictEqual(path.relative(fixturePath, report.results[0].filePath), "async.js");
             assert.strictEqual(report.results[0].errorCount, 0);
             assert.strictEqual(report.results[0].warningCount, 0);
             assert.strictEqual(report.results[0].fixableErrorCount, 0);
             assert.strictEqual(report.results[0].fixableWarningCount, 0);
-            assert.strictEqual(report.results[1].errorCount, 3);
+            assert.strictEqual(path.relative(fixturePath, report.results[1].filePath), "broken.js");
+            assert.strictEqual(report.results[1].errorCount, 0);
             assert.strictEqual(report.results[1].warningCount, 0);
-            assert.strictEqual(report.results[1].fixableErrorCount, 3);
+            assert.strictEqual(report.results[1].fixableErrorCount, 0);
             assert.strictEqual(report.results[1].fixableWarningCount, 0);
-            assert.strictEqual(report.results[2].errorCount, 3);
+            assert.strictEqual(path.relative(fixturePath, report.results[2].filePath), "cwd.js");
+            assert.strictEqual(report.results[2].errorCount, 0);
             assert.strictEqual(report.results[2].warningCount, 0);
-            assert.strictEqual(report.results[2].fixableErrorCount, 3);
+            assert.strictEqual(report.results[2].fixableErrorCount, 0);
             assert.strictEqual(report.results[2].fixableWarningCount, 0);
+            assert.strictEqual(path.relative(fixturePath, report.results[3].filePath), "simple.js");
+            assert.strictEqual(report.results[3].errorCount, 3);
+            assert.strictEqual(report.results[3].warningCount, 0);
+            assert.strictEqual(report.results[3].fixableErrorCount, 3);
+            assert.strictEqual(report.results[3].fixableWarningCount, 0);
+            assert.strictEqual(path.relative(fixturePath, report.results[4].filePath), path.join("test", "simple.js"));
+            assert.strictEqual(report.results[4].errorCount, 3);
+            assert.strictEqual(report.results[4].warningCount, 0);
+            assert.strictEqual(report.results[4].fixableErrorCount, 3);
+            assert.strictEqual(report.results[4].fixableWarningCount, 0);
         });
 
         it("should process when file is given by not specifying extensions", () => {
index 1b3828b4090215be50f05ce69f9edc030618fdf8..59ff0eaf7a417ab8c710a7ea4ee679f13b05bed7 100644 (file)
@@ -249,10 +249,13 @@ describe("cli", () => {
 
             // Check metadata.
             const { metadata } = JSON.parse(log.info.args[0][0]);
-            const expectedMetadata = Array.from(BuiltinRules).reduce((obj, [ruleId, rule]) => {
-                obj.rulesMeta[ruleId] = rule.meta;
-                return obj;
-            }, { rulesMeta: {} });
+            const expectedMetadata = {
+                cwd: process.cwd(),
+                rulesMeta: Array.from(BuiltinRules).reduce((obj, [ruleId, rule]) => {
+                    obj[ruleId] = rule.meta;
+                    return obj;
+                }, {})
+            };
 
             assert.deepStrictEqual(metadata, expectedMetadata);
         });
@@ -287,6 +290,17 @@ describe("cli", () => {
         });
     });
 
+    describe("when given an async formatter path", () => {
+        it("should execute without any errors", async () => {
+            const formatterPath = getFixturePath("formatters", "async.js");
+            const filePath = getFixturePath("passing.js");
+            const exit = await cli.execute(`-f ${formatterPath} ${filePath}`);
+
+            assert.strictEqual(log.info.getCall(0).args[0], "from async formatter");
+            assert.strictEqual(exit, 0);
+        });
+    });
+
     describe("when executing a file with a lint error", () => {
         it("should exit with error", async () => {
             const filePath = getFixturePath("undef.js");
index f6b099096e1694555b97d09a4beba32aa6250518..64cad9409cf5b6700167ecdec7083bd14cdd24e1 100644 (file)
@@ -78,7 +78,7 @@ const baseConfig = {
 function createFlatConfigArray(configs) {
     return new FlatConfigArray(configs, {
         basePath: __dirname,
-        baseConfig
+        baseConfig: [baseConfig]
     });
 }
 
@@ -143,6 +143,29 @@ function normalizeRuleConfig(rulesConfig) {
 
 describe("FlatConfigArray", () => {
 
+    it("should not reuse languageOptions.parserOptions across configs", () => {
+        const base = [{
+            languageOptions: {
+                parserOptions: {
+                    foo: true
+                }
+            }
+        }];
+
+        const configs = new FlatConfigArray([], {
+            basePath: __dirname,
+            baseConfig: base
+        });
+
+        configs.normalizeSync();
+
+        const config = configs.getConfig("foo.js");
+
+        assert.notStrictEqual(base[0].languageOptions, config.languageOptions);
+        assert.notStrictEqual(base[0].languageOptions.parserOptions, config.languageOptions.parserOptions, "parserOptions should be new object");
+    });
+
+
     describe("Special configs", () => {
         it("eslint:recommended is replaced with an actual config", async () => {
             const configs = new FlatConfigArray(["eslint:recommended"], { basePath: __dirname });
@@ -638,7 +661,7 @@ describe("FlatConfigArray", () => {
                                 ecmaVersion: "true"
                             }
                         }
-                    ], "Expected a number.");
+                    ], /Key "languageOptions": Key "ecmaVersion": Expected a number or "latest"\./u);
                 });
 
                 it("should merge two objects when second object has overrides", () => assertMergedResult([
index eaf4aaaaf05971245b36ff81838d7b882172862f..4e140f7fe0fd25d0aceccdb99a71d803e1fd4086 100644 (file)
@@ -1210,24 +1210,40 @@ describe("ESLint", () => {
                 cwd: path.join(fixtureDir, ".."),
                 overrideConfigFile: getFixturePath("configurations", "semi-error.json")
             });
-            const results = await eslint.lintFiles([getFixturePath("formatters")]);
+            const fixturePath = getFixturePath("formatters");
+            const results = await eslint.lintFiles([fixturePath]);
 
-            assert.strictEqual(results.length, 3);
-            assert.strictEqual(results[0].messages.length, 0);
-            assert.strictEqual(results[1].messages.length, 0);
-            assert.strictEqual(results[2].messages.length, 0);
+            assert.strictEqual(results.length, 5);
+            assert.strictEqual(path.relative(fixturePath, results[0].filePath), "async.js");
             assert.strictEqual(results[0].errorCount, 0);
             assert.strictEqual(results[0].warningCount, 0);
             assert.strictEqual(results[0].fixableErrorCount, 0);
             assert.strictEqual(results[0].fixableWarningCount, 0);
+            assert.strictEqual(results[0].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, results[1].filePath), "broken.js");
             assert.strictEqual(results[1].errorCount, 0);
             assert.strictEqual(results[1].warningCount, 0);
             assert.strictEqual(results[1].fixableErrorCount, 0);
             assert.strictEqual(results[1].fixableWarningCount, 0);
+            assert.strictEqual(results[1].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, results[2].filePath), "cwd.js");
             assert.strictEqual(results[2].errorCount, 0);
             assert.strictEqual(results[2].warningCount, 0);
             assert.strictEqual(results[2].fixableErrorCount, 0);
             assert.strictEqual(results[2].fixableWarningCount, 0);
+            assert.strictEqual(results[2].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, results[3].filePath), "simple.js");
+            assert.strictEqual(results[3].errorCount, 0);
+            assert.strictEqual(results[3].warningCount, 0);
+            assert.strictEqual(results[3].fixableErrorCount, 0);
+            assert.strictEqual(results[3].fixableWarningCount, 0);
+            assert.strictEqual(results[3].messages.length, 0);
+            assert.strictEqual(path.relative(fixturePath, results[4].filePath), path.join("test", "simple.js"));
+            assert.strictEqual(results[4].errorCount, 0);
+            assert.strictEqual(results[4].warningCount, 0);
+            assert.strictEqual(results[4].fixableErrorCount, 0);
+            assert.strictEqual(results[4].fixableWarningCount, 0);
+            assert.strictEqual(results[4].messages.length, 0);
         });
 
         it("should process when file is given by not specifying extensions", async () => {
@@ -4731,6 +4747,15 @@ describe("ESLint", () => {
                 await engine.loadFormatter(5);
             }, /'name' must be a string/u);
         });
+
+        it("should pass cwd to the `cwd` property of the second argument.", async () => {
+            const cwd = getFixturePath();
+            const engine = new ESLint({ cwd });
+            const formatterPath = getFixturePath("formatters", "cwd.js");
+            const formatter = await engine.loadFormatter(formatterPath);
+
+            assert.strictEqual(formatter.format([]), cwd);
+        });
     });
 
     describe("getErrorResults()", () => {
index 24dc4de43cef81239751894719a7a1a2d73e515f..3343461461013459bc4724dafc25f11895faa5bb 100644 (file)
@@ -16,6 +16,7 @@ const assert = require("chai").assert,
     testParsers = require("../../fixtures/parsers/linter-test-parsers");
 
 const { Linter } = require("../../../lib/linter");
+const { FlatConfigArray } = require("../../../lib/config/flat-config-array");
 
 //------------------------------------------------------------------------------
 // Constants
@@ -95,8 +96,8 @@ describe("Linter", () => {
 
             linter.defineRule("checker", () => ({ Program: spy }));
             linter.verify("foo", { rules: { checker: "error" } });
-            assert(spy.calledOnce);
-            assert.strictEqual(spy.firstCall.thisValue, void 0);
+            assert(spy.calledOnce, "Rule should have been called");
+            assert.strictEqual(spy.firstCall.thisValue, void 0, "this value should be undefined");
         });
 
         it("does not allow listeners to use special EventEmitter values", () => {
@@ -2356,7 +2357,7 @@ describe("Linter", () => {
                 assert.strictEqual(messages[1].ruleId, "no-console");
             });
 
-            it("should not ignore violations if comment is of the type Shebang", () => {
+            it("should not ignore violations if comment is of the type hashbang", () => {
                 const code = [
                     "#! eslint-disable-next-line no-alert",
                     "alert('test');",
@@ -2771,10 +2772,10 @@ var a = "test2";
         });
     });
 
-    describe("when evaluating a file with a shebang", () => {
-        const code = "#!bin/program\n\nvar foo;;";
+    describe("when evaluating a file with a hashbang", () => {
 
         it("should preserve line numbers", () => {
+            const code = "#!bin/program\n\nvar foo;;";
             const config = { rules: { "no-extra-semi": 1 } };
             const messages = linter.verify(code, config);
 
@@ -2784,7 +2785,8 @@ var a = "test2";
             assert.strictEqual(messages[0].line, 3);
         });
 
-        it("should have a comment with the shebang in it", () => {
+        it("should have a comment with the hashbang in it", () => {
+            const code = "#!bin/program\n\nvar foo;;";
             const config = { rules: { checker: "error" } };
             const spy = sinon.spy(context => {
                 const comments = context.getAllComments();
@@ -2798,6 +2800,23 @@ var a = "test2";
             linter.verify(code, config);
             assert(spy.calledOnce);
         });
+
+        it("should comment hashbang without breaking offset", () => {
+            const code = "#!/usr/bin/env node\n'123';";
+            const config = { rules: { checker: "error" } };
+            let spy;
+
+            linter.defineRule("checker", context => {
+                spy = sinon.spy(node => {
+                    assert.strictEqual(context.getSource(node), "'123';");
+                });
+                return { ExpressionStatement: spy };
+            });
+
+            linter.verify(code, config);
+            assert(spy && spy.calledOnce);
+        });
+
     });
 
     describe("when evaluating broken code", () => {
@@ -2835,12 +2854,16 @@ var a = "test2";
         linter = new Linter();
 
         const code = TEST_CODE;
-        const results = linter.verify(code, { rules: { foobar: 2 } });
-        const result = results[0];
-        const warningResult = linter.verify(code, { rules: { foobar: 1 } })[0];
-        const arrayOptionResults = linter.verify(code, { rules: { foobar: [2, "always"] } });
-        const objectOptionResults = linter.verify(code, { rules: { foobar: [1, { bar: false }] } });
-        const resultsMultiple = linter.verify(code, { rules: { foobar: 2, barfoo: 1 } });
+        let results, result, warningResult, arrayOptionResults, objectOptionResults, resultsMultiple;
+
+        beforeEach(() => {
+            results = linter.verify(code, { rules: { foobar: 2 } });
+            result = results[0];
+            warningResult = linter.verify(code, { rules: { foobar: 1 } })[0];
+            arrayOptionResults = linter.verify(code, { rules: { foobar: [2, "always"] } });
+            objectOptionResults = linter.verify(code, { rules: { foobar: [1, { bar: false }] } });
+            resultsMultiple = linter.verify(code, { rules: { foobar: 2, barfoo: 1 } });
+        });
 
         it("should report a problem", () => {
             assert.isNotNull(result);
@@ -2887,9 +2910,10 @@ var a = "test2";
 
     describe("when using a rule which has been replaced", () => {
         const code = TEST_CODE;
-        const results = linter.verify(code, { rules: { "no-comma-dangle": 2 } });
 
         it("should report the new rule", () => {
+            const results = linter.verify(code, { rules: { "no-comma-dangle": 2 } });
+
             assert.strictEqual(results[0].ruleId, "no-comma-dangle");
             assert.strictEqual(results[0].message, "Rule 'no-comma-dangle' was removed and replaced by: comma-dangle");
         });
@@ -4116,7 +4140,7 @@ var a = "test2";
                 assert.strictEqual(messages.length, 0);
             });
 
-            it("the 'latest' is equal to espree.lastEcmaVersion", () => {
+            it("the 'latest' is equal to espree.latestEcmaVersion", () => {
                 let ecmaVersion = null;
                 const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };
 
@@ -4126,7 +4150,62 @@ var a = "test2";
                     }
                 }));
                 linter.verify("", config);
-                assert.strictEqual(ecmaVersion, espree.latestEcmaVersion);
+                assert.strictEqual(ecmaVersion, espree.latestEcmaVersion, "ecmaVersion should be 13");
+            });
+
+            it("the 'latest' is not normalized for custom parsers", () => {
+                let ecmaVersion = null;
+                const config = { rules: { "ecma-version": 2 }, parser: "custom-parser", parserOptions: { ecmaVersion: "latest" } };
+
+                linter.defineParser("custom-parser", testParsers.enhancedParser);
+                linter.defineRule("ecma-version", context => ({
+                    Program() {
+                        ecmaVersion = context.parserOptions.ecmaVersion;
+                    }
+                }));
+                linter.verify("", config);
+                assert.strictEqual(ecmaVersion, "latest", "ecmaVersion should be latest");
+            });
+
+            it("the 'latest' is equal to espree.latestEcmaVersion on languageOptions", () => {
+                let ecmaVersion = null;
+                const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };
+
+                linter.defineRule("ecma-version", context => ({
+                    Program() {
+                        ecmaVersion = context.languageOptions.ecmaVersion;
+                    }
+                }));
+                linter.verify("", config);
+                assert.strictEqual(ecmaVersion, espree.latestEcmaVersion + 2009, "ecmaVersion should be 2022");
+            });
+
+            it("the 'next' is equal to espree.latestEcmaVersion on languageOptions with custom parser", () => {
+                let ecmaVersion = null;
+                const config = { rules: { "ecma-version": 2 }, parser: "custom-parser", parserOptions: { ecmaVersion: "next" } };
+
+                linter.defineParser("custom-parser", testParsers.stubParser);
+                linter.defineRule("ecma-version", context => ({
+                    Program() {
+                        ecmaVersion = context.languageOptions.ecmaVersion;
+                    }
+                }));
+                linter.verify("", config);
+                assert.strictEqual(ecmaVersion, espree.latestEcmaVersion + 2009, "ecmaVersion should be 2022");
+            });
+
+            it("missing ecmaVersion is equal to 5 on languageOptions with custom parser", () => {
+                let ecmaVersion = null;
+                const config = { rules: { "ecma-version": 2 }, parser: "custom-parser" };
+
+                linter.defineParser("custom-parser", testParsers.enhancedParser);
+                linter.defineRule("ecma-version", context => ({
+                    Program() {
+                        ecmaVersion = context.languageOptions.ecmaVersion;
+                    }
+                }));
+                linter.verify("", config);
+                assert.strictEqual(ecmaVersion, 5, "ecmaVersion should be 5");
             });
 
             it("should pass normalized ecmaVersion to eslint-scope", () => {
@@ -4358,6 +4437,82 @@ var a = "test2";
             assert.strictEqual(messages.length, 0);
         });
 
+        it("should not allow the use of reserved words as variable names in ES3", () => {
+            const code = "var char;";
+            const messages = linter.verify(code, { parserOptions: { ecmaVersion: 3 } }, filename);
+
+            assert.strictEqual(messages.length, 1);
+            assert.strictEqual(messages[0].severity, 2);
+            assert.isTrue(messages[0].fatal);
+            assert.match(messages[0].message, /^Parsing error:.*'char'/u);
+        });
+
+        it("should not allow the use of reserved words as property names in member expressions in ES3", () => {
+            const code = "obj.char;";
+            const messages = linter.verify(code, { parserOptions: { ecmaVersion: 3 } }, filename);
+
+            assert.strictEqual(messages.length, 1);
+            assert.strictEqual(messages[0].severity, 2);
+            assert.isTrue(messages[0].fatal);
+            assert.match(messages[0].message, /^Parsing error:.*'char'/u);
+        });
+
+        it("should not allow the use of reserved words as property names in object literals in ES3", () => {
+            const code = "var obj = { char: 1 };";
+            const messages = linter.verify(code, { parserOptions: { ecmaVersion: 3 } }, filename);
+
+            assert.strictEqual(messages.length, 1);
+            assert.strictEqual(messages[0].severity, 2);
+            assert.isTrue(messages[0].fatal);
+            assert.match(messages[0].message, /^Parsing error:.*'char'/u);
+        });
+
+        it("should allow the use of reserved words as variable and property names in ES3 when allowReserved is true", () => {
+            const code = "var char; obj.char; var obj = { char: 1 };";
+            const messages = linter.verify(code, { parserOptions: { ecmaVersion: 3, allowReserved: true } }, filename);
+
+            assert.strictEqual(messages.length, 0);
+        });
+
+        it("should not allow the use of reserved words as variable names in ES > 3", () => {
+            const ecmaVersions = [void 0, ...espree.supportedEcmaVersions.filter(ecmaVersion => ecmaVersion > 3)];
+
+            ecmaVersions.forEach(ecmaVersion => {
+                const code = "var enum;";
+                const messages = linter.verify(code, { parserOptions: { ecmaVersion } }, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].severity, 2);
+                assert.isTrue(messages[0].fatal);
+                assert.match(messages[0].message, /^Parsing error:.*'enum'/u);
+            });
+        });
+
+        it("should allow the use of reserved words as property names in ES > 3", () => {
+            const ecmaVersions = [void 0, ...espree.supportedEcmaVersions.filter(ecmaVersion => ecmaVersion > 3)];
+
+            ecmaVersions.forEach(ecmaVersion => {
+                const code = "obj.enum; obj.function; var obj = { enum: 1, function: 2 };";
+                const messages = linter.verify(code, { parserOptions: { ecmaVersion } }, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+        });
+
+        it("should not allow `allowReserved: true` in ES > 3", () => {
+            const ecmaVersions = [void 0, ...espree.supportedEcmaVersions.filter(ecmaVersion => ecmaVersion > 3)];
+
+            ecmaVersions.forEach(ecmaVersion => {
+                const code = "";
+                const messages = linter.verify(code, { parserOptions: { ecmaVersion, allowReserved: true } }, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].severity, 2);
+                assert.isTrue(messages[0].fatal);
+                assert.match(messages[0].message, /^Parsing error:.*allowReserved/u);
+            });
+        });
+
         it("should be able to use es6 features if there is a comment which has \"eslint-env es6\"", () => {
             const code = [
                 "/* eslint-env es6 */",
@@ -6242,3 +6397,7264 @@ var a = "test2";
         });
     });
 });
+
+describe("Linter with FlatConfigArray", () => {
+
+    let linter;
+    const filename = "filename.js";
+
+    /**
+     * Creates a config array with some default properties.
+     * @param {FlatConfig|FlatConfig[]} value The value to base the
+     *      config array on.
+     * @returns {FlatConfigArray} The created config array.
+     */
+    function createFlatConfigArray(value) {
+        return new FlatConfigArray(value, { basePath: "" });
+    }
+
+    beforeEach(() => {
+        linter = new Linter({ configType: "flat" });
+    });
+
+    describe("Static Members", () => {
+        describe("version", () => {
+            it("should return same version as instance property", () => {
+                assert.strictEqual(Linter.version, linter.version);
+            });
+        });
+    });
+
+    describe("Config Options", () => {
+
+        describe("languageOptions", () => {
+
+            describe("ecmaVersion", () => {
+
+                it("should error when accessing a global that isn't available in ecmaVersion 5", () => {
+                    const messages = linter.verify("new Map()", {
+                        languageOptions: {
+                            ecmaVersion: 5,
+                            sourceType: "script"
+                        },
+                        rules: {
+                            "no-undef": "error"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 1, "There should be one linting error.");
+                    assert.strictEqual(messages[0].ruleId, "no-undef", "The linting error should be no-undef.");
+                });
+
+                it("should error when accessing a global that isn't available in ecmaVersion 3", () => {
+                    const messages = linter.verify("JSON.stringify({})", {
+                        languageOptions: {
+                            ecmaVersion: 3,
+                            sourceType: "script"
+                        },
+                        rules: {
+                            "no-undef": "error"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 1, "There should be one linting error.");
+                    assert.strictEqual(messages[0].ruleId, "no-undef", "The linting error should be no-undef.");
+                });
+
+                it("should add globals for ES6 when ecmaVersion is 6", () => {
+                    const messages = linter.verify("new Map()", {
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: {
+                            "no-undef": "error"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 0, "There should be no linting errors.");
+                });
+
+                it("should allow destructuring when ecmaVersion is 6", () => {
+                    const messages = linter.verify("let {a} = b", {
+                        languageOptions: {
+                            ecmaVersion: 6
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 0, "There should be no linting errors.");
+                });
+
+                it("ecmaVersion should be normalized to year name for ES 6", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker(context) {
+                                        return {
+                                            Program() {
+                                                assert.strictEqual(context.languageOptions.ecmaVersion, 2015);
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("foo", config, filename);
+                });
+
+                it("ecmaVersion should be normalized to latest year by default", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker(context) {
+                                        return {
+                                            Program() {
+                                                assert.strictEqual(context.languageOptions.ecmaVersion, espree.latestEcmaVersion + 2009);
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("foo", config, filename);
+                });
+
+                it("ecmaVersion should not be normalized to year name for ES 5", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker(context) {
+                                        return {
+                                            Program() {
+                                                assert.strictEqual(context.languageOptions.ecmaVersion, 5);
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 5
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("foo", config, filename);
+                });
+
+                it("ecmaVersion should be normalized to year name for 'latest'", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker(context) {
+                                        return {
+                                            Program() {
+                                                assert.strictEqual(context.languageOptions.ecmaVersion, espree.latestEcmaVersion + 2009);
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: "latest"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("foo", config, filename);
+                });
+
+
+            });
+
+            describe("sourceType", () => {
+
+                it("should be module by default", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker(context) {
+                                        return {
+                                            Program() {
+                                                assert.strictEqual(context.languageOptions.sourceType, "module");
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("import foo from 'bar'", config, filename);
+                });
+
+                it("should default to commonjs when passed a .cjs filename", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker(context) {
+                                        return {
+                                            Program() {
+                                                assert.strictEqual(context.languageOptions.sourceType, "commonjs");
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("import foo from 'bar'", config, `${filename}.cjs`);
+                });
+
+
+                it("should error when import is used in a script", () => {
+                    const messages = linter.verify("import foo from 'bar';", {
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "script"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 1, "There should be one parsing error.");
+                    assert.strictEqual(messages[0].message, "Parsing error: 'import' and 'export' may appear only with 'sourceType: module'");
+                });
+
+                it("should not error when import is used in a module", () => {
+                    const messages = linter.verify("import foo from 'bar';", {
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "module"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 0, "There should no linting errors.");
+                });
+
+                it("should error when return is used at the top-level outside of commonjs", () => {
+                    const messages = linter.verify("return", {
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "script"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 1, "There should be one parsing error.");
+                    assert.strictEqual(messages[0].message, "Parsing error: 'return' outside of function");
+                });
+
+                it("should not error when top-level return is used in commonjs", () => {
+                    const messages = linter.verify("return", {
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "commonjs"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 0, "There should no linting errors.");
+                });
+
+                it("should error when accessing a Node.js global outside of commonjs", () => {
+                    const messages = linter.verify("require()", {
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: {
+                            "no-undef": "error"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 1, "There should be one linting error.");
+                    assert.strictEqual(messages[0].ruleId, "no-undef", "The linting error should be no-undef.");
+                });
+
+                it("should add globals for Node.js when sourceType is commonjs", () => {
+                    const messages = linter.verify("require()", {
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "commonjs"
+                        },
+                        rules: {
+                            "no-undef": "error"
+                        }
+                    });
+
+                    assert.strictEqual(messages.length, 0, "There should be no linting errors.");
+                });
+
+                it("should allow 'await' as a property name in modules", () => {
+                    const result = linter.verify(
+                        "obj.await",
+                        {
+                            languageOptions: {
+                                ecmaVersion: 6,
+                                sourceType: "module"
+                            }
+                        }
+                    );
+
+                    assert(result.length === 0);
+                });
+
+            });
+
+            describe("parser", () => {
+
+                it("should be able to define a custom parser", () => {
+                    const parser = {
+                        parseForESLint: function parse(code, options) {
+                            return {
+                                ast: esprima.parse(code, options),
+                                services: {
+                                    test: {
+                                        getMessage() {
+                                            return "Hi!";
+                                        }
+                                    }
+                                }
+                            };
+                        }
+                    };
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                parsers: {
+                                    "test-parser": parser
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parser: "test/test-parser"
+                        }
+                    };
+
+
+                    const messages = linter.verify("0", config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should pass parser as context.languageOptions.parser to all rules when provided on config", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    "test-rule": sinon.mock().withArgs(
+                                        sinon.match({ languageOptions: { parser: esprima } })
+                                    ).returns({})
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parser: esprima
+                        },
+                        rules: {
+                            "test/test-rule": 2
+                        }
+                    };
+
+                    linter.verify("0", config, filename);
+                });
+
+                it("should use parseForESLint() in custom parser when custom parser is specified", () => {
+                    const config = {
+                        plugins: {
+                            test: {
+                                parsers: {
+                                    "enhanced-parser": testParsers.enhancedParser
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parser: "test/enhanced-parser"
+                        }
+                    };
+
+                    const messages = linter.verify("0", config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should expose parser services when using parseForESLint() and services are specified", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                parsers: {
+                                    "enhanced-parser": testParsers.enhancedParser
+                                },
+                                rules: {
+                                    "test-service-rule": context => ({
+                                        Literal(node) {
+                                            context.report({
+                                                node,
+                                                message: context.parserServices.test.getMessage()
+                                            });
+                                        }
+                                    })
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parser: "test/enhanced-parser"
+                        },
+                        rules: {
+                            "test/test-service-rule": 2
+                        }
+                    };
+
+                    const messages = linter.verify("0", config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].message, "Hi!");
+                });
+
+                it("should use the same parserServices if source code object is reused", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                parsers: {
+                                    "enhanced-parser": testParsers.enhancedParser
+                                },
+                                rules: {
+                                    "test-service-rule": context => ({
+                                        Literal(node) {
+                                            context.report({
+                                                node,
+                                                message: context.parserServices.test.getMessage()
+                                            });
+                                        }
+                                    })
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parser: "test/enhanced-parser"
+                        },
+                        rules: {
+                            "test/test-service-rule": 2
+                        }
+                    };
+
+                    const messages = linter.verify("0", config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].message, "Hi!");
+
+                    const messages2 = linter.verify(linter.getSourceCode(), config, filename);
+
+                    assert.strictEqual(messages2.length, 1);
+                    assert.strictEqual(messages2[0].message, "Hi!");
+                });
+
+                it("should pass parser as context.languageOptions.parser to all rules when default parser is used", () => {
+
+                    // references to Espree get messed up in a browser context, so wrap it
+                    const fakeParser = {
+                        parse: espree.parse
+                    };
+
+                    const spy = sinon.spy(context => {
+                        assert.strictEqual(context.languageOptions.parser, fakeParser);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    "test-rule": spy
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parser: fakeParser
+                        },
+                        rules: {
+                            "test/test-rule": 2
+                        }
+                    };
+
+                    linter.verify("0", config, filename);
+                    assert.isTrue(spy.calledOnce);
+                });
+
+
+                describe("Custom Parsers", () => {
+
+                    const errorPrefix = "Parsing error: ";
+
+                    it("should have file path passed to it", () => {
+                        const code = "/* this is code */";
+                        const parseSpy = sinon.spy(testParsers.stubParser, "parse");
+                        const config = {
+                            languageOptions: {
+                                parser: testParsers.stubParser
+                            }
+                        };
+
+                        linter.verify(code, config, filename, true);
+
+                        sinon.assert.calledWithMatch(parseSpy, "", { filePath: filename });
+                    });
+
+                    it("should not report an error when JSX code contains a spread operator and JSX is enabled", () => {
+                        const code = "var myDivElement = <div {...this.props} />;";
+                        const config = {
+                            languageOptions: {
+                                parser: esprima,
+                                parserOptions: {
+                                    jsx: true
+                                }
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should not throw or report errors when the custom parser returns unrecognized operators (https://github.com/eslint/eslint/issues/10475)", () => {
+                        const code = "null %% 'foo'";
+                        const config = {
+                            languageOptions: {
+                                parser: testParsers.unknownLogicalOperator
+                            }
+                        };
+
+                        // This shouldn't throw
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should not throw or report errors when the custom parser returns nested unrecognized operators (https://github.com/eslint/eslint/issues/10560)", () => {
+                        const code = "foo && bar %% baz";
+                        const config = {
+                            languageOptions: {
+                                parser: testParsers.unknownLogicalOperatorNested
+                            }
+                        };
+
+                        // This shouldn't throw
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should not throw or return errors when the custom parser returns unknown AST nodes", () => {
+                        const code = "foo && bar %% baz";
+                        const nodes = [];
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        "collect-node-types": () => ({
+                                            "*"(node) {
+                                                nodes.push(node.type);
+                                            }
+                                        })
+                                    }
+                                }
+                            },
+                            languageOptions: {
+                                parser: testParsers.nonJSParser
+                            },
+                            rules: {
+                                "test/collect-node-types": "error"
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, filename, true);
+
+                        assert.strictEqual(messages.length, 0);
+                        assert.isTrue(nodes.length > 0);
+                    });
+
+                    it("should strip leading line: prefix from parser error", () => {
+                        const messages = linter.verify(";", {
+                            languageOptions: {
+                                parser: testParsers.lineError
+                            }
+                        }, "filename");
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].severity, 2);
+                        assert.strictEqual(messages[0].message, errorPrefix + testParsers.lineError.expectedError);
+                    });
+
+                    it("should not modify a parser error message without a leading line: prefix", () => {
+                        const messages = linter.verify(";", {
+                            languageOptions: {
+                                parser: testParsers.noLineError
+                            }
+                        }, "filename");
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].severity, 2);
+                        assert.strictEqual(messages[0].message, errorPrefix + testParsers.noLineError.expectedError);
+                    });
+
+                    describe("if a parser provides 'visitorKeys'", () => {
+                        let types = [];
+                        let sourceCode;
+                        let scopeManager;
+                        let firstChildNodes = [];
+
+                        beforeEach(() => {
+                            types = [];
+                            firstChildNodes = [];
+                            const config = {
+                                plugins: {
+                                    test: {
+                                        rules: {
+                                            "collect-node-types": () => ({
+                                                "*"(node) {
+                                                    types.push(node.type);
+                                                }
+                                            }),
+                                            "save-scope-manager": context => {
+                                                scopeManager = context.getSourceCode().scopeManager;
+
+                                                return {};
+                                            },
+                                            "esquery-option": () => ({
+                                                ":first-child"(node) {
+                                                    firstChildNodes.push(node);
+                                                }
+                                            })
+                                        }
+                                    }
+                                },
+                                languageOptions: {
+                                    parser: testParsers.enhancedParser2
+                                },
+                                rules: {
+                                    "test/collect-node-types": "error",
+                                    "test/save-scope-manager": "error",
+                                    "test/esquery-option": "error"
+                                }
+                            };
+
+                            linter.verify("@foo class A {}", config);
+
+                            sourceCode = linter.getSourceCode();
+                        });
+
+                        it("Traverser should use the visitorKeys (so 'types' includes 'Decorator')", () => {
+                            assert.deepStrictEqual(
+                                types,
+                                ["Program", "ClassDeclaration", "Decorator", "Identifier", "Identifier", "ClassBody"]
+                            );
+                        });
+
+                        it("eslint-scope should use the visitorKeys (so 'childVisitorKeys.ClassDeclaration' includes 'experimentalDecorators')", () => {
+                            assert.deepStrictEqual(
+                                scopeManager.__options.childVisitorKeys.ClassDeclaration, // eslint-disable-line no-underscore-dangle -- ScopeManager API
+                                ["experimentalDecorators", "id", "superClass", "body"]
+                            );
+                        });
+
+                        it("should use the same visitorKeys if the source code object is reused", () => {
+                            const types2 = [];
+                            const config = {
+                                plugins: {
+                                    test: {
+                                        rules: {
+                                            "collect-node-types": () => ({
+                                                "*"(node) {
+                                                    types2.push(node.type);
+                                                }
+                                            })
+                                        }
+                                    }
+                                },
+                                rules: {
+                                    "test/collect-node-types": "error"
+                                }
+                            };
+
+                            linter.verify(sourceCode, config);
+
+                            assert.deepStrictEqual(
+                                types2,
+                                ["Program", "ClassDeclaration", "Decorator", "Identifier", "Identifier", "ClassBody"]
+                            );
+                        });
+
+                        it("esquery should use the visitorKeys (so 'visitorKeys.ClassDeclaration' includes 'experimentalDecorators')", () => {
+                            assert.deepStrictEqual(
+                                firstChildNodes,
+                                [sourceCode.ast.body[0], sourceCode.ast.body[0].experimentalDecorators[0]]
+                            );
+                        });
+                    });
+
+                    describe("if a parser provides 'scope'", () => {
+                        let scope = null;
+                        let sourceCode = null;
+
+                        beforeEach(() => {
+                            const config = {
+                                plugins: {
+                                    test: {
+                                        rules: {
+                                            "save-scope1": context => ({
+                                                Program() {
+                                                    scope = context.getScope();
+                                                }
+                                            })
+                                        }
+                                    }
+                                },
+                                languageOptions: {
+                                    parser: testParsers.enhancedParser3
+                                },
+                                rules: {
+                                    "test/save-scope1": "error"
+                                }
+                            };
+
+                            linter.verify("@foo class A {}", config);
+
+                            sourceCode = linter.getSourceCode();
+                        });
+
+                        it("should use the scope (so the global scope has the reference of '@foo')", () => {
+                            assert.strictEqual(scope.references.length, 1);
+                            assert.deepStrictEqual(
+                                scope.references[0].identifier.name,
+                                "foo"
+                            );
+                        });
+
+                        it("should use the same scope if the source code object is reused", () => {
+                            let scope2 = null;
+                            const config = {
+                                plugins: {
+                                    test: {
+                                        rules: {
+                                            "save-scope2": context => ({
+                                                Program() {
+                                                    scope2 = context.getScope();
+                                                }
+                                            })
+                                        }
+                                    }
+                                },
+                                rules: {
+                                    "test/save-scope2": "error"
+                                }
+                            };
+
+                            linter.verify(sourceCode, config, "test.js");
+
+                            assert(scope2 !== null);
+                            assert(scope2 === scope);
+                        });
+                    });
+
+                    it("should pass default languageOptions to the parser", () => {
+
+                        const spy = sinon.spy((code, options) => espree.parse(code, options));
+
+                        linter.verify(";", {
+                            languageOptions: {
+                                parser: {
+                                    parse: spy
+                                }
+                            }
+                        }, "filename.js");
+
+                        assert(spy.calledWithMatch(";", {
+                            ecmaVersion: espree.latestEcmaVersion + 2009,
+                            sourceType: "module"
+                        }));
+                    });
+                });
+
+
+            });
+
+            describe("parseOptions", () => {
+
+                it("should pass ecmaFeatures to all rules when provided on config", () => {
+
+                    const parserOptions = {
+                        ecmaFeatures: {
+                            jsx: true
+                        }
+                    };
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    "test-rule": sinon.mock().withArgs(
+                                        sinon.match({ languageOptions: { parserOptions } })
+                                    ).returns({})
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            parserOptions
+                        },
+                        rules: {
+                            "test/test-rule": 2
+                        }
+                    };
+
+                    linter.verify("0", config, filename);
+                });
+
+                it("should switch globalReturn to false if sourceType is module", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    "test-rule": sinon.mock().withArgs(
+                                        sinon.match({
+                                            languageOptions: {
+                                                parserOptions: {
+                                                    ecmaFeatures: {
+                                                        globalReturn: false
+                                                    }
+                                                }
+                                            }
+                                        })
+                                    ).returns({})
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "module",
+                            parserOptions: {
+                                ecmaFeatures: {
+                                    globalReturn: true
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/test-rule": 2
+                        }
+                    };
+
+                    linter.verify("0", config, filename);
+                });
+
+                it("should not parse sloppy-mode code when impliedStrict is true", () => {
+
+                    const messages = linter.verify("var private;", {
+                        languageOptions: {
+                            parserOptions: {
+                                ecmaFeatures: {
+                                    impliedStrict: true
+                                }
+                            }
+                        }
+                    }, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].message, "Parsing error: The keyword 'private' is reserved");
+                });
+
+                it("should properly parse valid code when impliedStrict is true", () => {
+
+                    const messages = linter.verify("var foo;", {
+                        languageOptions: {
+                            parserOptions: {
+                                ecmaFeatures: {
+                                    impliedStrict: true
+                                }
+                            }
+                        }
+                    }, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should properly parse JSX when passed ecmaFeatures", () => {
+
+                    const messages = linter.verify("var x = <div/>;", {
+                        languageOptions: {
+                            parserOptions: {
+                                ecmaFeatures: {
+                                    jsx: true
+                                }
+                            }
+                        }
+                    }, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should report an error when JSX code is encountered and JSX is not enabled", () => {
+                    const code = "var myDivElement = <div className=\"foo\" />;";
+                    const messages = linter.verify(code, {}, "filename");
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].line, 1);
+                    assert.strictEqual(messages[0].column, 20);
+                    assert.strictEqual(messages[0].message, "Parsing error: Unexpected token <");
+                });
+
+                it("should not report an error when JSX code is encountered and JSX is enabled", () => {
+                    const code = "var myDivElement = <div className=\"foo\" />;";
+                    const messages = linter.verify(code, {
+                        languageOptions: {
+                            parserOptions: {
+                                ecmaFeatures: {
+                                    jsx: true
+                                }
+                            }
+                        }
+
+                    }, "filename");
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should not report an error when JSX code contains a spread operator and JSX is enabled", () => {
+                    const code = "var myDivElement = <div {...this.props} />;";
+                    const messages = linter.verify(code, {
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            parserOptions: {
+                                ecmaFeatures: {
+                                    jsx: true
+                                }
+                            }
+                        }
+
+                    }, "filename");
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+            });
+
+        });
+
+        describe("settings", () => {
+            const ruleId = "test-rule";
+
+            it("should pass settings to all rules", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                [ruleId]: context => ({
+                                    Literal(node) {
+                                        context.report(node, context.settings.info);
+                                    }
+                                })
+                            }
+                        }
+                    },
+                    settings: {
+                        info: "Hello"
+                    },
+                    rules: {
+                        [`test/${ruleId}`]: 1
+                    }
+                };
+
+                const messages = linter.verify("0", config, filename);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].message, "Hello");
+            });
+
+            it("should not have any settings if they were not passed in", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                [ruleId]: context => ({
+                                    Literal(node) {
+                                        if (Object.getOwnPropertyNames(context.settings).length !== 0) {
+                                            context.report(node, "Settings should be empty");
+                                        }
+                                    }
+                                })
+                            }
+                        }
+                    },
+                    settings: {
+                    },
+                    rules: {
+                        [`test/${ruleId}`]: 1
+                    }
+                };
+
+                const messages = linter.verify("0", config, filename);
+
+                assert.strictEqual(messages.length, 0);
+            });
+        });
+
+        describe("rules", () => {
+            const code = "var answer = 6 * 7";
+
+            it("should be configurable by only setting the integer value", () => {
+                const rule = "semi",
+                    config = { rules: {} };
+
+                config.rules[rule] = 1;
+
+                const messages = linter.verify(code, config, filename, true);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, rule);
+            });
+
+            it("should be configurable by only setting the string value", () => {
+                const rule = "semi",
+                    config = { rules: {} };
+
+                config.rules[rule] = "warn";
+
+                const messages = linter.verify(code, config, filename, true);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].severity, 1);
+                assert.strictEqual(messages[0].ruleId, rule);
+            });
+
+            it("should be configurable by passing in values as an array", () => {
+                const rule = "semi",
+                    config = { rules: {} };
+
+                config.rules[rule] = [1];
+
+                const messages = linter.verify(code, config, filename, true);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, rule);
+            });
+
+            it("should be configurable by passing in string value as an array", () => {
+                const rule = "semi",
+                    config = { rules: {} };
+
+                config.rules[rule] = ["warn"];
+
+                const messages = linter.verify(code, config, filename, true);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].severity, 1);
+                assert.strictEqual(messages[0].ruleId, rule);
+            });
+
+            it("should not be configurable by setting other value", () => {
+                const rule = "semi",
+                    config = { rules: {} };
+
+                config.rules[rule] = "1";
+
+                assert.throws(() => {
+                    linter.verify(code, config, filename, true);
+                }, /Key "rules": Key "semi"/u);
+            });
+
+            it("should process empty config", () => {
+                const config = {};
+                const messages = linter.verify(code, config, filename, true);
+
+                assert.strictEqual(messages.length, 0);
+            });
+        });
+
+    });
+
+    describe("verify()", () => {
+
+        it("should report warnings in order by line and column when called", () => {
+
+            const code = "foo()\n    alert('test')";
+            const config = { rules: { "no-mixed-spaces-and-tabs": 1, "eol-last": 1, semi: [1, "always"] } };
+
+            const messages = linter.verify(code, config, filename);
+
+            assert.strictEqual(messages.length, 3);
+            assert.strictEqual(messages[0].line, 1);
+            assert.strictEqual(messages[0].column, 6);
+            assert.strictEqual(messages[1].line, 2);
+            assert.strictEqual(messages[1].column, 18);
+            assert.strictEqual(messages[2].line, 2);
+            assert.strictEqual(messages[2].column, 18);
+        });
+
+        describe("Plugins", () => {
+
+            it("should not load rule definition when rule isn't used", () => {
+
+                const spy = sinon.spy();
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: spy
+                            }
+                        }
+                    }
+                };
+
+                linter.verify("code", config, filename);
+                assert.isTrue(spy.notCalled, "Rule should not have been called");
+            });
+        });
+
+        describe("Rule Internals", () => {
+
+            const code = TEST_CODE;
+
+            it("should throw an error when an error occurs inside of a rule visitor", () => {
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: () => ({
+                                    Program() {
+                                        throw new Error("Intentional error.");
+                                    }
+                                })
+                            }
+                        }
+                    },
+                    rules: { "test/checker": "error" }
+                };
+
+                assert.throws(() => {
+                    linter.verify(code, config, filename);
+                }, `Intentional error.\nOccurred while linting ${filename}:1\nRule: "test/checker"`);
+            });
+
+            it("should not call rule visitor with a `this` value", () => {
+                const spy = sinon.spy();
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: () => ({
+                                    Program: spy
+                                })
+                            }
+                        }
+                    },
+                    rules: { "test/checker": "error" }
+                };
+
+                linter.verify("foo", config);
+                assert(spy.calledOnce);
+                assert.strictEqual(spy.firstCall.thisValue, void 0);
+            });
+
+            it("should not call unrecognized rule visitor when present in a rule", () => {
+                const spy = sinon.spy();
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: () => ({
+                                    newListener: spy
+                                })
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/checker": "error",
+                        "no-undef": "error"
+                    }
+                };
+
+                linter.verify("foo", config);
+                assert(spy.notCalled);
+            });
+
+            it("should have all the `parent` properties on nodes when the rule visitors are created", () => {
+                const spy = sinon.spy(context => {
+                    const ast = context.getSourceCode().ast;
+
+                    assert.strictEqual(ast.body[0].parent, ast);
+                    assert.strictEqual(ast.body[0].expression.parent, ast.body[0]);
+                    assert.strictEqual(ast.body[0].expression.left.parent, ast.body[0].expression);
+                    assert.strictEqual(ast.body[0].expression.right.parent, ast.body[0].expression);
+
+                    return {};
+                });
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: spy
+                            }
+                        }
+                    },
+                    rules: { "test/checker": "error" }
+                };
+
+                linter.verify("foo + bar", config);
+                assert(spy.calledOnce);
+            });
+
+            it("events for each node type should fire", () => {
+
+                // spies for various AST node types
+                const spyLiteral = sinon.spy(),
+                    spyVariableDeclarator = sinon.spy(),
+                    spyVariableDeclaration = sinon.spy(),
+                    spyIdentifier = sinon.spy(),
+                    spyBinaryExpression = sinon.spy();
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker() {
+                                    return {
+                                        Literal: spyLiteral,
+                                        VariableDeclarator: spyVariableDeclarator,
+                                        VariableDeclaration: spyVariableDeclaration,
+                                        Identifier: spyIdentifier,
+                                        BinaryExpression: spyBinaryExpression
+                                    };
+                                }
+                            }
+                        }
+                    },
+                    rules: { "test/checker": "error" }
+                };
+
+                const messages = linter.verify(code, config, filename, true);
+
+                assert.strictEqual(messages.length, 0);
+                sinon.assert.calledOnce(spyVariableDeclaration);
+                sinon.assert.calledOnce(spyVariableDeclarator);
+                sinon.assert.calledOnce(spyIdentifier);
+                sinon.assert.calledTwice(spyLiteral);
+                sinon.assert.calledOnce(spyBinaryExpression);
+            });
+
+            it("should throw an error if a rule reports a problem without a message", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                "invalid-report"(context) {
+                                    return {
+                                        Program(node) {
+                                            context.report({ node });
+                                        }
+                                    };
+                                }
+                            }
+                        }
+                    },
+                    rules: { "test/invalid-report": "error" }
+                };
+
+                assert.throws(
+                    () => linter.verify("foo", config),
+                    TypeError,
+                    "Missing `message` property in report() call; add a message that describes the linting problem."
+                );
+            });
+
+
+        });
+
+        describe("Rule Context", () => {
+
+            describe("context.getFilename()", () => {
+                const ruleId = "filename-rule";
+
+                it("has access to the filename", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    [ruleId]: context => ({
+                                        Literal(node) {
+                                            context.report(node, context.getFilename());
+                                        }
+                                    })
+                                }
+                            }
+                        },
+                        rules: {
+                            [`test/${ruleId}`]: 1
+                        }
+                    };
+
+                    const messages = linter.verify("0", config, filename);
+
+                    assert.strictEqual(messages[0].message, filename);
+                });
+
+                it("defaults filename to '<input>'", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    [ruleId]: context => ({
+                                        Literal(node) {
+                                            context.report(node, context.getFilename());
+                                        }
+                                    })
+                                }
+                            }
+                        },
+                        rules: {
+                            [`test/${ruleId}`]: 1
+                        }
+                    };
+
+
+                    const messages = linter.verify("0", config);
+
+                    assert.strictEqual(messages[0].message, "<input>");
+                });
+            });
+
+            describe("context.getPhysicalFilename()", () => {
+
+                const ruleId = "filename-rule";
+
+                it("has access to the physicalFilename", () => {
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    [ruleId]: context => ({
+                                        Literal(node) {
+                                            context.report(node, context.getPhysicalFilename());
+                                        }
+                                    })
+                                }
+                            }
+                        },
+                        rules: {
+                            [`test/${ruleId}`]: 1
+                        }
+                    };
+
+                    const messages = linter.verify("0", config, filename);
+
+                    assert.strictEqual(messages[0].message, filename);
+                });
+
+            });
+
+            describe("context.getSourceLines()", () => {
+
+                it("should get proper lines when using \\n as a line break", () => {
+                    const code = "a;\nb;";
+                    const spy = sinon.spy(context => {
+                        assert.deepStrictEqual(context.getSourceLines(), ["a;", "b;"]);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should get proper lines when using \\r\\n as a line break", () => {
+                    const code = "a;\r\nb;";
+                    const spy = sinon.spy(context => {
+                        assert.deepStrictEqual(context.getSourceLines(), ["a;", "b;"]);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should get proper lines when using \\r as a line break", () => {
+                    const code = "a;\rb;";
+                    const spy = sinon.spy(context => {
+                        assert.deepStrictEqual(context.getSourceLines(), ["a;", "b;"]);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should get proper lines when using \\u2028 as a line break", () => {
+                    const code = "a;\u2028b;";
+                    const spy = sinon.spy(context => {
+                        assert.deepStrictEqual(context.getSourceLines(), ["a;", "b;"]);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should get proper lines when using \\u2029 as a line break", () => {
+                    const code = "a;\u2029b;";
+                    const spy = sinon.spy(context => {
+                        assert.deepStrictEqual(context.getSourceLines(), ["a;", "b;"]);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+            });
+
+            describe("context.getSource()", () => {
+                const code = TEST_CODE;
+
+                it("should retrieve all text when used without parameters", () => {
+
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            assert.strictEqual(context.getSource(), TEST_CODE);
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve all text for root node", () => {
+
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(node => {
+                                            assert.strictEqual(context.getSource(node), TEST_CODE);
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should clamp to valid range when retrieving characters before start of source", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(node => {
+                                            assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve all text for binary expression", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(node => {
+                                            assert.strictEqual(context.getSource(node), "6 * 7");
+                                        });
+                                        return { BinaryExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve all text plus two characters before for binary expression", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(node => {
+                                            assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
+                                        });
+                                        return { BinaryExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve all text plus one character after for binary expression", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(node => {
+                                            assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
+                                        });
+                                        return { BinaryExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve all text plus two characters before and one character after for binary expression", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(node => {
+                                            assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
+                                        });
+                                        return { BinaryExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+            });
+
+            describe("context.getAncestors()", () => {
+                const code = TEST_CODE;
+
+                it("should retrieve all ancestors when used", () => {
+
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const ancestors = context.getAncestors();
+
+                                            assert.strictEqual(ancestors.length, 3);
+                                        });
+                                        return { BinaryExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config, filename, true);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve empty ancestors for root node", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const ancestors = context.getAncestors();
+
+                                            assert.strictEqual(ancestors.length, 0);
+                                        });
+
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+            });
+
+            describe("context.getNodeByRangeIndex()", () => {
+                const code = TEST_CODE;
+
+                it("should retrieve a node starting at the given index", () => {
+                    const spy = sinon.spy(context => {
+                        assert.strictEqual(context.getNodeByRangeIndex(4).type, "Identifier");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should retrieve a node containing the given index", () => {
+                    const spy = sinon.spy(context => {
+                        assert.strictEqual(context.getNodeByRangeIndex(6).type, "Identifier");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should retrieve a node that is exactly the given index", () => {
+                    const spy = sinon.spy(context => {
+                        const node = context.getNodeByRangeIndex(13);
+
+                        assert.strictEqual(node.type, "Literal");
+                        assert.strictEqual(node.value, 6);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should retrieve a node ending with the given index", () => {
+                    const spy = sinon.spy(context => {
+                        assert.strictEqual(context.getNodeByRangeIndex(9).type, "Identifier");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should retrieve the deepest node containing the given index", () => {
+                    const spy = sinon.spy(context => {
+                        const node1 = context.getNodeByRangeIndex(14);
+
+                        assert.strictEqual(node1.type, "BinaryExpression");
+
+                        const node2 = context.getNodeByRangeIndex(3);
+
+                        assert.strictEqual(node2.type, "VariableDeclaration");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+
+                it("should return null if the index is outside the range of any node", () => {
+                    const spy = sinon.spy(context => {
+                        const node1 = context.getNodeByRangeIndex(-1);
+
+                        assert.isNull(node1);
+
+                        const node2 = context.getNodeByRangeIndex(-99);
+
+                        assert.isNull(node2);
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: spy
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy.calledOnce);
+                });
+            });
+
+            describe("context.getScope()", () => {
+                const codeToTestScope = "function foo() { q: for(;;) { break q; } } function bar () { var q = t; } var baz = (() => { return 1; });";
+
+                it("should retrieve the global scope correctly from a Program", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "global");
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(codeToTestScope, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from a FunctionDeclaration", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "function");
+                                        });
+                                        return { FunctionDeclaration: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(codeToTestScope, config);
+                    assert(spy && spy.calledTwice);
+                });
+
+                it("should retrieve the function scope correctly from a LabeledStatement", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "function");
+                                            assert.strictEqual(scope.block.id.name, "foo");
+                                        });
+                                        return { LabeledStatement: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify(codeToTestScope, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from within an ArrowFunctionExpression", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "function");
+                                            assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
+                                        });
+
+                                        return { ReturnStatement: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify(codeToTestScope, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from within an SwitchStatement", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "switch");
+                                            assert.strictEqual(scope.block.type, "SwitchStatement");
+                                        });
+
+                                        return { SwitchStatement: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("switch(foo){ case 'a': var b = 'foo'; }", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from within a BlockStatement", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "block");
+                                            assert.strictEqual(scope.block.type, "BlockStatement");
+                                        });
+
+                                        return { BlockStatement: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify("var x; {let y = 1}", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from within a nested block statement", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "block");
+                                            assert.strictEqual(scope.block.type, "BlockStatement");
+                                        });
+
+                                        return { BlockStatement: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify("if (true) { let x = 1 }", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from within a FunctionDeclaration", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "function");
+                                            assert.strictEqual(scope.block.type, "FunctionDeclaration");
+                                        });
+
+                                        return { FunctionDeclaration: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify("function foo() {}", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the function scope correctly from within a FunctionExpression", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "function");
+                                            assert.strictEqual(scope.block.type, "FunctionExpression");
+                                        });
+
+                                        return { FunctionExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify("(function foo() {})();", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve the catch scope correctly from within a CatchClause", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "catch");
+                                            assert.strictEqual(scope.block.type, "CatchClause");
+                                        });
+
+                                        return { CatchClause: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("try {} catch (err) {}", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve module scope correctly from an ES6 module", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "module");
+                                        });
+
+                                        return { AssignmentExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "module"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+
+                    linter.verify("var foo = {}; foo.bar = 1;", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should retrieve function scope correctly when sourceType is commonjs", () => {
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.strictEqual(scope.type, "function");
+                                        });
+
+                                        return { AssignmentExpression: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "commonjs"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify("var foo = {}; foo.bar = 1;", config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                describe("Scope Internals", () => {
+
+                    /**
+                     * Get the scope on the node `astSelector` specified.
+                     * @param {string} codeToEvaluate The source code to verify.
+                     * @param {string} astSelector The AST selector to get scope.
+                     * @param {number} [ecmaVersion=5] The ECMAScript version.
+                     * @returns {{node: ASTNode, scope: escope.Scope}} Gotten scope.
+                     */
+                    function getScope(codeToEvaluate, astSelector, ecmaVersion = 5) {
+                        let node, scope;
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        "get-scope": context => ({
+                                            [astSelector](node0) {
+                                                node = node0;
+                                                scope = context.getScope();
+                                            }
+                                        })
+                                    }
+                                }
+                            },
+                            languageOptions: {
+                                ecmaVersion,
+                                sourceType: "script"
+                            },
+                            rules: { "test/get-scope": "error" }
+                        };
+
+                        linter.verify(
+                            codeToEvaluate,
+                            config
+                        );
+
+                        return { node, scope };
+                    }
+
+                    it("should return 'function' scope on FunctionDeclaration (ES5)", () => {
+                        const { node, scope } = getScope("function f() {}", "FunctionDeclaration");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node);
+                    });
+
+                    it("should return 'function' scope on FunctionExpression (ES5)", () => {
+                        const { node, scope } = getScope("!function f() {}", "FunctionExpression");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node);
+                    });
+
+                    it("should return 'function' scope on the body of FunctionDeclaration (ES5)", () => {
+                        const { node, scope } = getScope("function f() {}", "BlockStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent);
+                    });
+
+                    it("should return 'function' scope on the body of FunctionDeclaration (ES2015)", () => {
+                        const { node, scope } = getScope("function f() {}", "BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent);
+                    });
+
+                    it("should return 'function' scope on BlockStatement in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { { var b; } }", "BlockStatement > BlockStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "b"]);
+                    });
+
+                    it("should return 'block' scope on BlockStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { { let a; var b; } }", "BlockStatement > BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.upper.type, "function");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["a"]);
+                        assert.deepStrictEqual(scope.variableScope.variables.map(v => v.name), ["arguments", "b"]);
+                    });
+
+                    it("should return 'block' scope on nested BlockStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { { let a; { let b; var c; } } }", "BlockStatement > BlockStatement > BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.upper.type, "block");
+                        assert.strictEqual(scope.upper.upper.type, "function");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["b"]);
+                        assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["a"]);
+                        assert.deepStrictEqual(scope.variableScope.variables.map(v => v.name), ["arguments", "c"]);
+                    });
+
+                    it("should return 'function' scope on SwitchStatement in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { switch (a) { case 0: var b; } }", "SwitchStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "b"]);
+                    });
+
+                    it("should return 'switch' scope on SwitchStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { switch (a) { case 0: let b; } }", "SwitchStatement", 2015);
+
+                        assert.strictEqual(scope.type, "switch");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["b"]);
+                    });
+
+                    it("should return 'function' scope on SwitchCase in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { switch (a) { case 0: var b; } }", "SwitchCase");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "b"]);
+                    });
+
+                    it("should return 'switch' scope on SwitchCase in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { switch (a) { case 0: let b; } }", "SwitchCase", 2015);
+
+                        assert.strictEqual(scope.type, "switch");
+                        assert.strictEqual(scope.block, node.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["b"]);
+                    });
+
+                    it("should return 'catch' scope on CatchClause in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { try {} catch (e) { var a; } }", "CatchClause");
+
+                        assert.strictEqual(scope.type, "catch");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["e"]);
+                    });
+
+                    it("should return 'catch' scope on CatchClause in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { try {} catch (e) { let a; } }", "CatchClause", 2015);
+
+                        assert.strictEqual(scope.type, "catch");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["e"]);
+                    });
+
+                    it("should return 'catch' scope on the block of CatchClause in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { try {} catch (e) { var a; } }", "CatchClause > BlockStatement");
+
+                        assert.strictEqual(scope.type, "catch");
+                        assert.strictEqual(scope.block, node.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["e"]);
+                    });
+
+                    it("should return 'block' scope on the block of CatchClause in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { try {} catch (e) { let a; } }", "CatchClause > BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["a"]);
+                    });
+
+                    it("should return 'function' scope on ForStatement in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { for (var i = 0; i < 10; ++i) {} }", "ForStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "i"]);
+                    });
+
+                    it("should return 'for' scope on ForStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { for (let i = 0; i < 10; ++i) {} }", "ForStatement", 2015);
+
+                        assert.strictEqual(scope.type, "for");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["i"]);
+                    });
+
+                    it("should return 'function' scope on the block body of ForStatement in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { for (var i = 0; i < 10; ++i) {} }", "ForStatement > BlockStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "i"]);
+                    });
+
+                    it("should return 'block' scope on the block body of ForStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { for (let i = 0; i < 10; ++i) {} }", "ForStatement > BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.upper.type, "for");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), []);
+                        assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["i"]);
+                    });
+
+                    it("should return 'function' scope on ForInStatement in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { for (var key in obj) {} }", "ForInStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "key"]);
+                    });
+
+                    it("should return 'for' scope on ForInStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { for (let key in obj) {} }", "ForInStatement", 2015);
+
+                        assert.strictEqual(scope.type, "for");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["key"]);
+                    });
+
+                    it("should return 'function' scope on the block body of ForInStatement in functions (ES5)", () => {
+                        const { node, scope } = getScope("function f() { for (var key in obj) {} }", "ForInStatement > BlockStatement");
+
+                        assert.strictEqual(scope.type, "function");
+                        assert.strictEqual(scope.block, node.parent.parent.parent);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["arguments", "key"]);
+                    });
+
+                    it("should return 'block' scope on the block body of ForInStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { for (let key in obj) {} }", "ForInStatement > BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.upper.type, "for");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), []);
+                        assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["key"]);
+                    });
+
+                    it("should return 'for' scope on ForOfStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { for (let x of xs) {} }", "ForOfStatement", 2015);
+
+                        assert.strictEqual(scope.type, "for");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), ["x"]);
+                    });
+
+                    it("should return 'block' scope on the block body of ForOfStatement in functions (ES2015)", () => {
+                        const { node, scope } = getScope("function f() { for (let x of xs) {} }", "ForOfStatement > BlockStatement", 2015);
+
+                        assert.strictEqual(scope.type, "block");
+                        assert.strictEqual(scope.upper.type, "for");
+                        assert.strictEqual(scope.block, node);
+                        assert.deepStrictEqual(scope.variables.map(v => v.name), []);
+                        assert.deepStrictEqual(scope.upper.variables.map(v => v.name), ["x"]);
+                    });
+
+                    it("should shadow the same name variable by the iteration variable.", () => {
+                        const { node, scope } = getScope("let x; for (let x of x) {}", "ForOfStatement", 2015);
+
+                        assert.strictEqual(scope.type, "for");
+                        assert.strictEqual(scope.upper.type, "global");
+                        assert.strictEqual(scope.block, node);
+                        assert.strictEqual(scope.upper.variables[0].references.length, 0);
+                        assert.strictEqual(scope.references[0].identifier, node.left.declarations[0].id);
+                        assert.strictEqual(scope.references[1].identifier, node.right);
+                        assert.strictEqual(scope.references[1].resolved, scope.variables[0]);
+                    });
+                });
+
+                describe("Variables and references", () => {
+                    const code = [
+                        "a;",
+                        "function foo() { b; }",
+                        "Object;",
+                        "foo;",
+                        "var c;",
+                        "c;",
+                        "/* global d */",
+                        "d;",
+                        "e;",
+                        "f;"
+                    ].join("\n");
+                    let scope = null;
+
+                    beforeEach(() => {
+                        let ok = false;
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        test(context) {
+                                            return {
+                                                Program() {
+                                                    scope = context.getScope();
+                                                    ok = true;
+                                                }
+                                            };
+                                        }
+                                    }
+                                }
+                            },
+                            languageOptions: {
+                                globals: { e: true, f: false },
+                                sourceType: "script",
+                                ecmaVersion: 5
+                            },
+                            rules: {
+                                "test/test": 2
+                            }
+                        };
+
+                        linter.verify(code, config);
+                        assert(ok);
+                    });
+
+                    afterEach(() => {
+                        scope = null;
+                    });
+
+                    it("Scope#through should contain references of undefined variables", () => {
+                        assert.strictEqual(scope.through.length, 2);
+                        assert.strictEqual(scope.through[0].identifier.name, "a");
+                        assert.strictEqual(scope.through[0].identifier.loc.start.line, 1);
+                        assert.strictEqual(scope.through[0].resolved, null);
+                        assert.strictEqual(scope.through[1].identifier.name, "b");
+                        assert.strictEqual(scope.through[1].identifier.loc.start.line, 2);
+                        assert.strictEqual(scope.through[1].resolved, null);
+                    });
+
+                    it("Scope#variables should contain global variables", () => {
+                        assert(scope.variables.some(v => v.name === "Object"));
+                        assert(scope.variables.some(v => v.name === "foo"));
+                        assert(scope.variables.some(v => v.name === "c"));
+                        assert(scope.variables.some(v => v.name === "d"));
+                        assert(scope.variables.some(v => v.name === "e"));
+                        assert(scope.variables.some(v => v.name === "f"));
+                    });
+
+                    it("Scope#set should contain global variables", () => {
+                        assert(scope.set.get("Object"));
+                        assert(scope.set.get("foo"));
+                        assert(scope.set.get("c"));
+                        assert(scope.set.get("d"));
+                        assert(scope.set.get("e"));
+                        assert(scope.set.get("f"));
+                    });
+
+                    it("Variables#references should contain their references", () => {
+                        assert.strictEqual(scope.set.get("Object").references.length, 1);
+                        assert.strictEqual(scope.set.get("Object").references[0].identifier.name, "Object");
+                        assert.strictEqual(scope.set.get("Object").references[0].identifier.loc.start.line, 3);
+                        assert.strictEqual(scope.set.get("Object").references[0].resolved, scope.set.get("Object"));
+                        assert.strictEqual(scope.set.get("foo").references.length, 1);
+                        assert.strictEqual(scope.set.get("foo").references[0].identifier.name, "foo");
+                        assert.strictEqual(scope.set.get("foo").references[0].identifier.loc.start.line, 4);
+                        assert.strictEqual(scope.set.get("foo").references[0].resolved, scope.set.get("foo"));
+                        assert.strictEqual(scope.set.get("c").references.length, 1);
+                        assert.strictEqual(scope.set.get("c").references[0].identifier.name, "c");
+                        assert.strictEqual(scope.set.get("c").references[0].identifier.loc.start.line, 6);
+                        assert.strictEqual(scope.set.get("c").references[0].resolved, scope.set.get("c"));
+                        assert.strictEqual(scope.set.get("d").references.length, 1);
+                        assert.strictEqual(scope.set.get("d").references[0].identifier.name, "d");
+                        assert.strictEqual(scope.set.get("d").references[0].identifier.loc.start.line, 8);
+                        assert.strictEqual(scope.set.get("d").references[0].resolved, scope.set.get("d"));
+                        assert.strictEqual(scope.set.get("e").references.length, 1);
+                        assert.strictEqual(scope.set.get("e").references[0].identifier.name, "e");
+                        assert.strictEqual(scope.set.get("e").references[0].identifier.loc.start.line, 9);
+                        assert.strictEqual(scope.set.get("e").references[0].resolved, scope.set.get("e"));
+                        assert.strictEqual(scope.set.get("f").references.length, 1);
+                        assert.strictEqual(scope.set.get("f").references[0].identifier.name, "f");
+                        assert.strictEqual(scope.set.get("f").references[0].identifier.loc.start.line, 10);
+                        assert.strictEqual(scope.set.get("f").references[0].resolved, scope.set.get("f"));
+                    });
+
+                    it("Reference#resolved should be their variable", () => {
+                        assert.strictEqual(scope.set.get("Object").references[0].resolved, scope.set.get("Object"));
+                        assert.strictEqual(scope.set.get("foo").references[0].resolved, scope.set.get("foo"));
+                        assert.strictEqual(scope.set.get("c").references[0].resolved, scope.set.get("c"));
+                        assert.strictEqual(scope.set.get("d").references[0].resolved, scope.set.get("d"));
+                        assert.strictEqual(scope.set.get("e").references[0].resolved, scope.set.get("e"));
+                        assert.strictEqual(scope.set.get("f").references[0].resolved, scope.set.get("f"));
+                    });
+                });
+            });
+
+            describe("context.getDeclaredVariables(node)", () => {
+
+                /**
+                 * Assert `context.getDeclaredVariables(node)` is valid.
+                 * @param {string} code A code to check.
+                 * @param {string} type A type string of ASTNode. This method checks variables on the node of the type.
+                 * @param {Array<Array<string>>} expectedNamesList An array of expected variable names. The expected variable names is an array of string.
+                 * @returns {void}
+                 */
+                function verify(code, type, expectedNamesList) {
+                    const config = {
+                        plugins: {
+                            test: {
+
+                                rules: {
+                                    test(context) {
+
+                                        /**
+                                         * Assert `context.getDeclaredVariables(node)` is empty.
+                                         * @param {ASTNode} node A node to check.
+                                         * @returns {void}
+                                         */
+                                        function checkEmpty(node) {
+                                            assert.strictEqual(0, context.getDeclaredVariables(node).length);
+                                        }
+                                        const rule = {
+                                            Program: checkEmpty,
+                                            EmptyStatement: checkEmpty,
+                                            BlockStatement: checkEmpty,
+                                            ExpressionStatement: checkEmpty,
+                                            LabeledStatement: checkEmpty,
+                                            BreakStatement: checkEmpty,
+                                            ContinueStatement: checkEmpty,
+                                            WithStatement: checkEmpty,
+                                            SwitchStatement: checkEmpty,
+                                            ReturnStatement: checkEmpty,
+                                            ThrowStatement: checkEmpty,
+                                            TryStatement: checkEmpty,
+                                            WhileStatement: checkEmpty,
+                                            DoWhileStatement: checkEmpty,
+                                            ForStatement: checkEmpty,
+                                            ForInStatement: checkEmpty,
+                                            DebuggerStatement: checkEmpty,
+                                            ThisExpression: checkEmpty,
+                                            ArrayExpression: checkEmpty,
+                                            ObjectExpression: checkEmpty,
+                                            Property: checkEmpty,
+                                            SequenceExpression: checkEmpty,
+                                            UnaryExpression: checkEmpty,
+                                            BinaryExpression: checkEmpty,
+                                            AssignmentExpression: checkEmpty,
+                                            UpdateExpression: checkEmpty,
+                                            LogicalExpression: checkEmpty,
+                                            ConditionalExpression: checkEmpty,
+                                            CallExpression: checkEmpty,
+                                            NewExpression: checkEmpty,
+                                            MemberExpression: checkEmpty,
+                                            SwitchCase: checkEmpty,
+                                            Identifier: checkEmpty,
+                                            Literal: checkEmpty,
+                                            ForOfStatement: checkEmpty,
+                                            ArrowFunctionExpression: checkEmpty,
+                                            YieldExpression: checkEmpty,
+                                            TemplateLiteral: checkEmpty,
+                                            TaggedTemplateExpression: checkEmpty,
+                                            TemplateElement: checkEmpty,
+                                            ObjectPattern: checkEmpty,
+                                            ArrayPattern: checkEmpty,
+                                            RestElement: checkEmpty,
+                                            AssignmentPattern: checkEmpty,
+                                            ClassBody: checkEmpty,
+                                            MethodDefinition: checkEmpty,
+                                            MetaProperty: checkEmpty
+                                        };
+
+                                        rule[type] = function(node) {
+                                            const expectedNames = expectedNamesList.shift();
+                                            const variables = context.getDeclaredVariables(node);
+
+                                            assert(Array.isArray(expectedNames));
+                                            assert(Array.isArray(variables));
+                                            assert.strictEqual(expectedNames.length, variables.length);
+                                            for (let i = variables.length - 1; i >= 0; i--) {
+                                                assert.strictEqual(expectedNames[i], variables[i].name);
+                                            }
+                                        };
+                                        return rule;
+                                    }
+                                }
+
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "module"
+                        },
+                        rules: {
+                            "test/test": 2
+                        }
+                    };
+
+                    linter.verify(code, config);
+
+                    // Check all expected names are asserted.
+                    assert.strictEqual(0, expectedNamesList.length);
+                }
+
+                it("VariableDeclaration", () => {
+                    const code = "\n var {a, x: [b], y: {c = 0}} = foo;\n let {d, x: [e], y: {f = 0}} = foo;\n const {g, x: [h], y: {i = 0}} = foo, {j, k = function(z) { let l; }} = bar;\n ";
+                    const namesList = [
+                        ["a", "b", "c"],
+                        ["d", "e", "f"],
+                        ["g", "h", "i", "j", "k"],
+                        ["l"]
+                    ];
+
+                    verify(code, "VariableDeclaration", namesList);
+                });
+
+                it("VariableDeclaration (on for-in/of loop)", () => {
+
+                    // TDZ scope is created here, so tests to exclude those.
+                    const code = "\n for (var {a, x: [b], y: {c = 0}} in foo) {\n let g;\n }\n for (let {d, x: [e], y: {f = 0}} of foo) {\n let h;\n }\n ";
+                    const namesList = [
+                        ["a", "b", "c"],
+                        ["g"],
+                        ["d", "e", "f"],
+                        ["h"]
+                    ];
+
+                    verify(code, "VariableDeclaration", namesList);
+                });
+
+                it("VariableDeclarator", () => {
+
+                    // TDZ scope is created here, so tests to exclude those.
+                    const code = "\n var {a, x: [b], y: {c = 0}} = foo;\n let {d, x: [e], y: {f = 0}} = foo;\n const {g, x: [h], y: {i = 0}} = foo, {j, k = function(z) { let l; }} = bar;\n ";
+                    const namesList = [
+                        ["a", "b", "c"],
+                        ["d", "e", "f"],
+                        ["g", "h", "i"],
+                        ["j", "k"],
+                        ["l"]
+                    ];
+
+                    verify(code, "VariableDeclarator", namesList);
+                });
+
+                it("FunctionDeclaration", () => {
+                    const code = "\n function foo({a, x: [b], y: {c = 0}}, [d, e]) {\n let z;\n }\n function bar({f, x: [g], y: {h = 0}}, [i, j = function(q) { let w; }]) {\n let z;\n }\n ";
+                    const namesList = [
+                        ["foo", "a", "b", "c", "d", "e"],
+                        ["bar", "f", "g", "h", "i", "j"]
+                    ];
+
+                    verify(code, "FunctionDeclaration", namesList);
+                });
+
+                it("FunctionExpression", () => {
+                    const code = "\n (function foo({a, x: [b], y: {c = 0}}, [d, e]) {\n let z;\n });\n (function bar({f, x: [g], y: {h = 0}}, [i, j = function(q) { let w; }]) {\n let z;\n });\n ";
+                    const namesList = [
+                        ["foo", "a", "b", "c", "d", "e"],
+                        ["bar", "f", "g", "h", "i", "j"],
+                        ["q"]
+                    ];
+
+                    verify(code, "FunctionExpression", namesList);
+                });
+
+                it("ArrowFunctionExpression", () => {
+                    const code = "\n (({a, x: [b], y: {c = 0}}, [d, e]) => {\n let z;\n });\n (({f, x: [g], y: {h = 0}}, [i, j]) => {\n let z;\n });\n ";
+                    const namesList = [
+                        ["a", "b", "c", "d", "e"],
+                        ["f", "g", "h", "i", "j"]
+                    ];
+
+                    verify(code, "ArrowFunctionExpression", namesList);
+                });
+
+                it("ClassDeclaration", () => {
+                    const code = "\n class A { foo(x) { let y; } }\n class B { foo(x) { let y; } }\n ";
+                    const namesList = [
+                        ["A", "A"], // outer scope's and inner scope's.
+                        ["B", "B"]
+                    ];
+
+                    verify(code, "ClassDeclaration", namesList);
+                });
+
+                it("ClassExpression", () => {
+                    const code = "\n (class A { foo(x) { let y; } });\n (class B { foo(x) { let y; } });\n ";
+                    const namesList = [
+                        ["A"],
+                        ["B"]
+                    ];
+
+                    verify(code, "ClassExpression", namesList);
+                });
+
+                it("CatchClause", () => {
+                    const code = "\n try {} catch ({a, b}) {\n let x;\n try {} catch ({c, d}) {\n let y;\n }\n }\n ";
+                    const namesList = [
+                        ["a", "b"],
+                        ["c", "d"]
+                    ];
+
+                    verify(code, "CatchClause", namesList);
+                });
+
+                it("ImportDeclaration", () => {
+                    const code = "\n import \"aaa\";\n import * as a from \"bbb\";\n import b, {c, x as d} from \"ccc\";\n ";
+                    const namesList = [
+                        [],
+                        ["a"],
+                        ["b", "c", "d"]
+                    ];
+
+                    verify(code, "ImportDeclaration", namesList);
+                });
+
+                it("ImportSpecifier", () => {
+                    const code = "\n import \"aaa\";\n import * as a from \"bbb\";\n import b, {c, x as d} from \"ccc\";\n ";
+                    const namesList = [
+                        ["c"],
+                        ["d"]
+                    ];
+
+                    verify(code, "ImportSpecifier", namesList);
+                });
+
+                it("ImportDefaultSpecifier", () => {
+                    const code = "\n import \"aaa\";\n import * as a from \"bbb\";\n import b, {c, x as d} from \"ccc\";\n ";
+                    const namesList = [
+                        ["b"]
+                    ];
+
+                    verify(code, "ImportDefaultSpecifier", namesList);
+                });
+
+                it("ImportNamespaceSpecifier", () => {
+                    const code = "\n import \"aaa\";\n import * as a from \"bbb\";\n import b, {c, x as d} from \"ccc\";\n ";
+                    const namesList = [
+                        ["a"]
+                    ];
+
+                    verify(code, "ImportNamespaceSpecifier", namesList);
+                });
+            });
+
+            describe("context.markVariableAsUsed()", () => {
+
+                it("should mark variables in current scope as used", () => {
+                    const code = "var a = 1, b = 2;";
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            assert.isTrue(context.markVariableAsUsed("a"));
+
+                                            const scope = context.getScope();
+
+                                            assert.isTrue(getVariable(scope, "a").eslintUsed);
+                                            assert.notOk(getVariable(scope, "b").eslintUsed);
+                                        });
+
+                                        return { "Program:exit": spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should mark variables in function args as used", () => {
+                    const code = "function abc(a, b) { return 1; }";
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            assert.isTrue(context.markVariableAsUsed("a"));
+
+                                            const scope = context.getScope();
+
+                                            assert.isTrue(getVariable(scope, "a").eslintUsed);
+                                            assert.notOk(getVariable(scope, "b").eslintUsed);
+                                        });
+
+                                        return { ReturnStatement: spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should mark variables in higher scopes as used", () => {
+                    const code = "var a, b; function abc() { return 1; }";
+                    let returnSpy, exitSpy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        returnSpy = sinon.spy(() => {
+                                            assert.isTrue(context.markVariableAsUsed("a"));
+                                        });
+                                        exitSpy = sinon.spy(() => {
+                                            const scope = context.getScope();
+
+                                            assert.isTrue(getVariable(scope, "a").eslintUsed);
+                                            assert.notOk(getVariable(scope, "b").eslintUsed);
+                                        });
+
+                                        return { ReturnStatement: returnSpy, "Program:exit": exitSpy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(returnSpy && returnSpy.calledOnce);
+                    assert(exitSpy && exitSpy.calledOnce);
+                });
+
+                it("should mark variables as used when sourceType is commonjs", () => {
+                    const code = "var a = 1, b = 2;";
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const globalScope = context.getScope(),
+                                                childScope = globalScope.childScopes[0];
+
+                                            assert.isTrue(context.markVariableAsUsed("a"), "Call to markVariableAsUsed should return true");
+
+                                            assert.isTrue(getVariable(childScope, "a").eslintUsed, "'a' should be marked as used.");
+                                            assert.isUndefined(getVariable(childScope, "b").eslintUsed, "'b' should be marked as used.");
+                                        });
+
+                                        return { "Program:exit": spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "commonjs"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce, "Spy wasn't called.");
+                });
+
+                it("should mark variables in modules as used", () => {
+                    const code = "var a = 1, b = 2;";
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const globalScope = context.getScope(),
+                                                childScope = globalScope.childScopes[0];
+
+                                            assert.isTrue(context.markVariableAsUsed("a"));
+
+                                            assert.isTrue(getVariable(childScope, "a").eslintUsed);
+                                            assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+                                        });
+
+                                        return { "Program:exit": spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "module"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should return false if the given variable is not found", () => {
+                    const code = "var a = 1, b = 2;";
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            assert.isFalse(context.markVariableAsUsed("c"));
+                                        });
+
+                                        return { "Program:exit": spy };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+            });
+
+            describe("context.getCwd()", () => {
+                const code = "a;\nb;";
+                const baseConfig = { rules: { "test/checker": "error" } };
+
+                it("should get cwd correctly in the context", () => {
+                    const cwd = "cwd";
+                    const linterWithOption = new Linter({ cwd, configType: "flat" });
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            assert.strictEqual(context.getCwd(), cwd);
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        ...baseConfig
+                    };
+
+                    linterWithOption.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should assign process.cwd() to it if cwd is undefined", () => {
+
+                    const linterWithOption = new Linter({ configType: "flat" });
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+
+                                        spy = sinon.spy(() => {
+                                            assert.strictEqual(context.getCwd(), process.cwd());
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        ...baseConfig
+                    };
+
+                    linterWithOption.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("should assign process.cwd() to it if the option is undefined", () => {
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+
+                                        spy = sinon.spy(() => {
+                                            assert.strictEqual(context.getCwd(), process.cwd());
+                                        });
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        ...baseConfig
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+            });
+
+        });
+
+        describe("Rule Severity", () => {
+
+            it("rule should run as warning when set to 1 with a config array", () => {
+                const ruleId = "semi",
+                    configs = createFlatConfigArray({
+                        files: ["**/*.js"],
+                        rules: {
+                            [ruleId]: 1
+                        }
+                    });
+
+                configs.normalizeSync();
+                const messages = linter.verify("foo", configs, filename, true);
+
+                assert.strictEqual(messages.length, 1, "Message length is wrong");
+                assert.strictEqual(messages[0].ruleId, ruleId);
+            });
+
+            it("rule should run as warning when set to 1 with a plain array", () => {
+                const ruleId = "semi",
+                    configs = [{
+                        files: ["**/*.js"],
+                        rules: {
+                            [ruleId]: 1
+                        }
+                    }];
+
+                const messages = linter.verify("foo", configs, filename, true);
+
+                assert.strictEqual(messages.length, 1, "Message length is wrong");
+                assert.strictEqual(messages[0].ruleId, ruleId);
+            });
+
+            it("rule should run as warning when set to 1 with an object", () => {
+                const ruleId = "semi",
+                    config = {
+                        files: ["**/*.js"],
+                        rules: {
+                            [ruleId]: 1
+                        }
+                    };
+
+                const messages = linter.verify("foo", config, filename, true);
+
+                assert.strictEqual(messages.length, 1, "Message length is wrong");
+                assert.strictEqual(messages[0].ruleId, ruleId);
+            });
+        });
+
+        describe("Code with a hashbang comment", () => {
+            const code = "#!bin/program\n\nvar foo;;";
+
+            it("should preserve line numbers", () => {
+                const config = { rules: { "no-extra-semi": 1 } };
+                const messages = linter.verify(code, config);
+
+                assert.strictEqual(messages.length, 1);
+                assert.strictEqual(messages[0].ruleId, "no-extra-semi");
+                assert.strictEqual(messages[0].nodeType, "EmptyStatement");
+                assert.strictEqual(messages[0].line, 3);
+            });
+
+            it("should have a comment with the hashbang in it", () => {
+                const spy = sinon.spy(context => {
+                    const comments = context.getAllComments();
+
+                    assert.strictEqual(comments.length, 1);
+                    assert.strictEqual(comments[0].type, "Shebang");
+                    return {};
+                });
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: spy
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/checker": "error"
+                    }
+                };
+
+                linter.verify(code, config);
+                assert(spy.calledOnce);
+            });
+        });
+
+        describe("Options", () => {
+
+            describe("filename", () => {
+                it("should allow filename to be passed on options object", () => {
+                    const filenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getFilename(), "foo.js");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: filenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config, { filename: "foo.js" });
+                    assert(filenameChecker.calledOnce);
+                });
+
+                it("should allow filename to be passed as third argument", () => {
+                    const filenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getFilename(), "bar.js");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: filenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config, "bar.js");
+                    assert(filenameChecker.calledOnce);
+                });
+
+                it("should default filename to <input> when options object doesn't have filename", () => {
+                    const filenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getFilename(), "<input>");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: filenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config, {});
+                    assert(filenameChecker.calledOnce);
+                });
+
+                it("should default filename to <input> when only two arguments are passed", () => {
+                    const filenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getFilename(), "<input>");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: filenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config);
+                    assert(filenameChecker.calledOnce);
+                });
+            });
+
+            describe("physicalFilename", () => {
+                it("should be same as `filename` passed on options object, if no processors are used", () => {
+                    const physicalFilenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getPhysicalFilename(), "foo.js");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: physicalFilenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config, { filename: "foo.js" });
+                    assert(physicalFilenameChecker.calledOnce);
+                });
+
+                it("should default physicalFilename to <input> when options object doesn't have filename", () => {
+                    const physicalFilenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getPhysicalFilename(), "<input>");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: physicalFilenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config, {});
+                    assert(physicalFilenameChecker.calledOnce);
+                });
+
+                it("should default physicalFilename to <input> when only two arguments are passed", () => {
+                    const physicalFilenameChecker = sinon.spy(context => {
+                        assert.strictEqual(context.getPhysicalFilename(), "<input>");
+                        return {};
+                    });
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: physicalFilenameChecker
+                                }
+                            }
+                        },
+                        rules: {
+                            "test/checker": "error"
+                        }
+                    };
+
+                    linter.verify("foo;", config);
+                    assert(physicalFilenameChecker.calledOnce);
+                });
+            });
+
+        });
+
+        describe("Inline Directives", () => {
+
+            describe("/*global*/ Comments", () => {
+
+                describe("when evaluating code containing /*global */ and /*globals */ blocks", () => {
+
+                    it("variables should be available in global scope", () => {
+                        const code = `
+                        /*global a b:true c:false d:readable e:writeable Math:off */
+                        function foo() {}
+                        /*globals f:true*/
+                        /* global ConfigGlobal : readable */
+                        `;
+                        let spy;
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        checker: context => {
+                                            spy = sinon.spy(() => {
+                                                const scope = context.getScope();
+                                                const a = getVariable(scope, "a"),
+                                                    b = getVariable(scope, "b"),
+                                                    c = getVariable(scope, "c"),
+                                                    d = getVariable(scope, "d"),
+                                                    e = getVariable(scope, "e"),
+                                                    f = getVariable(scope, "f"),
+                                                    mathGlobal = getVariable(scope, "Math"),
+                                                    arrayGlobal = getVariable(scope, "Array"),
+                                                    configGlobal = getVariable(scope, "ConfigGlobal");
+
+                                                assert.strictEqual(a.name, "a");
+                                                assert.strictEqual(a.writeable, false);
+                                                assert.strictEqual(b.name, "b");
+                                                assert.strictEqual(b.writeable, true);
+                                                assert.strictEqual(c.name, "c");
+                                                assert.strictEqual(c.writeable, false);
+                                                assert.strictEqual(d.name, "d");
+                                                assert.strictEqual(d.writeable, false);
+                                                assert.strictEqual(e.name, "e");
+                                                assert.strictEqual(e.writeable, true);
+                                                assert.strictEqual(f.name, "f");
+                                                assert.strictEqual(f.writeable, true);
+                                                assert.strictEqual(mathGlobal, null);
+                                                assert.strictEqual(arrayGlobal, null);
+                                                assert.strictEqual(configGlobal.name, "ConfigGlobal");
+                                                assert.strictEqual(configGlobal.writeable, false);
+                                            });
+
+                                            return { Program: spy };
+                                        }
+                                    }
+                                }
+                            },
+                            rules: { "test/checker": "error" },
+                            languageOptions: {
+                                globals: { Array: "off", ConfigGlobal: "writeable" }
+                            }
+                        };
+
+                        linter.verify(code, config);
+                        assert(spy && spy.calledOnce);
+                    });
+                });
+
+                describe("when evaluating code containing a /*global */ block with sloppy whitespace", () => {
+                    const code = "/* global  a b  : true   c:  false*/";
+
+                    it("variables should be available in global scope", () => {
+
+                        let spy;
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        checker: context => {
+                                            spy = sinon.spy(() => {
+                                                const scope = context.getScope(),
+                                                    a = getVariable(scope, "a"),
+                                                    b = getVariable(scope, "b"),
+                                                    c = getVariable(scope, "c");
+
+                                                assert.strictEqual(a.name, "a");
+                                                assert.strictEqual(a.writeable, false);
+                                                assert.strictEqual(b.name, "b");
+                                                assert.strictEqual(b.writeable, true);
+                                                assert.strictEqual(c.name, "c");
+                                                assert.strictEqual(c.writeable, false);
+                                            });
+
+                                            return { Program: spy };
+                                        }
+                                    }
+                                }
+                            },
+                            rules: { "test/checker": "error" }
+                        };
+
+                        linter.verify(code, config);
+                        assert(spy && spy.calledOnce);
+                    });
+                });
+
+                describe("when evaluating code containing a line comment", () => {
+                    const code = "//global a \n function f() {}";
+
+                    it("should not introduce a global variable", () => {
+                        let spy;
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        checker: context => {
+                                            spy = sinon.spy(() => {
+                                                const scope = context.getScope();
+
+                                                assert.strictEqual(getVariable(scope, "a"), null);
+                                            });
+
+                                            return { Program: spy };
+                                        }
+                                    }
+                                }
+                            },
+                            rules: { "test/checker": "error" }
+                        };
+
+
+                        linter.verify(code, config);
+                        assert(spy && spy.calledOnce);
+                    });
+                });
+
+                describe("when evaluating code containing normal block comments", () => {
+                    const code = "/**/  /*a*/  /*b:true*/  /*foo c:false*/";
+
+                    it("should not introduce a global variable", () => {
+                        let spy;
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        checker: context => {
+                                            spy = sinon.spy(() => {
+                                                const scope = context.getScope();
+
+                                                assert.strictEqual(getVariable(scope, "a"), null);
+                                                assert.strictEqual(getVariable(scope, "b"), null);
+                                                assert.strictEqual(getVariable(scope, "foo"), null);
+                                                assert.strictEqual(getVariable(scope, "c"), null);
+                                            });
+
+                                            return { Program: spy };
+                                        }
+                                    }
+                                }
+                            },
+                            rules: { "test/checker": "error" }
+                        };
+
+
+                        linter.verify(code, config);
+                        assert(spy && spy.calledOnce);
+                    });
+                });
+
+                it("should attach a \"/*global\" comment node to declared variables", () => {
+                    const code = "/* global foo */\n/* global bar, baz */";
+                    let ok = false;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    test(context) {
+                                        return {
+                                            Program() {
+                                                const scope = context.getScope();
+                                                const sourceCode = context.getSourceCode();
+                                                const comments = sourceCode.getAllComments();
+
+                                                assert.strictEqual(2, comments.length);
+
+                                                const foo = getVariable(scope, "foo");
+
+                                                assert.strictEqual(foo.eslintExplicitGlobal, true);
+                                                assert.strictEqual(foo.eslintExplicitGlobalComments[0], comments[0]);
+
+                                                const bar = getVariable(scope, "bar");
+
+                                                assert.strictEqual(bar.eslintExplicitGlobal, true);
+                                                assert.strictEqual(bar.eslintExplicitGlobalComments[0], comments[1]);
+
+                                                const baz = getVariable(scope, "baz");
+
+                                                assert.strictEqual(baz.eslintExplicitGlobal, true);
+                                                assert.strictEqual(baz.eslintExplicitGlobalComments[0], comments[1]);
+
+                                                ok = true;
+                                            }
+                                        };
+                                    }
+                                }
+                            }
+                        },
+                        rules: { "test/test": "error" }
+                    };
+
+
+                    linter.verify(code, config);
+                    assert(ok);
+                });
+
+                it("should report a linting error when a global is set to an invalid value", () => {
+                    const results = linter.verify("/* global foo: AAAAA, bar: readonly */\nfoo;\nbar;", { rules: { "no-undef": "error" } });
+
+                    assert.deepStrictEqual(results, [
+                        {
+                            ruleId: null,
+                            severity: 2,
+                            message: "'AAAAA' is not a valid configuration for a global (use 'readonly', 'writable', or 'off')",
+                            line: 1,
+                            column: 1,
+                            endLine: 1,
+                            endColumn: 39,
+                            nodeType: null
+                        },
+                        {
+                            ruleId: "no-undef",
+                            messageId: "undef",
+                            severity: 2,
+                            message: "'foo' is not defined.",
+                            line: 2,
+                            column: 1,
+                            endLine: 2,
+                            endColumn: 4,
+                            nodeType: "Identifier"
+                        }
+                    ]);
+                });
+
+            });
+
+            describe("/*exported*/ Comments", () => {
+
+                it("we should behave nicely when no matching variable is found", () => {
+                    const code = "/* exported horse */";
+                    const config = { rules: {} };
+
+                    linter.verify(code, config, filename, true);
+                });
+
+                it("variables should be exported", () => {
+                    const code = "/* exported horse */\n\nvar horse = 'circus'";
+                    let spy;
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope(),
+                                                horse = getVariable(scope, "horse");
+
+                                            assert.strictEqual(horse.eslintUsed, true);
+                                        });
+
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("undefined variables should not be exported", () => {
+                    const code = "/* exported horse */\n\nhorse = 'circus'";
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope(),
+                                                horse = getVariable(scope, "horse");
+
+                                            assert.strictEqual(horse, null);
+                                        });
+
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("variables should be exported in strict mode", () => {
+                    const code = "/* exported horse */\n'use strict';\nvar horse = 'circus'";
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope(),
+                                                horse = getVariable(scope, "horse");
+
+                                            assert.strictEqual(horse.eslintUsed, true);
+                                        });
+
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("variables should not be exported in the es6 module environment", () => {
+                    const code = "/* exported horse */\nvar horse = 'circus'";
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope(),
+                                                horse = getVariable(scope, "horse");
+
+                                            assert.strictEqual(horse, null); // there is no global scope at all
+                                        });
+
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            ecmaVersion: 6,
+                            sourceType: "module"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+
+                it("variables should not be exported when in a commonjs file", () => {
+                    const code = "/* exported horse */\nvar horse = 'circus'";
+                    let spy;
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    checker: context => {
+                                        spy = sinon.spy(() => {
+                                            const scope = context.getScope(),
+                                                horse = getVariable(scope, "horse");
+
+                                            assert.strictEqual(horse, null); // there is no global scope at all
+                                        });
+
+                                        return { Program: spy };
+                                    }
+                                }
+                            }
+                        },
+                        languageOptions: {
+                            sourceType: "commonjs"
+                        },
+                        rules: { "test/checker": "error" }
+                    };
+
+                    linter.verify(code, config);
+                    assert(spy && spy.calledOnce);
+                });
+            });
+
+            describe("/*eslint*/ Comments", () => {
+                describe("when evaluating code with comments to enable rules", () => {
+
+                    it("should report a violation", () => {
+                        const code = "/*eslint no-alert:1*/ alert('test');";
+                        const config = { rules: {} };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                        assert.strictEqual(messages[0].message, "Unexpected alert.");
+                        assert.include(messages[0].nodeType, "CallExpression");
+                    });
+
+                    it("rules should not change initial config", () => {
+                        const config = {
+                            languageOptions: {
+                                sourceType: "script"
+                            },
+                            rules: { strict: 2 }
+                        };
+                        const codeA = "/*eslint strict: 0*/ function bar() { return 2; }";
+                        const codeB = "function foo() { return 1; }";
+                        let messages = linter.verify(codeA, config, filename, false);
+
+                        assert.strictEqual(messages.length, 0);
+
+                        messages = linter.verify(codeB, config, filename, false);
+                        assert.strictEqual(messages.length, 1);
+                    });
+
+                    it("rules should not change initial config", () => {
+                        const config = {
+                            languageOptions: {
+                                sourceType: "script"
+                            },
+                            rules: { quotes: [2, "double"] }
+                        };
+                        const codeA = "/*eslint quotes: 0*/ function bar() { return '2'; }";
+                        const codeB = "function foo() { return '1'; }";
+                        let messages = linter.verify(codeA, config, filename, false);
+
+                        assert.strictEqual(messages.length, 0);
+
+                        messages = linter.verify(codeB, config, filename, false);
+                        assert.strictEqual(messages.length, 1);
+                    });
+
+                    it("rules should not change initial config", () => {
+                        const config = { rules: { quotes: [2, "double"] } };
+                        const codeA = "/*eslint quotes: [0, \"single\"]*/ function bar() { return '2'; }";
+                        const codeB = "function foo() { return '1'; }";
+                        let messages = linter.verify(codeA, config, filename, false);
+
+                        assert.strictEqual(messages.length, 0);
+
+                        messages = linter.verify(codeB, config, filename, false);
+                        assert.strictEqual(messages.length, 1);
+                    });
+
+                    it("rules should not change initial config", () => {
+                        const config = {
+                            languageOptions: {
+                                sourceType: "script"
+                            },
+                            rules: { "no-unused-vars": [2, { vars: "all" }] }
+                        };
+                        const codeA = "/*eslint no-unused-vars: [0, {\"vars\": \"local\"}]*/ var a = 44;";
+                        const codeB = "var b = 55;";
+                        let messages = linter.verify(codeA, config, filename, false);
+
+                        assert.strictEqual(messages.length, 0);
+
+                        messages = linter.verify(codeB, config, filename, false);
+                        assert.strictEqual(messages.length, 1);
+                    });
+                });
+
+                describe("when evaluating code with invalid comments to enable rules", () => {
+                    it("should report a violation when the config is not a valid rule configuration", () => {
+                        assert.deepStrictEqual(
+                            linter.verify("/*eslint no-alert:true*/ alert('test');", {}),
+                            [
+                                {
+                                    severity: 2,
+                                    ruleId: "no-alert",
+                                    message: "Configuration for rule \"no-alert\" is invalid:\n\tSeverity should be one of the following: 0 = off, 1 = warn, 2 = error (you passed 'true').\n",
+                                    line: 1,
+                                    column: 1,
+                                    endLine: 1,
+                                    endColumn: 25,
+                                    nodeType: null
+                                }
+                            ]
+                        );
+                    });
+
+                    it("should report a violation when the config violates a rule's schema", () => {
+                        assert.deepStrictEqual(
+                            linter.verify("/* eslint no-alert: [error, {nonExistentPropertyName: true}]*/", {}),
+                            [
+                                {
+                                    severity: 2,
+                                    ruleId: "no-alert",
+                                    message: "Configuration for rule \"no-alert\" is invalid:\n\tValue [{\"nonExistentPropertyName\":true}] should NOT have more than 0 items.\n",
+                                    line: 1,
+                                    column: 1,
+                                    endLine: 1,
+                                    endColumn: 63,
+                                    nodeType: null
+                                }
+                            ]
+                        );
+                    });
+                });
+
+                describe("when evaluating code with comments to disable rules", () => {
+
+                    it("should not report a violation", () => {
+                        const config = { rules: { "no-alert": 1 } };
+                        const messages = linter.verify("/*eslint no-alert:0*/ alert('test');", config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should report an error when disabling a non-existent rule in inline comment", () => {
+                        let code = "/*eslint foo:0*/ ;";
+                        let messages = linter.verify(code, {}, filename);
+
+                        assert.strictEqual(messages.length, 1, "/*eslint*/ comment should report problem.");
+                        assert.strictEqual(messages[0].message, "Definition for rule 'foo' was not found.");
+
+                        code = "/*eslint-disable foo*/ ;";
+                        messages = linter.verify(code, {}, filename);
+                        assert.strictEqual(messages.length, 1, "/*eslint-disable*/ comment should report problem.");
+                        assert.strictEqual(messages[0].message, "Definition for rule 'foo' was not found.");
+
+                        code = "/*eslint-disable-line foo*/ ;";
+                        messages = linter.verify(code, {}, filename);
+                        assert.strictEqual(messages.length, 1, "/*eslint-disable-line*/ comment should report problem.");
+                        assert.strictEqual(messages[0].message, "Definition for rule 'foo' was not found.");
+
+                        code = "/*eslint-disable-next-line foo*/ ;";
+                        messages = linter.verify(code, {}, filename);
+                        assert.strictEqual(messages.length, 1, "/*eslint-disable-next-line*/ comment should report problem.");
+                        assert.strictEqual(messages[0].message, "Definition for rule 'foo' was not found.");
+                    });
+
+                    it("should not report an error, when disabling a non-existent rule in config", () => {
+                        const messages = linter.verify("", { rules: { foo: 0 } }, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should throw an error when a non-existent rule in config", () => {
+                        assert.throws(() => {
+                            linter.verify("", { rules: { foo: 1 } }, filename);
+                        }, /Key "rules": Key "foo":/u);
+
+                        assert.throws(() => {
+                            linter.verify("", { rules: { foo: 2 } }, filename);
+                        }, /Key "rules": Key "foo":/u);
+
+                    });
+                });
+
+                describe("when evaluating code with comments to enable multiple rules", () => {
+                    const code = "/*eslint no-alert:1 no-console:1*/ alert('test'); console.log('test');";
+
+                    it("should report a violation", () => {
+                        const config = { rules: {} };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 2);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                        assert.strictEqual(messages[0].message, "Unexpected alert.");
+                        assert.include(messages[0].nodeType, "CallExpression");
+                        assert.strictEqual(messages[1].ruleId, "no-console");
+                    });
+                });
+
+                describe("when evaluating code with comments to enable and disable multiple rules", () => {
+                    const code = "/*eslint no-alert:1 no-console:0*/ alert('test'); console.log('test');";
+
+                    it("should report a violation", () => {
+                        const config = { rules: { "no-console": 1, "no-alert": 0 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                        assert.strictEqual(messages[0].message, "Unexpected alert.");
+                        assert.include(messages[0].nodeType, "CallExpression");
+                    });
+                });
+
+                describe("when evaluating code with comments to disable and enable configurable rule as part of plugin", () => {
+
+                    let baseConfig;
+
+                    beforeEach(() => {
+                        baseConfig = {
+                            plugins: {
+                                "test-plugin": {
+                                    rules: {
+                                        "test-rule"(context) {
+                                            return {
+                                                Literal(node) {
+                                                    if (node.value === "trigger violation") {
+                                                        context.report(node, "Reporting violation.");
+                                                    }
+                                                }
+                                            };
+                                        }
+                                    }
+                                }
+                            }
+                        };
+
+                    });
+
+                    it("should not report a violation when inline comment enables plugin rule and there's no violation", () => {
+                        const config = { ...baseConfig, rules: {} };
+                        const code = "/*eslint test-plugin/test-rule: 2*/ var a = \"no violation\";";
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should not report a violation when inline comment disables plugin rule", () => {
+                        const code = "/*eslint test-plugin/test-rule:0*/ var a = \"trigger violation\"";
+                        const config = { ...baseConfig, rules: { "test-plugin/test-rule": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should report a violation when the report is right before the comment", () => {
+                        const code = " /* eslint-disable */ ";
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        checker: context => ({
+                                            Program() {
+                                                context.report({ loc: { line: 1, column: 0 }, message: "foo" });
+                                            }
+                                        })
+                                    }
+                                }
+                            },
+                            rules: {
+                                "test/checker": "error"
+                            }
+                        };
+
+                        const problems = linter.verify(code, config);
+
+                        assert.strictEqual(problems.length, 1);
+                        assert.strictEqual(problems[0].message, "foo");
+                    });
+
+                    it("should not report a violation when the report is right at the start of the comment", () => {
+                        const code = " /* eslint-disable */ ";
+
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        checker: context => ({
+                                            Program() {
+                                                context.report({ loc: { line: 1, column: 1 }, message: "foo" });
+                                            }
+                                        })
+                                    }
+                                }
+                            },
+                            rules: {
+                                "test/checker": "error"
+                            }
+                        };
+
+                        const problems = linter.verify(code, config);
+
+                        assert.strictEqual(problems.length, 0);
+                    });
+
+                    it("rules should not change initial config", () => {
+                        const config = { ...baseConfig, rules: { "test-plugin/test-rule": 2 } };
+                        const codeA = "/*eslint test-plugin/test-rule: 0*/ var a = \"trigger violation\";";
+                        const codeB = "var a = \"trigger violation\";";
+                        let messages = linter.verify(codeA, config, filename, false);
+
+                        assert.strictEqual(messages.length, 0);
+
+                        messages = linter.verify(codeB, config, filename, false);
+                        assert.strictEqual(messages.length, 1);
+                    });
+                });
+
+                describe("when evaluating code with comments to enable and disable all reporting", () => {
+                    it("should report a violation", () => {
+
+                        const code = [
+                            "/*eslint-disable */",
+                            "alert('test');",
+                            "/*eslint-enable */",
+                            "alert('test');"
+                        ].join("\n");
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                        assert.strictEqual(messages[0].message, "Unexpected alert.");
+                        assert.include(messages[0].nodeType, "CallExpression");
+                        assert.strictEqual(messages[0].line, 4);
+                    });
+
+                    it("should not report a violation", () => {
+                        const code = [
+                            "/*eslint-disable */",
+                            "alert('test');",
+                            "alert('test');"
+                        ].join("\n");
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should not report a violation", () => {
+                        const code = [
+                            "                    alert('test1');/*eslint-disable */\n",
+                            "alert('test');",
+                            "                                         alert('test');\n",
+                            "/*eslint-enable */alert('test2');"
+                        ].join("");
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 2);
+                        assert.strictEqual(messages[0].column, 21);
+                        assert.strictEqual(messages[1].column, 19);
+                    });
+
+                    it("should report a violation", () => {
+
+                        const code = [
+                            "/*eslint-disable */",
+                            "alert('test');",
+                            "/*eslint-disable */",
+                            "alert('test');",
+                            "/*eslint-enable*/",
+                            "alert('test');",
+                            "/*eslint-enable*/"
+                        ].join("\n");
+
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                    });
+
+
+                    it("should not report a violation", () => {
+                        const code = [
+                            "/*eslint-disable */",
+                            "(function(){ var b = 44;})()",
+                            "/*eslint-enable */;any();"
+                        ].join("\n");
+
+                        const config = { rules: { "no-unused-vars": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should not report a violation", () => {
+                        const code = [
+                            "(function(){ /*eslint-disable */ var b = 44;})()",
+                            "/*eslint-enable */;any();"
+                        ].join("\n");
+
+                        const config = { rules: { "no-unused-vars": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+                });
+
+                describe("when evaluating code with comments to enable and disable multiple comma separated rules", () => {
+                    const code = "/*eslint no-alert:1, no-console:0*/ alert('test'); console.log('test');";
+
+                    it("should report a violation", () => {
+                        const config = { rules: { "no-console": 1, "no-alert": 0 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                        assert.strictEqual(messages[0].message, "Unexpected alert.");
+                        assert.include(messages[0].nodeType, "CallExpression");
+                    });
+                });
+
+                describe("when evaluating code with comments to enable configurable rule", () => {
+                    const code = "/*eslint quotes:[2, \"double\"]*/ alert('test');";
+
+                    it("should report a violation", () => {
+                        const config = { rules: { quotes: [2, "single"] } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "quotes");
+                        assert.strictEqual(messages[0].message, "Strings must use doublequote.");
+                        assert.include(messages[0].nodeType, "Literal");
+                    });
+                });
+
+                describe("when evaluating code with comments to enable configurable rule using string severity", () => {
+                    const code = "/*eslint quotes:[\"error\", \"double\"]*/ alert('test');";
+
+                    it("should report a violation", () => {
+                        const config = { rules: { quotes: [2, "single"] } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "quotes");
+                        assert.strictEqual(messages[0].message, "Strings must use doublequote.");
+                        assert.include(messages[0].nodeType, "Literal");
+                    });
+                });
+
+                describe("when evaluating code with incorrectly formatted comments to disable rule", () => {
+                    it("should report a violation", () => {
+                        const code = "/*eslint no-alert:'1'*/ alert('test');";
+
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 2);
+
+                        /*
+                         * Incorrectly formatted comment threw error;
+                         * message from caught exception
+                         * may differ amongst UAs, so verifying
+                         * first part only as defined in the
+                         * parseJsonConfig function in lib/eslint.js
+                         */
+                        assert.match(messages[0].message, /^Failed to parse JSON from ' "no-alert":'1'':/u);
+                        assert.strictEqual(messages[0].line, 1);
+                        assert.strictEqual(messages[0].column, 1);
+
+                        assert.strictEqual(messages[1].ruleId, "no-alert");
+                        assert.strictEqual(messages[1].message, "Unexpected alert.");
+                        assert.include(messages[1].nodeType, "CallExpression");
+                    });
+
+                    it("should report a violation", () => {
+                        const code = "/*eslint no-alert:abc*/ alert('test');";
+
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 2);
+
+                        /*
+                         * Incorrectly formatted comment threw error;
+                         * message from caught exception
+                         * may differ amongst UAs, so verifying
+                         * first part only as defined in the
+                         * parseJsonConfig function in lib/eslint.js
+                         */
+                        assert.match(messages[0].message, /^Failed to parse JSON from ' "no-alert":abc':/u);
+                        assert.strictEqual(messages[0].line, 1);
+                        assert.strictEqual(messages[0].column, 1);
+
+                        assert.strictEqual(messages[1].ruleId, "no-alert");
+                        assert.strictEqual(messages[1].message, "Unexpected alert.");
+                        assert.include(messages[1].nodeType, "CallExpression");
+                    });
+
+                    it("should report a violation", () => {
+                        const code = "/*eslint no-alert:0 2*/ alert('test');";
+
+                        const config = { rules: { "no-alert": 1 } };
+
+                        const messages = linter.verify(code, config, filename);
+
+                        assert.strictEqual(messages.length, 2);
+
+                        /*
+                         * Incorrectly formatted comment threw error;
+                         * message from caught exception
+                         * may differ amongst UAs, so verifying
+                         * first part only as defined in the
+                         * parseJsonConfig function in lib/eslint.js
+                         */
+                        assert.match(messages[0].message, /^Failed to parse JSON from ' "no-alert":0 2':/u);
+                        assert.strictEqual(messages[0].line, 1);
+                        assert.strictEqual(messages[0].column, 1);
+
+                        assert.strictEqual(messages[1].ruleId, "no-alert");
+                        assert.strictEqual(messages[1].message, "Unexpected alert.");
+                        assert.include(messages[1].nodeType, "CallExpression");
+                    });
+                });
+
+                describe("when evaluating code with comments which have colon in its value", () => {
+                    const code = String.raw`
+/* eslint max-len: [2, 100, 2, {ignoreUrls: true, ignorePattern: "data:image\\/|\\s*require\\s*\\(|^\\s*loader\\.lazy|-\\*-"}] */
+alert('test');
+`;
+
+                    it("should not parse errors, should report a violation", () => {
+                        const messages = linter.verify(code, {}, filename);
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "max-len");
+                        assert.strictEqual(messages[0].message, "This line has a length of 129. Maximum allowed is 100.");
+                        assert.include(messages[0].nodeType, "Program");
+                    });
+                });
+
+                describe("when evaluating code with comments that contain escape sequences", () => {
+                    const code = String.raw`
+/* eslint max-len: ["error", 1, { ignoreComments: true, ignorePattern: "console\\.log\\(" }] */
+console.log("test");
+consolexlog("test2");
+var a = "test2";
+`;
+
+                    it("should validate correctly", () => {
+                        const config = { rules: {} };
+                        const messages = linter.verify(code, config, filename);
+                        const [message1, message2] = messages;
+
+                        assert.strictEqual(messages.length, 2);
+                        assert.strictEqual(message1.ruleId, "max-len");
+                        assert.strictEqual(message1.message, "This line has a length of 21. Maximum allowed is 1.");
+                        assert.strictEqual(message1.line, 4);
+                        assert.strictEqual(message1.column, 1);
+                        assert.include(message1.nodeType, "Program");
+                        assert.strictEqual(message2.ruleId, "max-len");
+                        assert.strictEqual(message2.message, "This line has a length of 16. Maximum allowed is 1.");
+                        assert.strictEqual(message2.line, 5);
+                        assert.strictEqual(message2.column, 1);
+                        assert.include(message2.nodeType, "Program");
+                    });
+                });
+
+            });
+
+            describe("/*eslint-disable*/ and /*eslint-enable*/", () => {
+                it("should report a violation", () => {
+                    const code = [
+                        "/*eslint-disable no-alert */",
+                        "alert('test');",
+                        "console.log('test');" // here
+                    ].join("\n");
+                    const config = { rules: { "no-alert": 1, "no-console": 1 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+
+                it("should report no violation", () => {
+                    const code = [
+                        "/* eslint-disable quotes */",
+                        "console.log(\"foo\");",
+                        "/* eslint-enable quotes */"
+                    ].join("\n");
+                    const config = { rules: { quotes: 2 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should report a violation", () => {
+                    const code = [
+                        "/*eslint-disable no-alert, no-console */",
+                        "alert('test');",
+                        "console.log('test');",
+                        "/*eslint-enable*/",
+
+                        "alert('test');", // here
+                        "console.log('test');" // here
+                    ].join("\n");
+                    const config = { rules: { "no-alert": 1, "no-console": 1 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[0].line, 5);
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                    assert.strictEqual(messages[1].line, 6);
+                });
+
+                it("should report a violation", () => {
+                    const code = [
+                        "/*eslint-disable no-alert */",
+                        "alert('test');",
+                        "console.log('test');",
+                        "/*eslint-enable no-console */",
+
+                        "alert('test');" // here
+                    ].join("\n");
+                    const config = { rules: { "no-alert": 1, "no-console": 1 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+
+
+                it("should report a violation", () => {
+                    const code = [
+                        "/*eslint-disable no-alert, no-console */",
+                        "alert('test');",
+                        "console.log('test');",
+                        "/*eslint-enable no-alert*/",
+
+                        "alert('test');", // here
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = { rules: { "no-alert": 1, "no-console": 1 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[0].line, 5);
+                });
+
+
+                it("should report a violation", () => {
+                    const code = [
+                        "/*eslint-disable no-alert */",
+
+                        "/*eslint-disable no-console */",
+                        "alert('test');",
+                        "console.log('test');",
+                        "/*eslint-enable */",
+
+                        "alert('test');", // here
+                        "console.log('test');", // here
+
+                        "/*eslint-enable */",
+
+                        "alert('test');", // here
+                        "console.log('test');", // here
+
+                        "/*eslint-enable*/"
+                    ].join("\n");
+                    const config = { rules: { "no-alert": 1, "no-console": 1 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 4);
+
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[0].line, 6);
+
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                    assert.strictEqual(messages[1].line, 7);
+
+                    assert.strictEqual(messages[2].ruleId, "no-alert");
+                    assert.strictEqual(messages[2].line, 9);
+
+                    assert.strictEqual(messages[3].ruleId, "no-console");
+                    assert.strictEqual(messages[3].line, 10);
+
+                });
+
+                it("should report a violation", () => {
+                    const code = [
+                        "/*eslint-disable no-alert, no-console */",
+                        "alert('test');",
+                        "console.log('test');",
+
+                        "/*eslint-enable no-alert */",
+
+                        "alert('test');", // here
+                        "console.log('test');",
+
+                        "/*eslint-enable no-console */",
+
+                        "alert('test');", // here
+                        "console.log('test');", // here
+                        "/*eslint-enable no-console */"
+                    ].join("\n");
+                    const config = { rules: { "no-alert": 1, "no-console": 1 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 3);
+
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[0].line, 5);
+
+                    assert.strictEqual(messages[1].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].line, 8);
+
+                    assert.strictEqual(messages[2].ruleId, "no-console");
+                    assert.strictEqual(messages[2].line, 9);
+
+                });
+
+                it("should report a violation when severity is warn", () => {
+                    const code = [
+                        "/*eslint-disable no-alert, no-console */",
+                        "alert('test');",
+                        "console.log('test');",
+
+                        "/*eslint-enable no-alert */",
+
+                        "alert('test');", // here
+                        "console.log('test');",
+
+                        "/*eslint-enable no-console */",
+
+                        "alert('test');", // here
+                        "console.log('test');", // here
+                        "/*eslint-enable no-console */"
+                    ].join("\n");
+                    const config = { rules: { "no-alert": "warn", "no-console": "warn" } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 3);
+
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[0].line, 5);
+
+                    assert.strictEqual(messages[1].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].line, 8);
+
+                    assert.strictEqual(messages[2].ruleId, "no-console");
+                    assert.strictEqual(messages[2].line, 9);
+
+                });
+
+                it("should report no violation", () => {
+                    const code = [
+                        "/*eslint-disable no-unused-vars */",
+                        "var foo; // eslint-disable-line no-unused-vars",
+                        "var bar;",
+                        "/* eslint-enable no-unused-vars */" // here
+                    ].join("\n");
+                    const config = { rules: { "no-unused-vars": 2 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+            });
+
+            describe("/*eslint-disable-line*/", () => {
+
+                it("should report a violation", () => {
+                    const code = [
+                        "alert('test'); // eslint-disable-line no-alert",
+                        "console.log('test');" // here
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+
+                it("should report a violation", () => {
+                    const code = [
+                        "alert('test'); // eslint-disable-line no-alert",
+                        "console.log('test'); // eslint-disable-line no-console",
+                        "alert('test');" // here
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                });
+
+                it("should report a violation if eslint-disable-line in a block comment is not on a single line", () => {
+                    const code = [
+                        "/* eslint-disable-line",
+                        "*",
+                        "*/ console.log('test');" // here
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+
+                it("should not disable rule and add an extra report if eslint-disable-line in a block comment is not on a single line", () => {
+                    const code = [
+                        "alert('test'); /* eslint-disable-line ",
+                        "no-alert */"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config);
+
+                    assert.deepStrictEqual(messages, [
+                        {
+                            ruleId: "no-alert",
+                            severity: 1,
+                            line: 1,
+                            column: 1,
+                            endLine: 1,
+                            endColumn: 14,
+                            message: "Unexpected alert.",
+                            messageId: "unexpected",
+                            nodeType: "CallExpression"
+                        },
+                        {
+                            ruleId: null,
+                            severity: 2,
+                            message: "eslint-disable-line comment should not span multiple lines.",
+                            line: 1,
+                            column: 16,
+                            endLine: 2,
+                            endColumn: 12,
+                            nodeType: null
+                        }
+                    ]);
+                });
+
+                it("should not report a violation for eslint-disable-line in block comment", () => {
+                    const code = [
+                        "alert('test'); // eslint-disable-line no-alert",
+                        "alert('test'); /*eslint-disable-line no-alert*/"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should not report a violation", () => {
+                    const code = [
+                        "alert('test'); // eslint-disable-line no-alert",
+                        "console.log('test'); // eslint-disable-line no-console"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should not report a violation", () => {
+                    const code = [
+                        "alert('test') // eslint-disable-line no-alert, quotes, semi",
+                        "console.log('test'); // eslint-disable-line"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            quotes: [1, "double"],
+                            semi: [1, "always"],
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should not report a violation", () => {
+                    const code = [
+                        "alert('test') /* eslint-disable-line no-alert, quotes, semi */",
+                        "console.log('test'); /* eslint-disable-line */"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            quotes: [1, "double"],
+                            semi: [1, "always"],
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should ignore violations of multiple rules when specified in mixed comments", () => {
+                    const code = [
+                        " alert(\"test\"); /* eslint-disable-line no-alert */ // eslint-disable-line quotes"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            quotes: [1, "single"]
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should report no violation", () => {
+                    const code = [
+                        "var foo1; // eslint-disable-line no-unused-vars",
+                        "var foo2; // eslint-disable-line no-unused-vars",
+                        "var foo3; // eslint-disable-line no-unused-vars",
+                        "var foo4; // eslint-disable-line no-unused-vars",
+                        "var foo5; // eslint-disable-line no-unused-vars"
+                    ].join("\n");
+                    const config = { rules: { "no-unused-vars": 2 } };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+            });
+
+            describe("/*eslint-disable-next-line*/", () => {
+                it("should ignore violation of specified rule on next line", () => {
+                    const code = [
+                        "// eslint-disable-next-line no-alert",
+                        "alert('test');",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+
+                it("should ignore violation of specified rule if eslint-disable-next-line is a block comment", () => {
+                    const code = [
+                        "/* eslint-disable-next-line no-alert */",
+                        "alert('test');",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+                it("should ignore violation of specified rule if eslint-disable-next-line is a block comment", () => {
+                    const code = [
+                        "/* eslint-disable-next-line no-alert */",
+                        "alert('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should not ignore violation if block comment is not on a single line", () => {
+                    const code = [
+                        "/* eslint-disable-next-line",
+                        "no-alert */alert('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+                    assert.strictEqual(messages[1].ruleId, "no-alert");
+                });
+
+                it("should ignore violations only of specified rule", () => {
+                    const code = [
+                        "// eslint-disable-next-line no-console",
+                        "alert('test');",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+
+                it("should ignore violations of multiple rules when specified", () => {
+                    const code = [
+                        "// eslint-disable-next-line no-alert, quotes",
+                        "alert(\"test\");",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            quotes: [1, "single"],
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+
+                it("should ignore violations of multiple rules when specified in mixed comments", () => {
+                    const code = [
+                        "/* eslint-disable-next-line no-alert */ // eslint-disable-next-line quotes",
+                        "alert(\"test\");"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            quotes: [1, "single"]
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 0);
+                });
+
+                it("should ignore violations of only the specified rule on next line", () => {
+                    const code = [
+                        "// eslint-disable-next-line quotes",
+                        "alert(\"test\");",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            quotes: [1, "single"],
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+
+                it("should ignore violations of specified rule on next line only", () => {
+                    const code = [
+                        "alert('test');",
+                        "// eslint-disable-next-line no-alert",
+                        "alert('test');",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+
+                it("should ignore all rule violations on next line if none specified", () => {
+                    const code = [
+                        "// eslint-disable-next-line",
+                        "alert(\"test\");",
+                        "console.log('test')"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            semi: [1, "never"],
+                            quotes: [1, "single"],
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].ruleId, "no-console");
+                });
+
+                it("should ignore violations if eslint-disable-next-line is a block comment", () => {
+                    const code = [
+                        "alert('test');",
+                        "/* eslint-disable-next-line no-alert */",
+                        "alert('test');",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+
+                it("should report a violation", () => {
+                    const code = [
+                        "/* eslint-disable-next-line",
+                        "*",
+                        "*/",
+                        "console.log('test');" // here
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+
+                it("should not ignore violations if comment is of the type hashbang", () => {
+                    const code = [
+                        "#! eslint-disable-next-line no-alert",
+                        "alert('test');",
+                        "console.log('test');"
+                    ].join("\n");
+                    const config = {
+                        rules: {
+                            "no-alert": 1,
+                            "no-console": 1
+                        }
+                    };
+                    const messages = linter.verify(code, config, filename);
+
+                    assert.strictEqual(messages.length, 2);
+                    assert.strictEqual(messages[0].ruleId, "no-alert");
+                    assert.strictEqual(messages[1].ruleId, "no-console");
+                });
+            });
+
+            describe("descriptions in directive comments", () => {
+                it("should ignore the part preceded by '--' in '/*eslint*/'.", () => {
+                    const aaa = sinon.stub().returns({});
+                    const bbb = sinon.stub().returns({});
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    aaa: { create: aaa },
+                                    bbb: { create: bbb }
+                                }
+                            }
+                        }
+                    };
+
+                    const messages = linter.verify(`
+                    /*eslint test/aaa:error -- test/bbb:error */
+                    console.log("hello")
+                `, config);
+
+                    // Don't include syntax error of the comment.
+                    assert.deepStrictEqual(messages, []);
+
+                    // Use only `aaa`.
+                    assert.strictEqual(aaa.callCount, 1);
+                    assert.strictEqual(bbb.callCount, 0);
+                });
+
+                it("should ignore the part preceded by '--' in '/*globals*/'.", () => {
+                    const messages = linter.verify(`
+                    /*globals aaa -- bbb */
+                    var aaa = {}
+                    var bbb = {}
+                `, {
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "no-redeclare": "error" }
+                    });
+
+                    // Don't include `bbb`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 31,
+                            endColumn: 34,
+                            line: 2,
+                            endLine: 2,
+                            message: "'aaa' is already defined by a variable declaration.",
+                            messageId: "redeclaredBySyntax",
+                            nodeType: "Block",
+                            ruleId: "no-redeclare",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '/*exported*/'.", () => {
+                    const messages = linter.verify(`
+                    /*exported aaa -- bbb */
+                    var aaa = {}
+                    var bbb = {}
+                `, {
+                        languageOptions: {
+                            sourceType: "script"
+                        },
+                        rules: { "no-unused-vars": "error" }
+                    });
+
+                    // Don't include `aaa`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endColumn: 28,
+                            endLine: 4,
+                            line: 4,
+                            message: "'bbb' is assigned a value but never used.",
+                            messageId: "unusedVar",
+                            nodeType: "Identifier",
+                            ruleId: "no-unused-vars",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '/*eslint-disable*/'.", () => {
+                    const messages = linter.verify(`
+                    /*eslint-disable no-redeclare -- no-unused-vars */
+                    var aaa = {}
+                    var aaa = {}
+                `, { rules: { "no-redeclare": "error", "no-unused-vars": "error" } });
+
+                    // Do include `no-unused-vars` but not `no-redeclare`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endLine: 4,
+                            endColumn: 28,
+                            line: 4,
+                            message: "'aaa' is assigned a value but never used.",
+                            messageId: "unusedVar",
+                            nodeType: "Identifier",
+                            ruleId: "no-unused-vars",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '/*eslint-enable*/'.", () => {
+                    const messages = linter.verify(`
+                    /*eslint-disable no-redeclare, no-unused-vars */
+                    /*eslint-enable no-redeclare -- no-unused-vars */
+                    var aaa = {}
+                    var aaa = {}
+                `, { rules: { "no-redeclare": "error", "no-unused-vars": "error" } });
+
+                    // Do include `no-redeclare` but not `no-unused-vars`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endLine: 5,
+                            endColumn: 28,
+                            line: 5,
+                            message: "'aaa' is already defined.",
+                            messageId: "redeclared",
+                            nodeType: "Identifier",
+                            ruleId: "no-redeclare",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '//eslint-disable-line'.", () => {
+                    const messages = linter.verify(`
+                    var aaa = {} //eslint-disable-line no-redeclare -- no-unused-vars
+                    var aaa = {} //eslint-disable-line no-redeclare -- no-unused-vars
+                `, { rules: { "no-redeclare": "error", "no-unused-vars": "error" } });
+
+                    // Do include `no-unused-vars` but not `no-redeclare`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endLine: 3,
+                            endColumn: 28,
+                            line: 3,
+                            message: "'aaa' is assigned a value but never used.",
+                            messageId: "unusedVar",
+                            nodeType: "Identifier",
+                            ruleId: "no-unused-vars",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '/*eslint-disable-line*/'.", () => {
+                    const messages = linter.verify(`
+                    var aaa = {} /*eslint-disable-line no-redeclare -- no-unused-vars */
+                    var aaa = {} /*eslint-disable-line no-redeclare -- no-unused-vars */
+                `, { rules: { "no-redeclare": "error", "no-unused-vars": "error" } });
+
+                    // Do include `no-unused-vars` but not `no-redeclare`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endLine: 3,
+                            endColumn: 28,
+                            line: 3,
+                            message: "'aaa' is assigned a value but never used.",
+                            messageId: "unusedVar",
+                            nodeType: "Identifier",
+                            ruleId: "no-unused-vars",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '//eslint-disable-next-line'.", () => {
+                    const messages = linter.verify(`
+                    //eslint-disable-next-line no-redeclare -- no-unused-vars
+                    var aaa = {}
+                    //eslint-disable-next-line no-redeclare -- no-unused-vars
+                    var aaa = {}
+                `, { rules: { "no-redeclare": "error", "no-unused-vars": "error" } });
+
+                    // Do include `no-unused-vars` but not `no-redeclare`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endLine: 5,
+                            endColumn: 28,
+                            line: 5,
+                            message: "'aaa' is assigned a value but never used.",
+                            messageId: "unusedVar",
+                            nodeType: "Identifier",
+                            ruleId: "no-unused-vars",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should ignore the part preceded by '--' in '/*eslint-disable-next-line*/'.", () => {
+                    const messages = linter.verify(`
+                    /*eslint-disable-next-line no-redeclare -- no-unused-vars */
+                    var aaa = {}
+                    /*eslint-disable-next-line no-redeclare -- no-unused-vars */
+                    var aaa = {}
+                `, { rules: { "no-redeclare": "error", "no-unused-vars": "error" } });
+
+                    // Do include `no-unused-vars` but not `no-redeclare`
+                    assert.deepStrictEqual(
+                        messages,
+                        [{
+                            column: 25,
+                            endLine: 5,
+                            endColumn: 28,
+                            line: 5,
+                            message: "'aaa' is assigned a value but never used.",
+                            messageId: "unusedVar",
+                            nodeType: "Identifier",
+                            ruleId: "no-unused-vars",
+                            severity: 2
+                        }]
+                    );
+                });
+
+                it("should not ignore the part preceded by '--' if the '--' is not surrounded by whitespaces.", () => {
+                    const rule = sinon.stub().returns({});
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    "a--rule": { create: rule }
+                                }
+                            }
+                        }
+                    };
+
+                    const messages = linter.verify(`
+                    /*eslint test/a--rule:error */
+                    console.log("hello")
+                `, config);
+
+                    // Don't include syntax error of the comment.
+                    assert.deepStrictEqual(messages, []);
+
+                    // Use `a--rule`.
+                    assert.strictEqual(rule.callCount, 1);
+                });
+
+                it("should ignore the part preceded by '--' even if the '--' is longer than 2.", () => {
+                    const aaa = sinon.stub().returns({});
+                    const bbb = sinon.stub().returns({});
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    aaa: { create: aaa },
+                                    bbb: { create: bbb }
+                                }
+                            }
+                        }
+                    };
+
+                    const messages = linter.verify(`
+                    /*eslint test/aaa:error -------- test/bbb:error */
+                    console.log("hello")
+                `, config);
+
+                    // Don't include syntax error of the comment.
+                    assert.deepStrictEqual(messages, []);
+
+                    // Use only `aaa`.
+                    assert.strictEqual(aaa.callCount, 1);
+                    assert.strictEqual(bbb.callCount, 0);
+                });
+
+                it("should ignore the part preceded by '--' with line breaks.", () => {
+                    const aaa = sinon.stub().returns({});
+                    const bbb = sinon.stub().returns({});
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {
+                                    aaa: { create: aaa },
+                                    bbb: { create: bbb }
+                                }
+                            }
+                        }
+                    };
+
+                    const messages = linter.verify(`
+                    /*eslint test/aaa:error
+                        --------
+                        test/bbb:error */
+                    console.log("hello")
+                `, config);
+
+                    // Don't include syntax error of the comment.
+                    assert.deepStrictEqual(messages, []);
+
+                    // Use only `aaa`.
+                    assert.strictEqual(aaa.callCount, 1);
+                    assert.strictEqual(bbb.callCount, 0);
+                });
+            });
+
+            describe("allowInlineConfig option", () => {
+                describe("when evaluating code with comments to change config when allowInlineConfig is enabled", () => {
+                    it("should report a violation for disabling rules", () => {
+                        const code = [
+                            "alert('test'); // eslint-disable-line no-alert"
+                        ].join("\n");
+                        const config = {
+                            rules: {
+                                "no-alert": 1
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, {
+                            filename,
+                            allowInlineConfig: false
+                        });
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                    });
+
+                    it("should report a violation for global variable declarations", () => {
+                        let ok = false;
+                        const code = [
+                            "/* global foo */"
+                        ].join("\n");
+                        const config = {
+                            plugins: {
+                                test: {
+                                    rules: {
+                                        test(context) {
+                                            return {
+                                                Program() {
+                                                    const scope = context.getScope();
+                                                    const sourceCode = context.getSourceCode();
+                                                    const comments = sourceCode.getAllComments();
+
+                                                    assert.strictEqual(1, comments.length);
+
+                                                    const foo = getVariable(scope, "foo");
+
+                                                    assert.notOk(foo);
+
+                                                    ok = true;
+                                                }
+                                            };
+                                        }
+                                    }
+                                }
+                            },
+                            rules: {
+                                "test/test": 2
+                            }
+                        };
+
+                        linter.verify(code, config, { allowInlineConfig: false });
+                        assert(ok);
+                    });
+
+                    it("should report a violation for eslint-disable", () => {
+                        const code = [
+                            "/* eslint-disable */",
+                            "alert('test');"
+                        ].join("\n");
+                        const config = {
+                            rules: {
+                                "no-alert": 1
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, {
+                            filename,
+                            allowInlineConfig: false
+                        });
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                    });
+
+                    it("should not report a violation for rule changes", () => {
+                        const code = [
+                            "/*eslint no-alert:2*/",
+                            "alert('test');"
+                        ].join("\n");
+                        const config = {
+                            rules: {
+                                "no-alert": 0
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, {
+                            filename,
+                            allowInlineConfig: false
+                        });
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+
+                    it("should report a violation for disable-line", () => {
+                        const code = [
+                            "alert('test'); // eslint-disable-line"
+                        ].join("\n");
+                        const config = {
+                            rules: {
+                                "no-alert": 2
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, {
+                            filename,
+                            allowInlineConfig: false
+                        });
+
+                        assert.strictEqual(messages.length, 1);
+                        assert.strictEqual(messages[0].ruleId, "no-alert");
+                    });
+
+                });
+
+                describe("when evaluating code with 'noInlineConfig'", () => {
+                    for (const directive of [
+                        "globals foo",
+                        "global foo",
+                        "exported foo",
+                        "eslint eqeqeq: error",
+                        "eslint-disable eqeqeq",
+                        "eslint-disable-line eqeqeq",
+                        "eslint-disable-next-line eqeqeq",
+                        "eslint-enable eqeqeq"
+                    ]) {
+                        // eslint-disable-next-line no-loop-func -- No closures
+                        it(`should warn '/* ${directive} */' if 'noInlineConfig' was given.`, () => {
+                            const messages = linter.verify(`/* ${directive} */`, {
+                                linterOptions: {
+                                    noInlineConfig: true
+                                }
+                            });
+
+                            assert.deepStrictEqual(messages.length, 1);
+                            assert.deepStrictEqual(messages[0].fatal, void 0);
+                            assert.deepStrictEqual(messages[0].ruleId, null);
+                            assert.deepStrictEqual(messages[0].severity, 1);
+                            assert.deepStrictEqual(messages[0].message, `'/*${directive.split(" ")[0]}*/' has no effect because you have 'noInlineConfig' setting in your config.`);
+                        });
+                    }
+
+                    for (const directive of [
+                        "eslint-disable-line eqeqeq",
+                        "eslint-disable-next-line eqeqeq"
+                    ]) {
+                        // eslint-disable-next-line no-loop-func -- No closures
+                        it(`should warn '// ${directive}' if 'noInlineConfig' was given.`, () => {
+                            const messages = linter.verify(`// ${directive}`, {
+                                linterOptions: {
+                                    noInlineConfig: true
+                                }
+                            });
+
+                            assert.deepStrictEqual(messages.length, 1);
+                            assert.deepStrictEqual(messages[0].fatal, void 0);
+                            assert.deepStrictEqual(messages[0].ruleId, null);
+                            assert.deepStrictEqual(messages[0].severity, 1);
+                            assert.deepStrictEqual(messages[0].message, `'//${directive.split(" ")[0]}' has no effect because you have 'noInlineConfig' setting in your config.`);
+                        });
+                    }
+
+                    it("should not warn if 'noInlineConfig' and '--no-inline-config' were given.", () => {
+                        const messages = linter.verify("/* globals foo */", {
+                            linterOptions: {
+                                noInlineConfig: true
+                            }
+                        }, { allowInlineConfig: false });
+
+                        assert.deepStrictEqual(messages.length, 0);
+                    });
+                });
+
+                describe("when evaluating code with comments to change config when allowInlineConfig is disabled", () => {
+                    it("should not report a violation", () => {
+                        const code = [
+                            "alert('test'); // eslint-disable-line no-alert"
+                        ].join("\n");
+                        const config = {
+                            rules: {
+                                "no-alert": 1
+                            }
+                        };
+
+                        const messages = linter.verify(code, config, {
+                            filename,
+                            allowInlineConfig: true
+                        });
+
+                        assert.strictEqual(messages.length, 0);
+                    });
+                });
+
+            });
+
+            describe("reportUnusedDisableDirectives option", () => {
+                it("reports problems for unused eslint-disable comments", () => {
+                    assert.deepStrictEqual(
+                        linter.verify("/* eslint-disable */", {}, { reportUnusedDisableDirectives: true }),
+                        [
+                            {
+                                ruleId: null,
+                                message: "Unused eslint-disable directive (no problems were reported).",
+                                line: 1,
+                                column: 1,
+                                fix: {
+                                    range: [0, 20],
+                                    text: " "
+                                },
+                                severity: 2,
+                                nodeType: null
+                            }
+                        ]
+                    );
+                });
+
+                it("reports problems for unused eslint-disable comments (error)", () => {
+                    assert.deepStrictEqual(
+                        linter.verify("/* eslint-disable */", {}, { reportUnusedDisableDirectives: "error" }),
+                        [
+                            {
+                                ruleId: null,
+                                message: "Unused eslint-disable directive (no problems were reported).",
+                                line: 1,
+                                column: 1,
+                                fix: {
+                                    range: [0, 20],
+                                    text: " "
+                                },
+                                severity: 2,
+                                nodeType: null
+                            }
+                        ]
+                    );
+                });
+
+                it("reports problems for unused eslint-disable comments (warn)", () => {
+                    assert.deepStrictEqual(
+                        linter.verify("/* eslint-disable */", {}, { reportUnusedDisableDirectives: "warn" }),
+                        [
+                            {
+                                ruleId: null,
+                                message: "Unused eslint-disable directive (no problems were reported).",
+                                line: 1,
+                                column: 1,
+                                fix: {
+                                    range: [0, 20],
+                                    text: " "
+                                },
+                                severity: 1,
+                                nodeType: null
+                            }
+                        ]
+                    );
+                });
+
+                it("reports problems for unused eslint-disable comments (in config)", () => {
+                    assert.deepStrictEqual(
+                        linter.verify("/* eslint-disable */", {
+                            linterOptions: {
+                                reportUnusedDisableDirectives: true
+                            }
+                        }),
+                        [
+                            {
+                                ruleId: null,
+                                message: "Unused eslint-disable directive (no problems were reported).",
+                                line: 1,
+                                column: 1,
+                                fix: {
+                                    range: [0, 20],
+                                    text: " "
+                                },
+                                severity: 1,
+                                nodeType: null
+                            }
+                        ]
+                    );
+                });
+
+                it("reports problems for partially unused eslint-disable comments (in config)", () => {
+                    const code = "alert('test'); // eslint-disable-line no-alert, no-redeclare";
+                    const config = {
+                        linterOptions: {
+                            reportUnusedDisableDirectives: true
+                        },
+                        rules: {
+                            "no-alert": 1,
+                            "no-redeclare": 1
+                        }
+                    };
+
+                    const messages = linter.verify(code, config, {
+                        filename,
+                        allowInlineConfig: true
+                    });
+
+                    assert.deepStrictEqual(
+                        messages,
+                        [
+                            {
+                                ruleId: null,
+                                message: "Unused eslint-disable directive (no problems were reported from 'no-redeclare').",
+                                line: 1,
+                                column: 16,
+                                fix: {
+                                    range: [46, 60],
+                                    text: ""
+                                },
+                                severity: 1,
+                                nodeType: null
+                            }
+                        ]
+                    );
+                });
+
+                describe("autofix", () => {
+                    const alwaysReportsRule = {
+                        create(context) {
+                            return {
+                                Program(node) {
+                                    context.report({ message: "bad code", loc: node.loc.end });
+                                }
+                            };
+                        }
+                    };
+
+                    const neverReportsRule = {
+                        create() {
+                            return {};
+                        }
+                    };
+
+                    const ruleCount = 3;
+                    const usedRules = Array.from(
+                        { length: ruleCount },
+                        (_, index) => `used${index ? `-${index}` : ""}` // "used", "used-1", "used-2"
+                    );
+                    const unusedRules = usedRules.map(name => `un${name}`); // "unused", "unused-1", "unused-2"
+
+                    const config = {
+                        plugins: {
+                            test: {
+                                rules: {}
+                            }
+                        },
+                        linterOptions: {
+                            reportUnusedDisableDirectives: true
+                        },
+                        rules: {
+                            ...Object.fromEntries(usedRules.map(name => [`test/${name}`, "error"])),
+                            ...Object.fromEntries(unusedRules.map(name => [`test/${name}`, "error"]))
+                        }
+                    };
+
+                    beforeEach(() => {
+                        config.plugins.test.rules = {
+                            ...Object.fromEntries(usedRules.map(name => [name, alwaysReportsRule])),
+                            ...Object.fromEntries(unusedRules.map(name => [name, neverReportsRule]))
+                        };
+                    });
+
+                    const tests = [
+
+                        //-----------------------------------------------
+                        // Removing the entire comment
+                        //-----------------------------------------------
+
+                        {
+                            code: "// eslint-disable-line test/unused",
+                            output: " "
+                        },
+                        {
+                            code: "foo// eslint-disable-line test/unused",
+                            output: "foo "
+                        },
+                        {
+                            code: "// eslint-disable-line ,test/unused,",
+                            output: " "
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused-1, test/unused-2",
+                            output: " "
+                        },
+                        {
+                            code: "// eslint-disable-line ,test/unused-1,, test/unused-2,, -- comment",
+                            output: " "
+                        },
+                        {
+                            code: "// eslint-disable-next-line test/unused\n",
+                            output: " \n"
+                        },
+                        {
+                            code: "// eslint-disable-next-line test/unused\nfoo",
+                            output: " \nfoo"
+                        },
+                        {
+                            code: "/* eslint-disable \ntest/unused\n*/",
+                            output: " "
+                        },
+
+                        //-----------------------------------------------
+                        // Removing only individual rules
+                        //-----------------------------------------------
+
+                        // content before the first rule should not be changed
+                        {
+                            code: "//eslint-disable-line test/unused, test/used",
+                            output: "//eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused, test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "//  eslint-disable-line test/unused, test/used",
+                            output: "//  eslint-disable-line test/used"
+                        },
+                        {
+                            code: "/*\neslint-disable test/unused, test/used*/",
+                            output: "/*\neslint-disable test/used*/"
+                        },
+                        {
+                            code: "/*\n eslint-disable test/unused, test/used*/",
+                            output: "/*\n eslint-disable test/used*/"
+                        },
+                        {
+                            code: "/*\r\neslint-disable test/unused, test/used*/",
+                            output: "/*\r\neslint-disable test/used*/"
+                        },
+                        {
+                            code: "/*\u2028eslint-disable test/unused, test/used*/",
+                            output: "/*\u2028eslint-disable test/used*/"
+                        },
+                        {
+                            code: "/*\u00A0eslint-disable test/unused, test/used*/",
+                            output: "/*\u00A0eslint-disable test/used*/"
+                        },
+                        {
+                            code: "// eslint-disable-line  test/unused, test/used",
+                            output: "// eslint-disable-line  test/used"
+                        },
+                        {
+                            code: "/* eslint-disable\ntest/unused, test/used*/",
+                            output: "/* eslint-disable\ntest/used*/"
+                        },
+                        {
+                            code: "/* eslint-disable\n test/unused, test/used*/",
+                            output: "/* eslint-disable\n test/used*/"
+                        },
+                        {
+                            code: "/* eslint-disable\r\ntest/unused, test/used*/",
+                            output: "/* eslint-disable\r\ntest/used*/"
+                        },
+                        {
+                            code: "/* eslint-disable\u2028test/unused, test/used*/",
+                            output: "/* eslint-disable\u2028test/used*/"
+                        },
+                        {
+                            code: "/* eslint-disable\u00A0test/unused, test/used*/",
+                            output: "/* eslint-disable\u00A0test/used*/"
+                        },
+
+                        // when removing the first rule, the comma and all whitespace up to the next rule (or next lone comma) should also be removed
+                        {
+                            code: "// eslint-disable-line test/unused,test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused, test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused , test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused,  test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused  ,test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "/* eslint-disable test/unused\n,\ntest/used */",
+                            output: "/* eslint-disable test/used */"
+                        },
+                        {
+                            code: "/* eslint-disable test/unused \n \n,\n\n test/used */",
+                            output: "/* eslint-disable test/used */"
+                        },
+                        {
+                            code: "/* eslint-disable test/unused\u2028,\u2028test/used */",
+                            output: "/* eslint-disable test/used */"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused\u00A0,\u00A0test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused,,test/used",
+                            output: "// eslint-disable-line ,test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused, ,test/used",
+                            output: "// eslint-disable-line ,test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused,, test/used",
+                            output: "// eslint-disable-line , test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused,test/used ",
+                            output: "// eslint-disable-line test/used "
+                        },
+                        {
+                            code: "// eslint-disable-next-line test/unused,test/used\n",
+                            output: "// eslint-disable-next-line test/used\n"
+                        },
+
+                        // when removing a rule in the middle, one comma and all whitespace between commas should also be removed
+                        {
+                            code: "// eslint-disable-line test/used-1,test/unused,test/used-2",
+                            output: "// eslint-disable-line test/used-1,test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1, test/unused,test/used-2",
+                            output: "// eslint-disable-line test/used-1,test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1,test/unused ,test/used-2",
+                            output: "// eslint-disable-line test/used-1,test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1,  test/unused  ,test/used-2",
+                            output: "// eslint-disable-line test/used-1,test/used-2"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1,\ntest/unused\n,test/used-2 */",
+                            output: "/* eslint-disable test/used-1,test/used-2 */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1,\n\n test/unused \n \n ,test/used-2 */",
+                            output: "/* eslint-disable test/used-1,test/used-2 */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1,\u2028test/unused\u2028,test/used-2 */",
+                            output: "/* eslint-disable test/used-1,test/used-2 */"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1,\u00A0test/unused\u00A0,test/used-2",
+                            output: "// eslint-disable-line test/used-1,test/used-2"
+                        },
+
+                        // when removing a rule in the middle, content around commas should not be changed
+                        {
+                            code: "// eslint-disable-line test/used-1, test/unused ,test/used-2",
+                            output: "// eslint-disable-line test/used-1,test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1,test/unused, test/used-2",
+                            output: "// eslint-disable-line test/used-1, test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1 ,test/unused,test/used-2",
+                            output: "// eslint-disable-line test/used-1 ,test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1 ,test/unused, test/used-2",
+                            output: "// eslint-disable-line test/used-1 , test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1  , test/unused ,  test/used-2",
+                            output: "// eslint-disable-line test/used-1  ,  test/used-2"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1\n,test/unused,\ntest/used-2 */",
+                            output: "/* eslint-disable test/used-1\n,\ntest/used-2 */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1\u2028,test/unused,\u2028test/used-2 */",
+                            output: "/* eslint-disable test/used-1\u2028,\u2028test/used-2 */"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1\u00A0,test/unused,\u00A0test/used-2",
+                            output: "// eslint-disable-line test/used-1\u00A0,\u00A0test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line , test/unused ,test/used",
+                            output: "// eslint-disable-line ,test/used"
+                        },
+                        {
+                            code: "/* eslint-disable\n, test/unused ,test/used */",
+                            output: "/* eslint-disable\n,test/used */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1,\n,test/unused,test/used-2 */",
+                            output: "/* eslint-disable test/used-1,\n,test/used-2 */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1,test/unused,\n,test/used-2 */",
+                            output: "/* eslint-disable test/used-1,\n,test/used-2 */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used-1,\n,test/unused,\n,test/used-2 */",
+                            output: "/* eslint-disable test/used-1,\n,\n,test/used-2 */"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used, test/unused,",
+                            output: "// eslint-disable-line test/used,"
+                        },
+                        {
+                            code: "// eslint-disable-next-line test/used, test/unused,\n",
+                            output: "// eslint-disable-next-line test/used,\n"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used, test/unused, ",
+                            output: "// eslint-disable-line test/used, "
+                        },
+                        {
+                            code: "// eslint-disable-line test/used, test/unused, -- comment",
+                            output: "// eslint-disable-line test/used, -- comment"
+                        },
+                        {
+                            code: "/* eslint-disable test/used, test/unused,\n*/",
+                            output: "/* eslint-disable test/used,\n*/"
+                        },
+
+                        // when removing the last rule, the comma and all whitespace up to the previous rule (or previous lone comma) should also be removed
+                        {
+                            code: "// eslint-disable-line test/used,test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used, test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used ,test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used , test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used,  test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used  ,test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "/* eslint-disable test/used\n,\ntest/unused */",
+                            output: "/* eslint-disable test/used */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used \n \n,\n\n test/unused */",
+                            output: "/* eslint-disable test/used */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used\u2028,\u2028test/unused */",
+                            output: "/* eslint-disable test/used */"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used\u00A0,\u00A0test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used,,test/unused",
+                            output: "// eslint-disable-line test/used,"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used, ,test/unused",
+                            output: "// eslint-disable-line test/used,"
+                        },
+                        {
+                            code: "/* eslint-disable test/used,\n,test/unused */",
+                            output: "/* eslint-disable test/used, */"
+                        },
+                        {
+                            code: "/* eslint-disable test/used\n, ,test/unused */",
+                            output: "/* eslint-disable test/used\n, */"
+                        },
+
+                        // content after the last rule should not be changed
+                        {
+                            code: "// eslint-disable-line test/used,test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used,test/unused ",
+                            output: "// eslint-disable-line test/used "
+                        },
+                        {
+                            code: "// eslint-disable-line test/used,test/unused  ",
+                            output: "// eslint-disable-line test/used  "
+                        },
+                        {
+                            code: "// eslint-disable-line test/used,test/unused -- comment",
+                            output: "// eslint-disable-line test/used -- comment"
+                        },
+                        {
+                            code: "// eslint-disable-next-line test/used,test/unused\n",
+                            output: "// eslint-disable-next-line test/used\n"
+                        },
+                        {
+                            code: "// eslint-disable-next-line test/used,test/unused \n",
+                            output: "// eslint-disable-next-line test/used \n"
+                        },
+                        {
+                            code: "/* eslint-disable test/used,test/unused\u2028*/",
+                            output: "/* eslint-disable test/used\u2028*/"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used,test/unused\u00A0",
+                            output: "// eslint-disable-line test/used\u00A0"
+                        },
+
+                        // multiply rules to remove
+                        {
+                            code: "// eslint-disable-line test/used, test/unused-1, test/unused-2",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused-1, test/used, test/unused-2",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused-1, test/unused-2, test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used-1, test/unused-1, test/used-2, test/unused-2",
+                            output: "// eslint-disable-line test/used-1, test/used-2"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused-1, test/used-1, test/unused-2, test/used-2",
+                            output: "// eslint-disable-line test/used-1, test/used-2"
+                        },
+                        {
+                            code: `
+                        /* eslint-disable test/unused-1,
+                           test/used-1,
+                           test/unused-2,
+                           test/used-2
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable test/used-1,
+                           test/used-2
+                        */
+                    `
+                        },
+                        {
+                            code: `
+                        /* eslint-disable
+                               test/unused-1,
+                               test/used-1,
+                               test/unused-2,
+                               test/used-2
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/used-2
+                        */
+                    `
+                        },
+                        {
+                            code: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/unused-1,
+                               test/used-2,
+                               test/unused-2
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/used-2
+                        */
+                    `
+                        },
+                        {
+                            code: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/unused-1,
+                               test/used-2,
+                               test/unused-2,
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/used-2,
+                        */
+                    `
+                        },
+                        {
+                            code: `
+                        /* eslint-disable
+                               ,test/unused-1
+                               ,test/used-1
+                               ,test/unused-2
+                               ,test/used-2
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable
+                               ,test/used-1
+                               ,test/used-2
+                        */
+                    `
+                        },
+                        {
+                            code: `
+                        /* eslint-disable
+                               ,test/used-1
+                               ,test/unused-1
+                               ,test/used-2
+                               ,test/unused-2
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable
+                               ,test/used-1
+                               ,test/used-2
+                        */
+                    `
+                        },
+                        {
+                            code: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/unused-1,
+                               test/used-2,
+                               test/unused-2
+
+                               -- comment
+                        */
+                    `,
+                            output: `
+                        /* eslint-disable
+                               test/used-1,
+                               test/used-2
+
+                               -- comment
+                        */
+                    `
+                        },
+
+                        // duplicates in the list
+                        {
+                            code: "// eslint-disable-line test/unused, test/unused, test/used",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/unused, test/used, test/unused",
+                            output: "// eslint-disable-line test/used"
+                        },
+                        {
+                            code: "// eslint-disable-line test/used, test/unused, test/unused, test/used",
+                            output: "// eslint-disable-line test/used, test/used"
+                        }
+                    ];
+
+                    for (const { code, output } of tests) {
+                        // eslint-disable-next-line no-loop-func -- `linter` is getting updated in beforeEach()
+                        it(code, () => {
+                            assert.strictEqual(
+                                linter.verifyAndFix(code, config).output,
+                                output
+                            );
+                        });
+                    }
+                });
+            });
+
+        });
+
+        describe("Default Global Variables", () => {
+            const code = "x";
+
+            it("builtin global variables should be available in the global scope", () => {
+                let spy;
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: context => {
+                                    spy = sinon.spy(() => {
+                                        const scope = context.getScope();
+
+                                        assert.notStrictEqual(getVariable(scope, "Object"), null);
+                                        assert.notStrictEqual(getVariable(scope, "Array"), null);
+                                        assert.notStrictEqual(getVariable(scope, "undefined"), null);
+                                    });
+
+                                    return { Program: spy };
+                                }
+                            }
+                        }
+                    },
+                    languageOptions: {
+                        ecmaVersion: 5,
+                        sourceType: "script"
+                    },
+                    rules: {
+                        "test/checker": "error"
+                    }
+                };
+
+                linter.verify(code, config);
+                assert(spy && spy.calledOnce, "Rule should have been called.");
+            });
+
+            it("ES6 global variables should be available by default", () => {
+                let spy;
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                checker: context => {
+                                    spy = sinon.spy(() => {
+                                        const scope = context.getScope();
+
+                                        assert.notStrictEqual(getVariable(scope, "Promise"), null);
+                                        assert.notStrictEqual(getVariable(scope, "Symbol"), null);
+                                        assert.notStrictEqual(getVariable(scope, "WeakMap"), null);
+                                    });
+
+                                    return { Program: spy };
+                                }
+                            }
+                        }
+                    },
+                    languageOptions: {
+                        sourceType: "script"
+                    },
+                    rules: {
+                        "test/checker": "error"
+                    }
+                };
+
+                linter.verify(code, config);
+                assert(spy && spy.calledOnce);
+            });
+
+        });
+
+        describe("Suggestions", () => {
+            it("provides suggestion information for tools to use", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                "rule-with-suggestions": {
+                                    meta: { hasSuggestions: true },
+                                    create: context => ({
+                                        Program(node) {
+                                            context.report({
+                                                node,
+                                                message: "Incorrect spacing",
+                                                suggest: [{
+                                                    desc: "Insert space at the beginning",
+                                                    fix: fixer => fixer.insertTextBefore(node, " ")
+                                                }, {
+                                                    desc: "Insert space at the end",
+                                                    fix: fixer => fixer.insertTextAfter(node, " ")
+                                                }]
+                                            });
+                                        }
+                                    })
+                                }
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/rule-with-suggestions": "error"
+                    }
+                };
+
+                const messages = linter.verify("var a = 1;", config);
+
+                assert.deepStrictEqual(messages[0].suggestions, [{
+                    desc: "Insert space at the beginning",
+                    fix: {
+                        range: [0, 0],
+                        text: " "
+                    }
+                }, {
+                    desc: "Insert space at the end",
+                    fix: {
+                        range: [10, 10],
+                        text: " "
+                    }
+                }]);
+            });
+
+            it("supports messageIds for suggestions", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                "rule-with-suggestions": {
+                                    meta: {
+                                        messages: {
+                                            suggestion1: "Insert space at the beginning",
+                                            suggestion2: "Insert space at the end"
+                                        },
+                                        hasSuggestions: true
+                                    },
+                                    create: context => ({
+                                        Program(node) {
+                                            context.report({
+                                                node,
+                                                message: "Incorrect spacing",
+                                                suggest: [{
+                                                    messageId: "suggestion1",
+                                                    fix: fixer => fixer.insertTextBefore(node, " ")
+                                                }, {
+                                                    messageId: "suggestion2",
+                                                    fix: fixer => fixer.insertTextAfter(node, " ")
+                                                }]
+                                            });
+                                        }
+                                    })
+                                }
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/rule-with-suggestions": "error"
+                    }
+                };
+
+                const messages = linter.verify("var a = 1;", config);
+
+                assert.deepStrictEqual(messages[0].suggestions, [{
+                    messageId: "suggestion1",
+                    desc: "Insert space at the beginning",
+                    fix: {
+                        range: [0, 0],
+                        text: " "
+                    }
+                }, {
+                    messageId: "suggestion2",
+                    desc: "Insert space at the end",
+                    fix: {
+                        range: [10, 10],
+                        text: " "
+                    }
+                }]);
+            });
+
+            it("should throw an error if suggestion is passed but `meta.hasSuggestions` property is not enabled", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                "rule-with-suggestions": {
+                                    meta: { docs: {}, schema: [] },
+                                    create: context => ({
+                                        Program(node) {
+                                            context.report({
+                                                node,
+                                                message: "hello world",
+                                                suggest: [{ desc: "convert to foo", fix: fixer => fixer.insertTextBefore(node, " ") }]
+                                            });
+                                        }
+                                    })
+                                }
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/rule-with-suggestions": "error"
+                    }
+                };
+
+                assert.throws(() => {
+                    linter.verify("0", config);
+                }, "Rules with suggestions must set the `meta.hasSuggestions` property to `true`.");
+            });
+
+            it("should throw an error if suggestion is passed but `meta.hasSuggestions` property is not enabled and the rule has the obsolete `meta.docs.suggestion` property", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                "rule-with-meta-docs-suggestion": {
+                                    meta: { docs: { suggestion: true }, schema: [] },
+                                    create: context => ({
+                                        Program(node) {
+                                            context.report({
+                                                node,
+                                                message: "hello world",
+                                                suggest: [{ desc: "convert to foo", fix: fixer => fixer.insertTextBefore(node, " ") }]
+                                            });
+                                        }
+                                    })
+                                }
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/rule-with-meta-docs-suggestion": "error"
+                    }
+                };
+
+                assert.throws(() => {
+                    linter.verify("0", config);
+                }, "Rules with suggestions must set the `meta.hasSuggestions` property to `true`. `meta.docs.suggestion` is ignored by ESLint.");
+            });
+        });
+
+
+        describe("Error Conditions", () => {
+            describe("when evaluating broken code", () => {
+                const code = BROKEN_TEST_CODE;
+
+                it("should report a violation with a useful parse error prefix", () => {
+                    const messages = linter.verify(code);
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].severity, 2);
+                    assert.isNull(messages[0].ruleId);
+                    assert.strictEqual(messages[0].line, 1);
+                    assert.strictEqual(messages[0].column, 4);
+                    assert.isTrue(messages[0].fatal);
+                    assert.match(messages[0].message, /^Parsing error:/u);
+                });
+
+                it("should report source code where the issue is present", () => {
+                    const inValidCode = [
+                        "var x = 20;",
+                        "if (x ==4 {",
+                        "    x++;",
+                        "}"
+                    ];
+                    const messages = linter.verify(inValidCode.join("\n"));
+
+                    assert.strictEqual(messages.length, 1);
+                    assert.strictEqual(messages[0].severity, 2);
+                    assert.isTrue(messages[0].fatal);
+                    assert.match(messages[0].message, /^Parsing error:/u);
+                });
+            });
+
+            describe("when using a rule which has been replaced", () => {
+                const code = TEST_CODE;
+
+                it("should report the new rule", () => {
+
+                    assert.throws(() => {
+                        linter.verify(code, { rules: { "no-comma-dangle": 2 } });
+                    }, /Key "rules": Key "no-comma-dangle": Rule "no-comma-dangle" was removed and replaced by "comma-dangle"/u);
+
+                });
+            });
+
+        });
+    });
+
+    describe("getSourceCode()", () => {
+        const code = TEST_CODE;
+
+        it("should retrieve SourceCode object after reset", () => {
+            linter.verify(code, {}, filename, true);
+
+            const sourceCode = linter.getSourceCode();
+
+            assert.isObject(sourceCode);
+            assert.strictEqual(sourceCode.text, code);
+            assert.isObject(sourceCode.ast);
+        });
+
+        it("should retrieve SourceCode object without reset", () => {
+            linter.verify(code, {}, filename);
+
+            const sourceCode = linter.getSourceCode();
+
+            assert.isObject(sourceCode);
+            assert.strictEqual(sourceCode.text, code);
+            assert.isObject(sourceCode.ast);
+        });
+
+    });
+
+    describe("defineRule()", () => {
+        it("should throw an error when called in flat config mode", () => {
+            assert.throws(() => {
+                linter.defineRule("foo", () => {});
+            }, /This method cannot be used with flat config/u);
+        });
+    });
+
+    describe("defineRules()", () => {
+        it("should throw an error when called in flat config mode", () => {
+            assert.throws(() => {
+                linter.defineRules({});
+            }, /This method cannot be used with flat config/u);
+        });
+    });
+
+    describe("defineParser()", () => {
+        it("should throw an error when called in flat config mode", () => {
+            assert.throws(() => {
+                linter.defineParser("foo", {});
+            }, /This method cannot be used with flat config/u);
+        });
+    });
+
+    describe("getRules()", () => {
+        it("should throw an error when called in flat config mode", () => {
+            assert.throws(() => {
+                linter.getRules();
+            }, /This method cannot be used with flat config/u);
+        });
+    });
+
+    describe("version", () => {
+        it("should return current version number", () => {
+            const version = linter.version;
+
+            assert.isString(version);
+            assert.isTrue(parseInt(version[0], 10) >= 3);
+        });
+    });
+
+    describe("verifyAndFix()", () => {
+        it("Fixes the code", () => {
+            const messages = linter.verifyAndFix("var a", {
+                rules: {
+                    semi: 2
+                }
+            }, { filename: "test.js" });
+
+            assert.strictEqual(messages.output, "var a;", "Fixes were applied correctly");
+            assert.isTrue(messages.fixed);
+        });
+
+        it("does not require a third argument", () => {
+            const fixResult = linter.verifyAndFix("var a", {
+                rules: {
+                    semi: 2
+                }
+            });
+
+            assert.deepStrictEqual(fixResult, {
+                fixed: true,
+                messages: [],
+                output: "var a;"
+            });
+        });
+
+        it("does not include suggestions in autofix results", () => {
+            const fixResult = linter.verifyAndFix("var foo = /\\#/", {
+                rules: {
+                    semi: 2,
+                    "no-useless-escape": 2
+                }
+            });
+
+            assert.strictEqual(fixResult.output, "var foo = /\\#/;");
+            assert.strictEqual(fixResult.fixed, true);
+            assert.strictEqual(fixResult.messages[0].suggestions.length > 0, true);
+        });
+
+        it("does not apply autofixes when fix argument is `false`", () => {
+            const fixResult = linter.verifyAndFix("var a", {
+                rules: {
+                    semi: 2
+                }
+            }, { fix: false });
+
+            assert.strictEqual(fixResult.fixed, false);
+        });
+
+        it("stops fixing after 10 passes", () => {
+
+            const config = {
+                plugins: {
+                    test: {
+                        rules: {
+                            "add-spaces": {
+                                meta: {
+                                    fixable: "whitespace"
+                                },
+                                create(context) {
+                                    return {
+                                        Program(node) {
+                                            context.report({
+                                                node,
+                                                message: "Add a space before this node.",
+                                                fix: fixer => fixer.insertTextBefore(node, " ")
+                                            });
+                                        }
+                                    };
+                                }
+                            }
+                        }
+                    }
+                },
+                rules: {
+                    "test/add-spaces": "error"
+                }
+            };
+
+            const fixResult = linter.verifyAndFix("a", config);
+
+            assert.strictEqual(fixResult.fixed, true);
+            assert.strictEqual(fixResult.output, `${" ".repeat(10)}a`);
+            assert.strictEqual(fixResult.messages.length, 1);
+        });
+
+        it("should throw an error if fix is passed but meta has no `fixable` property", () => {
+
+            const config = {
+                plugins: {
+                    test: {
+                        rules: {
+                            "test-rule": {
+                                meta: {
+                                    docs: {},
+                                    schema: []
+                                },
+                                create: context => ({
+                                    Program(node) {
+                                        context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
+                                    }
+                                })
+                            }
+                        }
+                    }
+                },
+                rules: {
+                    "test/test-rule": "error"
+                }
+            };
+
+
+            assert.throws(() => {
+                linter.verify("0", config);
+            }, /Fixable rules must set the `meta\.fixable` property to "code" or "whitespace".\nOccurred while linting <input>:1\nRule: "test\/test-rule"$/u);
+        });
+
+        it("should throw an error if fix is passed and there is no metadata", () => {
+
+            const config = {
+                plugins: {
+                    test: {
+                        rules: {
+                            "test-rule": {
+                                create: context => ({
+                                    Program(node) {
+                                        context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
+                                    }
+                                })
+                            }
+                        }
+                    }
+                },
+                rules: {
+                    "test/test-rule": "error"
+                }
+            };
+
+            assert.throws(() => {
+                linter.verify("0", config);
+            }, /Fixable rules must set the `meta\.fixable` property/u);
+        });
+
+        it("should throw an error if fix is passed from a legacy-format rule", () => {
+
+            const config = {
+                plugins: {
+                    test: {
+                        rules: {
+                            "test-rule": context => ({
+                                Program(node) {
+                                    context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
+                                }
+                            })
+                        }
+                    }
+                },
+                rules: {
+                    "test/test-rule": "error"
+                }
+            };
+
+
+            assert.throws(() => {
+                linter.verify("0", config);
+            }, /Fixable rules must set the `meta\.fixable` property/u);
+        });
+    });
+
+    describe("Mutability", () => {
+        let linter1 = null;
+        let linter2 = null;
+
+        beforeEach(() => {
+            linter1 = new Linter();
+            linter2 = new Linter();
+        });
+
+        describe("rules", () => {
+            it("with no changes, same rules are loaded", () => {
+                assert.sameDeepMembers(Array.from(linter1.getRules().keys()), Array.from(linter2.getRules().keys()));
+            });
+
+            it("loading rule in one doesn't change the other", () => {
+                linter1.defineRule("mock-rule", () => ({}));
+
+                assert.isTrue(linter1.getRules().has("mock-rule"), "mock rule is present");
+                assert.isFalse(linter2.getRules().has("mock-rule"), "mock rule is not present");
+            });
+        });
+    });
+
+
+    describe("processors", () => {
+        let receivedFilenames = [];
+        let receivedPhysicalFilenames = [];
+        const extraConfig = {
+            plugins: {
+                test: {
+                    rules: {
+                        "report-original-text": {
+                            meta: {
+
+                            },
+                            create(context) {
+                                return {
+                                    Program(ast) {
+                                        receivedFilenames.push(context.getFilename());
+                                        receivedPhysicalFilenames.push(context.getPhysicalFilename());
+                                        context.report({ node: ast, message: context.getSourceCode().text });
+                                    }
+                                };
+                            }
+                        }
+                    }
+                }
+            }
+        };
+
+        beforeEach(() => {
+            receivedFilenames = [];
+            receivedPhysicalFilenames = [];
+        });
+
+        describe("preprocessors", () => {
+            it("should receive text and filename.", () => {
+                const code = "foo bar baz";
+                const preprocess = sinon.spy(text => text.split(" "));
+                const configs = createFlatConfigArray({});
+
+                configs.normalizeSync();
+
+                linter.verify(code, configs, { filename, preprocess });
+
+                assert.strictEqual(preprocess.calledOnce, true, "preprocess wasn't called");
+                assert.deepStrictEqual(preprocess.args[0], [code, filename], "preprocess was called with the wrong arguments");
+            });
+
+            it("should run preprocess only once", () => {
+                const logs = [];
+                const config = {
+                    files: ["*.md"],
+                    processor: {
+                        preprocess(text, filenameForText) {
+                            logs.push({
+                                text,
+                                filename: filenameForText
+                            });
+
+                            return [{ text: "bar", filename: "0.js" }];
+                        },
+                        postprocess() {
+                            return [];
+                        }
+                    }
+                };
+
+                linter.verify("foo", config, "a.md");
+                assert.strictEqual(logs.length, 1, "preprocess() should only be called once.");
+            });
+
+            it("should apply a preprocessor to the code, and lint each code sample separately", () => {
+                const code = "foo bar baz";
+                const configs = createFlatConfigArray([
+                    extraConfig,
+                    { rules: { "test/report-original-text": "error" } }
+                ]);
+
+                configs.normalizeSync();
+
+                const problems = linter.verify(
+                    code,
+                    configs,
+                    {
+                        filename,
+
+                        // Apply a preprocessor that splits the source text into spaces and lints each word individually
+                        preprocess(input) {
+                            return input.split(" ");
+                        }
+                    }
+                );
+
+                assert.strictEqual(problems.length, 3);
+                assert.deepStrictEqual(problems.map(problem => problem.message), ["foo", "bar", "baz"]);
+            });
+
+            it("should apply a preprocessor to the code even if the preprocessor returned code block objects.", () => {
+                const code = "foo bar baz";
+                const configs = createFlatConfigArray([
+                    extraConfig,
+                    { rules: { "test/report-original-text": "error" } }
+                ]);
+
+                configs.normalizeSync();
+
+                const problems = linter.verify(
+                    code,
+                    configs,
+                    {
+                        filename,
+
+                        // Apply a preprocessor that splits the source text into spaces and lints each word individually
+                        preprocess(input) {
+                            return input.split(" ").map(text => ({
+                                filename: "block.js",
+                                text
+                            }));
+                        }
+                    }
+                );
+
+                assert.strictEqual(problems.length, 3);
+                assert.deepStrictEqual(problems.map(problem => problem.message), ["foo", "bar", "baz"]);
+
+                // filename
+                assert.strictEqual(receivedFilenames.length, 3);
+                assert(/^filename\.js[/\\]0_block\.js/u.test(receivedFilenames[0]));
+                assert(/^filename\.js[/\\]1_block\.js/u.test(receivedFilenames[1]));
+                assert(/^filename\.js[/\\]2_block\.js/u.test(receivedFilenames[2]));
+
+                // physical filename
+                assert.strictEqual(receivedPhysicalFilenames.length, 3);
+                assert.strictEqual(receivedPhysicalFilenames.every(name => name === filename), true);
+            });
+
+            it("should receive text even if a SourceCode object was given.", () => {
+                const code = "foo";
+                const preprocess = sinon.spy(text => text.split(" "));
+                const configs = createFlatConfigArray([
+                    extraConfig
+                ]);
+
+                configs.normalizeSync();
+
+                linter.verify(code, configs);
+                const sourceCode = linter.getSourceCode();
+
+                linter.verify(sourceCode, configs, { filename, preprocess });
+
+                assert.strictEqual(preprocess.calledOnce, true);
+                assert.deepStrictEqual(preprocess.args[0], [code, filename]);
+            });
+
+            it("should receive text even if a SourceCode object was given (with BOM).", () => {
+                const code = "\uFEFFfoo";
+                const preprocess = sinon.spy(text => text.split(" "));
+                const configs = createFlatConfigArray([
+                    extraConfig
+                ]);
+
+                configs.normalizeSync();
+
+                linter.verify(code, configs);
+                const sourceCode = linter.getSourceCode();
+
+                linter.verify(sourceCode, configs, { filename, preprocess });
+
+                assert.strictEqual(preprocess.calledOnce, true);
+                assert.deepStrictEqual(preprocess.args[0], [code, filename]);
+            });
+        });
+
+        describe("postprocessors", () => {
+            it("should receive result and filename.", () => {
+                const code = "foo bar baz";
+                const preprocess = sinon.spy(text => text.split(" "));
+                const postprocess = sinon.spy(text => [text]);
+                const configs = createFlatConfigArray([
+                    extraConfig
+                ]);
+
+                configs.normalizeSync();
+
+                linter.verify(code, configs, { filename, postprocess, preprocess });
+
+                assert.strictEqual(postprocess.calledOnce, true);
+                assert.deepStrictEqual(postprocess.args[0], [[[], [], []], filename]);
+            });
+
+            it("should apply a postprocessor to the reported messages", () => {
+                const code = "foo bar baz";
+                const configs = createFlatConfigArray([
+                    extraConfig,
+                    { rules: { "test/report-original-text": "error" } }
+                ]);
+
+                configs.normalizeSync();
+
+                const problems = linter.verify(
+                    code,
+                    configs,
+                    {
+                        preprocess: input => input.split(" "),
+
+                        /*
+                         * Apply a postprocessor that updates the locations of the reported problems
+                         * to make sure they correspond to the locations in the original text.
+                         */
+                        postprocess(problemLists) {
+                            problemLists.forEach(problemList => assert.strictEqual(problemList.length, 1));
+                            return problemLists.reduce(
+                                (combinedList, problemList, index) =>
+                                    combinedList.concat(
+                                        problemList.map(
+                                            problem =>
+                                                Object.assign(
+                                                    {},
+                                                    problem,
+                                                    {
+                                                        message: problem.message.toUpperCase(),
+                                                        column: problem.column + index * 4
+                                                    }
+                                                )
+                                        )
+                                    ),
+                                []
+                            );
+                        }
+                    }
+                );
+
+                assert.strictEqual(problems.length, 3);
+                assert.deepStrictEqual(problems.map(problem => problem.message), ["FOO", "BAR", "BAZ"]);
+                assert.deepStrictEqual(problems.map(problem => problem.column), [1, 5, 9]);
+            });
+
+            it("should use postprocessed problem ranges when applying autofixes", () => {
+                const code = "foo bar baz";
+                const configs = createFlatConfigArray([
+                    extraConfig,
+                    {
+                        plugins: {
+                            test2: {
+                                rules: {
+                                    "capitalize-identifiers": {
+                                        meta: {
+                                            fixable: "code"
+                                        },
+                                        create(context) {
+                                            return {
+                                                Identifier(node) {
+                                                    if (node.name !== node.name.toUpperCase()) {
+                                                        context.report({
+                                                            node,
+                                                            message: "Capitalize this identifier",
+                                                            fix: fixer => fixer.replaceText(node, node.name.toUpperCase())
+                                                        });
+                                                    }
+                                                }
+                                            };
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    },
+                    { rules: { "test2/capitalize-identifiers": "error" } }
+                ]);
+
+                configs.normalizeSync();
+
+                const fixResult = linter.verifyAndFix(
+                    code,
+                    configs,
+                    {
+
+                        /*
+                         * Apply a postprocessor that updates the locations of autofixes
+                         * to make sure they correspond to locations in the original text.
+                         */
+                        preprocess: input => input.split(" "),
+                        postprocess(problemLists) {
+                            return problemLists.reduce(
+                                (combinedProblems, problemList, blockIndex) =>
+                                    combinedProblems.concat(
+                                        problemList.map(problem =>
+                                            Object.assign(problem, {
+                                                fix: {
+                                                    text: problem.fix.text,
+                                                    range: problem.fix.range.map(
+                                                        rangeIndex => rangeIndex + blockIndex * 4
+                                                    )
+                                                }
+                                            }))
+                                    ),
+                                []
+                            );
+                        }
+                    }
+                );
+
+                assert.strictEqual(fixResult.fixed, true);
+                assert.strictEqual(fixResult.messages.length, 0);
+                assert.strictEqual(fixResult.output, "FOO BAR BAZ");
+            });
+        });
+    });
+
+    describe("Edge cases", () => {
+
+        describe("Modules", () => {
+            const moduleConfig = {
+                languageOptions: {
+                    sourceType: "module",
+                    ecmaVersion: 6
+                }
+            };
+
+            it("should properly parse import statements when sourceType is module", () => {
+                const code = "import foo from 'foo';";
+                const messages = linter.verify(code, moduleConfig);
+
+                assert.strictEqual(messages.length, 0, "Unexpected linting error.");
+            });
+
+            it("should properly parse import all statements when sourceType is module", () => {
+                const code = "import * as foo from 'foo';";
+                const messages = linter.verify(code, moduleConfig);
+
+                assert.strictEqual(messages.length, 0, "Unexpected linting error.");
+            });
+
+            it("should properly parse default export statements when sourceType is module", () => {
+                const code = "export default function initialize() {}";
+                const messages = linter.verify(code, moduleConfig);
+
+                assert.strictEqual(messages.length, 0, "Unexpected linting error.");
+            });
+
+        });
+
+
+        // https://github.com/eslint/eslint/issues/9687
+        it("should report an error when invalid languageOptions found", () => {
+            let messages = linter.verify("", { languageOptions: { ecmaVersion: 222 } });
+
+            assert.deepStrictEqual(messages.length, 1);
+            assert.ok(messages[0].message.includes("Invalid ecmaVersion"));
+
+            assert.throws(() => {
+                linter.verify("", { languageOptions: { sourceType: "foo" } });
+            }, /Expected "script", "module", or "commonjs"./u);
+
+
+            messages = linter.verify("", { languageOptions: { ecmaVersion: 5, sourceType: "module" } });
+
+            assert.deepStrictEqual(messages.length, 1);
+            assert.ok(messages[0].message.includes("sourceType 'module' is not supported when ecmaVersion < 2015"));
+        });
+
+        it("should not crash when invalid parentheses syntax is encountered", () => {
+            linter.verify("left = (aSize.width/2) - ()");
+        });
+
+        it("should not crash when let is used inside of switch case", () => {
+            linter.verify("switch(foo) { case 1: let bar=2; }", { languageOptions: { ecmaVersion: 6 } });
+        });
+
+        it("should not crash when parsing destructured assignment", () => {
+            linter.verify("var { a='a' } = {};", { languageOptions: { ecmaVersion: 6 } });
+        });
+
+        it("should report syntax error when a keyword exists in object property shorthand", () => {
+            const messages = linter.verify("let a = {this}", { languageOptions: { ecmaVersion: 6 } });
+
+            assert.strictEqual(messages.length, 1);
+            assert.strictEqual(messages[0].fatal, true);
+        });
+
+        it("should not crash when we reuse the SourceCode object", () => {
+            const config = {
+                languageOptions: {
+                    ecmaVersion: 6,
+                    parserOptions: {
+                        ecmaFeatures: { jsx: true }
+                    }
+                }
+            };
+
+            linter.verify("function render() { return <div className='test'>{hello}</div> }", config);
+            linter.verify(linter.getSourceCode(), config);
+        });
+
+        it("should reuse the SourceCode object", () => {
+            let ast1 = null,
+                ast2 = null;
+
+            const config = {
+                plugins: {
+                    test: {
+                        rules: {
+                            "save-ast1": () => ({
+                                Program(node) {
+                                    ast1 = node;
+                                }
+                            }),
+
+                            "save-ast2": () => ({
+                                Program(node) {
+                                    ast2 = node;
+                                }
+                            })
+
+                        }
+                    }
+                },
+                languageOptions: {
+                    ecmaVersion: 6,
+                    parserOptions: {
+                        ecmaFeatures: { jsx: true }
+                    }
+                }
+            };
+
+
+            linter.verify("function render() { return <div className='test'>{hello}</div> }", { ...config, rules: { "test/save-ast1": "error" } });
+            linter.verify(linter.getSourceCode(), { ...config, rules: { "test/save-ast2": "error" } });
+
+            assert(ast1 !== null);
+            assert(ast2 !== null);
+            assert(ast1 === ast2);
+        });
+
+        it("should not modify config object passed as argument", () => {
+            const config = {};
+
+            Object.freeze(config);
+            linter.verify("var", config);
+        });
+
+        it("should pass 'id' to rule contexts with the rule id", () => {
+
+            const spy = sinon.spy(context => {
+                assert.strictEqual(context.id, "test/foo-bar-baz");
+                return {};
+            });
+
+            const config = {
+                plugins: {
+                    test: {
+                        rules: {
+                            "foo-bar-baz": spy
+                        }
+                    }
+                },
+                rules: {
+                    "test/foo-bar-baz": "error"
+                }
+            };
+
+
+            linter.verify("x", config);
+            assert(spy.calledOnce);
+        });
+
+
+        describe("when evaluating an empty string", () => {
+            it("runs rules", () => {
+
+                const config = {
+                    plugins: {
+                        test: {
+                            rules: {
+                                "no-programs": context => ({
+                                    Program(node) {
+                                        context.report({ node, message: "No programs allowed." });
+                                    }
+                                })
+                            }
+                        }
+                    },
+                    rules: {
+                        "test/no-programs": "error"
+                    }
+                };
+
+                assert.strictEqual(
+                    linter.verify("", config).length,
+                    1
+                );
+            });
+        });
+
+    });
+
+});
index 6ebd82fb5ab283842b4ba8d2a102f4bc4197bb67..5018a037b09f6da0144c067c979930a22fe49332 100644 (file)
@@ -1042,6 +1042,7 @@ describe("RuleTester", () => {
         });
         assert.strictEqual(spy.args[1][1].parser, require.resolve("esprima"));
     });
+
     it("should pass normalized ecmaVersion to the rule", () => {
         const reportEcmaVersionRule = {
             meta: {
@@ -1169,6 +1170,8 @@ describe("RuleTester", () => {
                     parserOptions: { ecmaVersion: "latest" },
                     env: { es2020: true }
                 },
+
+                // Non-Espree parsers normalize ecmaVersion if it's not "latest"
                 {
                     code: "",
                     errors: [{ messageId: "ecmaVersionMessage", data: { type: "undefined", ecmaVersion: "undefined" } }],
@@ -1194,7 +1197,7 @@ describe("RuleTester", () => {
                 },
                 {
                     code: "",
-                    errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: "6" } }],
+                    errors: [{ messageId: "ecmaVersionMessage", data: { type: "number", ecmaVersion: 6 } }],
                     parser: notEspree,
                     parserOptions: { ecmaVersion: 2015 }
                 },
index ba01206f4a3549bfd1b518b04d3789119b9dd41b..74acab2af2e78e647d8fbcfa3d5e4797363942f8 100644 (file)
@@ -199,7 +199,14 @@ if ( x === y ) {
             code: "function name() {\n}",
             options: [1],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 2, maxLines: 1 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 1 },
+                    line: 2,
+                    column: 1,
+                    endLine: 2,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -208,7 +215,14 @@ if ( x === y ) {
             code: "var func = function() {\n}",
             options: [1],
             errors: [
-                { messageId: "exceed", data: { name: "Function", lineCount: 2, maxLines: 1 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function", linesExceed: 1, maxLines: 1 },
+                    line: 2,
+                    column: 1,
+                    endLine: 2,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -217,7 +231,14 @@ if ( x === y ) {
             code: "const bar = () => {\nconst x = 2 + 1;\nreturn x;\n}",
             options: [3],
             errors: [
-                { messageId: "exceed", data: { name: "Arrow function", lineCount: 4, maxLines: 3 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Arrow function", linesExceed: 1, maxLines: 3 },
+                    line: 4,
+                    column: 1,
+                    endLine: 4,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -226,7 +247,14 @@ if ( x === y ) {
             code: "const bar = () =>\n 2",
             options: [1],
             errors: [
-                { messageId: "exceed", data: { name: "Arrow function", lineCount: 2, maxLines: 1 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Arrow function", linesExceed: 1, maxLines: 1 },
+                    line: 2,
+                    column: 1,
+                    endLine: 2,
+                    endColumn: 3
+                }
             ]
         },
 
@@ -235,7 +263,14 @@ if ( x === y ) {
             code: `() => {${"foo\n".repeat(60)}}`,
             options: [{}],
             errors: [
-                { messageId: "exceed", data: { name: "Arrow function", lineCount: 61, maxLines: 50 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Arrow function", linesExceed: 11, maxLines: 50 },
+                    line: 51,
+                    column: 1,
+                    endLine: 61,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -244,7 +279,14 @@ if ( x === y ) {
             code: "function name() {\nvar x = 5;\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 6, skipComments: false, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 7, maxLines: 6 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 6 },
+                    line: 7,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -253,7 +295,14 @@ if ( x === y ) {
             code: "function name() {\r\nvar x = 5;\r\n\t\r\n \r\n\r\nvar x = 2;\r\n}",
             options: [{ max: 6, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 7, maxLines: 6 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 6 },
+                    line: 7,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -262,7 +311,14 @@ if ( x === y ) {
             code: "function name() {\nvar x = 5;\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 2, skipComments: true, skipBlankLines: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 4, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 2, maxLines: 2 },
+                    line: 6,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -271,7 +327,14 @@ if ( x === y ) {
             code: "function name() {\r\nvar x = 5;\r\n\t\r\n \r\n\r\nvar x = 2;\r\n}",
             options: [{ max: 2, skipComments: true, skipBlankLines: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 4, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 2, maxLines: 2 },
+                    line: 6,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -280,7 +343,14 @@ if ( x === y ) {
             code: "function name() { // end of line comment\nvar x = 5; /* mid line comment */\n\t// single line comment taking up whole line\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 6, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 7, maxLines: 6 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 1, maxLines: 6 },
+                    line: 8,
+                    column: 1,
+                    endLine: 8,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -289,7 +359,14 @@ if ( x === y ) {
             code: "function name() { // end of line comment\nvar x = 5; /* mid line comment */\n\t// single line comment taking up whole line\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 1, skipComments: true, skipBlankLines: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 4, maxLines: 1 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 3, maxLines: 1 },
+                    line: 2,
+                    column: 1,
+                    endLine: 8,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -298,7 +375,14 @@ if ( x === y ) {
             code: "function name() { // end of line comment\nvar x = 5; /* mid line comment */\n\t// single line comment taking up whole line\n\t\n \n\nvar x = 2;\n}",
             options: [{ max: 1, skipComments: false, skipBlankLines: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'name'", lineCount: 5, maxLines: 1 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 4, maxLines: 1 },
+                    line: 2,
+                    column: 1,
+                    endLine: 8,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -313,7 +397,14 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'foo'", lineCount: 7, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'foo'", linesExceed: 5, maxLines: 2 },
+                    line: 3,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -328,7 +419,14 @@ function
 ()`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false, IIFEs: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Function", lineCount: 4, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function", linesExceed: 2, maxLines: 2 },
+                    line: 4,
+                    column: 1,
+                    endLine: 5,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -346,7 +444,14 @@ if ( x === y ) {
 }`,
             options: [{ max: 9, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'parent'", lineCount: 10, maxLines: 9 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'parent'", linesExceed: 1, maxLines: 9 },
+                    line: 10,
+                    column: 1,
+                    endLine: 10,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -364,8 +469,22 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Function 'parent'", lineCount: 10, maxLines: 2 } },
-                { messageId: "exceed", data: { name: "Function 'nested'", lineCount: 4, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'parent'", linesExceed: 8, maxLines: 2 },
+                    line: 3,
+                    column: 1,
+                    endLine: 10,
+                    endColumn: 2
+                },
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'nested'", linesExceed: 2, maxLines: 2 },
+                    line: 5,
+                    column: 1,
+                    endLine: 6,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -380,7 +499,14 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Method 'method'", lineCount: 5, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Method 'method'", linesExceed: 3, maxLines: 2 },
+                    line: 4,
+                    column: 1,
+                    endLine: 6,
+                    endColumn: 6
+                }
             ]
         },
 
@@ -395,7 +521,14 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Static method 'foo'", lineCount: 5, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Static method 'foo'", linesExceed: 3, maxLines: 2 },
+                    line: 4,
+                    column: 1,
+                    endLine: 6,
+                    endColumn: 6
+                }
             ]
         },
 
@@ -408,9 +541,16 @@ if ( x === y ) {
         return 1
     }
 }`,
-            options: [{ max: 2, skipComments: true, skipBlankLines: false }],
+            options: [{ max: 4, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Getter 'foo'", lineCount: 5, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Getter 'foo'", linesExceed: 1, maxLines: 4 },
+                    line: 6,
+                    column: 1,
+                    endLine: 6,
+                    endColumn: 6
+                }
             ]
         },
 
@@ -425,7 +565,14 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Setter 'foo'", lineCount: 5, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Setter 'foo'", linesExceed: 3, maxLines: 2 },
+                    line: 4,
+                    column: 1,
+                    endLine: 6,
+                    endColumn: 6
+                }
             ]
         },
 
@@ -443,7 +590,14 @@ if ( x === y ) {
 }`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false }],
             errors: [
-                { messageId: "exceed", data: { name: "Static method", lineCount: 8, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Static method", linesExceed: 6, maxLines: 2 },
+                    line: 4,
+                    column: 1,
+                    endLine: 9,
+                    endColumn: 6
+                }
             ]
         },
 
@@ -458,7 +612,14 @@ if ( x === y ) {
 }());`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false, IIFEs: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Function", lineCount: 7, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Function", linesExceed: 5, maxLines: 2 },
+                    line: 3,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
             ]
         },
 
@@ -473,7 +634,28 @@ if ( x === y ) {
 })();`,
             options: [{ max: 2, skipComments: true, skipBlankLines: false, IIFEs: true }],
             errors: [
-                { messageId: "exceed", data: { name: "Arrow function", lineCount: 7, maxLines: 2 } }
+                {
+                    messageId: "exceed",
+                    data: { name: "Arrow function", linesExceed: 5, maxLines: 2 },
+                    line: 3,
+                    column: 1,
+                    endLine: 7,
+                    endColumn: 2
+                }
+            ]
+        },
+        {
+            code: "\nfoo();\nbar();\nbaz();\nfunction name() {\nvar x = 5;\n/* comment 1 */\n/* comment 2 */\n\t\n \n\nvar x = 2;\n}\nquz();",
+            options: [{ max: 2, skipComments: true, skipBlankLines: true }],
+            errors: [
+                {
+                    messageId: "exceed",
+                    data: { name: "Function 'name'", linesExceed: 2, maxLines: 2 },
+                    line: 12,
+                    column: 1,
+                    endLine: 13,
+                    endColumn: 2
+                }
             ]
         }
     ]
index ecb6de534260d41e3e2e445ad3736635704a25b9..0b5f3c5a1dc9294bc5f479c205d73ca0b56129ca 100644 (file)
@@ -174,7 +174,8 @@ ruleTester.run("no-constant-condition", rule, {
         "function* foo() {for (; ; yield) {}}",
         "function* foo() {while (true) {function* foo() {yield;}yield;}}",
         "function* foo() { for (let x = yield; x < 10; x++) {yield;}yield;}",
-        "function* foo() { for (let x = yield; ; x++) { yield; }}"
+        "function* foo() { for (let x = yield; ; x++) { yield; }}",
+        "if (new Number(x) + 1 === 2) {}"
     ],
     invalid: [
         { code: "for(;true;);", errors: [{ messageId: "unexpected", type: "Literal" }] },
@@ -387,6 +388,16 @@ ruleTester.run("no-constant-condition", rule, {
         { code: "if(0b1n);", parserOptions: { ecmaVersion: 11 }, errors: [{ messageId: "unexpected", type: "Literal" }] },
         { code: "if(0o1n);", parserOptions: { ecmaVersion: 11 }, errors: [{ messageId: "unexpected", type: "Literal" }] },
         { code: "if(0x1n);", parserOptions: { ecmaVersion: 11 }, errors: [{ messageId: "unexpected", type: "Literal" }] },
-        { code: "if(0x1n || foo);", parserOptions: { ecmaVersion: 11 }, errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }
+        { code: "if(0x1n || foo);", parserOptions: { ecmaVersion: 11 }, errors: [{ messageId: "unexpected", type: "LogicalExpression" }] },
+
+        // Classes and instances are always truthy
+        { code: "if(class {}) {}", errors: [{ messageId: "unexpected" }] },
+        { code: "if(new Foo()) {}", errors: [{ messageId: "unexpected" }] },
+
+        // Boxed primitives are always truthy
+        { code: "if(new Boolean(foo)) {}", errors: [{ messageId: "unexpected" }] },
+        { code: "if(new String(foo)) {}", errors: [{ messageId: "unexpected" }] },
+        { code: "if(new Number(foo)) {}", errors: [{ messageId: "unexpected" }] }
+
     ]
 });
index 55efb6f2c521a0f43c488083902f2c6dadbb9193..0704ceff13720afec9574171d32f141ef4af1a82 100644 (file)
@@ -123,5 +123,8 @@ let newReadme = readme.replace(/<!--teamstart-->[\w\W]*?<!--teamend-->/u, ejs.re
 
 newReadme = newReadme.replace(/<!--sponsorsstart-->[\w\W]*?<!--sponsorsend-->/u, formatSponsors(allSponsors));
 
+// replace multiple consecutive blank lines with just one blank line
+newReadme = newReadme.replace(/(?<=^|\n)\n{2,}/gu, "\n");
+
 // output to the file
 fs.writeFileSync(README_FILE_PATH, newReadme, "utf8");