SRCDIR=src
UPSTREAM=eslint
-UPSTREAMTAG=v8.23.1
+UPSTREAMTAG=v8.41.0
BUILDSRC=${UPSTREAM}-${UPSTREAMTAG}
all: ${DEB}
/build/**
/coverage/**
-/docs/**
-!/docs/.eleventy.js
+/docs/*
+!/docs/*.js
+!/docs/tools/
/jsdoc/**
/templates/**
/tests/bench/**
},
overrides: [
{
- files: ["tools/*.js"],
+ files: ["tools/*.js", "docs/tools/*.js"],
rules: {
- "no-console": "off"
+ "no-console": "off",
+ "n/no-process-exit": "off"
}
},
{
"eslint-plugin/prefer-placeholders": "error",
"eslint-plugin/prefer-replace-text": "error",
"eslint-plugin/report-message-format": ["error", "[^a-z].*\\.$"],
- "eslint-plugin/require-meta-docs-description": ["error", { pattern: "^(Enforce|Require|Disallow)" }],
+ "eslint-plugin/require-meta-docs-description": ["error", { pattern: "^(Enforce|Require|Disallow) .+[^. ]$" }],
"internal-rules/no-invalid-meta": "error"
}
},
files: ["lib/rules/*"],
excludedFiles: ["index.js"],
rules: {
- "eslint-plugin/require-meta-docs-url": ["error", { pattern: "https://eslint.org/docs/rules/{{name}}" }]
+ "eslint-plugin/require-meta-docs-url": ["error", { pattern: "https://eslint.org/docs/latest/rules/{{name}}" }]
}
},
{
--- /dev/null
+/docs/ @eslint/website-team @eslint/eslint-team
+* @eslint/eslint-team
\ No newline at end of file
+++ /dev/null
-# Config-related files
-
-lib/conf/config-schema.js @nzakas
-lib/cli-engine/config-array/* @nzakas
-lib/cli-engine/config-array-factory.js @nzakas
-lib/cli-engine/cascading-config-array-factory.js @nzakas
-lib/shared/config-* @nzakas
-lib/shared/naming.js @nzakas
-lib/shared/relative-module-resolver.js @nzakas
-
-tests/lib/conf/config-schema.js @nzakas
-tests/lib/cli-engine/config-array/* @nzakas
-tests/lib/cli-engine/config-array-factory.js @nzakas
-tests/lib/cli-engine/cascading-config-array-factory.js @nzakas
-tests/lib/shared/config-* @nzakas
-tests/lib/shared/naming.js @nzakas
-tests/lib/shared/relative-module-resolver.js @nzakas
Please copy-paste the actual ESLint output. You can use Markdown in this field.
validations:
required: true
+- type: input
+ attributes:
+ label: Link to Minimal Reproducible Example
+ description: 'Link to a [playground](https://eslint.org/play), [StackBlitz](https://stackblitz.com), or GitHub repo with a minimal reproduction of the problem. **A minimal reproduction is required** so that others can help debug your issue. If a report is vague (e.g. just a generic error message) and has no reproduction, it may be auto-closed.'
+ placeholder: 'https://stackblitz.com/abcd1234'
+ validations:
+ required: true
- type: checkboxes
attributes:
label: Participation
title: "Change Request: (fill in)"
labels:
- enhancement
- - triage
- core
body:
- type: markdown
- name: 🗣 Ask a Question, Discuss
url: https://github.com/eslint/eslint/discussions
about: Get help using ESLint
+ - name: 📝 Help with VS Code ESLint
+ url: https://github.com/microsoft/vscode-eslint/issues/
+ about: Bugs and feature requests for the VS Code ESLint plugin
+ - name: Discord Server
+ url: https://eslint.org/chat
+ about: Talk with the team
<!--
Please ensure your pull request is ready:
- - Read the pull request guide (https://eslint.org/docs/developer-guide/contributing/pull-requests)
+ - Read the pull request guide (https://eslint.org/docs/latest/contribute/pull-requests)
- Include tests for this change
- Update documentation for this change (if appropriate)
-->
directory: "/"
schedule:
interval: "weekly"
+ commit-message:
+ prefix: "ci"
--- /dev/null
+name: Add to Triage
+
+on:
+ issues:
+ types:
+ - opened
+
+jobs:
+ add-to-project:
+ name: Add issue to project
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/add-to-project@v0.5.0
+ with:
+ project-url: https://github.com/orgs/eslint/projects/3
+ github-token: ${{ secrets.PROJECT_BOT_TOKEN }}
+ labeled: "triage:no"
+ label-operator: NOT
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
- node-version: '16.x'
+ node-version: 'lts/*'
- name: Install Packages
run: npm install
- name: Lint Files
- name: Install Docs Packages
working-directory: docs
run: npm install
+ - name: Stylelint Docs
+ working-directory: docs
+ run: npm run lint:scss
- name: Lint Docs JS Files
run: node Makefile lintDocsJS
+ - name: Build Docs Website
+ working-directory: docs
+ run: npm run build
+ - name: Validate internal links
+ working-directory: docs
+ run: npm run lint:links
test_on_node:
name: Test
strategy:
matrix:
os: [ubuntu-latest]
- node: [18.x, 17.x, 16.x, 14.x, 12.x, "12.22.0"]
+ node: [20.x, 19.x, 18.x, 17.x, 16.x, 14.x, 12.x, "12.22.0"]
include:
- os: windows-latest
- node: "16.x"
+ node: "lts/*"
- os: macOS-latest
- node: "16.x"
+ node: "lts/*"
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
pull-requests: write
steps:
- - uses: actions/stale@v5
+ - uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- days-before-stale: 60
+ days-before-issue-stale: 30
+ days-before-pr-stale: 10
days-before-close: 7
stale-issue-message: 'Oops! It looks like we lost track of this issue. What do we want to do here? This issue will auto-close in 7 days without an update.'
- stale-pr-message: 'Oops! It looks like we lost track of this pull request. What do we want to do here? This pull request will auto-close in 7 days without an update.'
+ close-issue-message: 'This issue was auto-closed due to inactivity. While we wish we could keep responding to every issue, we unfortunately don''t have the bandwidth and need to focus on high-value issues.'
+ stale-pr-message: 'Hi everyone, it looks like we lost track of this pull request. Please review and see what the next steps are. This pull request will auto-close in 7 days without an update.'
+ close-pr-message: 'This pull request was auto-closed due to inactivity. While we wish we could keep working on every request, we unfortunately don''t have the bandwidth to continue here and need to focus on other things. You can resubmit this pull request if you would like to continue working on it.'
exempt-all-assignees: true
exempt-issue-labels: accepted
- exempt-pr-labels: accepted
--- /dev/null
+name: Data Fetch
+
+on:
+ schedule:
+ - cron: "0 8 * * *" # Every day at 1am PDT
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out repo
+ uses: actions/checkout@v3
+ with:
+ token: ${{ secrets.WORKFLOW_PUSH_BOT_TOKEN }}
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v3
+
+ - name: Install npm packages
+ run: npm install
+
+ - name: Update README with latest team and sponsor data
+ run: npm run build:readme
+
+ - name: Setup Git
+ run: |
+ git config user.name "GitHub Actions Bot"
+ git config user.email "<eslint@googlegroups.com>"
+
+ - name: Save updated files
+ run: |
+ chmod +x ./tools/commit-readme.sh
+ ./tools/commit-readme.sh
package-lock = false
+install-links = false
+v8.41.0 - May 19, 2023
+
+* [`f43216a`](https://github.com/eslint/eslint/commit/f43216a8c77ab6cf1d0823978e8c728786b4cba7) chore: upgrade @eslint/js@8.41.0 (#17200) (Milos Djermanovic)
+* [`95c3007`](https://github.com/eslint/eslint/commit/95c300780a1cfd9ad680bc78850542eb55d7fbf4) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`4f5440d`](https://github.com/eslint/eslint/commit/4f5440db631707b17140c4e5cc7beb223afbd2b9) fix: incorrect warning message for ignored dotfiles (#17196) (Milos Djermanovic)
+* [`ddc5291`](https://github.com/eslint/eslint/commit/ddc5291debd90ff476e17c532af7577e26720b91) chore: don't use deprecated `context` methods in `ast-utils` tests (#17194) (Milos Djermanovic)
+* [`880a431`](https://github.com/eslint/eslint/commit/880a4317b949e575a4a6c5e8baaba1eea7674cc6) feat: change default ignore pattern to `**/node_modules/` in flat config (#17184) (Milos Djermanovic)
+* [`94da96c`](https://github.com/eslint/eslint/commit/94da96cbf0fb2bb6694fa2e757eb1b3e74c40db7) fix: unify `LintMessage` type (#17076) (Brandon Mills)
+* [`7709b14`](https://github.com/eslint/eslint/commit/7709b14e18ad4e11c1119ed6575454243b8e7084) docs: Update README (GitHub Actions Bot)
+* [`8bf5505`](https://github.com/eslint/eslint/commit/8bf550594fca6d29fab1a3453e701c1a457767e1) feat: expose `shouldUseFlatConfig` (#17169) (Connor Prussin)
+* [`7f183e0`](https://github.com/eslint/eslint/commit/7f183e020579380fa57473caaf9ed154470c25b3) docs: Update triage process description (#17157) (Nicholas C. Zakas)
+* [`0c415cd`](https://github.com/eslint/eslint/commit/0c415cda5d76dbe5120ab9f3c4c81320538e35f0) fix: validate `ignorePatterns` constructor option in `FlatESLint` class (#17139) (Milos Djermanovic)
+* [`b1516db`](https://github.com/eslint/eslint/commit/b1516db51514032ed06e1425c4b1f955238dc682) chore: Fix return type of `findFlatConfigFile` (#17161) (Milos Djermanovic)
+* [`b68346b`](https://github.com/eslint/eslint/commit/b68346b290d55324e73868ca42b3854157b27375) docs: fix license to reflect relicensing of jshint (#17165) (Stefan Bischof)
+* [`9682d66`](https://github.com/eslint/eslint/commit/9682d669e4ee8641293914e21679f40fee8bc354) fix: switch `grapheme-splitter` to `graphemer` (#17160) (fisker Cheung)
+* [`918b0fd`](https://github.com/eslint/eslint/commit/918b0fd21723e84bd7acb17942a36606f1d8360a) perf: Store indent descriptors in a plain array (#17148) (Francesco Trotta)
+* [`4caa344`](https://github.com/eslint/eslint/commit/4caa34449555d8a680222ec2049d97c59476c11e) refactor: locateConfigFileToUse returns an Error object (#17159) (唯然)
+
+v8.40.0 - May 5, 2023
+
+* [`4053004`](https://github.com/eslint/eslint/commit/4053004c951813473d1c43f9f9959a9a3484242f) chore: upgrade @eslint/js@8.40.0 (#17156) (Milos Djermanovic)
+* [`50fed1d`](https://github.com/eslint/eslint/commit/50fed1da4449ad7ecbb558294438273cfce603d4) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`f076e54`](https://github.com/eslint/eslint/commit/f076e54ecdb0fae70d9b43ad6888606097beef97) fix: Ensure FlatESLint#findConfigFile() doesn't throw. (#17151) (Nicholas C. Zakas)
+* [`4c7a170`](https://github.com/eslint/eslint/commit/4c7a170b04c5a746e401bef7ce79766ff66a1168) chore: upgrade @eslint/eslintrc@2.0.3 (#17155) (Milos Djermanovic)
+* [`e80b7cc`](https://github.com/eslint/eslint/commit/e80b7cce640b60c00802148dbb51d03c7223afa9) chore: upgrade espree@9.5.2 (#17154) (Milos Djermanovic)
+* [`ce3ac91`](https://github.com/eslint/eslint/commit/ce3ac91b510576e2afba1657aa5f09e162b4ab07) chore: upgrade eslint-visitor-keys@3.4.1 (#17153) (Milos Djermanovic)
+* [`5db7808`](https://github.com/eslint/eslint/commit/5db7808139c1f2172797285a0700f01644bda254) feat: improve flat config errors for invalid rule options and severities (#17140) (Josh Goldberg ✨)
+* [`f5574dc`](https://github.com/eslint/eslint/commit/f5574dc739fcc74a7841217ba1f31cce02bee1ff) feat: Add findConfigFile() method to FlatESLint (#17142) (Nicholas C. Zakas)
+* [`e52b98b`](https://github.com/eslint/eslint/commit/e52b98bf25d882da4efd5559ce5974b6697cf701) feat: add `sourceCode` property to the rule context (#17107) (Nitin Kumar)
+* [`e980bf3`](https://github.com/eslint/eslint/commit/e980bf38cf441f2eb29c458b93df77dc0111b391) docs: Update README (GitHub Actions Bot)
+* [`9094d79`](https://github.com/eslint/eslint/commit/9094d79fb42c0ebb6100426a3f2f851e8d42a0ee) chore: add `latest/` to `meta.docs.url` in all core rules (#17136) (Milos Djermanovic)
+* [`1468f5b`](https://github.com/eslint/eslint/commit/1468f5b640cfa6fdd8a5ec895337f692def2780b) feat: add `physicalFilename` property to the rule context (#17111) (Nitin Kumar)
+* [`0df4d4f`](https://github.com/eslint/eslint/commit/0df4d4f658c214e51310a986c03d44d34ceae3ec) feat: add `cwd` to rule context (#17106) (Nitin Kumar)
+* [`52018f2`](https://github.com/eslint/eslint/commit/52018f21c19b3e461cae32843cddd17ed42f19cd) feat: add `filename` property to the rule context (#17108) (Nitin Kumar)
+* [`559ff4e`](https://github.com/eslint/eslint/commit/559ff4e4bc54a8b6e6b54825d83c532d724204b3) feat: add new `omitLastInOneLineClassBody` option to the `semi` rule (#17105) (Nitin Kumar)
+* [`e92a6fc`](https://github.com/eslint/eslint/commit/e92a6fc7ed2a427f5e95f4b3a1c21d71553c97ee) docs: Update README (GitHub Actions Bot)
+* [`d85efad`](https://github.com/eslint/eslint/commit/d85efad655deacc0dc3fdbbace33307094c3b91b) perf: don't use `grapheme-splitter` on ASCII strings in key-spacing rule (#17122) (Milos Djermanovic)
+* [`af5fe64`](https://github.com/eslint/eslint/commit/af5fe64c398c9bd4206c3c6c1ade81768b291031) docs: Fix custom rule schema docs (#17115) (Adam Jones)
+* [`4a352a9`](https://github.com/eslint/eslint/commit/4a352a957ba9e721bec9f6f403b419a22b0ec423) docs: explain how to include predefined globals (#17114) (Marcus Wyatt)
+* [`5ea15d9`](https://github.com/eslint/eslint/commit/5ea15d92ee358e8f3f652c94c019cac96aaec651) docs: add mastodon link in readme (#17110) (唯然)
+
+v8.39.0 - April 21, 2023
+
+* [`60a6f26`](https://github.com/eslint/eslint/commit/60a6f2694deb4aa1c54de2a28d0357cddfd16644) chore: upgrade @eslint/js@8.39.0 (#17102) (Milos Djermanovic)
+* [`d5ba5c0`](https://github.com/eslint/eslint/commit/d5ba5c0a85e7a10777761f5d46c104ab7f25845b) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`6987dc5`](https://github.com/eslint/eslint/commit/6987dc59e46f4e345d0d6c20c1f2c6846bbd7acc) docs: Fix formatting in Custom Rules docs (#17097) (Milos Djermanovic)
+* [`4ee92e5`](https://github.com/eslint/eslint/commit/4ee92e5cbdeba6fea2147901ce926de16946958a) docs: Update README (GitHub Actions Bot)
+* [`3f7af9f`](https://github.com/eslint/eslint/commit/3f7af9f408625dbc486af914706d34c4b483b5ba) feat: Implement `SourceCode#markVariableAsUsed()` (#17086) (Nicholas C. Zakas)
+* [`d8e9887`](https://github.com/eslint/eslint/commit/d8e9887c2c384d24d586d08ee9ae2ada79bd234c) docs: Custom Rules cleanup/expansion (#16906) (Ben Perlmutter)
+* [`f57eff2`](https://github.com/eslint/eslint/commit/f57eff20f5789408e95061f1af5354bb9b4f4784) ci: run tests on Node.js v20 (#17093) (Nitin Kumar)
+* [`1fea279`](https://github.com/eslint/eslint/commit/1fea2797801a82a2718814c83dad641dab092bcc) docs: Clarify how to add to tsc agenda (#17084) (Nicholas C. Zakas)
+* [`970ef1c`](https://github.com/eslint/eslint/commit/970ef1c868235a58297682513842f1256cdfbd03) docs: Update triage board location (Nicholas C. Zakas)
+* [`9d1b8fc`](https://github.com/eslint/eslint/commit/9d1b8fc60cc31f12618e58c10a2669506b7ce9bf) perf: Binary search in token store `utils.search` (#17066) (Francesco Trotta)
+* [`07a4435`](https://github.com/eslint/eslint/commit/07a4435a0c08cb63ebf11b71f735bac20318829b) chore: Add request for minimal repro to bug report (#17081) (Nicholas C. Zakas)
+* [`eac4943`](https://github.com/eslint/eslint/commit/eac4943ba2e4edb3dbfea0470e5d4b15a4926c40) refactor: remove unnecessary use of `SourceCode#getAncestors` in rules (#17075) (Milos Djermanovic)
+* [`6d8bffd`](https://github.com/eslint/eslint/commit/6d8bffdf45d50e272dc45e6d2d05b4a737514468) docs: Update README (GitHub Actions Bot)
+* [`0a7b60a`](https://github.com/eslint/eslint/commit/0a7b60a9d5621dbbc1a8a8adda3b7c2060c779ca) chore: update description of `SourceCode#getDeclaredVariables` (#17072) (Milos Djermanovic)
+* [`6e2df71`](https://github.com/eslint/eslint/commit/6e2df71cc390252aaca212abe3dc0467fe397450) chore: remove unnecessary references to the LICENSE file (#17071) (Milos Djermanovic)
+
+v8.38.0 - April 7, 2023
+
+* [`59ed060`](https://github.com/eslint/eslint/commit/59ed06041d4670781956221086ea0fca6683788d) chore: upgrade @eslint/js@8.38.0 (#17069) (Milos Djermanovic)
+* [`88c0898`](https://github.com/eslint/eslint/commit/88c08984ec259ac22d839397c06beec8ef213120) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`7162d34`](https://github.com/eslint/eslint/commit/7162d34df9a66c817c3bd4aafd3a03d226b58dd5) docs: Mention new config system is complete (#17068) (Nicholas C. Zakas)
+* [`a1d561d`](https://github.com/eslint/eslint/commit/a1d561d18ed653b56bddbfb1bab1ebe957293563) feat: Move getDeclaredVariables and getAncestors to SourceCode (#17059) (Nicholas C. Zakas)
+* [`0fd6bb2`](https://github.com/eslint/eslint/commit/0fd6bb213ad2de77543c936eda21501653182e52) docs: Update README (GitHub Actions Bot)
+* [`c83531c`](https://github.com/eslint/eslint/commit/c83531c1a6026675f36aa9e33fef14458043974a) docs: Update/remove external links, eg. point to `eslint-community` (#17061) (Pelle Wessman)
+* [`cf682d2`](https://github.com/eslint/eslint/commit/cf682d249f04a6a304407d5b9ddbbc4a9714dd62) refactor: simplify new-parens rule schema (#17060) (MHO)
+* [`a3aa6f5`](https://github.com/eslint/eslint/commit/a3aa6f5f146534ed7999ebf8930c524a4871ec0b) docs: Clarify `no-div-regex` rule docs (#17051) (Francesco Trotta)
+* [`0dde022`](https://github.com/eslint/eslint/commit/0dde02211268394bcbc2b0beef55ea2409b6f55d) ci: bump actions/add-to-project from 0.4.1 to 0.5.0 (#17055) (dependabot[bot])
+* [`b0f11cf`](https://github.com/eslint/eslint/commit/b0f11cf977a4180bf7c3042e7faeaaa067ffafd0) docs: Update README (GitHub Actions Bot)
+* [`da8d52a`](https://github.com/eslint/eslint/commit/da8d52a9d4edd9b2016cd4a15cd78f1ddadf20c7) docs: Update the second object instance for the "no-new" rule (#17020) (Ahmadou Waly NDIAYE)
+* [`518130a`](https://github.com/eslint/eslint/commit/518130ae79a16d7bf4d752c211ae88152cc5a6f0) docs: switch language based on current path (#16687) (Percy Ma)
+* [`24206c4`](https://github.com/eslint/eslint/commit/24206c49a138d4390f815ae122ee12f564bc604b) docs: Update README (GitHub Actions Bot)
+* [`1c1ece2`](https://github.com/eslint/eslint/commit/1c1ece26d1da61e523b83dda25353ec9379eb6c9) fix: do not report on `RegExp(...args)` in `require-unicode-regexp` (#17037) (Francesco Trotta)
+
+v8.37.0 - March 28, 2023
+
+* [`c67f299`](https://github.com/eslint/eslint/commit/c67f2992a743de4765bb6f11c12622e3651324b9) chore: upgrade @eslint/js@8.37.0 (#17033) (Milos Djermanovic)
+* [`ee9ddbd`](https://github.com/eslint/eslint/commit/ee9ddbd63e262aed0052853760866c7a054af561) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`dddb475`](https://github.com/eslint/eslint/commit/dddb47528816cd7e2e737bfde108ed4d62e6a219) chore: upgrade @eslint/eslintrc@2.0.2 (#17032) (Milos Djermanovic)
+* [`522431e`](https://github.com/eslint/eslint/commit/522431e5206bac2fcb41c0d6dc98a84929203bee) chore: upgrade espree@9.5.1 (#17031) (Milos Djermanovic)
+* [`f5f9a88`](https://github.com/eslint/eslint/commit/f5f9a88c79b32222c0331a9bac1c02571d953b69) chore: upgrade eslint-visitor-keys@3.4.0 (#17030) (Milos Djermanovic)
+* [`75339df`](https://github.com/eslint/eslint/commit/75339df99418df4d7e05a77e42ed7e22eabcc9e0) docs: fix typos and missing info in id-match docs (#17029) (Ed Lucas)
+* [`b6ab8b2`](https://github.com/eslint/eslint/commit/b6ab8b2a2ca8807baca121407f5bfb0a0a839427) feat: `require-unicode-regexp` add suggestions (#17007) (Josh Goldberg)
+* [`4dd8d52`](https://github.com/eslint/eslint/commit/4dd8d524e0fc9e8e2019df13f8b968021600e85c) ci: bump actions/stale from 7 to 8 (#17026) (dependabot[bot])
+* [`619f3fd`](https://github.com/eslint/eslint/commit/619f3fd17324c7b71bf17e02047d0c6dc7e5109e) fix: correctly handle `null` default config in `RuleTester` (#17023) (Brad Zacher)
+* [`ec2d830`](https://github.com/eslint/eslint/commit/ec2d8307850dd039e118c001416606e1e0342bc8) docs: Fix typos in the `semi` rule docs (#17012) (Andrii Lundiak)
+* [`e39f28d`](https://github.com/eslint/eslint/commit/e39f28d8578a00f4da8d4ddad559547950128a0d) docs: add back to top button (#16979) (Tanuj Kanti)
+* [`ad9dd6a`](https://github.com/eslint/eslint/commit/ad9dd6a933fd098a0d99c6a9aa059850535c23ee) chore: remove duplicate scss, (#17005) (Strek)
+* [`10022b1`](https://github.com/eslint/eslint/commit/10022b1f4bda1ad89193512ecf18c2ee61db8202) feat: Copy getScope() to SourceCode (#17004) (Nicholas C. Zakas)
+* [`1665c02`](https://github.com/eslint/eslint/commit/1665c029acb92bf8812267f1647ad1a7054cbcb4) feat: Use plugin metadata for flat config serialization (#16992) (Nicholas C. Zakas)
+* [`b3634f6`](https://github.com/eslint/eslint/commit/b3634f695ddab6a82c0a9b1d8695e62b60d23366) feat: docs license (#17010) (Samuel Roldan)
+* [`721c717`](https://github.com/eslint/eslint/commit/721c71782a7c11025689a1500e7690fb3794fcce) docs: Custom Processors cleanup and expansion (#16838) (Ben Perlmutter)
+* [`1fbf118`](https://github.com/eslint/eslint/commit/1fbf1184fed57df02640aad4659afb54dc26a2e9) fix: `getFirstToken`/`getLastToken` on comment-only node (#16889) (Francesco Trotta)
+* [`129e252`](https://github.com/eslint/eslint/commit/129e252132c7c476d7de17f40b54a333ddb2e6bb) fix: Fix typo in `logical-assignment-operators` rule description (#17000) (Francesco Trotta)
+* [`892e6e5`](https://github.com/eslint/eslint/commit/892e6e58c5a07a549d3104de3b6b5879797dc97f) feat: languageOptions.parser must be an object. (#16985) (Nicholas C. Zakas)
+* [`ada6a3e`](https://github.com/eslint/eslint/commit/ada6a3e6e3607523958f35e1260537630ec0e976) ci: unpin Node 19 (#16993) (Milos Djermanovic)
+* [`c3da975`](https://github.com/eslint/eslint/commit/c3da975e69fde46f35338ce48528841a8dc1ffd2) chore: Remove triage label from template (#16990) (Nicholas C. Zakas)
+* [`d049f97`](https://github.com/eslint/eslint/commit/d049f974103e530ef76ede25af701635caf1f405) docs: 'How ESLint is Maintained' page (#16961) (Ben Perlmutter)
+* [`5251a92`](https://github.com/eslint/eslint/commit/5251a921866e8d3b380dfe8db8a6e6ab97773d5e) docs: Describe guard options for guard-for-in (#16986) (alope107)
+* [`69bc0e2`](https://github.com/eslint/eslint/commit/69bc0e2f4412998f9384600a100d7882ea4dd3f3) ci: pin Node 19 to 19.7.0 (#16987) (Milos Djermanovic)
+* [`6157d81`](https://github.com/eslint/eslint/commit/6157d813e19b80481a46f8cbdf9eae18a55e5619) docs: Add example to guard-for-in docs. (#16983) (alope107)
+* [`fd47998`](https://github.com/eslint/eslint/commit/fd47998af6efadcdf5ba93e0bd1f4c02d97d22b3) docs: update `Array.prototype.toSorted` specification link (#16982) (Milos Djermanovic)
+* [`3e1cf6b`](https://github.com/eslint/eslint/commit/3e1cf6bfc5ebc29314ddbe462d6cb580e9ab085c) docs: Copy edits on Maintain ESLint docs (#16939) (Ben Perlmutter)
+
+v8.36.0 - March 10, 2023
+
+* [`602b111`](https://github.com/eslint/eslint/commit/602b11121910a97ab2bc4a95a46dd0ccd0a89309) chore: upgrade @eslint/js@8.36.0 (#16978) (Milos Djermanovic)
+* [`43c2345`](https://github.com/eslint/eslint/commit/43c2345c27024aeab6127e6bbfd55c8b70bd317e) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`00afb84`](https://github.com/eslint/eslint/commit/00afb84e5039874c8745a45c953fceaf0c71c454) chore: upgrade @eslint/eslintrc@2.0.1 (#16977) (Milos Djermanovic)
+* [`698c5aa`](https://github.com/eslint/eslint/commit/698c5aad50e628ff00281dbc786e42de79834035) chore: upgrade espree@9.5.0 (#16976) (Milos Djermanovic)
+* [`b98fdd4`](https://github.com/eslint/eslint/commit/b98fdd413a3b07b262bfce6f704c1c1bb8582770) docs: Update README (GitHub Actions Bot)
+* [`c89a485`](https://github.com/eslint/eslint/commit/c89a485c49450532ee3db74f2638429f1f37d0dd) feat: Add `checkJSDoc` option to multiline-comment-style (#16807) (Laurent Cozic)
+* [`f5f5e11`](https://github.com/eslint/eslint/commit/f5f5e11bd5fd3daab9ccae41e270739c836c305e) feat: Serialize parsers/processors in flat config (#16944) (Nicholas C. Zakas)
+* [`caf08ce`](https://github.com/eslint/eslint/commit/caf08ce0cc74917f7c0eec92d25fd784dc33ac4d) docs: fix estree link in custom formatters docs (#16967) (Milos Djermanovic)
+* [`75acdd2`](https://github.com/eslint/eslint/commit/75acdd21c5ce7024252e9d41ed77d2f30587caac) chore: lint more js files in docs (#16964) (Milos Djermanovic)
+* [`3398431`](https://github.com/eslint/eslint/commit/3398431574b903757bc78b08c8ed36b7b9fce8eb) docs: Custom Parsers cleanup/expansion (#16887) (Ben Perlmutter)
+* [`19d3531`](https://github.com/eslint/eslint/commit/19d3531d9b54e1004318d28f9a6e18305c5bcc18) docs: Update README (GitHub Actions Bot)
+* [`4799297`](https://github.com/eslint/eslint/commit/4799297ea582c81fd1e5623d32a7ddf7a7f3a126) feat: use @eslint-community dependencies (#16784) (Michaël De Boey)
+* [`b09a512`](https://github.com/eslint/eslint/commit/b09a512107249a4eb19ef5a37b0bd672266eafdb) docs: detect and fix broken links (#16837) (Nitin Kumar)
+* [`92c1943`](https://github.com/eslint/eslint/commit/92c1943ba73ea01e87086236e8736539b0eed558) fix: correctly iterate files matched by glob patterns (#16831) (Nitin Kumar)
+* [`89d9844`](https://github.com/eslint/eslint/commit/89d9844b3151f09b5b21b6eeeda671009ec301e9) ci: bump actions/add-to-project from 0.4.0 to 0.4.1 (#16943) (dependabot[bot])
+
+v8.35.0 - February 26, 2023
+
+* [`cdcbe12`](https://github.com/eslint/eslint/commit/cdcbe127de20cbcc4e24131a808c13b1024e61a2) chore: upgrade @eslint/js@8.35.0 (#16935) (Brandon Mills)
+* [`c954c34`](https://github.com/eslint/eslint/commit/c954c349c0c2f88919614efc95e1368c245582fd) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`5a517da`](https://github.com/eslint/eslint/commit/5a517da8e55f6de28e9c028c5627fa7d82945969) chore: package.json update for @eslint/js release (ESLint Jenkins)
+* [`9f10926`](https://github.com/eslint/eslint/commit/9f10926d76be7cf675721b29bd5030e85cb4ab30) chore: upgrade @eslint/eslintrc@2.0.0 (#16928) (Milos Djermanovic)
+* [`8e34a04`](https://github.com/eslint/eslint/commit/8e34a04e3a4395bce59bc6acadf84281abc11d18) feat: add `afterHashbangComment` option to `lines-around-comment` rule (#16920) (SUZUKI Sosuke)
+* [`c8c0c71`](https://github.com/eslint/eslint/commit/c8c0c715a2964cc1859b99f9d4f542675094d1d5) feat: Move all and recommended configs into package. (#16844) (Nicholas C. Zakas)
+* [`f9f195e`](https://github.com/eslint/eslint/commit/f9f195ef12deb114fb86763010a23ea0cb4c78d1) docs: Plugin docs cleanup & expansion (#16862) (Ben Perlmutter)
+* [`df809fd`](https://github.com/eslint/eslint/commit/df809fdedc5fc92df4be8340e28baedbde605b4f) docs: Custom Formatters page cleanup/expansion (#16886) (Ben Perlmutter)
+* [`0700d1b`](https://github.com/eslint/eslint/commit/0700d1b14659bf39b1a08f082c44c9084cf676a8) docs: Add PostCSS/Autoprefixer/CSSNano (#16502) (Nick Schonning)
+* [`da728fa`](https://github.com/eslint/eslint/commit/da728fae6c4e5fdda74195e84d45d67ad5cafc45) ci: use LTS node version in workflows (#16907) (Nitin Kumar)
+* [`7b9e9bf`](https://github.com/eslint/eslint/commit/7b9e9bf78bedb009fe2813308ede1f46502c3890) docs: support unicode anchors (#16782) (Percy Ma)
+* [`5fbc0bf`](https://github.com/eslint/eslint/commit/5fbc0bffdd9f84feb43296eb502d1e484fb323f2) docs: Update README (GitHub Actions Bot)
+* [`c57b4f3`](https://github.com/eslint/eslint/commit/c57b4f3dc6383e452120381204ee4a7c874225a0) perf: upgrade to esquery@1.4.2 (#16901) (Milos Djermanovic)
+* [`9698bc5`](https://github.com/eslint/eslint/commit/9698bc5cdec1bbee567a6a489da82e87fe65d019) fix: pin esquery v1.4.0 (fixes #16896) (#16897) (唯然)
+* [`67865a0`](https://github.com/eslint/eslint/commit/67865a064cc1a4e320030299edc1cfdd1f9ac3b8) docs: Remove mention of mailing list (#16869) (Amaresh S M)
+* [`43af24a`](https://github.com/eslint/eslint/commit/43af24a88b939a62880c37d1332b02f677d82f16) docs: Add explanation of when to use 'warn' severity (#16882) (Nicholas C. Zakas)
+* [`71f6f0d`](https://github.com/eslint/eslint/commit/71f6f0dcd574320ee71c3eb1f313841899bdf260) feat: report more cases with `??` in no-constant-binary-expression (#16826) (Daiki Nishikawa)
+* [`ed2999b`](https://github.com/eslint/eslint/commit/ed2999b38b4d61f5c278301738e294012d5d3c9e) docs: Shareable configs page edits and expansion (#16824) (Ben Perlmutter)
+* [`2780635`](https://github.com/eslint/eslint/commit/27806358b5e1c4d37b63b1c61595e86ff03b5b42) docs: fix typos (#16884) (Lioness100)
+* [`5bdaae2`](https://github.com/eslint/eslint/commit/5bdaae205c3a0089ea338b382df59e21d5b06436) docs: Ways to Extend ESLint page (#16861) (Ben Perlmutter)
+* [`9122f07`](https://github.com/eslint/eslint/commit/9122f0764031dc36970df715bc5e16973890e18d) chore: Update stale bot settings (#16870) (Nicholas C. Zakas)
+
+v8.34.0 - February 10, 2023
+
+* [`f0a9883`](https://github.com/eslint/eslint/commit/f0a988384ea1a262150e70d83abd8a5e50c46fa7) docs: split rules documentation (#16797) (Ben Perlmutter)
+* [`923f61d`](https://github.com/eslint/eslint/commit/923f61d8fc82d83b912c6ba95abb5a509c4d7b52) fix: false positive with assignment in `no-extra-parens` (#16872) (Francesco Trotta)
+* [`9dbe06d`](https://github.com/eslint/eslint/commit/9dbe06d0ad875e6d5964497e2975e8d789e763d0) chore: add `type` property to array-element-newline schema (#16877) (MHO)
+* [`a061527`](https://github.com/eslint/eslint/commit/a061527a0332f0edf559acfc2902a327cae098d9) chore: Remove unused functions (#16868) (Nicholas C. Zakas)
+* [`67aa37b`](https://github.com/eslint/eslint/commit/67aa37b583f059226b9c959672400f04ed6a56b5) docs: fix typo in command-line-interface.md (#16871) (Kevin Rouchut)
+* [`337f7ed`](https://github.com/eslint/eslint/commit/337f7ed96131d873be7ae6b010739476d0ad15e9) docs: fix width of language input (#16849) (Tanuj Kanti)
+* [`9b2fcf7`](https://github.com/eslint/eslint/commit/9b2fcf7e928fc92ac6d43617bdee1bda250b7491) feat: `array-callback-return` supports `Array.prototype.toSorted` (#16845) (SUZUKI Sosuke)
+* [`71349a1`](https://github.com/eslint/eslint/commit/71349a1f709baa361bd656a7ce4a7d35d857a9a8) docs: Configure a Parser page (#16803) (Ben Perlmutter)
+* [`de7e925`](https://github.com/eslint/eslint/commit/de7e925d03764f3681269b30bb60b92ee463c10f) docs: remove extra line numbers in example (#16848) (jonz94)
+* [`ad38d77`](https://github.com/eslint/eslint/commit/ad38d77102d6fe30cfa92c831174f178bb35c88b) docs: Update README (GitHub Actions Bot)
+
+v8.33.0 - January 28, 2023
+
+* [`17f4be2`](https://github.com/eslint/eslint/commit/17f4be2b66deb81f4e9ffb3d6bdfb79f3fcf85a2) docs: Fix examples in no-multiple-empty-lines rule (#16835) (jonz94)
+* [`9c7cfe3`](https://github.com/eslint/eslint/commit/9c7cfe33c4a39cf2c23529afe02030ea7f8acf70) docs: 'Source Code' content in 'Set up Development Environment' page (#16780) (Ben Perlmutter)
+* [`ede5c64`](https://github.com/eslint/eslint/commit/ede5c6475469a905da4f559ab55f0ee73168a9d7) docs: Custom processors page (#16802) (Ben Perlmutter)
+* [`2620614`](https://github.com/eslint/eslint/commit/2620614f525de13f2e3ab0a7cd92abe89dae4897) docs: Code of Conduct page (#16781) (Ben Perlmutter)
+* [`50a8efd`](https://github.com/eslint/eslint/commit/50a8efd957c70c9978a8ed25744a24193b00e078) docs: report a sec vulnerability page (#16808) (Ben Perlmutter)
+* [`2cc7954`](https://github.com/eslint/eslint/commit/2cc7954cdb1fed44e8a5d3c9b3ea1deceadb5e00) feat: add `restrictDefaultExports` option to no-restricted-exports rule (#16785) (Nitin Kumar)
+* [`ed60afd`](https://github.com/eslint/eslint/commit/ed60afd4450e769a975447178299446f4439d926) docs: Update page titles, section landing pages, and side TOC (#16760) (Ben Perlmutter)
+* [`333c712`](https://github.com/eslint/eslint/commit/333c71243537966930e9ab8178bc98c37949b5f2) docs: add background to code-path-diagrams for dark-mode (#16822) (Tanuj Kanti)
+* [`f5f7b9b`](https://github.com/eslint/eslint/commit/f5f7b9b8b512f5c6a5b4a1037f81bb3f5a7311e0) docs: Update README (GitHub Actions Bot)
+* [`2aa4f5f`](https://github.com/eslint/eslint/commit/2aa4f5fb2fdb1c4a1734093c225e5c6251b0ee0f) docs: no-constant-condition: Add multi-comparison example (#16776) (Sebastian Simon)
+* [`40287db`](https://github.com/eslint/eslint/commit/40287dbe7407934a69805f02ece07491778c3694) docs: Remove Google Group icon (#16779) (Nicholas C. Zakas)
+* [`ea10ca5`](https://github.com/eslint/eslint/commit/ea10ca5b7b5bd8f6e6daf030ece9a3a82f10994c) docs: 'a .eslint' -> 'an .eslint' for consistency (#16809) (Ben Perlmutter)
+* [`3be0748`](https://github.com/eslint/eslint/commit/3be07488ee7b6a9591d169be9648fbd36b32105e) docs: add example for nodejs lintText api (#16789) (Siva K)
+* [`ce4f5ff`](https://github.com/eslint/eslint/commit/ce4f5ff30590df053a539c8e8e2597838e038a36) docs: Replace removed related rules with a valid rule (#16800) (Ville Saalo)
+
+v8.32.0 - January 14, 2023
+
+* [`17b65ad`](https://github.com/eslint/eslint/commit/17b65ad10d653bb05077f21d8b1f79bee96e38d8) docs: IA Update page URL move (#16665) (Ben Perlmutter)
+* [`b4f8329`](https://github.com/eslint/eslint/commit/b4f8329164d7b293a1557e05b987d2a685fe1d30) fix: ignore directives for no-fallthrough (#16757) (gfyoung)
+* [`5981296`](https://github.com/eslint/eslint/commit/5981296d5c7c86228ad766009901191fdd87d5a4) docs: fix theme switcher button (#16752) (Sam Chen)
+* [`6669413`](https://github.com/eslint/eslint/commit/66694136b67277c050bd27f60050779687a88c9f) docs: deploy prerelease docs under the `/docs/next/` path (#16541) (Nitin Kumar)
+* [`2952d6e`](https://github.com/eslint/eslint/commit/2952d6ed95811ce0971b6855d66fb7a9767a7b72) chore: sync templates/*.md files with issue templates (#16758) (gfyoung)
+* [`78ecfe0`](https://github.com/eslint/eslint/commit/78ecfe0e52c0e5780fefc8dc9a98864e48de6637) docs: use inline code for rule options name (#16768) (Percy Ma)
+* [`3e34418`](https://github.com/eslint/eslint/commit/3e34418b31664decfb2337de798feafbf985b66c) chore: Add new issues to triage project (#16740) (Nicholas C. Zakas)
+* [`fc2ea59`](https://github.com/eslint/eslint/commit/fc2ea598aee97beb6d768866da1ee4f63775f0c9) docs: Update README (GitHub Actions Bot)
+* [`fc20f24`](https://github.com/eslint/eslint/commit/fc20f242a2ac073b5af6d5fca67e07a175f36c3b) feat: add suggestions for redundant wrapping in prefer-regex-literals (#16658) (YeonJuan)
+* [`762a872`](https://github.com/eslint/eslint/commit/762a8727fb3b5619cff900826053b643ca5f1162) docs: Update README (GitHub Actions Bot)
+
+v8.31.0 - December 31, 2022
+
+* [`65d4e24`](https://github.com/eslint/eslint/commit/65d4e24c36367cd63f0eba7371820e0e81dae7aa) chore: Upgrade @eslint/eslintrc@1.4.1 (#16729) (Brandon Mills)
+* [`35439f1`](https://github.com/eslint/eslint/commit/35439f1572e1a8888f7feb6c5e51a15b5582495d) fix: correct syntax error in `prefer-arrow-callback` autofix (#16722) (Francesco Trotta)
+* [`87b2470`](https://github.com/eslint/eslint/commit/87b247058ed520061fe1a146b7f0e7072a94990d) fix: new instance of FlatESLint should load latest config file version (#16608) (Milos Djermanovic)
+* [`8d93081`](https://github.com/eslint/eslint/commit/8d93081a717f6e8b8cb60c3075cc1d7e4e655e6b) chore: fix CI failure (#16721) (Sam Chen)
+* [`4339dc4`](https://github.com/eslint/eslint/commit/4339dc462d78888fe2e10acdfacd6f57245ce6ae) docs: Update README (GitHub Actions Bot)
+* [`8f17247`](https://github.com/eslint/eslint/commit/8f17247a93240ff8a08980d8e06352e4ff4e8fe3) chore: Set up automatic updating of README (#16717) (Nicholas C. Zakas)
+* [`4e4049c`](https://github.com/eslint/eslint/commit/4e4049c5fa355b2091afc8948690fcd7b1c1e6df) docs: optimize code block structure (#16669) (Sam Chen)
+* [`54a7ade`](https://github.com/eslint/eslint/commit/54a7ade5d8e6f59554afeb9202ba6143f8afdf57) docs: do not escape code blocks of formatters examples (#16719) (Sam Chen)
+* [`52c7c73`](https://github.com/eslint/eslint/commit/52c7c73c052e1ec2528c6b4af78181bc30cf8cdd) feat: check assignment patterns in no-underscore-dangle (#16693) (Milos Djermanovic)
+* [`e5ecfef`](https://github.com/eslint/eslint/commit/e5ecfefa1c952195a3a8371f5953cc655d844079) docs: Add function call example for no-undefined (#16712) (Elliot Huffman)
+* [`a3262f0`](https://github.com/eslint/eslint/commit/a3262f0a6305d2a721fac137a60c62c019b26aa4) docs: Add mastodon link (#16638) (Amaresh S M)
+* [`4cd87cb`](https://github.com/eslint/eslint/commit/4cd87cb3c52412277577ba00c4fbb1aec36acc8c) ci: bump actions/stale from 6 to 7 (#16713) (dependabot[bot])
+* [`a14ccf9`](https://github.com/eslint/eslint/commit/a14ccf91af1122e419710f58ef494980fc4894b3) docs: clarify files property (#16709) (Sam Chen)
+* [`3b29eb1`](https://github.com/eslint/eslint/commit/3b29eb14e00182614c986d8498b483a9917976e7) docs: fix npm link (#16710) (Abdullah Osama)
+* [`fd20c75`](https://github.com/eslint/eslint/commit/fd20c75b1059c54d598c0abaf63e7d7a80f04f32) chore: sort package.json scripts in alphabetical order (#16705) (Darius Dzien)
+* [`a638673`](https://github.com/eslint/eslint/commit/a638673ee6e94344c46d12dfc988adeb3783f817) docs: fix search bar focus on `Esc` (#16700) (Shanmughapriyan S)
+* [`f62b722`](https://github.com/eslint/eslint/commit/f62b722251858a5dfb157591910edbaaeb4a966f) docs: country flag missing in windows (#16698) (Shanmughapriyan S)
+* [`4d27ec6`](https://github.com/eslint/eslint/commit/4d27ec6019847afabeebf592dddc014e9220057c) docs: display zh-hans in the docs language switcher (#16686) (Percy Ma)
+* [`8bda20e`](https://github.com/eslint/eslint/commit/8bda20e8276c6ba17d31842fcdd63ba65476fbbd) docs: remove manually maintained anchors (#16685) (Percy Ma)
+* [`b401cde`](https://github.com/eslint/eslint/commit/b401cde47d44746ff91b8feced3fb3a4e32c0e12) feat: add options to check destructuring in no-underscore-dangle (#16006) (Morten Kaltoft)
+* [`b68440f`](https://github.com/eslint/eslint/commit/b68440ff2b8322fc00373792701169205c94ed94) docs: User Guide Getting Started expansion (#16596) (Ben Perlmutter)
+* [`30d0daf`](https://github.com/eslint/eslint/commit/30d0daf55e85a412995f6d69f47cab3fb591f2c3) feat: group properties with values in parentheses in `key-spacing` (#16677) (Francesco Trotta)
+* [`10a5c78`](https://github.com/eslint/eslint/commit/10a5c7839370219c79f44d4206cbd7c28a72bad5) chore: update ignore patterns in `eslint.config.js` (#16678) (Milos Djermanovic)
+
+v8.30.0 - December 16, 2022
+
+* [`f2c4737`](https://github.com/eslint/eslint/commit/f2c47372420f050ad8f2300271345de1c1232635) chore: upgrade @eslint/eslintrc@1.4.0 (#16675) (Milos Djermanovic)
+* [`1a327aa`](https://github.com/eslint/eslint/commit/1a327aae57f1b68c96b27cc1bd57f8198d5a3a7c) fix: Ensure flat config unignores work consistently like eslintrc (#16579) (Nicholas C. Zakas)
+* [`075ef2c`](https://github.com/eslint/eslint/commit/075ef2cf315e75b51b671c40ce9a97c66b2e4b50) feat: add suggestion for no-return-await (#16637) (Daniel Bartholomae)
+* [`ba74253`](https://github.com/eslint/eslint/commit/ba74253e8bd63e9e163bbee0540031be77e39253) chore: standardize npm script names per #14827 (#16315) (Patrick McElhaney)
+* [`6a8cd94`](https://github.com/eslint/eslint/commit/6a8cd94ed08983c70ca7d72dc6e360770a743405) docs: Clarify Discord info in issue template config (#16663) (Nicholas C. Zakas)
+* [`0d9af4c`](https://github.com/eslint/eslint/commit/0d9af4c5674809be993439c766dcd9d7f65fcec9) ci: fix npm v9 problem with `file:` (#16664) (Milos Djermanovic)
+* [`7190d98`](https://github.com/eslint/eslint/commit/7190d98ff40023f24b0c6a98319ae8a82c99ff5b) feat: update globals (#16654) (Sébastien Règne)
+* [`ad44344`](https://github.com/eslint/eslint/commit/ad44344ef6fdeac7217eb83bc54a230382c0da5e) docs: CLI documentation standardization (#16563) (Ben Perlmutter)
+* [`90c9219`](https://github.com/eslint/eslint/commit/90c9219181e0aadcae7224602d2988186d457113) refactor: migrate off deprecated function-style rules in all tests (#16618) (Bryan Mishkin)
+* [`9b8bb72`](https://github.com/eslint/eslint/commit/9b8bb72c49a453086954b06a5d7dd390731b1975) fix: autofix recursive functions in no-var (#16611) (Milos Djermanovic)
+* [`293573e`](https://github.com/eslint/eslint/commit/293573eb530d161d2a5b01efd9d3de49dadea022) docs: fix broken line numbers (#16606) (Sam Chen)
+* [`fa2c64b`](https://github.com/eslint/eslint/commit/fa2c64be10d5854fb586c20957737d7d2da1975a) docs: use relative links for internal links (#16631) (Percy Ma)
+* [`75276c9`](https://github.com/eslint/eslint/commit/75276c9bc7c4bc013fc6bdf277353c979934d73b) docs: reorder options in no-unused-vars (#16625) (Milos Djermanovic)
+* [`7276fe5`](https://github.com/eslint/eslint/commit/7276fe5776f03fb90e575ed63a9b1a6766993e42) docs: Fix anchor in URL (#16628) (Karl Horky)
+* [`6bef135`](https://github.com/eslint/eslint/commit/6bef1350e692c818c55c6d2074c12506e98cdf4f) docs: don't apply layouts to html formatter example (#16591) (Tanuj Kanti)
+* [`dfc7ec1`](https://github.com/eslint/eslint/commit/dfc7ec11b11b56daaa10e8e6d08c5cddfc8c2c59) docs: Formatters page updates (#16566) (Ben Perlmutter)
+* [`8ba124c`](https://github.com/eslint/eslint/commit/8ba124cfd8aaf01d14ccbcb1654798624948fb0a) docs: update the `prefer-const` example (#16607) (Pavel)
+* [`e6cb05a`](https://github.com/eslint/eslint/commit/e6cb05aa35bafb9e88f161ad1fa6b01942a7c13c) docs: fix css leaking (#16603) (Sam Chen)
+
+v8.29.0 - December 2, 2022
+
+* [`0311d81`](https://github.com/eslint/eslint/commit/0311d81834d675b8ae7cc92a460b37115edc4018) docs: Configuring Plugins page intro, page tweaks, and rename (#16534) (Ben Perlmutter)
+* [`57089b1`](https://github.com/eslint/eslint/commit/57089b1ede624452bc94404b6e60d01d48cfd468) docs: add a property assignment example for camelcase rule (#16605) (Milos Djermanovic)
+* [`b6ab030`](https://github.com/eslint/eslint/commit/b6ab030897d2e8b314b33a6502346a4ac45bb8da) docs: add docs codeowners (#16601) (Strek)
+* [`7628403`](https://github.com/eslint/eslint/commit/7628403a57d9d9b4e2cb2b36309170900f58832e) chore: add discord channel link (#16590) (Amaresh S M)
+* [`49a07c5`](https://github.com/eslint/eslint/commit/49a07c52c5af7e98d161ff4acd44bbbe0aa6383b) feat: add `allowParensAfterCommentPattern` option to no-extra-parens (#16561) (Nitin Kumar)
+* [`6380c87`](https://github.com/eslint/eslint/commit/6380c87c563be5dc78ce0ddd5c7409aaf71692bb) docs: fix sitemap and feed (#16592) (Milos Djermanovic)
+* [`e6a865d`](https://github.com/eslint/eslint/commit/e6a865d70aed9e1c07be712e40c38da1a5dda849) feat: `prefer-named-capture-group` add suggestions (#16544) (Josh Goldberg)
+* [`ade621d`](https://github.com/eslint/eslint/commit/ade621dd12fcd3b65644bb3468248cc040db756c) docs: perf debounce the search query (#16586) (Shanmughapriyan S)
+* [`a91332b`](https://github.com/eslint/eslint/commit/a91332b8bd9adfa2aa8110071bdf73f56d400050) feat: In no-invalid-regexp validate flags also for non-literal patterns (#16583) (trosos)
+* [`fbcf3ab`](https://github.com/eslint/eslint/commit/fbcf3abd54dd20aec3c695cacece56493633c97f) docs: fix searchbar clear button (#16585) (Shanmughapriyan S)
+* [`f894035`](https://github.com/eslint/eslint/commit/f89403553b31d24f4fc841424cc7dcb8c3ef689f) docs: HTTPS link to yeoman.io (#16582) (Christian Oliff)
+* [`de12b26`](https://github.com/eslint/eslint/commit/de12b266f2aa6f063d0af888b8f0de41d09ec33f) docs: Update configuration file pages (#16509) (Ben Perlmutter)
+* [`f5808cb`](https://github.com/eslint/eslint/commit/f5808cb51529174a67b4938223f06435ad6d5118) chore: fix rule doc headers check (#16564) (Milos Djermanovic)
+* [`1ae9f20`](https://github.com/eslint/eslint/commit/1ae9f2067442434c6ccc6b41703624b302d17c67) docs: update correct code examples for `no-extra-parens` rule (#16560) (Nitin Kumar)
+
+v8.28.0 - November 18, 2022
+
+* [`34c05a7`](https://github.com/eslint/eslint/commit/34c05a779ada3142995392ae12978461900088df) docs: Language Options page intro and tweaks (#16511) (Ben Perlmutter)
+* [`3e66387`](https://github.com/eslint/eslint/commit/3e663873c97773ab1ecdff54aaa122075d5bb389) docs: add intro and edit ignoring files page (#16510) (Ben Perlmutter)
+* [`436f712`](https://github.com/eslint/eslint/commit/436f712843360f98b2bd63256bf0c4f77013b54c) docs: fix Header UI inconsistency (#16464) (Tanuj Kanti)
+* [`f743816`](https://github.com/eslint/eslint/commit/f74381696703d8eed0e175d42f96904a3d1cb4cb) docs: switch to wrench emoji for auto-fixable rules (#16545) (Bryan Mishkin)
+* [`bc0547e`](https://github.com/eslint/eslint/commit/bc0547eb149a1e04211826662d2d798fb331983d) docs: improve styles for versions and languages page (#16553) (Nitin Kumar)
+* [`6070f58`](https://github.com/eslint/eslint/commit/6070f58d802d77c6c781c6bc1f554eef8b3d8f68) docs: clarify esquery issue workaround (#16556) (Milos Djermanovic)
+* [`b48e4f8`](https://github.com/eslint/eslint/commit/b48e4f89c59bd1c5408e3db492a0e95a402820bd) docs: Command Line Interface intro and tweaks (#16535) (Ben Perlmutter)
+* [`b92b30f`](https://github.com/eslint/eslint/commit/b92b30f93db64314827305b552cbb832c63fa949) docs: Add Rules page intro and content tweaks (#16523) (Ben Perlmutter)
+* [`1769b42`](https://github.com/eslint/eslint/commit/1769b423392512db4adf1eff75896c1ac0c3606b) docs: Integrations page introduction (#16548) (Ben Perlmutter)
+* [`63bce44`](https://github.com/eslint/eslint/commit/63bce44e7b6326e1e94fc7f6283df8de7bbac273) feat: add `ignoreClassFieldInitialValues` option to no-magic-numbers (#16539) (Milos Djermanovic)
+* [`c50ae4f`](https://github.com/eslint/eslint/commit/c50ae4f840d1ee9dc7b80a46c887398c0ec0a67c) fix: Ensure that dot files are found with globs. (#16550) (Nicholas C. Zakas)
+* [`a8d0a57`](https://github.com/eslint/eslint/commit/a8d0a57cbc29a917258df41d3254ecd29bcf61ab) docs: make table of contents sticky on desktop (#16506) (Sam Chen)
+* [`9432b67`](https://github.com/eslint/eslint/commit/9432b67f76ddd7b8a73d37e8a041a9ff25822f0c) fix: throw error for first unmatched pattern (#16533) (Milos Djermanovic)
+* [`8385ecd`](https://github.com/eslint/eslint/commit/8385ecdbbe342211e20aebe76fa7affe8ec04c33) feat: multiline properties in rule `key-spacing` with option `align` (#16532) (Francesco Trotta)
+* [`a4e89db`](https://github.com/eslint/eslint/commit/a4e89dbe85589dab982885872dc206e090c27b3c) feat: `no-obj-calls` support `Intl` (#16543) (Sosuke Suzuki)
+* [`a01315a`](https://github.com/eslint/eslint/commit/a01315a7d8f3a70468b7a644fde01d6983778c6b) docs: fix route of japanese translation site (#16542) (Tanuj Kanti)
+* [`e94a4a9`](https://github.com/eslint/eslint/commit/e94a4a95ee301b0344d3292c37a0b29d8e18ab30) chore: Add tests to verify #16038 is fixed (#16538) (Nicholas C. Zakas)
+* [`0515628`](https://github.com/eslint/eslint/commit/05156285396eba9ce3d3a0990a8c89d5bc229636) docs: use emoji instead of svg for deprecated rule (#16536) (Bryan Mishkin)
+* [`e76c382`](https://github.com/eslint/eslint/commit/e76c3827727b48c16af8467c02c31160e5595d83) fix: allow `* 1` when followed by `/` in no-implicit-coercion (#16522) (Milos Djermanovic)
+* [`68f1288`](https://github.com/eslint/eslint/commit/68f12882fbaeda8ffb26425d42d261346ff5af51) docs: set default layouts (#16484) (Percy Ma)
+* [`e13f194`](https://github.com/eslint/eslint/commit/e13f194f89f591730aa955f7b62192c7e8296069) chore: stricter validation of `meta.docs.description` in core rules (#16529) (Milos Djermanovic)
+* [`776827a`](https://github.com/eslint/eslint/commit/776827a1748da88a25e7903bd794f5439de922b5) docs: init config about specifying shared configs (#16483) (Percy Ma)
+* [`72dbfbc`](https://github.com/eslint/eslint/commit/72dbfbc0c45d2b9d19b21c6a5a6b4ca71403ffbf) chore: use `pkg` parameter in `getNpmPackageVersion` (#16525) (webxmsj)
+* [`5c39425`](https://github.com/eslint/eslint/commit/5c39425fc55ecc0b97bbd07ac22654c0eb4f789c) docs: fix broken link to plugins (#16520) (Ádám T. Nagy)
+* [`c97c789`](https://github.com/eslint/eslint/commit/c97c7897686ac4dc2828537d6a017f3c99f7d905) docs: Add missing no-new-native-nonconstructor docs code fence (#16503) (Brandon Mills)
+
+v8.27.0 - November 6, 2022
+
+* [`f14587c`](https://github.com/eslint/eslint/commit/f14587c42bb0fe6ec89529aede045a488083d6ee) feat: new `no-new-native-nonconstructor` rule (#16368) (Sosuke Suzuki)
+* [`978799b`](https://github.com/eslint/eslint/commit/978799bd5c76fecf4ce8f17d89ad6c9f436c3228) feat: add new rule `no-empty-static-block` (#16325) (Sosuke Suzuki)
+* [`ce93b42`](https://github.com/eslint/eslint/commit/ce93b429bf917640473dd7e26b49bba993c68ce4) docs: Stylelint property-no-unknown (#16497) (Nick Schonning)
+* [`d2cecb4`](https://github.com/eslint/eslint/commit/d2cecb4ad2a6d33444cf0288a863c43acb3b468a) docs: Stylelint declaration-block-no-shorthand-property-overrides (#16498) (Nick Schonning)
+* [`0a92805`](https://github.com/eslint/eslint/commit/0a92805d7713118866e519b0ff2a61c5d6238ad9) docs: stylelint color-hex-case (#16496) (Nick Schonning)
+* [`c3ce521`](https://github.com/eslint/eslint/commit/c3ce5212f672d95dde3465d7d3c4bf99ff665f8b) fix: Ensure unmatched glob patterns throw an error (#16462) (Nicholas C. Zakas)
+* [`74a5af4`](https://github.com/eslint/eslint/commit/74a5af487ac7296a46a8078e585f00df72b63d83) docs: fix stylelint error (#16491) (Milos Djermanovic)
+* [`69216ee`](https://github.com/eslint/eslint/commit/69216ee69c7172e847b64e0e934b5121a34d0ea3) feat: no-empty suggest to add comment in empty BlockStatement (#16470) (Nitin Kumar)
+* [`324db1a`](https://github.com/eslint/eslint/commit/324db1a11e43ba9d954dc522763faea19129ce6a) docs: explicit stylelint color related rules (#16465) (Nick Schonning)
+* [`94dc4f1`](https://github.com/eslint/eslint/commit/94dc4f19ba49fe2358f8bcc2fc3555d222766755) docs: use Stylelint for HTML files (#16468) (Nick Schonning)
+* [`cc6128d`](https://github.com/eslint/eslint/commit/cc6128db4f489c3ab80fff2f9dbeea313e72208d) docs: enable stylelint declaration-block-no-duplicate-properties (#16466) (Nick Schonning)
+* [`d03a8bf`](https://github.com/eslint/eslint/commit/d03a8bf8978bd330aeb951f18cc92bf1ad24eeec) docs: Add heading to justification explanation (#16430) (Maritaria)
+* [`886a038`](https://github.com/eslint/eslint/commit/886a0386897f96d2da95eba8c52bd893fcbf7e86) fix: handle files with unspecified path in `getRulesMetaForResults` (#16437) (Francesco Trotta)
+* [`319f0a5`](https://github.com/eslint/eslint/commit/319f0a5491598825bbd528c6d1fc12771056a74c) feat: use `context.languageOptions.ecmaVersion` in core rules (#16458) (Milos Djermanovic)
+* [`8a15968`](https://github.com/eslint/eslint/commit/8a159686f9d497262d573dd601855ce28362199b) docs: add Stylelint configuration and cleanup (#16379) (Nick Schonning)
+* [`9b0a469`](https://github.com/eslint/eslint/commit/9b0a469d1e4650c1d9da26239357e715b11b2d97) docs: note commit messages don't support scope (#16435) (Andy Edwards)
+* [`1581405`](https://github.com/eslint/eslint/commit/15814057fd69319b3744bdea5db2455f85d2e74f) docs: improve context.getScope() docs (#16417) (Ben Perlmutter)
+* [`b797149`](https://github.com/eslint/eslint/commit/b7971496e9b44add405ca0360294f5c3be85b540) docs: update formatters template (#16454) (Milos Djermanovic)
+* [`5ac4de9`](https://github.com/eslint/eslint/commit/5ac4de911f712cb3a5a16eb7a4063eee09dfc97c) docs: fix link to formatters on the Core Concepts page (#16455) (Vladislav)
+* [`33313ef`](https://github.com/eslint/eslint/commit/33313ef56258a6a96b00a3e70025b94bd2f2fe9f) docs: core-concepts: fix link to semi rule (#16453) (coderaiser)
+
+v8.26.0 - October 21, 2022
+
+* [`df77409`](https://github.com/eslint/eslint/commit/df7740967ffab2915974c7b310ac76ea2915ac2d) fix: use `baseConfig` constructor option in FlatESLint (#16432) (Milos Djermanovic)
+* [`33668ee`](https://github.com/eslint/eslint/commit/33668ee9d22e1988ba03e07fb547738bdb21dc0e) fix: Ensure that glob patterns are matched correctly. (#16449) (Nicholas C. Zakas)
+* [`651649b`](https://github.com/eslint/eslint/commit/651649b12797594a86c0d659d6a0d1cdbda6f57b) docs: Core concepts page (#16399) (Ben Perlmutter)
+* [`4715787`](https://github.com/eslint/eslint/commit/4715787724a71494ba0bb0c5fe4639570bb6985b) feat: check `Object.create()` in getter-return (#16420) (Yuki Hirasawa)
+* [`e917a9a`](https://github.com/eslint/eslint/commit/e917a9a2e555d398c64b985fc933d44a42c958f0) ci: add node v19 (#16443) (Koichi ITO)
+* [`740b208`](https://github.com/eslint/eslint/commit/740b20826fadc5322ea5547c1ba41793944e571d) fix: ignore messages without a `ruleId` in `getRulesMetaForResults` (#16409) (Francesco Trotta)
+* [`8f9759e`](https://github.com/eslint/eslint/commit/8f9759e2a94586357d85fac902e038fabdba79a7) fix: `--ignore-pattern` in flat config mode should be relative to `cwd` (#16425) (Milos Djermanovic)
+* [`325ad37`](https://github.com/eslint/eslint/commit/325ad375a52d1c7b8b8fd23943350c91781366a2) fix: make `getRulesMetaForResults` return a plain object in trivial case (#16438) (Francesco Trotta)
+* [`a2810bc`](https://github.com/eslint/eslint/commit/a2810bc485d9f1123a86b60702fcaa51e19d71a3) fix: Ensure that directories can be unignored. (#16436) (Nicholas C. Zakas)
+* [`631cf72`](https://github.com/eslint/eslint/commit/631cf72e82f316a2cc08770e5c81b858637ab04a) docs: note --ignore-path not supported with flat config (#16434) (Andy Edwards)
+* [`1692840`](https://github.com/eslint/eslint/commit/1692840a2f763737a4891419dc304db4ebedab5d) docs: fix syntax in examples for new config files (#16427) (Milos Djermanovic)
+* [`28d1902`](https://github.com/eslint/eslint/commit/28d190264017dbaa29f2ab218f73b623143cd1af) feat: `no-implicit-globals` supports `exported` block comment (#16343) (Sosuke Suzuki)
+* [`35916ad`](https://github.com/eslint/eslint/commit/35916ad9bfc07dab63361721df1bd7f21e43e094) fix: Ensure unignore and reignore work correctly in flat config. (#16422) (Nicholas C. Zakas)
+* [`4b70b91`](https://github.com/eslint/eslint/commit/4b70b91a6e28669ab8e2a4ce2a6d9ed40be20fa7) chore: Add VS Code issues link (#16423) (Nicholas C. Zakas)
+* [`e940be7`](https://github.com/eslint/eslint/commit/e940be7a83d0caea15b64c1e1c2785a6540e2641) feat: Use ESLINT_USE_FLAT_CONFIG environment variable for flat config (#16356) (Tomer Aberbach)
+* [`d336cfc`](https://github.com/eslint/eslint/commit/d336cfc9145a72bf8730250ee1e331a135e6ee2c) docs: Document extending plugin with new config (#16394) (Ben Perlmutter)
+* [`dd0c58f`](https://github.com/eslint/eslint/commit/dd0c58f0f34d24331ae55139af39cf2747125f5e) feat: Swap out Globby for custom globbing solution. (#16369) (Nicholas C. Zakas)
+* [`232d291`](https://github.com/eslint/eslint/commit/232d2916ac5e44db55c2ffbd2f3b37ad70037b7b) chore: suppress a Node.js deprecation warning (#16398) (Koichi ITO)
+
+v8.25.0 - October 7, 2022
+
+* [`1f78594`](https://github.com/eslint/eslint/commit/1f785944f61c97996445e48cb74fc300142e7310) chore: upgrade @eslint/eslintrc@1.3.3 (#16397) (Milos Djermanovic)
+* [`173e820`](https://github.com/eslint/eslint/commit/173e82040895ad53b2d9940bfb3fb67a0478f00b) feat: Pass --max-warnings value to formatters (#16348) (Brandon Mills)
+* [`8476a9b`](https://github.com/eslint/eslint/commit/8476a9b8b81164887cdf38a21d431b75ff2956b1) chore: Remove CODEOWNERS (#16375) (Nick Schonning)
+* [`720ff75`](https://github.com/eslint/eslint/commit/720ff75beb9f4fdcf2a185fcb8020cf78483fdeb) chore: use "ci" for Dependabot commit message (#16377) (Nick Schonning)
+* [`90c6028`](https://github.com/eslint/eslint/commit/90c602802b6e330b79c42f282e9a615c583e32d7) docs: Conflicting fixes (#16366) (Ben Perlmutter)
+* [`5a3fe70`](https://github.com/eslint/eslint/commit/5a3fe70c5261acbf115fa5f47231cbc4ac62c1bc) docs: Add VS to integrations page (#16381) (Maria José Solano)
+* [`6964cb1`](https://github.com/eslint/eslint/commit/6964cb1e0f073b236cb3288b9d8be495336bbf29) feat: remove support for ignore files in FlatESLint (#16355) (Milos Djermanovic)
+* [`49bd1e5`](https://github.com/eslint/eslint/commit/49bd1e5669b34fd7e0f4a3cf42009866980d7e15) docs: remove unused link definitions (#16376) (Nick Schonning)
+* [`42f5479`](https://github.com/eslint/eslint/commit/42f547948f284f1c67799f237dfeb86fc400c7c7) chore: bump actions/stale from 5 to 6 (#16350) (dependabot[bot])
+* [`3bd380d`](https://github.com/eslint/eslint/commit/3bd380d3ea7e88ade4905ec0b240c866ab79a69d) docs: typo cleanups for docs (#16374) (Nick Schonning)
+* [`b3a0837`](https://github.com/eslint/eslint/commit/b3a08376cfb61275a7557d6d166b6116f36e5ac2) docs: remove duplicate words (#16378) (Nick Schonning)
+* [`a682562`](https://github.com/eslint/eslint/commit/a682562458948f74a227be60a80e10e7a3753124) docs: add `BigInt` to `new-cap` docs (#16362) (Sosuke Suzuki)
+* [`1cc4b3a`](https://github.com/eslint/eslint/commit/1cc4b3a8f82a7945dcd8c59550b6a906a0fabbb4) feat: `id-length` counts graphemes instead of code units (#16321) (Sosuke Suzuki)
+* [`f6d57fb`](https://github.com/eslint/eslint/commit/f6d57fb657c2f4e8e0140ad057da34c935482972) docs: Update docs README (#16352) (Ben Perlmutter)
+* [`e5e9e27`](https://github.com/eslint/eslint/commit/e5e9e271da58361bda16f7abc8f367ccc6f91510) chore: remove `jsdoc` dev dependency (#16344) (Milos Djermanovic)
+* [`7214347`](https://github.com/eslint/eslint/commit/721434705bd569e33911e25d2688e33f10898d52) docs: fix logical-assignment-operators option typo (#16346) (Jonathan Wilsson)
+
+v8.24.0 - September 23, 2022
+
+* [`131e646`](https://github.com/eslint/eslint/commit/131e646e227b9aca3937fe287343bf2c3df408af) chore: Upgrade @humanwhocodes/config-array for perf (#16339) (Nicholas C. Zakas)
+* [`2c152ff`](https://github.com/eslint/eslint/commit/2c152ff0fb709b99e62c19ecd2c95689efacbe4c) docs: note false positive `Object.getOwnPropertyNames` in prefer-reflect (#16317) (AnnAngela)
+* [`bf7bd88`](https://github.com/eslint/eslint/commit/bf7bd885a92046a6b6bcbcaaa1e78e9f2c4b482f) docs: fix warn severity description for new config files (#16324) (Nitin Kumar)
+* [`504fe59`](https://github.com/eslint/eslint/commit/504fe59b0e0f4f5a2afb6a69aaed5cb4ca631012) perf: switch from object spread to `Object.assign` when merging globals (#16311) (Milos Djermanovic)
+* [`1729f9e`](https://github.com/eslint/eslint/commit/1729f9ea4d7b2945b2b701d72027fd4aace954cf) feat: account for `sourceType: "commonjs"` in the strict rule (#16308) (Milos Djermanovic)
+* [`b0d72c9`](https://github.com/eslint/eslint/commit/b0d72c96b2a9cde7a5798c2b08ec4e70683c6aca) feat: add rule logical-assignment-operators (#16102) (fnx)
+* [`f02bcd9`](https://github.com/eslint/eslint/commit/f02bcd91bf89b6c167d5346a36677fdb854f0c05) feat: `array-callback-return` support `findLast` and `findLastIndex` (#16314) (Sosuke Suzuki)
+* [`8cc0bbe`](https://github.com/eslint/eslint/commit/8cc0bbe440dc5e6af6ef02f00d0514a40ca07c24) docs: use more clean link syntax (#16309) (Percy Ma)
+* [`6ba269e`](https://github.com/eslint/eslint/commit/6ba269ed673f965d081287b769c12beeb5f98887) docs: fix typo (#16288) (jjangga0214)
+
v8.23.1 - September 12, 2022
* [`b719893`](https://github.com/eslint/eslint/commit/b71989388a921886caa4c6cb48729bbf60c46100) fix: Upgrade eslintrc to stop redefining plugins (#16297) (Brandon Mills)
Before filing an issue, please be sure to read the guidelines for what you're reporting:
-* [Bug Report](https://eslint.org/docs/developer-guide/contributing/reporting-bugs)
-* [Propose a New Rule](https://eslint.org/docs/developer-guide/contributing/new-rules)
-* [Proposing a Rule Change](https://eslint.org/docs/developer-guide/contributing/rule-changes)
-* [Request a Change](https://eslint.org/docs/developer-guide/contributing/changes)
+* [Report Bugs](https://eslint.org/docs/latest/contribute/report-bugs)
+* [Propose a New Rule](https://eslint.org/docs/latest/contribute/propose-new-rule)
+* [Propose a Rule Change](https://eslint.org/docs/latest/contribute/propose-rule-change)
+* [Request a Change](https://eslint.org/docs/latest/contribute/request-change)
To report a security vulnerability in ESLint, please use our [HackerOne program](https://hackerone.com/eslint).
## Contributing Code
-In order to submit code or documentation to an ESLint project, you’ll be asked to sign our CLA when you send your first pull request. (Read more about the Open JS Foundation CLA process at <https://cla.openjsf.org/>.) Also, please read over the [Pull Request Guidelines](https://eslint.org/docs/developer-guide/contributing/pull-requests).
+In order to submit code or documentation to an ESLint project, you’ll be asked to sign our CLA when you send your first pull request. (Read more about the Open JS Foundation CLA process at <https://cla.openjsf.org/>.) Also, please read over the [Pull Request Guidelines](https://eslint.org/docs/latest/contribute/pull-requests).
## Full Documentation
Our full contribution guidelines can be found at:
-<https://eslint.org/docs/developer-guide/contributing/>
+<https://eslint.org/docs/latest/contribute/>
fs = require("fs"),
glob = require("glob"),
marked = require("marked"),
+ matter = require("gray-matter"),
markdownlint = require("markdownlint"),
os = require("os"),
path = require("path"),
*/
function generateFormatterExamples(formatterInfo) {
const output = ejs.render(cat("./templates/formatter-examples.md.ejs"), formatterInfo);
- const outputDir = path.join(DOCS_SRC_DIR, "user-guide/formatters/"),
+ const outputDir = path.join(DOCS_SRC_DIR, "use/formatters/"),
filename = path.join(outputDir, "index.md"),
htmlFilename = path.join(outputDir, "html-formatter-example.html");
*/
function publishRelease() {
ReleaseOps.publishRelease();
+ const releaseInfo = JSON.parse(cat(".eslint-release-info.json"));
+ const isPreRelease = /[a-z]/u.test(releaseInfo.version);
- // push to latest branch to trigger docs deploy
- exec("git push origin HEAD:latest -f");
+ /*
+ * for a pre-release, push to the "next" branch to trigger docs deploy
+ * for a release, push to the "latest" branch to trigger docs deploy
+ */
+ if (isPreRelease) {
+ exec("git push origin HEAD:next -f");
+ } else {
+ exec("git push origin HEAD:latest -f");
+ }
publishSite();
}
*/
function getFormatterResults() {
const stripAnsi = require("strip-ansi");
+ const formattersMetadata = require("./lib/cli-engine/formatters/formatters-meta.json");
- const formatterFiles = fs.readdirSync("./lib/cli-engine/formatters/"),
+ const formatterFiles = fs.readdirSync("./lib/cli-engine/formatters/").filter(fileName => !fileName.includes("formatters-meta.json")),
rules = {
"no-else-return": "warn",
indent: ["warn", 4],
);
data.formatterResults[name] = {
- result: stripAnsi(formattedOutput)
+ result: stripAnsi(formattedOutput),
+ description: formattersMetadata.find(formatter => formatter.name === name).description
};
}
return data;
* when analyzing `require()` calls from CJS modules in the `docs` directory. Since our release process does not run `npm install`
* in the `docs` directory, linting would fail and break the release. Also, working on the main `eslint` package does not require
* installing dependencies declared in `docs/package.json`, so most contributors will not have `docs/node_modules` locally.
- * Therefore, we add `--ignore-pattern docs` to exclude linting the `docs` directory from this command.
+ * Therefore, we add `--ignore-pattern "docs/**"` to exclude linting the `docs` directory from this command.
* There is a separate command `target.lintDocsJS` for linting JavaScript files in the `docs` directory.
*/
echo("Validating JavaScript files");
- lastReturn = exec(`${ESLINT}${fix ? "--fix" : ""} . --ignore-pattern docs`);
+ lastReturn = exec(`${ESLINT}${fix ? "--fix" : ""} . --ignore-pattern "docs/**"`);
if (lastReturn.code !== 0) {
errors++;
}
let errors = 0;
echo("Validating JavaScript files in the docs directory");
- const lastReturn = exec(`${ESLINT}${fix ? "--fix" : ""} docs/.eleventy.js`);
+ const lastReturn = exec(`${ESLINT}${fix ? "--fix" : ""} docs`);
if (lastReturn.code !== 0) {
errors++;
};
target.test = function() {
- target.lint();
target.checkRuleFiles();
target.mocha();
target.karma();
const basename = path.basename(filename, ".js");
const docFilename = `docs/src/rules/${basename}.md`;
const docText = cat(docFilename);
- const docMarkdown = marked.lexer(docText, { gfm: true, silent: false });
+ const docTextWithoutFrontmatter = matter(String(docText)).content;
+ const docMarkdown = marked.lexer(docTextWithoutFrontmatter, { gfm: true, silent: false });
const ruleCode = cat(filename);
const knownHeaders = ["Rule Details", "Options", "Environments", "Examples", "Known Limitations", "When Not To Use It", "Compatibility"];
}
// check eslint:recommended
- const recommended = require("./conf/eslint-recommended");
+ const recommended = require("./packages/js").configs.recommended;
if (ruleDef.meta.docs.recommended) {
if (recommended.rules[basename] !== "error") {
- console.error(`Missing rule from eslint:recommended (./conf/eslint-recommended.js): ${basename}. If you just made a rule recommended then add an entry for it in this file.`);
+ console.error(`Missing rule from eslint:recommended (./packages/js/src/configs/eslint-recommended.js): ${basename}. If you just made a rule recommended then add an entry for it in this file.`);
errors++;
}
} else {
if (basename in recommended.rules) {
- console.error(`Extra rule in eslint:recommended (./conf/eslint-recommended.js): ${basename}. If you just added a rule then don't add an entry for it in this file.`);
+ console.error(`Extra rule in eslint:recommended (./packages/js/src/configs/eslint-recommended.js): ${basename}. If you just added a rule then don't add an entry for it in this file.`);
errors++;
}
}
# ESLint
[Website](https://eslint.org) |
-[Configuring](https://eslint.org/docs/user-guide/configuring) |
+[Configure ESLint](https://eslint.org/docs/latest/use/configure) |
[Rules](https://eslint.org/docs/rules/) |
-[Contributing](https://eslint.org/docs/developer-guide/contributing) |
-[Reporting Bugs](https://eslint.org/docs/developer-guide/contributing/reporting-bugs) |
+[Contribute to ESLint](https://eslint.org/docs/latest/contribute) |
+[Report Bugs](https://eslint.org/docs/latest/contribute/report-bugs) |
[Code of Conduct](https://eslint.org/conduct) |
[Twitter](https://twitter.com/geteslint) |
-[Mailing List](https://groups.google.com/group/eslint) |
-[Chat Room](https://eslint.org/chat)
+[Discord](https://eslint.org/chat) |
+[Mastodon](https://fosstodon.org/@eslint)
ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code. In many ways, it is similar to JSLint and JSHint with a few exceptions:
2. [Configuration](#configuration)
3. [Code of Conduct](#code-of-conduct)
4. [Filing Issues](#filing-issues)
-5. [Frequently Asked Questions](#faq)
+5. [Frequently Asked Questions](#frequently-asked-questions)
6. [Releases](#releases)
7. [Security Policy](#security-policy)
8. [Semantic Versioning Policy](#semantic-versioning-policy)
12. [Sponsors](#sponsors)
13. [Technology Sponsors](#technology-sponsors)
-## <a name="installation-and-usage"></a>Installation and Usage
+## Installation and Usage
Prerequisites: [Node.js](https://nodejs.org/) (`^12.22.0`, `^14.17.0`, or `>=16.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
./node_modules/.bin/eslint yourfile.js
```
-## <a name="configuration"></a>Configuration
+## Configuration
-After running `npm init @eslint/config`, you'll have a `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
+After running `npm init @eslint/config`, you'll have an `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
```json
{
* `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
* `"error"` or `2` - turn the rule on as an error (exit code will be 1)
-The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the [configuration docs](https://eslint.org/docs/user-guide/configuring)).
+The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the [configuration docs](https://eslint.org/docs/latest/use/configure)).
-## <a name="code-of-conduct"></a>Code of Conduct
+## Code of Conduct
ESLint adheres to the [JS Foundation Code of Conduct](https://eslint.org/conduct).
-## <a name="filing-issues"></a>Filing Issues
+## Filing Issues
Before filing an issue, please be sure to read the guidelines for what you're reporting:
-* [Bug Report](https://eslint.org/docs/developer-guide/contributing/reporting-bugs)
-* [Propose a New Rule](https://eslint.org/docs/developer-guide/contributing/new-rules)
-* [Proposing a Rule Change](https://eslint.org/docs/developer-guide/contributing/rule-changes)
-* [Request a Change](https://eslint.org/docs/developer-guide/contributing/changes)
+* [Bug Report](https://eslint.org/docs/latest/contribute/report-bugs)
+* [Propose a New Rule](https://eslint.org/docs/latest/contribute/propose-new-rule)
+* [Proposing a Rule Change](https://eslint.org/docs/latest/contribute/propose-rule-change)
+* [Request a Change](https://eslint.org/docs/latest/contribute/request-change)
-## <a name="faq"></a>Frequently Asked Questions
+## Frequently Asked Questions
### I'm using JSCS, should I migrate to ESLint?
Yes. [JSCS has reached end of life](https://eslint.org/blog/2016/07/jscs-end-of-life) and is no longer supported.
-We have prepared a [migration guide](https://eslint.org/docs/user-guide/migrating-from-jscs) to help you convert your JSCS settings to an ESLint configuration.
+We have prepared a [migration guide](https://eslint.org/docs/latest/use/migrating-from-jscs) to help you convert your JSCS settings to an ESLint configuration.
We are now at or near 100% compatibility with JSCS. If you try ESLint and believe we are not yet compatible with a JSCS rule/configuration, please create an issue (mentioning that it is a JSCS compatibility issue) and we will evaluate it as per our normal process.
### Does ESLint support JSX?
-Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [configuration](https://eslint.org/docs/user-guide/configuring)). Please note that supporting JSX syntax *is not* the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) if you are using React and want React semantics.
+Yes, ESLint natively supports parsing JSX syntax (this must be enabled in [configuration](https://eslint.org/docs/latest/use/configure)). Please note that supporting JSX syntax *is not* the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://www.npmjs.com/package/eslint-plugin-react) if you are using React and want React semantics.
### What ECMAScript versions does ESLint support?
-ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2019, 2020, 2021 and 2022. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/user-guide/configuring).
+ESLint has full support for ECMAScript 3, 5 (default), 2015, 2016, 2017, 2018, 2019, 2020, 2021 and 2022. You can set your desired ECMAScript syntax (and other settings, like global variables or your target environments) through [configuration](https://eslint.org/docs/latest/use/configure).
### What about experimental features?
In other cases (including if rules need to warn on more or fewer cases due to new syntax, rather than just not crashing), we recommend you use other parsers and/or rule plugins. If you are using Babel, you can use [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) and [@babel/eslint-plugin](https://www.npmjs.com/package/@babel/eslint-plugin) to use any option available in Babel.
-Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the [TC39 process](https://tc39.github.io/process-document/)), we will accept issues and pull requests related to the new feature, subject to our [contributing guidelines](https://eslint.org/docs/developer-guide/contributing). Until then, please use the appropriate parser and plugin(s) for your experimental feature.
+Once a language feature has been adopted into the ECMAScript standard (stage 4 according to the [TC39 process](https://tc39.github.io/process-document/)), we will accept issues and pull requests related to the new feature, subject to our [contributing guidelines](https://eslint.org/docs/latest/contribute). Until then, please use the appropriate parser and plugin(s) for your experimental feature.
### Where to ask for help?
-Join our [Mailing List](https://groups.google.com/group/eslint) or [Chatroom](https://eslint.org/chat).
+Open a [discussion](https://github.com/eslint/eslint/discussions) or stop by our [Discord server](https://eslint.org/chat).
### Why doesn't ESLint lock dependency versions?
The Twilio blog has a [deeper dive](https://www.twilio.com/blog/lockfiles-nodejs) to learn more.
-## <a name="releases"></a>Releases
+## Releases
We have scheduled releases every two weeks on Friday or Saturday. You can follow a [release issue](https://github.com/eslint/eslint/issues?q=is%3Aopen+is%3Aissue+label%3Arelease) for updates about the scheduling of any particular release.
-## <a name="security-policy"></a>Security Policy
+## Security Policy
ESLint takes security seriously. We work hard to ensure that ESLint is safe for everyone and that security issues are addressed quickly and responsibly. Read the full [security policy](https://github.com/eslint/.github/blob/master/SECURITY.md).
-## <a name="semantic-versioning-policy"></a>Semantic Versioning Policy
+## Semantic Versioning Policy
ESLint follows [semantic versioning](https://semver.org). However, due to the nature of ESLint as a code quality tool, it's not always clear when a minor or major version bump occurs. To help clarify this for everyone, we've defined the following semantic versioning policy for ESLint:
According to our policy, any minor update may report more linting errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (`~`) in `package.json` e.g. `"eslint": "~3.1.0"` to guarantee the results of your builds.
-## <a name="stylistic-rule-updates"></a>Stylistic Rule Updates
+## Stylistic Rule Updates
Stylistic rules are frozen according to [our policy](https://eslint.org/blog/2020/05/changes-to-rules-policies) on how we evaluate new rules and rule changes.
This means:
* **New ECMAScript features**: We will also make sure stylistic rules are compatible with new ECMAScript features.
* **New options**: We will **not** add any new options to stylistic rules unless an option is the only way to fix a bug or support a newly-added ECMAScript feature.
-## <a name="license"></a>License
+## License
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Feslint%2Feslint.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Feslint%2Feslint?ref=badge_large)
-## <a name="team"></a>Team
+## Team
These folks keep the project moving and are resources for help.
Nicholas C. Zakas
</a>
</td><td align="center" valign="top" width="11%">
-<a href="https://github.com/btmills">
-<img src="https://github.com/btmills.png?s=75" width="75" height="75"><br />
-Brandon Mills
-</a>
-</td><td align="center" valign="top" width="11%">
<a href="https://github.com/mdjermanovic">
<img src="https://github.com/mdjermanovic.png?s=75" width="75" height="75"><br />
Milos Djermanovic
The people who review and fix bugs and help triage issues.
<table><tbody><tr><td align="center" valign="top" width="11%">
-<a href="https://github.com/brettz9">
-<img src="https://github.com/brettz9.png?s=75" width="75" height="75"><br />
-Brett Zamir
-</a>
-</td><td align="center" valign="top" width="11%">
<a href="https://github.com/bmish">
<img src="https://github.com/bmish.png?s=75" width="75" height="75"><br />
Bryan Mishkin
</a>
</td><td align="center" valign="top" width="11%">
-<a href="https://github.com/SaraSoueidan">
-<img src="https://github.com/SaraSoueidan.png?s=75" width="75" height="75"><br />
-Sara Soueidan
+<a href="https://github.com/fasttime">
+<img src="https://github.com/fasttime.png?s=75" width="75" height="75"><br />
+Francesco Trotta
</a>
-</td><td align="center" valign="top" width="11%">
-<a href="https://github.com/g-plane">
-<img src="https://github.com/g-plane.png?s=75" width="75" height="75"><br />
-Pig Fang
+</td></tr></tbody></table>
+
+### Website Team
+
+Team members who focus specifically on eslint.org
+
+<table><tbody><tr><td align="center" valign="top" width="11%">
+<a href="https://github.com/amareshsm">
+<img src="https://github.com/amareshsm.png?s=75" width="75" height="75"><br />
+Amaresh S M
</a>
</td><td align="center" valign="top" width="11%">
-<a href="https://github.com/anikethsaha">
-<img src="https://github.com/anikethsaha.png?s=75" width="75" height="75"><br />
-Anix
+<a href="https://github.com/harish-sethuraman">
+<img src="https://github.com/harish-sethuraman.png?s=75" width="75" height="75"><br />
+Strek
</a>
</td><td align="center" valign="top" width="11%">
-<a href="https://github.com/yeonjuan">
-<img src="https://github.com/yeonjuan.png?s=75" width="75" height="75"><br />
-YeonJuan
+<a href="https://github.com/kecrily">
+<img src="https://github.com/kecrily.png?s=75" width="75" height="75"><br />
+Percy Ma
</a>
</td></tr></tbody></table>
<!--teamend-->
-## <a name="sponsors"></a>Sponsors
+## 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.
<!-- 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/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
-<p><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://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" 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://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" 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" 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.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a></p>
+<p><a href="#"><img src="https://images.opencollective.com/2021-frameworks-fund/logo.png" alt="Chrome Frameworks Fund" height="undefined"></a> <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://engineering.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></p><h3>Silver Sponsors</h3>
+<p><a href="https://sentry.io"><img src="https://avatars.githubusercontent.com/u/1396951?v=4" alt="Sentry" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://americanexpress.io"><img src="https://avatars.githubusercontent.com/u/3853301?v=4" alt="American Express" height="64"></a></p><h3>Bronze Sponsors</h3>
+<p><a href="https://www.vedonlyontibonukset.com/pitkavetovihjeet"><img src="https://images.opencollective.com/pitkavetovihjeet/0131f1d/logo.png" alt="Ilmaiset Pitkävetovihjeet" height="32"></a> <a href="https://paydaysay.com/"><img src="https://images.opencollective.com/payday-say-organization/9cd2467/logo.png" alt="PayDay Say" 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://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" 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://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://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p>
<!--sponsorsend-->
-## <a name="technology-sponsors"></a>Technology Sponsors
+## Technology Sponsors
* Site search ([eslint.org](https://eslint.org)) is sponsored by [Algolia](https://www.algolia.com)
* Hosting for ([eslint.org](https://eslint.org)) is sponsored by [Netlify](https://www.netlify.com)
],
"deprecated": {
"name": "Deprecated",
- "description": "These rules have been deprecated in accordance with the <a href=\"/docs/user-guide/rule-deprecation\">deprecation policy</a>, and replaced by newer rules:",
+ "description": "These rules have been deprecated in accordance with the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a>, and replaced by newer rules:",
"rules": []
},
"removed": {
"name": "Removed",
- "description": "These rules from older versions of ESLint (before the <a href=\"/docs/user-guide/rule-deprecation\">deprecation policy</a> existed) have been replaced by newer rules:",
+ "description": "These rules from older versions of ESLint (before the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a> existed) have been replaced by newer rules:",
"rules": [
{ "removed": "generator-star", "replacedBy": ["generator-star-spacing"] },
{ "removed": "global-strict", "replacedBy": ["strict"] },
const path = require("path");
const { slug } = require("github-slugger");
const yaml = require("js-yaml");
-
+const { highlighter, lineNumberPlugin } = require("./src/_plugins/md-syntax-highlighter");
const {
DateTime
} = require("luxon");
* it's easier to see if URLs are broken.
*
* When a release is published, HEAD is pushed to the "latest" branch.
- * Netlify deploys that branch as well, and in that case, we want the
- * docs to be loaded from /docs/latest on eslint.org.
+ * When a pre-release is published, HEAD is pushed to the "next" branch.
+ * Netlify deploys those branches as well, and in that case, we want the
+ * docs to be loaded from /docs/latest or /docs/next on eslint.org.
*
* The path prefix is turned off for deploy previews so we can properly
* see changes before deployed.
pathPrefix = "/";
} else if (process.env.BRANCH === "latest") {
pathPrefix = "/docs/latest/";
+ } else if (process.env.BRANCH === "next") {
+ pathPrefix = "/docs/next/";
}
//------------------------------------------------------------------------------
eleventyConfig.addGlobalData("site_name", siteName);
eleventyConfig.addGlobalData("GIT_BRANCH", process.env.BRANCH);
+ eleventyConfig.addGlobalData("HEAD", process.env.BRANCH === "main");
eleventyConfig.addGlobalData("NOINDEX", process.env.BRANCH !== "latest");
eleventyConfig.addDataExtension("yml", contents => yaml.load(contents));
eleventyConfig.addFilter("jsonify", variable => JSON.stringify(variable));
- /**
- * Takes in a string and converts to a slug
- * @param {string} text text to be converted into slug
- * @returns {string} slug to be used as anchors
- */
- function slugify(text) {
- return slug(text.replace(/[<>()[\]{}]/gu, ""))
- // eslint-disable-next-line no-control-regex -- used regex from https://github.com/eslint/archive-website/blob/master/_11ty/plugins/markdown-plugins.js#L37
- .replace(/[^\u{00}-\u{FF}]/gu, "");
- }
-
eleventyConfig.addFilter("slugify", str => {
if (!str) {
return "";
}
- return slugify(str);
+ return slug(str);
});
eleventyConfig.addFilter("URIencode", str => {
eleventyConfig.addPlugin(eleventyNavigationPlugin);
eleventyConfig.addPlugin(syntaxHighlight, {
- alwaysWrapLineHighlights: true
+ alwaysWrapLineHighlights: true,
+ templateFormats: ["liquid", "njk"]
});
eleventyConfig.addPlugin(pluginRss);
eleventyConfig.addPlugin(pluginTOC, {
}
const markdownIt = require("markdown-it");
+ const md = markdownIt({ html: true, linkify: true, typographer: true, highlight: (str, lang) => highlighter(md, str, lang) })
+ .use(markdownItAnchor, {
+ slugify: s => slug(s)
+ })
+ .use(markdownItContainer, "img-container", {})
+ .use(markdownItContainer, "correct", {})
+ .use(markdownItContainer, "incorrect", {})
+ .use(markdownItContainer, "warning", {
+ render(tokens, idx) {
+ return generateAlertMarkup("warning", tokens, idx);
+ }
+ })
+ .use(markdownItContainer, "tip", {
+ render(tokens, idx) {
+ return generateAlertMarkup("tip", tokens, idx);
+ }
+ })
+ .use(markdownItContainer, "important", {
+ render(tokens, idx) {
+ return generateAlertMarkup("important", tokens, idx);
+ }
+ })
+ .use(lineNumberPlugin)
+ .disable("code");
- eleventyConfig.setLibrary("md",
- markdownIt({ html: true, linkify: true, typographer: true })
- .use(markdownItAnchor, {
- slugify
- })
- .use(markdownItContainer, "correct", {})
- .use(markdownItContainer, "incorrect", {})
- .use(markdownItContainer, "warning", {
- render(tokens, idx) {
- return generateAlertMarkup("warning", tokens, idx);
- }
- })
- .use(markdownItContainer, "tip", {
- render(tokens, idx) {
- return generateAlertMarkup("tip", tokens, idx);
- }
- })
- .use(markdownItContainer, "important", {
- render(tokens, idx) {
- return generateAlertMarkup("important", tokens, idx);
- }
- })
- .disable("code"));
+ eleventyConfig.setLibrary("md", md);
//------------------------------------------------------------------------------
// Shortcodes
eleventyConfig.addShortcode("fixable", () => `
<div class="rule-category">
- <span class="rule-category__icon">ð\9f\9b <span class="visually-hidden">Fixable</span></span>
+ <span class="rule-category__icon">ð\9f\94§ <span class="visually-hidden">Fixable</span></span>
<p class="rule-category__description">
if some problems reported by the rule are automatically fixable by the <code>--fix</code> command line option
</p>
* URLs with a file extension, like main.css, main.js, sitemap.xml, etc. should not be rewritten
*/
eleventyConfig.setBrowserSyncConfig({
- middleware: (req, res, next) => {
+ middleware(req, res, next) {
if (!/(?:\.[a-zA-Z][^/]*|\/)$/u.test(req.url)) {
req.url += ".html";
}
--- /dev/null
+{
+ "extends": ["stylelint-config-standard-scss"],
+ "rules": {
+ "alpha-value-notation": "number",
+ "at-rule-empty-line-before": null,
+ "color-function-notation": "legacy",
+ "custom-property-empty-line-before": null,
+ "custom-property-pattern": null,
+ "declaration-block-no-duplicate-properties": [true, {
+ "ignore": ["consecutive-duplicates-with-different-values"]
+ }],
+ "declaration-block-no-redundant-longhand-properties": null,
+ "hue-degree-notation": "number",
+ "indentation": 4,
+ "max-line-length": null,
+ "no-descending-specificity": null,
+ "number-leading-zero": null,
+ "number-no-trailing-zeros": null,
+ "selector-class-pattern": null,
+ "value-keyword-case": null
+ },
+ "overrides": [
+ {
+ "files": [
+ "**/*.html"
+ ],
+ "extends": ["stylelint-config-html/html", "stylelint-config-standard"]
+ }
+ ],
+ "ignoreFiles": [
+ "_site/**"
+ ]
+ }
# ESLint Documentation
+## Install Dependencies
+
+Install the necessary dependencies for the documentation site by running this
+from the `docs` folder:
+
+```shell
+npm install
+```
+
## Run Locally
+Run this from the `docs` folder:
+
```shell
npm start
```
+Once the script finishes building the documentation site, you can visit it at
+<http://localhost:2023>.
+
## Scripts
To update the links data file, run this from the root folder (not the `docs` folder):
```shell
npm run fix:docsjs
```
+
+## License
+
+© OpenJS Foundation and ESLint contributors, [www.openjsf.org](https://www.openjsf.org/). Content licensed under [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-nc-sa/4.0/).
{
"name": "docs-eslint",
"private": true,
- "version": "8.23.1",
+ "version": "8.41.0",
"description": "",
"main": "index.js",
"keywords": [],
"files": [],
"scripts": {
"images": "imagemin '_site/assets/images' --out-dir='_site/assets/images'",
- "watch:sass": "sass --watch --poll src/assets/scss:src/assets/css",
+ "watch:postcss": "postcss src/assets/css -d src/assets/css --watch --poll",
+ "watch:sass": "sass --watch --poll src/assets/scss:src/assets/css --no-source-map",
"watch:eleventy": "eleventy --serve --port=2023",
- "build:sass": "sass --style=compressed src/assets/scss:src/assets/css --no-source-map",
+ "build:postcss": "postcss src/assets/css -d src/assets/css",
+ "build:sass": "sass src/assets/scss:src/assets/css --no-source-map",
"build:eleventy": "npx @11ty/eleventy",
- "start": "npm-run-all build:sass --parallel watch:*",
- "build": "npm-run-all build:sass build:eleventy images"
+ "start": "npm-run-all build:sass build:postcss --parallel watch:*",
+ "build": "npm-run-all build:sass build:postcss build:eleventy images",
+ "lint:scss": "stylelint \"**/*.{scss,html}\"",
+ "lint:links": "cross-env NODE_OPTIONS=--max-old-space-size=4096 node tools/validate-links.js",
+ "lint:fix:scss": "npm run lint:scss -- --fix"
},
"devDependencies": {
"@11ty/eleventy": "^1.0.1",
"@11ty/eleventy-navigation": "^0.3.2",
"@11ty/eleventy-plugin-rss": "^1.1.1",
"@11ty/eleventy-plugin-syntaxhighlight": "^3.1.2",
+ "@munter/tap-render": "^0.2.0",
"@types/markdown-it": "^12.2.3",
"algoliasearch": "^4.12.1",
+ "autoprefixer": "^10.4.13",
+ "cross-env": "^7.0.3",
+ "cssnano": "^5.1.14",
"dom-parser": "^0.1.6",
"eleventy-plugin-nesting-toc": "^1.3.0",
"eleventy-plugin-page-assets": "^0.3.0",
"eleventy-plugin-reading-time": "^0.0.1",
- "github-slugger": "^1.4.0",
+ "github-slugger": "^1.5.0",
+ "hyperlink": "^5.0.4",
"imagemin": "^8.0.1",
"imagemin-cli": "^7.0.0",
"js-yaml": "^3.14.1",
"markdown-it-container": "^3.0.0",
"netlify-cli": "^10.3.1",
"npm-run-all": "^4.1.5",
+ "postcss-cli": "^10.0.0",
+ "postcss-html": "^1.5.0",
+ "prismjs": "^1.29.0",
"rimraf": "^3.0.2",
- "sass": "^1.52.1"
+ "sass": "^1.52.1",
+ "stylelint": "^14.13.0",
+ "stylelint-config-html": "^1.1.0",
+ "stylelint-config-standard": "^29.0.0",
+ "stylelint-config-standard-scss": "^5.0.0",
+ "tap-spot": "^1.1.2"
},
"engines": {
"node": ">=14.0.0"
- }
+ },
+ "browserslist": [
+ "defaults",
+ "IE 11"
+ ]
}
--- /dev/null
+"use strict";
+
+module.exports = {
+ plugins: [
+ require("autoprefixer"),
+ require("cssnano")
+ ],
+ map: false
+};
{
"lang": "en",
- "version": "7.26.0"
+ "version": "7.26.0",
+ "showNextVersion": false
}
"logo": "https://eslint.org/apple-touch-icon.png",
"title": "Interesting bugs caught by no-constant-binary-expression - ESLint - Pluggable JavaScript Linter",
"description": "A pluggable and configurable linter tool for identifying and reporting on patterns in JavaScript. Maintain your code quality with ease."
+ },
+ "https://github.com/tc39/proposal-class-static-block": {
+ "domain": "github.com",
+ "url": "https://github.com/tc39/proposal-class-static-block",
+ "logo": "https://github.com/fluidicon.png",
+ "title": "GitHub - tc39/proposal-class-static-block: ECMAScript class static initialization blocks",
+ "description": "ECMAScript class static initialization blocks. Contribute to tc39/proposal-class-static-block development by creating an account on GitHub."
+ },
+ "https://tc39.es/ecma262/#sec-symbol-constructor": {
+ "domain": "tc39.es",
+ "url": "https://tc39.es/ecma262/#sec-symbol-constructor",
+ "logo": "https://tc39.es/ecma262/img/favicon.ico",
+ "title": "ECMAScript® 2023 Language Specification",
+ "description": null
+ },
+ "https://tc39.es/ecma262/#sec-bigint-constructor": {
+ "domain": "tc39.es",
+ "url": "https://tc39.es/ecma262/#sec-bigint-constructor",
+ "logo": "https://tc39.es/ecma262/img/favicon.ico",
+ "title": "ECMAScript® 2023 Language Specification",
+ "description": null
}
}
\ No newline at end of file
},
{
"flag": "🇯🇵",
- "code": "jp",
+ "code": "ja",
"name": "Japanese - 日本語",
- "url": "https://jp.eslint.org"
+ "url": "https://ja.eslint.org"
},
{
"flag": "🇫🇷",
--- /dev/null
+module.exports = "doc.html";
"github": "https://github.com/eslint/eslint",
"twitter": "https://twitter.com/geteslint",
"chat": "https://eslint.org/chat",
- "group": "https://groups.google.com/group/eslint",
-
+ "mastodon": "https://fosstodon.org/@eslint",
"blog": "/blog",
"docs": "/docs/latest/",
"playground": "/play",
- "getStarted": "/docs/latest/user-guide/getting-started",
+ "getStarted": "/docs/latest/use/getting-started",
"sponsors": "/sponsors",
"branding": "/branding",
"store": "https://eslint.threadless.com",
"team": "/team",
-
- "configuring": "https://eslint.org/docs/user-guide/configuring/",
- "fixProblems": "https://eslint.org/docs/user-guide/command-line-interface#fixing-problems",
-
+ "configuring": "https://eslint.org/docs/latest/use/configure/",
+ "fixProblems": "https://eslint.org/docs/latest/use/command-line-interface#fix-problems",
"donate": "/donate",
"openCollective": "https://opencollective.com/eslint",
"githubSponsors": "https://github.com/sponsors/eslint"
-}
+}
\ No newline at end of file
"wrap-iife": "0.0.9",
"wrap-regex": "0.1.0",
"yield-star-spacing": "2.0.0-alpha-1",
- "yoda": "0.7.1"
+ "yoda": "0.7.1",
+ "logical-assignment-operators": "8.24.0",
+ "no-empty-static-block": "8.27.0",
+ "no-new-native-nonconstructor": "8.27.0"
},
"removed": {
"generator-star": "1.0.0-rc-1",
},
{
"name": "for-direction",
- "description": "Enforce \"for\" loop update clause moving the counter in the right direction.",
+ "description": "Enforce \"for\" loop update clause moving the counter in the right direction",
"recommended": true,
"fixable": false,
"hasSuggestions": false
"fixable": false,
"hasSuggestions": true
},
+ {
+ "name": "no-new-native-nonconstructor",
+ "description": "Disallow `new` operators with global non-constructor functions",
+ "recommended": false,
+ "fixable": false,
+ "hasSuggestions": false
+ },
{
"name": "no-new-symbol",
"description": "Disallow `new` operators with the `Symbol` object",
"fixable": false,
"hasSuggestions": false
},
+ {
+ "name": "logical-assignment-operators",
+ "description": "Require or disallow logical assignment operator shorthand",
+ "recommended": false,
+ "fixable": true,
+ "hasSuggestions": true
+ },
{
"name": "max-classes-per-file",
"description": "Enforce a maximum number of classes per file",
},
{
"name": "no-div-regex",
- "description": "Disallow division operators explicitly at the beginning of regular expressions",
+ "description": "Disallow equal signs explicitly at the beginning of regular expressions",
"recommended": false,
"fixable": true,
"hasSuggestions": false
"description": "Disallow empty block statements",
"recommended": true,
"fixable": false,
- "hasSuggestions": false
+ "hasSuggestions": true
},
{
"name": "no-empty-function",
"fixable": false,
"hasSuggestions": false
},
+ {
+ "name": "no-empty-static-block",
+ "description": "Disallow empty static blocks",
+ "recommended": false,
+ "fixable": false,
+ "hasSuggestions": false
+ },
{
"name": "no-eq-null",
"description": "Disallow `null` comparisons without type-checking operators",
"description": "Disallow unnecessary `return await`",
"recommended": false,
"fixable": false,
- "hasSuggestions": false
+ "hasSuggestions": true
},
{
"name": "no-script-url",
"description": "Enforce using named capture group in regular expression",
"recommended": false,
"fixable": false,
- "hasSuggestions": false
+ "hasSuggestions": true
},
{
"name": "prefer-numeric-literals",
},
{
"name": "prefer-object-spread",
- "description": "Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead.",
+ "description": "Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead",
"recommended": false,
"fixable": true,
"hasSuggestions": false
"description": "Enforce the use of `u` flag on RegExp",
"recommended": false,
"fixable": false,
- "hasSuggestions": false
+ "hasSuggestions": true
},
{
"name": "require-yield",
],
"deprecated": {
"name": "Deprecated",
- "description": "These rules have been deprecated in accordance with the <a href=\"/docs/user-guide/rule-deprecation\">deprecation policy</a>, and replaced by newer rules:",
+ "description": "These rules have been deprecated in accordance with the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a>, and replaced by newer rules:",
"rules": [
{
"name": "callback-return",
},
"removed": {
"name": "Removed",
- "description": "These rules from older versions of ESLint (before the <a href=\"/docs/user-guide/rule-deprecation\">deprecation policy</a> existed) have been replaced by newer rules:",
+ "description": "These rules from older versions of ESLint (before the <a href=\"{{ '/use/rule-deprecation' | url }}\">deprecation policy</a> existed) have been replaced by newer rules:",
"rules": [
{
"removed": "generator-star",
"docs": {
"description": "Enforce getter and setter pairs in objects and classes",
"recommended": false,
- "url": "https://eslint.org/docs/rules/accessor-pairs"
+ "url": "https://eslint.org/docs/latest/rules/accessor-pairs"
}
},
"array-bracket-newline": {
"docs": {
"description": "Enforce linebreaks after opening and before closing array brackets",
"recommended": false,
- "url": "https://eslint.org/docs/rules/array-bracket-newline"
+ "url": "https://eslint.org/docs/latest/rules/array-bracket-newline"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing inside array brackets",
"recommended": false,
- "url": "https://eslint.org/docs/rules/array-bracket-spacing"
+ "url": "https://eslint.org/docs/latest/rules/array-bracket-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce `return` statements in callbacks of array methods",
"recommended": false,
- "url": "https://eslint.org/docs/rules/array-callback-return"
+ "url": "https://eslint.org/docs/latest/rules/array-callback-return"
}
},
"array-element-newline": {
"docs": {
"description": "Enforce line breaks after each array element",
"recommended": false,
- "url": "https://eslint.org/docs/rules/array-element-newline"
+ "url": "https://eslint.org/docs/latest/rules/array-element-newline"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require braces around arrow function bodies",
"recommended": false,
- "url": "https://eslint.org/docs/rules/arrow-body-style"
+ "url": "https://eslint.org/docs/latest/rules/arrow-body-style"
},
"fixable": "code"
},
"docs": {
"description": "Require parentheses around arrow function arguments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/arrow-parens"
+ "url": "https://eslint.org/docs/latest/rules/arrow-parens"
},
"fixable": "code"
},
"docs": {
"description": "Enforce consistent spacing before and after the arrow in arrow functions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/arrow-spacing"
+ "url": "https://eslint.org/docs/latest/rules/arrow-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce the use of variables within the scope they are defined",
"recommended": false,
- "url": "https://eslint.org/docs/rules/block-scoped-var"
+ "url": "https://eslint.org/docs/latest/rules/block-scoped-var"
}
},
"block-spacing": {
"docs": {
"description": "Disallow or enforce spaces inside of blocks after opening block and before closing block",
"recommended": false,
- "url": "https://eslint.org/docs/rules/block-spacing"
+ "url": "https://eslint.org/docs/latest/rules/block-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent brace style for blocks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/brace-style"
+ "url": "https://eslint.org/docs/latest/rules/brace-style"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require `return` statements after callbacks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/callback-return"
+ "url": "https://eslint.org/docs/latest/rules/callback-return"
}
},
"camelcase": {
"docs": {
"description": "Enforce camelcase naming convention",
"recommended": false,
- "url": "https://eslint.org/docs/rules/camelcase"
+ "url": "https://eslint.org/docs/latest/rules/camelcase"
}
},
"capitalized-comments": {
"docs": {
"description": "Enforce or disallow capitalization of the first letter of a comment",
"recommended": false,
- "url": "https://eslint.org/docs/rules/capitalized-comments"
+ "url": "https://eslint.org/docs/latest/rules/capitalized-comments"
},
"fixable": "code"
},
"docs": {
"description": "Enforce that class methods utilize `this`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/class-methods-use-this"
+ "url": "https://eslint.org/docs/latest/rules/class-methods-use-this"
}
},
"comma-dangle": {
"docs": {
"description": "Require or disallow trailing commas",
"recommended": false,
- "url": "https://eslint.org/docs/rules/comma-dangle"
+ "url": "https://eslint.org/docs/latest/rules/comma-dangle"
},
"fixable": "code"
},
"docs": {
"description": "Enforce consistent spacing before and after commas",
"recommended": false,
- "url": "https://eslint.org/docs/rules/comma-spacing"
+ "url": "https://eslint.org/docs/latest/rules/comma-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent comma style",
"recommended": false,
- "url": "https://eslint.org/docs/rules/comma-style"
+ "url": "https://eslint.org/docs/latest/rules/comma-style"
},
"fixable": "code"
},
"docs": {
"description": "Enforce a maximum cyclomatic complexity allowed in a program",
"recommended": false,
- "url": "https://eslint.org/docs/rules/complexity"
+ "url": "https://eslint.org/docs/latest/rules/complexity"
}
},
"computed-property-spacing": {
"docs": {
"description": "Enforce consistent spacing inside computed property brackets",
"recommended": false,
- "url": "https://eslint.org/docs/rules/computed-property-spacing"
+ "url": "https://eslint.org/docs/latest/rules/computed-property-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require `return` statements to either always or never specify values",
"recommended": false,
- "url": "https://eslint.org/docs/rules/consistent-return"
+ "url": "https://eslint.org/docs/latest/rules/consistent-return"
}
},
"consistent-this": {
"docs": {
"description": "Enforce consistent naming when capturing the current execution context",
"recommended": false,
- "url": "https://eslint.org/docs/rules/consistent-this"
+ "url": "https://eslint.org/docs/latest/rules/consistent-this"
}
},
"constructor-super": {
"docs": {
"description": "Require `super()` calls in constructors",
"recommended": true,
- "url": "https://eslint.org/docs/rules/constructor-super"
+ "url": "https://eslint.org/docs/latest/rules/constructor-super"
}
},
"curly": {
"docs": {
"description": "Enforce consistent brace style for all control statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/curly"
+ "url": "https://eslint.org/docs/latest/rules/curly"
},
"fixable": "code"
},
"docs": {
"description": "Require `default` cases in `switch` statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/default-case"
+ "url": "https://eslint.org/docs/latest/rules/default-case"
}
},
"default-case-last": {
"docs": {
"description": "Enforce default clauses in switch statements to be last",
"recommended": false,
- "url": "https://eslint.org/docs/rules/default-case-last"
+ "url": "https://eslint.org/docs/latest/rules/default-case-last"
}
},
"default-param-last": {
"docs": {
"description": "Enforce default parameters to be last",
"recommended": false,
- "url": "https://eslint.org/docs/rules/default-param-last"
+ "url": "https://eslint.org/docs/latest/rules/default-param-last"
}
},
"dot-location": {
"docs": {
"description": "Enforce consistent newlines before and after dots",
"recommended": false,
- "url": "https://eslint.org/docs/rules/dot-location"
+ "url": "https://eslint.org/docs/latest/rules/dot-location"
},
"fixable": "code"
},
"docs": {
"description": "Enforce dot notation whenever possible",
"recommended": false,
- "url": "https://eslint.org/docs/rules/dot-notation"
+ "url": "https://eslint.org/docs/latest/rules/dot-notation"
},
"fixable": "code"
},
"docs": {
"description": "Require or disallow newline at the end of files",
"recommended": false,
- "url": "https://eslint.org/docs/rules/eol-last"
+ "url": "https://eslint.org/docs/latest/rules/eol-last"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require the use of `===` and `!==`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/eqeqeq"
+ "url": "https://eslint.org/docs/latest/rules/eqeqeq"
},
"fixable": "code"
},
"for-direction": {
"type": "problem",
"docs": {
- "description": "Enforce \"for\" loop update clause moving the counter in the right direction.",
+ "description": "Enforce \"for\" loop update clause moving the counter in the right direction",
"recommended": true,
- "url": "https://eslint.org/docs/rules/for-direction"
+ "url": "https://eslint.org/docs/latest/rules/for-direction"
},
"fixable": null
},
"docs": {
"description": "Require or disallow spacing between function identifiers and their invocations",
"recommended": false,
- "url": "https://eslint.org/docs/rules/func-call-spacing"
+ "url": "https://eslint.org/docs/latest/rules/func-call-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require function names to match the name of the variable or property to which they are assigned",
"recommended": false,
- "url": "https://eslint.org/docs/rules/func-name-matching"
+ "url": "https://eslint.org/docs/latest/rules/func-name-matching"
}
},
"func-names": {
"docs": {
"description": "Require or disallow named `function` expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/func-names"
+ "url": "https://eslint.org/docs/latest/rules/func-names"
}
},
"func-style": {
"docs": {
"description": "Enforce the consistent use of either `function` declarations or expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/func-style"
+ "url": "https://eslint.org/docs/latest/rules/func-style"
}
},
"function-call-argument-newline": {
"docs": {
"description": "Enforce line breaks between arguments of a function call",
"recommended": false,
- "url": "https://eslint.org/docs/rules/function-call-argument-newline"
+ "url": "https://eslint.org/docs/latest/rules/function-call-argument-newline"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent line breaks inside function parentheses",
"recommended": false,
- "url": "https://eslint.org/docs/rules/function-paren-newline"
+ "url": "https://eslint.org/docs/latest/rules/function-paren-newline"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing around `*` operators in generator functions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/generator-star-spacing"
+ "url": "https://eslint.org/docs/latest/rules/generator-star-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce `return` statements in getters",
"recommended": true,
- "url": "https://eslint.org/docs/rules/getter-return"
+ "url": "https://eslint.org/docs/latest/rules/getter-return"
},
"fixable": null
},
"docs": {
"description": "Require `require()` calls to be placed at top-level module scope",
"recommended": false,
- "url": "https://eslint.org/docs/rules/global-require"
+ "url": "https://eslint.org/docs/latest/rules/global-require"
}
},
"grouped-accessor-pairs": {
"docs": {
"description": "Require grouped accessor pairs in object literals and classes",
"recommended": false,
- "url": "https://eslint.org/docs/rules/grouped-accessor-pairs"
+ "url": "https://eslint.org/docs/latest/rules/grouped-accessor-pairs"
}
},
"guard-for-in": {
"docs": {
"description": "Require `for-in` loops to include an `if` statement",
"recommended": false,
- "url": "https://eslint.org/docs/rules/guard-for-in"
+ "url": "https://eslint.org/docs/latest/rules/guard-for-in"
}
},
"handle-callback-err": {
"docs": {
"description": "Require error handling in callbacks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/handle-callback-err"
+ "url": "https://eslint.org/docs/latest/rules/handle-callback-err"
}
},
"id-blacklist": {
"docs": {
"description": "Disallow specified identifiers",
"recommended": false,
- "url": "https://eslint.org/docs/rules/id-blacklist"
+ "url": "https://eslint.org/docs/latest/rules/id-blacklist"
}
},
"id-denylist": {
"docs": {
"description": "Disallow specified identifiers",
"recommended": false,
- "url": "https://eslint.org/docs/rules/id-denylist"
+ "url": "https://eslint.org/docs/latest/rules/id-denylist"
}
},
"id-length": {
"docs": {
"description": "Enforce minimum and maximum identifier lengths",
"recommended": false,
- "url": "https://eslint.org/docs/rules/id-length"
+ "url": "https://eslint.org/docs/latest/rules/id-length"
}
},
"id-match": {
"docs": {
"description": "Require identifiers to match a specified regular expression",
"recommended": false,
- "url": "https://eslint.org/docs/rules/id-match"
+ "url": "https://eslint.org/docs/latest/rules/id-match"
}
},
"implicit-arrow-linebreak": {
"docs": {
"description": "Enforce the location of arrow function bodies",
"recommended": false,
- "url": "https://eslint.org/docs/rules/implicit-arrow-linebreak"
+ "url": "https://eslint.org/docs/latest/rules/implicit-arrow-linebreak"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent indentation",
"recommended": false,
- "url": "https://eslint.org/docs/rules/indent"
+ "url": "https://eslint.org/docs/latest/rules/indent"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent indentation",
"recommended": false,
- "url": "https://eslint.org/docs/rules/indent-legacy"
+ "url": "https://eslint.org/docs/latest/rules/indent-legacy"
},
"deprecated": true,
"replacedBy": [
"docs": {
"description": "Require or disallow initialization in variable declarations",
"recommended": false,
- "url": "https://eslint.org/docs/rules/init-declarations"
+ "url": "https://eslint.org/docs/latest/rules/init-declarations"
}
},
"jsx-quotes": {
"docs": {
"description": "Enforce the consistent use of either double or single quotes in JSX attributes",
"recommended": false,
- "url": "https://eslint.org/docs/rules/jsx-quotes"
+ "url": "https://eslint.org/docs/latest/rules/jsx-quotes"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing between keys and values in object literal properties",
"recommended": false,
- "url": "https://eslint.org/docs/rules/key-spacing"
+ "url": "https://eslint.org/docs/latest/rules/key-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing before and after keywords",
"recommended": false,
- "url": "https://eslint.org/docs/rules/keyword-spacing"
+ "url": "https://eslint.org/docs/latest/rules/keyword-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce position of line comments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/line-comment-position"
+ "url": "https://eslint.org/docs/latest/rules/line-comment-position"
}
},
"linebreak-style": {
"docs": {
"description": "Enforce consistent linebreak style",
"recommended": false,
- "url": "https://eslint.org/docs/rules/linebreak-style"
+ "url": "https://eslint.org/docs/latest/rules/linebreak-style"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require empty lines around comments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/lines-around-comment"
+ "url": "https://eslint.org/docs/latest/rules/lines-around-comment"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow newlines around directives",
"recommended": false,
- "url": "https://eslint.org/docs/rules/lines-around-directive"
+ "url": "https://eslint.org/docs/latest/rules/lines-around-directive"
},
"fixable": "whitespace",
"deprecated": true,
"docs": {
"description": "Require or disallow an empty line between class members",
"recommended": false,
- "url": "https://eslint.org/docs/rules/lines-between-class-members"
+ "url": "https://eslint.org/docs/latest/rules/lines-between-class-members"
},
"fixable": "whitespace"
},
+ "logical-assignment-operators": {
+ "type": "suggestion",
+ "docs": {
+ "description": "Require or disallow logical assignment operator shorthand",
+ "recommended": false,
+ "url": "https://eslint.org/docs/latest/rules/logical-assignment-operators"
+ },
+ "fixable": "code",
+ "hasSuggestions": true
+ },
"max-classes-per-file": {
"type": "suggestion",
"docs": {
"description": "Enforce a maximum number of classes per file",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-classes-per-file"
+ "url": "https://eslint.org/docs/latest/rules/max-classes-per-file"
}
},
"max-depth": {
"docs": {
"description": "Enforce a maximum depth that blocks can be nested",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-depth"
+ "url": "https://eslint.org/docs/latest/rules/max-depth"
}
},
"max-len": {
"docs": {
"description": "Enforce a maximum line length",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-len"
+ "url": "https://eslint.org/docs/latest/rules/max-len"
}
},
"max-lines": {
"docs": {
"description": "Enforce a maximum number of lines per file",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-lines"
+ "url": "https://eslint.org/docs/latest/rules/max-lines"
}
},
"max-lines-per-function": {
"docs": {
"description": "Enforce a maximum number of lines of code in a function",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-lines-per-function"
+ "url": "https://eslint.org/docs/latest/rules/max-lines-per-function"
}
},
"max-nested-callbacks": {
"docs": {
"description": "Enforce a maximum depth that callbacks can be nested",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-nested-callbacks"
+ "url": "https://eslint.org/docs/latest/rules/max-nested-callbacks"
}
},
"max-params": {
"docs": {
"description": "Enforce a maximum number of parameters in function definitions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-params"
+ "url": "https://eslint.org/docs/latest/rules/max-params"
}
},
"max-statements": {
"docs": {
"description": "Enforce a maximum number of statements allowed in function blocks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-statements"
+ "url": "https://eslint.org/docs/latest/rules/max-statements"
}
},
"max-statements-per-line": {
"docs": {
"description": "Enforce a maximum number of statements allowed per line",
"recommended": false,
- "url": "https://eslint.org/docs/rules/max-statements-per-line"
+ "url": "https://eslint.org/docs/latest/rules/max-statements-per-line"
}
},
"multiline-comment-style": {
"docs": {
"description": "Enforce a particular style for multiline comments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/multiline-comment-style"
+ "url": "https://eslint.org/docs/latest/rules/multiline-comment-style"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce newlines between operands of ternary expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/multiline-ternary"
+ "url": "https://eslint.org/docs/latest/rules/multiline-ternary"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require constructor names to begin with a capital letter",
"recommended": false,
- "url": "https://eslint.org/docs/rules/new-cap"
+ "url": "https://eslint.org/docs/latest/rules/new-cap"
}
},
"new-parens": {
"docs": {
"description": "Enforce or disallow parentheses when invoking a constructor with no arguments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/new-parens"
+ "url": "https://eslint.org/docs/latest/rules/new-parens"
},
"fixable": "code"
},
"docs": {
"description": "Require or disallow an empty line after variable declarations",
"recommended": false,
- "url": "https://eslint.org/docs/rules/newline-after-var"
+ "url": "https://eslint.org/docs/latest/rules/newline-after-var"
},
"fixable": "whitespace",
"deprecated": true,
"docs": {
"description": "Require an empty line before `return` statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/newline-before-return"
+ "url": "https://eslint.org/docs/latest/rules/newline-before-return"
},
"fixable": "whitespace",
"deprecated": true,
"docs": {
"description": "Require a newline after each call in a method chain",
"recommended": false,
- "url": "https://eslint.org/docs/rules/newline-per-chained-call"
+ "url": "https://eslint.org/docs/latest/rules/newline-per-chained-call"
},
"fixable": "whitespace"
},
"docs": {
"description": "Disallow the use of `alert`, `confirm`, and `prompt`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-alert"
+ "url": "https://eslint.org/docs/latest/rules/no-alert"
}
},
"no-array-constructor": {
"docs": {
"description": "Disallow `Array` constructors",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-array-constructor"
+ "url": "https://eslint.org/docs/latest/rules/no-array-constructor"
}
},
"no-async-promise-executor": {
"docs": {
"description": "Disallow using an async function as a Promise executor",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-async-promise-executor"
+ "url": "https://eslint.org/docs/latest/rules/no-async-promise-executor"
},
"fixable": null
},
"docs": {
"description": "Disallow `await` inside of loops",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-await-in-loop"
+ "url": "https://eslint.org/docs/latest/rules/no-await-in-loop"
}
},
"no-bitwise": {
"docs": {
"description": "Disallow bitwise operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-bitwise"
+ "url": "https://eslint.org/docs/latest/rules/no-bitwise"
}
},
"no-buffer-constructor": {
"docs": {
"description": "Disallow use of the `Buffer()` constructor",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-buffer-constructor"
+ "url": "https://eslint.org/docs/latest/rules/no-buffer-constructor"
}
},
"no-caller": {
"docs": {
"description": "Disallow the use of `arguments.caller` or `arguments.callee`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-caller"
+ "url": "https://eslint.org/docs/latest/rules/no-caller"
}
},
"no-case-declarations": {
"docs": {
"description": "Disallow lexical declarations in case clauses",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-case-declarations"
+ "url": "https://eslint.org/docs/latest/rules/no-case-declarations"
}
},
"no-catch-shadow": {
"docs": {
"description": "Disallow `catch` clause parameters from shadowing variables in the outer scope",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-catch-shadow"
+ "url": "https://eslint.org/docs/latest/rules/no-catch-shadow"
},
"replacedBy": [
"no-shadow"
"docs": {
"description": "Disallow reassigning class members",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-class-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-class-assign"
}
},
"no-compare-neg-zero": {
"docs": {
"description": "Disallow comparing against -0",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-compare-neg-zero"
+ "url": "https://eslint.org/docs/latest/rules/no-compare-neg-zero"
},
"fixable": null
},
"docs": {
"description": "Disallow assignment operators in conditional expressions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-cond-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-cond-assign"
}
},
"no-confusing-arrow": {
"docs": {
"description": "Disallow arrow functions where they could be confused with comparisons",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-confusing-arrow"
+ "url": "https://eslint.org/docs/latest/rules/no-confusing-arrow"
},
"fixable": "code"
},
"docs": {
"description": "Disallow the use of `console`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-console"
+ "url": "https://eslint.org/docs/latest/rules/no-console"
}
},
"no-const-assign": {
"docs": {
"description": "Disallow reassigning `const` variables",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-const-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-const-assign"
}
},
"no-constant-binary-expression": {
"docs": {
"description": "Disallow expressions where the operation doesn't affect the value",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-constant-binary-expression"
+ "url": "https://eslint.org/docs/latest/rules/no-constant-binary-expression"
}
},
"no-constant-condition": {
"docs": {
"description": "Disallow constant expressions in conditions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-constant-condition"
+ "url": "https://eslint.org/docs/latest/rules/no-constant-condition"
}
},
"no-constructor-return": {
"docs": {
"description": "Disallow returning value from constructor",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-constructor-return"
+ "url": "https://eslint.org/docs/latest/rules/no-constructor-return"
},
"fixable": null
},
"docs": {
"description": "Disallow `continue` statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-continue"
+ "url": "https://eslint.org/docs/latest/rules/no-continue"
}
},
"no-control-regex": {
"docs": {
"description": "Disallow control characters in regular expressions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-control-regex"
+ "url": "https://eslint.org/docs/latest/rules/no-control-regex"
}
},
"no-debugger": {
"docs": {
"description": "Disallow the use of `debugger`",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-debugger"
+ "url": "https://eslint.org/docs/latest/rules/no-debugger"
},
"fixable": null
},
"docs": {
"description": "Disallow deleting variables",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-delete-var"
+ "url": "https://eslint.org/docs/latest/rules/no-delete-var"
}
},
"no-div-regex": {
"type": "suggestion",
"docs": {
- "description": "Disallow division operators explicitly at the beginning of regular expressions",
+ "description": "Disallow equal signs explicitly at the beginning of regular expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-div-regex"
+ "url": "https://eslint.org/docs/latest/rules/no-div-regex"
},
"fixable": "code"
},
"docs": {
"description": "Disallow duplicate arguments in `function` definitions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-dupe-args"
+ "url": "https://eslint.org/docs/latest/rules/no-dupe-args"
}
},
"no-dupe-class-members": {
"docs": {
"description": "Disallow duplicate class members",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-dupe-class-members"
+ "url": "https://eslint.org/docs/latest/rules/no-dupe-class-members"
}
},
"no-dupe-else-if": {
"docs": {
"description": "Disallow duplicate conditions in if-else-if chains",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-dupe-else-if"
+ "url": "https://eslint.org/docs/latest/rules/no-dupe-else-if"
}
},
"no-dupe-keys": {
"docs": {
"description": "Disallow duplicate keys in object literals",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-dupe-keys"
+ "url": "https://eslint.org/docs/latest/rules/no-dupe-keys"
}
},
"no-duplicate-case": {
"docs": {
"description": "Disallow duplicate case labels",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-duplicate-case"
+ "url": "https://eslint.org/docs/latest/rules/no-duplicate-case"
}
},
"no-duplicate-imports": {
"docs": {
"description": "Disallow duplicate module imports",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-duplicate-imports"
+ "url": "https://eslint.org/docs/latest/rules/no-duplicate-imports"
}
},
"no-else-return": {
"docs": {
"description": "Disallow `else` blocks after `return` statements in `if` statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-else-return"
+ "url": "https://eslint.org/docs/latest/rules/no-else-return"
},
"fixable": "code"
},
"no-empty": {
+ "hasSuggestions": true,
"type": "suggestion",
"docs": {
"description": "Disallow empty block statements",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-empty"
+ "url": "https://eslint.org/docs/latest/rules/no-empty"
}
},
"no-empty-character-class": {
"docs": {
"description": "Disallow empty character classes in regular expressions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-empty-character-class"
+ "url": "https://eslint.org/docs/latest/rules/no-empty-character-class"
}
},
"no-empty-function": {
"docs": {
"description": "Disallow empty functions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-empty-function"
+ "url": "https://eslint.org/docs/latest/rules/no-empty-function"
}
},
"no-empty-pattern": {
"docs": {
"description": "Disallow empty destructuring patterns",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-empty-pattern"
+ "url": "https://eslint.org/docs/latest/rules/no-empty-pattern"
+ }
+ },
+ "no-empty-static-block": {
+ "type": "suggestion",
+ "docs": {
+ "description": "Disallow empty static blocks",
+ "recommended": false,
+ "url": "https://eslint.org/docs/latest/rules/no-empty-static-block"
}
},
"no-eq-null": {
"docs": {
"description": "Disallow `null` comparisons without type-checking operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-eq-null"
+ "url": "https://eslint.org/docs/latest/rules/no-eq-null"
}
},
"no-eval": {
"docs": {
"description": "Disallow the use of `eval()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-eval"
+ "url": "https://eslint.org/docs/latest/rules/no-eval"
}
},
"no-ex-assign": {
"docs": {
"description": "Disallow reassigning exceptions in `catch` clauses",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-ex-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-ex-assign"
}
},
"no-extend-native": {
"docs": {
"description": "Disallow extending native types",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-extend-native"
+ "url": "https://eslint.org/docs/latest/rules/no-extend-native"
}
},
"no-extra-bind": {
"docs": {
"description": "Disallow unnecessary calls to `.bind()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-extra-bind"
+ "url": "https://eslint.org/docs/latest/rules/no-extra-bind"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unnecessary boolean casts",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-extra-boolean-cast"
+ "url": "https://eslint.org/docs/latest/rules/no-extra-boolean-cast"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unnecessary labels",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-extra-label"
+ "url": "https://eslint.org/docs/latest/rules/no-extra-label"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unnecessary parentheses",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-extra-parens"
+ "url": "https://eslint.org/docs/latest/rules/no-extra-parens"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unnecessary semicolons",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-extra-semi"
+ "url": "https://eslint.org/docs/latest/rules/no-extra-semi"
},
"fixable": "code"
},
"docs": {
"description": "Disallow fallthrough of `case` statements",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-fallthrough"
+ "url": "https://eslint.org/docs/latest/rules/no-fallthrough"
}
},
"no-floating-decimal": {
"docs": {
"description": "Disallow leading or trailing decimal points in numeric literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-floating-decimal"
+ "url": "https://eslint.org/docs/latest/rules/no-floating-decimal"
},
"fixable": "code"
},
"docs": {
"description": "Disallow reassigning `function` declarations",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-func-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-func-assign"
}
},
"no-global-assign": {
"docs": {
"description": "Disallow assignments to native objects or read-only global variables",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-global-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-global-assign"
}
},
"no-implicit-coercion": {
"docs": {
"description": "Disallow shorthand type conversions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-implicit-coercion"
+ "url": "https://eslint.org/docs/latest/rules/no-implicit-coercion"
},
"fixable": "code"
},
"docs": {
"description": "Disallow declarations in the global scope",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-implicit-globals"
+ "url": "https://eslint.org/docs/latest/rules/no-implicit-globals"
}
},
"no-implied-eval": {
"docs": {
"description": "Disallow the use of `eval()`-like methods",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-implied-eval"
+ "url": "https://eslint.org/docs/latest/rules/no-implied-eval"
}
},
"no-import-assign": {
"docs": {
"description": "Disallow assigning to imported bindings",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-import-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-import-assign"
}
},
"no-inline-comments": {
"docs": {
"description": "Disallow inline comments after code",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-inline-comments"
+ "url": "https://eslint.org/docs/latest/rules/no-inline-comments"
}
},
"no-inner-declarations": {
"docs": {
"description": "Disallow variable or `function` declarations in nested blocks",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-inner-declarations"
+ "url": "https://eslint.org/docs/latest/rules/no-inner-declarations"
}
},
"no-invalid-regexp": {
"docs": {
"description": "Disallow invalid regular expression strings in `RegExp` constructors",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-invalid-regexp"
+ "url": "https://eslint.org/docs/latest/rules/no-invalid-regexp"
}
},
"no-invalid-this": {
"docs": {
"description": "Disallow use of `this` in contexts where the value of `this` is `undefined`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-invalid-this"
+ "url": "https://eslint.org/docs/latest/rules/no-invalid-this"
}
},
"no-irregular-whitespace": {
"docs": {
"description": "Disallow irregular whitespace",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-irregular-whitespace"
+ "url": "https://eslint.org/docs/latest/rules/no-irregular-whitespace"
}
},
"no-iterator": {
"docs": {
"description": "Disallow the use of the `__iterator__` property",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-iterator"
+ "url": "https://eslint.org/docs/latest/rules/no-iterator"
}
},
"no-label-var": {
"docs": {
"description": "Disallow labels that share a name with a variable",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-label-var"
+ "url": "https://eslint.org/docs/latest/rules/no-label-var"
}
},
"no-labels": {
"docs": {
"description": "Disallow labeled statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-labels"
+ "url": "https://eslint.org/docs/latest/rules/no-labels"
}
},
"no-lone-blocks": {
"docs": {
"description": "Disallow unnecessary nested blocks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-lone-blocks"
+ "url": "https://eslint.org/docs/latest/rules/no-lone-blocks"
}
},
"no-lonely-if": {
"docs": {
"description": "Disallow `if` statements as the only statement in `else` blocks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-lonely-if"
+ "url": "https://eslint.org/docs/latest/rules/no-lonely-if"
},
"fixable": "code"
},
"docs": {
"description": "Disallow function declarations that contain unsafe references inside loop statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-loop-func"
+ "url": "https://eslint.org/docs/latest/rules/no-loop-func"
}
},
"no-loss-of-precision": {
"docs": {
"description": "Disallow literal numbers that lose precision",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-loss-of-precision"
+ "url": "https://eslint.org/docs/latest/rules/no-loss-of-precision"
}
},
"no-magic-numbers": {
"docs": {
"description": "Disallow magic numbers",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-magic-numbers"
+ "url": "https://eslint.org/docs/latest/rules/no-magic-numbers"
}
},
"no-misleading-character-class": {
"docs": {
"description": "Disallow characters which are made with multiple code points in character class syntax",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-misleading-character-class"
+ "url": "https://eslint.org/docs/latest/rules/no-misleading-character-class"
},
"hasSuggestions": true
},
"docs": {
"description": "Disallow mixed binary operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-mixed-operators"
+ "url": "https://eslint.org/docs/latest/rules/no-mixed-operators"
}
},
"no-mixed-requires": {
"docs": {
"description": "Disallow `require` calls to be mixed with regular variable declarations",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-mixed-requires"
+ "url": "https://eslint.org/docs/latest/rules/no-mixed-requires"
}
},
"no-mixed-spaces-and-tabs": {
"docs": {
"description": "Disallow mixed spaces and tabs for indentation",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-mixed-spaces-and-tabs"
+ "url": "https://eslint.org/docs/latest/rules/no-mixed-spaces-and-tabs"
}
},
"no-multi-assign": {
"docs": {
"description": "Disallow use of chained assignment expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-multi-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-multi-assign"
}
},
"no-multi-spaces": {
"docs": {
"description": "Disallow multiple spaces",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-multi-spaces"
+ "url": "https://eslint.org/docs/latest/rules/no-multi-spaces"
},
"fixable": "whitespace"
},
"docs": {
"description": "Disallow multiline strings",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-multi-str"
+ "url": "https://eslint.org/docs/latest/rules/no-multi-str"
}
},
"no-multiple-empty-lines": {
"docs": {
"description": "Disallow multiple empty lines",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-multiple-empty-lines"
+ "url": "https://eslint.org/docs/latest/rules/no-multiple-empty-lines"
},
"fixable": "whitespace"
},
"docs": {
"description": "Disallow assignments to native objects or read-only global variables",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-native-reassign"
+ "url": "https://eslint.org/docs/latest/rules/no-native-reassign"
},
"deprecated": true,
"replacedBy": [
"docs": {
"description": "Disallow negated conditions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-negated-condition"
+ "url": "https://eslint.org/docs/latest/rules/no-negated-condition"
}
},
"no-negated-in-lhs": {
"docs": {
"description": "Disallow negating the left operand in `in` expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-negated-in-lhs"
+ "url": "https://eslint.org/docs/latest/rules/no-negated-in-lhs"
},
"replacedBy": [
"no-unsafe-negation"
"docs": {
"description": "Disallow nested ternary expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-nested-ternary"
+ "url": "https://eslint.org/docs/latest/rules/no-nested-ternary"
}
},
"no-new": {
"docs": {
"description": "Disallow `new` operators outside of assignments or comparisons",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-new"
+ "url": "https://eslint.org/docs/latest/rules/no-new"
}
},
"no-new-func": {
"docs": {
"description": "Disallow `new` operators with the `Function` object",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-new-func"
+ "url": "https://eslint.org/docs/latest/rules/no-new-func"
+ }
+ },
+ "no-new-native-nonconstructor": {
+ "type": "problem",
+ "docs": {
+ "description": "Disallow `new` operators with global non-constructor functions",
+ "recommended": false,
+ "url": "https://eslint.org/docs/latest/rules/no-new-native-nonconstructor"
}
},
"no-new-object": {
"docs": {
"description": "Disallow `Object` constructors",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-new-object"
+ "url": "https://eslint.org/docs/latest/rules/no-new-object"
}
},
"no-new-require": {
"docs": {
"description": "Disallow `new` operators with calls to `require`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-new-require"
+ "url": "https://eslint.org/docs/latest/rules/no-new-require"
}
},
"no-new-symbol": {
"docs": {
"description": "Disallow `new` operators with the `Symbol` object",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-new-symbol"
+ "url": "https://eslint.org/docs/latest/rules/no-new-symbol"
}
},
"no-new-wrappers": {
"docs": {
"description": "Disallow `new` operators with the `String`, `Number`, and `Boolean` objects",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-new-wrappers"
+ "url": "https://eslint.org/docs/latest/rules/no-new-wrappers"
}
},
"no-nonoctal-decimal-escape": {
"docs": {
"description": "Disallow `\\8` and `\\9` escape sequences in string literals",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-nonoctal-decimal-escape"
+ "url": "https://eslint.org/docs/latest/rules/no-nonoctal-decimal-escape"
},
"hasSuggestions": true
},
"docs": {
"description": "Disallow calling global object properties as functions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-obj-calls"
+ "url": "https://eslint.org/docs/latest/rules/no-obj-calls"
}
},
"no-octal": {
"docs": {
"description": "Disallow octal literals",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-octal"
+ "url": "https://eslint.org/docs/latest/rules/no-octal"
}
},
"no-octal-escape": {
"docs": {
"description": "Disallow octal escape sequences in string literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-octal-escape"
+ "url": "https://eslint.org/docs/latest/rules/no-octal-escape"
}
},
"no-param-reassign": {
"docs": {
"description": "Disallow reassigning `function` parameters",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-param-reassign"
+ "url": "https://eslint.org/docs/latest/rules/no-param-reassign"
}
},
"no-path-concat": {
"docs": {
"description": "Disallow string concatenation with `__dirname` and `__filename`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-path-concat"
+ "url": "https://eslint.org/docs/latest/rules/no-path-concat"
}
},
"no-plusplus": {
"docs": {
"description": "Disallow the unary operators `++` and `--`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-plusplus"
+ "url": "https://eslint.org/docs/latest/rules/no-plusplus"
}
},
"no-process-env": {
"docs": {
"description": "Disallow the use of `process.env`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-process-env"
+ "url": "https://eslint.org/docs/latest/rules/no-process-env"
}
},
"no-process-exit": {
"docs": {
"description": "Disallow the use of `process.exit()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-process-exit"
+ "url": "https://eslint.org/docs/latest/rules/no-process-exit"
}
},
"no-promise-executor-return": {
"docs": {
"description": "Disallow returning values from Promise executor functions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-promise-executor-return"
+ "url": "https://eslint.org/docs/latest/rules/no-promise-executor-return"
}
},
"no-proto": {
"docs": {
"description": "Disallow the use of the `__proto__` property",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-proto"
+ "url": "https://eslint.org/docs/latest/rules/no-proto"
}
},
"no-prototype-builtins": {
"docs": {
"description": "Disallow calling some `Object.prototype` methods directly on objects",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-prototype-builtins"
+ "url": "https://eslint.org/docs/latest/rules/no-prototype-builtins"
}
},
"no-redeclare": {
"docs": {
"description": "Disallow variable redeclaration",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-redeclare"
+ "url": "https://eslint.org/docs/latest/rules/no-redeclare"
}
},
"no-regex-spaces": {
"docs": {
"description": "Disallow multiple spaces in regular expressions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-regex-spaces"
+ "url": "https://eslint.org/docs/latest/rules/no-regex-spaces"
},
"fixable": "code"
},
"docs": {
"description": "Disallow specified names in exports",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-restricted-exports"
+ "url": "https://eslint.org/docs/latest/rules/no-restricted-exports"
}
},
"no-restricted-globals": {
"docs": {
"description": "Disallow specified global variables",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-restricted-globals"
+ "url": "https://eslint.org/docs/latest/rules/no-restricted-globals"
}
},
"no-restricted-imports": {
"docs": {
"description": "Disallow specified modules when loaded by `import`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-restricted-imports"
+ "url": "https://eslint.org/docs/latest/rules/no-restricted-imports"
}
},
"no-restricted-modules": {
"docs": {
"description": "Disallow specified modules when loaded by `require`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-restricted-modules"
+ "url": "https://eslint.org/docs/latest/rules/no-restricted-modules"
}
},
"no-restricted-properties": {
"docs": {
"description": "Disallow certain properties on certain objects",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-restricted-properties"
+ "url": "https://eslint.org/docs/latest/rules/no-restricted-properties"
}
},
"no-restricted-syntax": {
"docs": {
"description": "Disallow specified syntax",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-restricted-syntax"
+ "url": "https://eslint.org/docs/latest/rules/no-restricted-syntax"
}
},
"no-return-assign": {
"docs": {
"description": "Disallow assignment operators in `return` statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-return-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-return-assign"
}
},
"no-return-await": {
+ "hasSuggestions": true,
"type": "suggestion",
"docs": {
"description": "Disallow unnecessary `return await`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-return-await"
+ "url": "https://eslint.org/docs/latest/rules/no-return-await"
},
"fixable": null
},
"docs": {
"description": "Disallow `javascript:` urls",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-script-url"
+ "url": "https://eslint.org/docs/latest/rules/no-script-url"
}
},
"no-self-assign": {
"docs": {
"description": "Disallow assignments where both sides are exactly the same",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-self-assign"
+ "url": "https://eslint.org/docs/latest/rules/no-self-assign"
}
},
"no-self-compare": {
"docs": {
"description": "Disallow comparisons where both sides are exactly the same",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-self-compare"
+ "url": "https://eslint.org/docs/latest/rules/no-self-compare"
}
},
"no-sequences": {
"docs": {
"description": "Disallow comma operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-sequences"
+ "url": "https://eslint.org/docs/latest/rules/no-sequences"
}
},
"no-setter-return": {
"docs": {
"description": "Disallow returning values from setters",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-setter-return"
+ "url": "https://eslint.org/docs/latest/rules/no-setter-return"
}
},
"no-shadow": {
"docs": {
"description": "Disallow variable declarations from shadowing variables declared in the outer scope",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-shadow"
+ "url": "https://eslint.org/docs/latest/rules/no-shadow"
}
},
"no-shadow-restricted-names": {
"docs": {
"description": "Disallow identifiers from shadowing restricted names",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-shadow-restricted-names"
+ "url": "https://eslint.org/docs/latest/rules/no-shadow-restricted-names"
}
},
"no-spaced-func": {
"docs": {
"description": "Disallow spacing between function identifiers and their applications (deprecated)",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-spaced-func"
+ "url": "https://eslint.org/docs/latest/rules/no-spaced-func"
},
"deprecated": true,
"replacedBy": [
"docs": {
"description": "Disallow sparse arrays",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-sparse-arrays"
+ "url": "https://eslint.org/docs/latest/rules/no-sparse-arrays"
}
},
"no-sync": {
"docs": {
"description": "Disallow synchronous methods",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-sync"
+ "url": "https://eslint.org/docs/latest/rules/no-sync"
}
},
"no-tabs": {
"docs": {
"description": "Disallow all tabs",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-tabs"
+ "url": "https://eslint.org/docs/latest/rules/no-tabs"
}
},
"no-template-curly-in-string": {
"docs": {
"description": "Disallow template literal placeholder syntax in regular strings",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-template-curly-in-string"
+ "url": "https://eslint.org/docs/latest/rules/no-template-curly-in-string"
}
},
"no-ternary": {
"docs": {
"description": "Disallow ternary operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-ternary"
+ "url": "https://eslint.org/docs/latest/rules/no-ternary"
}
},
"no-this-before-super": {
"docs": {
"description": "Disallow `this`/`super` before calling `super()` in constructors",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-this-before-super"
+ "url": "https://eslint.org/docs/latest/rules/no-this-before-super"
}
},
"no-throw-literal": {
"docs": {
"description": "Disallow throwing literals as exceptions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-throw-literal"
+ "url": "https://eslint.org/docs/latest/rules/no-throw-literal"
}
},
"no-trailing-spaces": {
"docs": {
"description": "Disallow trailing whitespace at the end of lines",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-trailing-spaces"
+ "url": "https://eslint.org/docs/latest/rules/no-trailing-spaces"
},
"fixable": "whitespace"
},
"docs": {
"description": "Disallow the use of undeclared variables unless mentioned in `/*global */` comments",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-undef"
+ "url": "https://eslint.org/docs/latest/rules/no-undef"
}
},
"no-undef-init": {
"docs": {
"description": "Disallow initializing variables to `undefined`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-undef-init"
+ "url": "https://eslint.org/docs/latest/rules/no-undef-init"
},
"fixable": "code"
},
"docs": {
"description": "Disallow the use of `undefined` as an identifier",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-undefined"
+ "url": "https://eslint.org/docs/latest/rules/no-undefined"
}
},
"no-underscore-dangle": {
"docs": {
"description": "Disallow dangling underscores in identifiers",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-underscore-dangle"
+ "url": "https://eslint.org/docs/latest/rules/no-underscore-dangle"
}
},
"no-unexpected-multiline": {
"docs": {
"description": "Disallow confusing multiline expressions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unexpected-multiline"
+ "url": "https://eslint.org/docs/latest/rules/no-unexpected-multiline"
}
},
"no-unmodified-loop-condition": {
"docs": {
"description": "Disallow unmodified loop conditions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-unmodified-loop-condition"
+ "url": "https://eslint.org/docs/latest/rules/no-unmodified-loop-condition"
}
},
"no-unneeded-ternary": {
"docs": {
"description": "Disallow ternary operators when simpler alternatives exist",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-unneeded-ternary"
+ "url": "https://eslint.org/docs/latest/rules/no-unneeded-ternary"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unreachable"
+ "url": "https://eslint.org/docs/latest/rules/no-unreachable"
}
},
"no-unreachable-loop": {
"docs": {
"description": "Disallow loops with a body that allows only one iteration",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-unreachable-loop"
+ "url": "https://eslint.org/docs/latest/rules/no-unreachable-loop"
}
},
"no-unsafe-finally": {
"docs": {
"description": "Disallow control flow statements in `finally` blocks",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unsafe-finally"
+ "url": "https://eslint.org/docs/latest/rules/no-unsafe-finally"
}
},
"no-unsafe-negation": {
"docs": {
"description": "Disallow negating the left operand of relational operators",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unsafe-negation"
+ "url": "https://eslint.org/docs/latest/rules/no-unsafe-negation"
},
"hasSuggestions": true,
"fixable": null
"docs": {
"description": "Disallow use of optional chaining in contexts where the `undefined` value is not allowed",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unsafe-optional-chaining"
+ "url": "https://eslint.org/docs/latest/rules/no-unsafe-optional-chaining"
},
"fixable": null
},
"docs": {
"description": "Disallow unused expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-unused-expressions"
+ "url": "https://eslint.org/docs/latest/rules/no-unused-expressions"
}
},
"no-unused-labels": {
"docs": {
"description": "Disallow unused labels",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unused-labels"
+ "url": "https://eslint.org/docs/latest/rules/no-unused-labels"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unused private class members",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-unused-private-class-members"
+ "url": "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
}
},
"no-unused-vars": {
"docs": {
"description": "Disallow unused variables",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-unused-vars"
+ "url": "https://eslint.org/docs/latest/rules/no-unused-vars"
}
},
"no-use-before-define": {
"docs": {
"description": "Disallow the use of variables before they are defined",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-use-before-define"
+ "url": "https://eslint.org/docs/latest/rules/no-use-before-define"
}
},
"no-useless-backreference": {
"docs": {
"description": "Disallow useless backreferences in regular expressions",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-useless-backreference"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-backreference"
}
},
"no-useless-call": {
"docs": {
"description": "Disallow unnecessary calls to `.call()` and `.apply()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-useless-call"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-call"
}
},
"no-useless-catch": {
"docs": {
"description": "Disallow unnecessary `catch` clauses",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-useless-catch"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-catch"
}
},
"no-useless-computed-key": {
"docs": {
"description": "Disallow unnecessary computed property keys in objects and classes",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-useless-computed-key"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-computed-key"
},
"fixable": "code"
},
"docs": {
"description": "Disallow unnecessary concatenation of literals or template literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-useless-concat"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-concat"
}
},
"no-useless-constructor": {
"docs": {
"description": "Disallow unnecessary constructors",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-useless-constructor"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-constructor"
}
},
"no-useless-escape": {
"docs": {
"description": "Disallow unnecessary escape characters",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-useless-escape"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-escape"
},
"hasSuggestions": true
},
"docs": {
"description": "Disallow renaming import, export, and destructured assignments to the same name",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-useless-rename"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-rename"
},
"fixable": "code"
},
"docs": {
"description": "Disallow redundant return statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-useless-return"
+ "url": "https://eslint.org/docs/latest/rules/no-useless-return"
},
"fixable": "code"
},
"docs": {
"description": "Require `let` or `const` instead of `var`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-var"
+ "url": "https://eslint.org/docs/latest/rules/no-var"
},
"fixable": "code"
},
"docs": {
"description": "Disallow `void` operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-void"
+ "url": "https://eslint.org/docs/latest/rules/no-void"
}
},
"no-warning-comments": {
"docs": {
"description": "Disallow specified warning terms in comments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-warning-comments"
+ "url": "https://eslint.org/docs/latest/rules/no-warning-comments"
}
},
"no-whitespace-before-property": {
"docs": {
"description": "Disallow whitespace before properties",
"recommended": false,
- "url": "https://eslint.org/docs/rules/no-whitespace-before-property"
+ "url": "https://eslint.org/docs/latest/rules/no-whitespace-before-property"
},
"fixable": "whitespace"
},
"docs": {
"description": "Disallow `with` statements",
"recommended": true,
- "url": "https://eslint.org/docs/rules/no-with"
+ "url": "https://eslint.org/docs/latest/rules/no-with"
}
},
"nonblock-statement-body-position": {
"docs": {
"description": "Enforce the location of single-line statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/nonblock-statement-body-position"
+ "url": "https://eslint.org/docs/latest/rules/nonblock-statement-body-position"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent line breaks after opening and before closing braces",
"recommended": false,
- "url": "https://eslint.org/docs/rules/object-curly-newline"
+ "url": "https://eslint.org/docs/latest/rules/object-curly-newline"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing inside braces",
"recommended": false,
- "url": "https://eslint.org/docs/rules/object-curly-spacing"
+ "url": "https://eslint.org/docs/latest/rules/object-curly-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce placing object properties on separate lines",
"recommended": false,
- "url": "https://eslint.org/docs/rules/object-property-newline"
+ "url": "https://eslint.org/docs/latest/rules/object-property-newline"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow method and property shorthand syntax for object literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/object-shorthand"
+ "url": "https://eslint.org/docs/latest/rules/object-shorthand"
},
"fixable": "code"
},
"docs": {
"description": "Enforce variables to be declared either together or separately in functions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/one-var"
+ "url": "https://eslint.org/docs/latest/rules/one-var"
},
"fixable": "code"
},
"docs": {
"description": "Require or disallow newlines around variable declarations",
"recommended": false,
- "url": "https://eslint.org/docs/rules/one-var-declaration-per-line"
+ "url": "https://eslint.org/docs/latest/rules/one-var-declaration-per-line"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow assignment operator shorthand where possible",
"recommended": false,
- "url": "https://eslint.org/docs/rules/operator-assignment"
+ "url": "https://eslint.org/docs/latest/rules/operator-assignment"
},
"fixable": "code"
},
"docs": {
"description": "Enforce consistent linebreak style for operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/operator-linebreak"
+ "url": "https://eslint.org/docs/latest/rules/operator-linebreak"
},
"fixable": "code"
},
"docs": {
"description": "Require or disallow padding within blocks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/padded-blocks"
+ "url": "https://eslint.org/docs/latest/rules/padded-blocks"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow padding lines between statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/padding-line-between-statements"
+ "url": "https://eslint.org/docs/latest/rules/padding-line-between-statements"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require using arrow functions for callbacks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-arrow-callback"
+ "url": "https://eslint.org/docs/latest/rules/prefer-arrow-callback"
},
"fixable": "code"
},
"docs": {
"description": "Require `const` declarations for variables that are never reassigned after declared",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-const"
+ "url": "https://eslint.org/docs/latest/rules/prefer-const"
},
"fixable": "code"
},
"docs": {
"description": "Require destructuring from arrays and/or objects",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-destructuring"
+ "url": "https://eslint.org/docs/latest/rules/prefer-destructuring"
},
"fixable": "code"
},
"docs": {
"description": "Disallow the use of `Math.pow` in favor of the `**` operator",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-exponentiation-operator"
+ "url": "https://eslint.org/docs/latest/rules/prefer-exponentiation-operator"
},
"fixable": "code"
},
"docs": {
"description": "Enforce using named capture group in regular expression",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-named-capture-group"
- }
+ "url": "https://eslint.org/docs/latest/rules/prefer-named-capture-group"
+ },
+ "hasSuggestions": true
},
"prefer-numeric-literals": {
"type": "suggestion",
"docs": {
"description": "Disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-numeric-literals"
+ "url": "https://eslint.org/docs/latest/rules/prefer-numeric-literals"
},
"fixable": "code"
},
"docs": {
"description": "Disallow use of `Object.prototype.hasOwnProperty.call()` and prefer use of `Object.hasOwn()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-object-has-own"
+ "url": "https://eslint.org/docs/latest/rules/prefer-object-has-own"
},
"fixable": "code"
},
"prefer-object-spread": {
"type": "suggestion",
"docs": {
- "description": "Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead.",
+ "description": "Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-object-spread"
+ "url": "https://eslint.org/docs/latest/rules/prefer-object-spread"
},
"fixable": "code"
},
"docs": {
"description": "Require using Error objects as Promise rejection reasons",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-promise-reject-errors"
+ "url": "https://eslint.org/docs/latest/rules/prefer-promise-reject-errors"
},
"fixable": null
},
"docs": {
"description": "Require `Reflect` methods where applicable",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-reflect"
+ "url": "https://eslint.org/docs/latest/rules/prefer-reflect"
},
"deprecated": true,
"replacedBy": []
"docs": {
"description": "Disallow use of the `RegExp` constructor in favor of regular expression literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-regex-literals"
+ "url": "https://eslint.org/docs/latest/rules/prefer-regex-literals"
},
"hasSuggestions": true
},
"docs": {
"description": "Require rest parameters instead of `arguments`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-rest-params"
+ "url": "https://eslint.org/docs/latest/rules/prefer-rest-params"
}
},
"prefer-spread": {
"docs": {
"description": "Require spread operators instead of `.apply()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-spread"
+ "url": "https://eslint.org/docs/latest/rules/prefer-spread"
},
"fixable": null
},
"docs": {
"description": "Require template literals instead of string concatenation",
"recommended": false,
- "url": "https://eslint.org/docs/rules/prefer-template"
+ "url": "https://eslint.org/docs/latest/rules/prefer-template"
},
"fixable": "code"
},
"docs": {
"description": "Require quotes around object literal property names",
"recommended": false,
- "url": "https://eslint.org/docs/rules/quote-props"
+ "url": "https://eslint.org/docs/latest/rules/quote-props"
},
"fixable": "code"
},
"docs": {
"description": "Enforce the consistent use of either backticks, double, or single quotes",
"recommended": false,
- "url": "https://eslint.org/docs/rules/quotes"
+ "url": "https://eslint.org/docs/latest/rules/quotes"
},
"fixable": "code"
},
"docs": {
"description": "Enforce the consistent use of the radix argument when using `parseInt()`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/radix"
+ "url": "https://eslint.org/docs/latest/rules/radix"
},
"hasSuggestions": true
},
"docs": {
"description": "Disallow assignments that can lead to race conditions due to usage of `await` or `yield`",
"recommended": false,
- "url": "https://eslint.org/docs/rules/require-atomic-updates"
+ "url": "https://eslint.org/docs/latest/rules/require-atomic-updates"
},
"fixable": null
},
"docs": {
"description": "Disallow async functions which have no `await` expression",
"recommended": false,
- "url": "https://eslint.org/docs/rules/require-await"
+ "url": "https://eslint.org/docs/latest/rules/require-await"
}
},
"require-jsdoc": {
"docs": {
"description": "Require JSDoc comments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/require-jsdoc"
+ "url": "https://eslint.org/docs/latest/rules/require-jsdoc"
},
"deprecated": true,
"replacedBy": []
"docs": {
"description": "Enforce the use of `u` flag on RegExp",
"recommended": false,
- "url": "https://eslint.org/docs/rules/require-unicode-regexp"
- }
+ "url": "https://eslint.org/docs/latest/rules/require-unicode-regexp"
+ },
+ "hasSuggestions": true
},
"require-yield": {
"type": "suggestion",
"docs": {
"description": "Require generator functions to contain `yield`",
"recommended": true,
- "url": "https://eslint.org/docs/rules/require-yield"
+ "url": "https://eslint.org/docs/latest/rules/require-yield"
}
},
"rest-spread-spacing": {
"docs": {
"description": "Enforce spacing between rest and spread operators and their expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/rest-spread-spacing"
+ "url": "https://eslint.org/docs/latest/rules/rest-spread-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow semicolons instead of ASI",
"recommended": false,
- "url": "https://eslint.org/docs/rules/semi"
+ "url": "https://eslint.org/docs/latest/rules/semi"
},
"fixable": "code"
},
"docs": {
"description": "Enforce consistent spacing before and after semicolons",
"recommended": false,
- "url": "https://eslint.org/docs/rules/semi-spacing"
+ "url": "https://eslint.org/docs/latest/rules/semi-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce location of semicolons",
"recommended": false,
- "url": "https://eslint.org/docs/rules/semi-style"
+ "url": "https://eslint.org/docs/latest/rules/semi-style"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce sorted import declarations within modules",
"recommended": false,
- "url": "https://eslint.org/docs/rules/sort-imports"
+ "url": "https://eslint.org/docs/latest/rules/sort-imports"
},
"fixable": "code"
},
"docs": {
"description": "Require object keys to be sorted",
"recommended": false,
- "url": "https://eslint.org/docs/rules/sort-keys"
+ "url": "https://eslint.org/docs/latest/rules/sort-keys"
}
},
"sort-vars": {
"docs": {
"description": "Require variables within the same declaration block to be sorted",
"recommended": false,
- "url": "https://eslint.org/docs/rules/sort-vars"
+ "url": "https://eslint.org/docs/latest/rules/sort-vars"
},
"fixable": "code"
},
"docs": {
"description": "Enforce consistent spacing before blocks",
"recommended": false,
- "url": "https://eslint.org/docs/rules/space-before-blocks"
+ "url": "https://eslint.org/docs/latest/rules/space-before-blocks"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing before `function` definition opening parenthesis",
"recommended": false,
- "url": "https://eslint.org/docs/rules/space-before-function-paren"
+ "url": "https://eslint.org/docs/latest/rules/space-before-function-paren"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing inside parentheses",
"recommended": false,
- "url": "https://eslint.org/docs/rules/space-in-parens"
+ "url": "https://eslint.org/docs/latest/rules/space-in-parens"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require spacing around infix operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/space-infix-ops"
+ "url": "https://eslint.org/docs/latest/rules/space-infix-ops"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing before or after unary operators",
"recommended": false,
- "url": "https://eslint.org/docs/rules/space-unary-ops"
+ "url": "https://eslint.org/docs/latest/rules/space-unary-ops"
},
"fixable": "whitespace"
},
"docs": {
"description": "Enforce consistent spacing after the `//` or `/*` in a comment",
"recommended": false,
- "url": "https://eslint.org/docs/rules/spaced-comment"
+ "url": "https://eslint.org/docs/latest/rules/spaced-comment"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow strict mode directives",
"recommended": false,
- "url": "https://eslint.org/docs/rules/strict"
+ "url": "https://eslint.org/docs/latest/rules/strict"
},
"fixable": "code"
},
"docs": {
"description": "Enforce spacing around colons of switch statements",
"recommended": false,
- "url": "https://eslint.org/docs/rules/switch-colon-spacing"
+ "url": "https://eslint.org/docs/latest/rules/switch-colon-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require symbol descriptions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/symbol-description"
+ "url": "https://eslint.org/docs/latest/rules/symbol-description"
},
"fixable": null
},
"docs": {
"description": "Require or disallow spacing around embedded expressions of template strings",
"recommended": false,
- "url": "https://eslint.org/docs/rules/template-curly-spacing"
+ "url": "https://eslint.org/docs/latest/rules/template-curly-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow spacing between template tags and their literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/template-tag-spacing"
+ "url": "https://eslint.org/docs/latest/rules/template-tag-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow Unicode byte order mark (BOM)",
"recommended": false,
- "url": "https://eslint.org/docs/rules/unicode-bom"
+ "url": "https://eslint.org/docs/latest/rules/unicode-bom"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require calls to `isNaN()` when checking for `NaN`",
"recommended": true,
- "url": "https://eslint.org/docs/rules/use-isnan"
+ "url": "https://eslint.org/docs/latest/rules/use-isnan"
}
},
"valid-jsdoc": {
"docs": {
"description": "Enforce valid JSDoc comments",
"recommended": false,
- "url": "https://eslint.org/docs/rules/valid-jsdoc"
+ "url": "https://eslint.org/docs/latest/rules/valid-jsdoc"
},
"fixable": "code",
"deprecated": true,
"docs": {
"description": "Enforce comparing `typeof` expressions against valid strings",
"recommended": true,
- "url": "https://eslint.org/docs/rules/valid-typeof"
+ "url": "https://eslint.org/docs/latest/rules/valid-typeof"
},
"hasSuggestions": true
},
"docs": {
"description": "Require `var` declarations be placed at the top of their containing scope",
"recommended": false,
- "url": "https://eslint.org/docs/rules/vars-on-top"
+ "url": "https://eslint.org/docs/latest/rules/vars-on-top"
}
},
"wrap-iife": {
"docs": {
"description": "Require parentheses around immediate `function` invocations",
"recommended": false,
- "url": "https://eslint.org/docs/rules/wrap-iife"
+ "url": "https://eslint.org/docs/latest/rules/wrap-iife"
},
"fixable": "code"
},
"docs": {
"description": "Require parenthesis around regex literals",
"recommended": false,
- "url": "https://eslint.org/docs/rules/wrap-regex"
+ "url": "https://eslint.org/docs/latest/rules/wrap-regex"
},
"fixable": "code"
},
"docs": {
"description": "Require or disallow spacing around the `*` in `yield*` expressions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/yield-star-spacing"
+ "url": "https://eslint.org/docs/latest/rules/yield-star-spacing"
},
"fixable": "whitespace"
},
"docs": {
"description": "Require or disallow \"Yoda\" conditions",
"recommended": false,
- "url": "https://eslint.org/docs/rules/yoda"
+ "url": "https://eslint.org/docs/latest/rules/yoda"
},
"fixable": "code"
}
title: Social Media
twitter: Twitter
chat: Discord
- mailing_list: Google Group
github: GitHub
+ mastodon: Mastodon
theme_switcher:
title: Theme Switcher
light: Light
description: Selecting a language will take you to the ESLint website in that language.
change_language: Change Language
language: Language
+ latest: Latest
copyright: >
- © OpenJS Foundation and ESLint contributors, <a href="https://www.openjsf.org">www.openjsf.org</a>
+ © OpenJS Foundation and ESLint contributors, <a href="https://www.openjsf.org">www.openjsf.org</a>. Content licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.
links:
open_jsf: The OpenJS Foundation
terms: Terms of Use
--- /dev/null
+#------------------------------------------------------------------------------
+# Simplified Chinese Site Details
+# The documentation site that is hosted at zh-hans.eslint.org/docs
+# Author: Percy Ma
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# Global Settings
+#------------------------------------------------------------------------------
+
+language:
+ code: zh-hans
+ flag: 🇨🇳
+ name: 简体中文
+locale: zh-hans
+hostname: zh-hans.eslint.org
+
+#------------------------------------------------------------------------------
+# Analytics
+#------------------------------------------------------------------------------
+
+google_analytics:
+ code: "G-6ELXTK7GZR"
+
+#------------------------------------------------------------------------------
+# Ads
+#------------------------------------------------------------------------------
+
+carbon_ads:
+ serve: ""
+ placement: ""
+
+#------------------------------------------------------------------------------
+# Shared
+#------------------------------------------------------------------------------
+
+shared:
+ get_started: 开始
+ become_a_sponsor: 捐赠
+ eslint_logo_alt: ESLint 图标
+ description: >
+ 插件化、可配置的 JavaScript 代码检查工具,让你轻松地提高代码质量。
+ title_format: PAGE_TITLE - ESLint - 插件化的 JavaScript 代码检查工具
+ skip_to_content: 跳转到正文
+ donate: 捐赠
+
+#------------------------------------------------------------------------------
+# Navigation
+#------------------------------------------------------------------------------
+
+navigation:
+- text: 团队
+ link: team
+- text: 博客
+ link: blog
+- text: 文档
+ link: docs
+- text: 商店
+ link: store
+ target: _blank
+- text: 演练场
+ link: playground
+
+#------------------------------------------------------------------------------
+# Footer
+#------------------------------------------------------------------------------
+
+footer:
+ title: 准备修复你的 JavaScript 代码了吗?
+ description: 从 npm 安装或捐赠开始。
+ secondary: 次要
+ social_icons:
+ title: 社交媒体
+ twitter: Twitter
+ chat: Discord
+ github: GitHub
+ theme_switcher:
+ title: 主题切换
+ light: 浅色
+ dark: 深色
+ language_switcher:
+ title: 语言切换
+ description: 切换到你所选择语言版本对应的 ESLint 网站。
+ change_language: 更改语言
+ language: 语言
+ latest: 最新
+ copyright: >
+ © OpenJS Foundation and ESLint contributors, <a href="https://www.openjsf.org">www.openjsf.org</a>. Content licensed under <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License</a>.
+ links:
+ open_jsf: OpenJS 基金会
+ terms: 使用条款
+ privacy: 隐私策略
+ bylaws: OpenJS 基金会章程
+ trademark: 商标策略
+ trademark_list: 商标列表
+ cookies: Cookie 策略
+
+#------------------------------------------------------------------------------
+# 404 Page
+#------------------------------------------------------------------------------
+
+404_page:
+ title: 404 错误
+ subtitle: 页面未找到
+ description: 对不起,你正在寻找的页面不存在或已被移动。
+ actions:
+ back_to_home: 回到主页
+ browse_docs: 浏览文档
+
+#------------------------------------------------------------------------------
+# Edit link
+#------------------------------------------------------------------------------
+
+edit_link:
+ start_with: https://github.com/eslint/eslint/edit/main/docs/
+ text: 编辑此页
<select name="language selector" id="language-select" aria-describedby="language-infobox"
class="c-custom-select switcher__select">
{% for key, other_site in sites %}
- <option value="{{ other_site.language.code }}" data-url="https://{{ other_site.hostname }}" {% if
- site.language.code==other_site.language.code %} selected {% endif %}>
+ <option
+ value="{{ other_site.language.code }}"
+ data-url="https://{{ other_site.hostname }}/docs/latest{{ page.url | prettyURL }}"
+ {% if site.language.code==other_site.language.code %}selected{% endif %}
+ >
{{ other_site.language.flag }} {{ other_site.language.name }}
+ {% if site.language.code!=other_site.language.code or GIT_BRANCH=="latest" %}({{ other_site.footer.language_switcher.latest }}){% endif %}
</option>
{% endfor %}
</select>
}
[data-theme="dark"] #logo-center {
- opacity: 60%;
+ opacity: 0.6;
}
</style>
<svg class="brand-logo" width="203" height="58" viewBox="0 0 203 58" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="ESLint logo">
<span class="label__text">Version</span>
</label>
<select name="version selector" id="nav-version-select" aria-describedby="nav-version-infobox" class="c-custom-select switcher__select auto-switcher">
- <option value="HEAD" data-url="/docs/head/" {% if GIT_BRANCH !="latest" %}selected{% endif %}>HEAD</option>
- <option value="{{ eslintVersion }}" data-url="/docs/latest/" {% if GIT_BRANCH=="latest" %}selected{% endif %}>v{{ eslintVersion }}</option>
+ <option value="HEAD" data-url="/docs/head/" {% if HEAD %}selected{% endif %}>HEAD</option>
+ {% if config.showNextVersion == true %}
+ <option value="NEXT" data-url="/docs/next/" {% if GIT_BRANCH == "next" %}selected{% endif %}>NEXT</option>
+ {% endif %}
+ <option value="{{ eslintVersion }}" data-url="/docs/latest/" {% if GIT_BRANCH == "latest" %}selected{% endif %}>v{{ eslintVersion }}</option>
{% for version in versions.items %}
<option value="{{ version.number }}"
data-url="{{ version.url }}">
<div class="rule-category">
<span class="rule-category__icon">✅ <span class="visually-hidden">Recommended</span></span>
<p class="rule-category__description">
- The <code>"extends": "eslint:recommended"</code> property in a <a href="../user-guide/configuring/configuration-files#extending-configuration-files">configuration file</a> enables this rule
+ The <code>"extends": "eslint:recommended"</code> property in a <a href="../use/configure/configuration-files#extending-configuration-files">configuration file</a> enables this rule
</p>
</div>
{%- endif -%}
{%- if params.fixable -%}
<div class="rule-category">
- <span class="rule-category__icon">ð\9f\9b <span class="visually-hidden">Fixable</span></span>
+ <span class="rule-category__icon">ð\9f\94§ <span class="visually-hidden">Fixable</span></span>
<p class="rule-category__description">
- Some problems reported by this rule are automatically fixable by the <code>--fix</code> <a href="../user-guide/command-line-interface#--fix">command line</a> option
+ Some problems reported by this rule are automatically fixable by the <code>--fix</code> <a href="../use/command-line-interface#--fix">command line</a> option
</p>
</div>
{%- endif -%}
<div class="rule-category">
<span class="rule-category__icon">💡 <span class="visually-hidden">hasSuggestions</span></span>
<p class="rule-category__description">
- Some problems reported by this rule are manually fixable by editor <a href="../developer-guide/working-with-rules#providing-suggestions">suggestions</a>
+ Some problems reported by this rule are manually fixable by editor <a href="../extend/custom-rules#providing-suggestions">suggestions</a>
</p>
</div>
{%- endif -%}
{%- macro fixable() -%}
<div class="rule-category">
- <span class="rule-category__icon">ð\9f\9b <span class="visually-hidden">Fixable</span></span>
+ <span class="rule-category__icon">ð\9f\94§ <span class="visually-hidden">Fixable</span></span>
<p class="rule-category__description">
if some problems reported by the rule are automatically fixable by the <code>--fix</code> command line option
</p>
<div class="rule__categories">
<span class="visually-hidden">Categories:</span>
{%- if (params.deprecated) or (params.removed) -%}
- <p class="rule__categories__type">
- <svg width="24" height="24" viewBox="12 12 20 20" fill="none" aria-hidden="true" focusable="false" style="position: relative; right: -1px;">
- <path d="M28.5 16L16.5 28M16.5 16L28.5 28" stroke="#F63D68" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
- </svg>
- </p>
+ <p class="rule__categories__type">❌</p>
{%- else -%}
<p class="rule__categories__type" {% if params.categories.recommended == false %}aria-hidden="true" {%- endif -%}>
✅ <span class="visually-hidden">Extends</span>
{%- endif -%}
<p class="rule__categories__type" {% if params.categories.fixable == false %}aria-hidden="true" {%- endif -%}>
- ð\9f\9b <span class="visually-hidden">Fix</span>
+ ð\9f\94§ <span class="visually-hidden">Fix</span>
</p>
<p class="rule__categories__type" {% if params.categories.hasSuggestions == false %}aria-hidden="true" {%- endif -%}>
💡 <span class="visually-hidden">Suggestions</span>
<h2 id="eslint-social-label" hidden>{{ site.footer.social_icons.title }}</h2>
<ul role="list">
<li>
- <a href="{{ links.twitter }}" target="_blank">
+ <a href="{{ links.twitter }}" rel="noopener noreferrer" target="_blank">
<svg width="24" height="25" viewBox="0 0 24 25" class="c-icon" role="img"
aria-label="{{ site.footer.social_icons.twitter }}">
<path
</a>
</li>
<li>
- <a href="{{ links.group }}" target="_blank">
- <svg width="24" height="25" viewBox="0 0 24 25" class="c-icon" role="img"
- aria-label="{{ site.footer.social_icons.mailing_list }}">
- <path
- d="M23.5072 9.92762H12.0522V14.8366H18.5442C17.5072 18.1096 14.9442 19.2006 12.0002 19.2006C10.8597 19.202 9.73567 18.9283 8.7235 18.4026C7.71133 17.877 6.84089 17.1149 6.18603 16.1812C5.53116 15.2474 5.11119 14.1695 4.96174 13.0388C4.8123 11.9081 4.93779 10.758 5.32758 9.68619C5.71736 8.61435 6.35993 7.65234 7.20078 6.88179C8.04162 6.11123 9.05593 5.55486 10.1576 5.25989C11.2594 4.96491 12.416 4.94004 13.5293 5.18736C14.6427 5.43469 15.68 5.94693 16.5532 6.68062L20.1202 3.28062C18.6835 1.95814 16.9458 1.00625 15.0578 0.507551C13.1698 0.0088549 11.1887 -0.0215774 9.28633 0.418895C7.38395 0.859367 5.61779 1.75744 4.14115 3.03516C2.6645 4.31289 1.52197 5.93167 0.812711 7.75102C0.103454 9.57037 -0.151101 11.5353 0.0711364 13.4753C0.293374 15.4154 0.98569 17.2718 2.088 18.8837C3.19032 20.4955 4.66932 21.814 6.39666 22.7247C8.124 23.6354 10.0475 24.1108 12.0002 24.1096C18.6172 24.1096 24.6002 19.7456 23.5072 9.92762Z"
- fill="currentColor" />
- </svg>
- </a>
- </li>
- <li>
- <a href="{{ links.github }}" target="_blank">
+ <a href="{{ links.github }}" rel="noopener noreferrer" target="_blank">
<svg width="25" height="24" viewBox="0 0 25 24" class="c-icon" role="img"
aria-label="{{ site.footer.social_icons.github }}">
<path fill-rule="evenodd" clip-rule="evenodd"
</a>
</li>
<li>
- <a href="{{ links.chat }}" target="_blank">
+ <a href="{{ links.chat }}" rel="noopener noreferrer" target="_blank">
<svg width="24" height="25" viewBox="0 0 24 25" class="c-icon" role="img"
aria-label="{{ site.footer.social_icons.chat }}">
<g clip-path="url(#clip0_256:2722)">
</a>
</li>
-
+ <li>
+ <a href="{{ links.mastodon }}" rel="noopener noreferrer" target="_blank">
+ <svg width="24" height="25" viewBox="0 0 216.4144 232.00976" class="c-icon" role="img" aria-label="{{ site.footer.social_icons.mastodon }}">
+ <path fill="currentColor" d="M211.80734 139.0875c-3.18125 16.36625-28.4925 34.2775-57.5625 37.74875-15.15875 1.80875-30.08375 3.47125-45.99875 2.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125 0 2.53375.15625 4.94625.46875 7.2025 3.38375 25.68625 25.47 27.225 46.39125 27.9425 21.11625.7225 39.91875-5.20625 39.91875-5.20625l.8675 19.09s-14.77 7.93125-41.08125 9.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234 213.82 1.40609 165.31125.20859 116.09125c-.365-14.61375-.14-28.39375-.14-39.91875 0-50.33 32.97625-65.0825 32.97625-65.0825C49.67234 3.45375 78.20359.2425 107.86484 0h.72875c29.66125.2425 58.21125 3.45375 74.8375 11.09 0 0 32.975 14.7525 32.975 65.0825 0 0 .41375 37.13375-4.59875 62.915" />
+ <path fill="var(--lighter-background-color)" d="M177.50984 80.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025 0-17.4175 7.5075-17.4175 22.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375 0-15.74 6.32875-15.74 18.7975v59.15H38.90484V80.077c0-12.455 3.17125-22.3525 9.54125-29.675 6.56875-7.3225 15.17125-11.07625 25.85-11.07625 12.355 0 21.71125 4.74875 27.8975 14.2475l6.01375 10.08125 6.015-10.08125c6.185-9.49875 15.54125-14.2475 27.8975-14.2475 10.6775 0 19.28 3.75375 25.85 11.07625 6.36875 7.3225 9.54 17.22 9.54 29.675" />
+ </svg>
+ </a>
+ </li>
</ul>
</nav>
<span class="label__text">Version</span>
</label>
<select name="version selector" id="version-select" aria-describedby="version-infobox" class="c-custom-select switcher__select auto-switcher">
- <option value="HEAD" data-url="/docs/head/" {% if GIT_BRANCH != "latest" %}selected{% endif %}>HEAD</option>
+ <option value="HEAD" data-url="/docs/head/" {% if HEAD %}selected{% endif %}>HEAD</option>
+ {% if config.showNextVersion == true %}
+ <option value="NEXT" data-url="/docs/next/" {% if GIT_BRANCH=="next" %}selected{% endif %}>NEXT</option>
+ {% endif %}
<option value="{{ eslintVersion }}" data-url="/docs/latest/" {% if GIT_BRANCH == "latest" %}selected{% endif %}>v{{ eslintVersion }}</option>
{% for version in versions.items %}
<option value="{{ version.number }}"
<!DOCTYPE html>
-<html lang="{{ config.lang }}" class="no-js">
+<html lang="{{ config.lang }}" class="no-js" id="site_top">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{ page_title }}</title>
<meta name="description" content="{{ page_desc }}">
<link rel="canonical" href="{{ page_url }}">
-
+
<!-- https://github.com/eslint/eslint/issues/15844 -->
<base href="{{ relative_page_url }}">
<style>
-
/* Overrides for funky punctuators */
@font-face {
font-family: "Mono Punctuators";
unicode-range: U+40, U+7B, U+7D, U+28, U+29;
font-display: swap;
}
-
+
/* Space Grotesk for headings */
@font-face {
font-family: "Space Grotesk";
- src: url("{{ '/assets/fonts/SpaceGrotesk-Medium-subset.woff2' | url }}") format("woff2"),
- url("{{ '/assets/fonts/SpaceGrotesk-Medium-subset.zopfli.woff' | url }}") format("woff");
+ src:
+ url("{{ '/assets/fonts/SpaceGrotesk-Medium-subset.woff2' | url }}") format("woff2"),
+ url("{{ '/assets/fonts/SpaceGrotesk-Medium-subset.zopfli.woff' | url }}") format("woff");
font-weight: 500;
font-display: swap;
}
/* Inter for body text */
@font-face {
- font-family: "Inter";
- src: url("{{ '/assets/fonts/Inter-Regular-subset.woff2' | url }}") format("woff2"),
- url("{{ '/assets/fonts/Inter-Regular-subset.zopfli.woff' | url }}") format("woff");
+ font-family: Inter;
+ src:
+ url("{{ '/assets/fonts/Inter-Regular-subset.woff2' | url }}") format("woff2"),
+ url("{{ '/assets/fonts/Inter-Regular-subset.zopfli.woff' | url }}") format("woff");
font-weight: 400;
font-display: swap;
}
@font-face {
font-family: "Space Mono";
- src: url("{{ '/assets/fonts/SpaceMono-Regular-subset.woff2' | url }}") format("woff2"),
- url("{{ '/assets/fonts/SpaceMono-Regular-subset.zopfli.woff' | url }}") format("woff");
+ src:
+ url("{{ '/assets/fonts/SpaceMono-Regular-subset.woff2' | url }}") format("woff2"),
+ url("{{ '/assets/fonts/SpaceMono-Regular-subset.zopfli.woff' | url }}") format("woff");
font-weight: 400;
font-display: swap;
}
+
+ /* Country Flags for Windows */
+ @font-face {
+ font-family: "Twemoji Country Flags";
+ unicode-range: U+1F1E6-1F1FF, U+1F3F4, U+E0062-E0063, U+E0065, U+E0067, U+E006C, U+E006E, U+E0073-E0074, U+E0077, U+E007F;
+ src: url("https://cdn.jsdelivr.net/npm/country-flag-emoji-polyfill@0.1/dist/TwemojiCountryFlags.woff2") format("woff2");
+ }
</style>
<script>
if ("fonts" in document) {
<script src="https://unpkg.com/anchor-js@4.3.1/anchor.min.js"></script>
</head>
-<body class="{{ hook }} docs">
+<body class="{{ hook }}">
<a href="#main" class="c-btn c-btn--primary" id="skip-link">Skip to main content</a>
{{ content | safe }}
<script src="{{ '/assets/js/focus-visible.js' | url }}"></script>
<script src="{{ '/assets/js/main.js' | url }}"></script>
<script src="{{ '/assets/js/tabs.js' | url }}"></script>
+ <script src="{{ '/assets/js/scroll-up-btn.js' | url }}"></script>
{% include 'partials/analytics.html' %}
{%- if hook == "component-library" -%}
{% include "partials/docs-footer.html" %}
</div>
</div>
+ <a id="scroll-up-btn" href="#site_top">
+ <svg fill="none" height="24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" width="24"><line x1="12" x2="12" y1="19" y2="5"/><polyline points="5 12 12 5 19 12"/></svg>
+ </a>
</div>
<script src="{{ '/assets/js/tabs.js' | url }}"></script>
<ul class="versions-list">
- <li><a href="/docs/head/" {% if GIT_BRANCH != "latest" %} data-current="true" {% endif %}>HEAD</a></li>
+ <li><a href="/docs/head/" {% if HEAD %} data-current="true" {% endif %}>HEAD</a></li>
+ {% if config.showNextVersion == true %}
+ <li><a href="/docs/next/" {% if GIT_BRANCH == "next" %} data-current="true" {% endif %}>NEXT</a></li>
+ {% endif %}
<li><a href="/docs/latest/" {% if GIT_BRANCH == "latest" %} data-current="true" {% endif %}>v{{ eslintVersion }}</a></li>
{%- for version in versions.items -%}
<li><a href="{{ version.url }}">v{{ version.number }}</a></li>
--- /dev/null
+/**
+ * MIT License
+
+Copyright (c) 2019-present, Yuxi (Evan) You
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+ */
+
+/** @typedef {import("markdown-it")} MarkdownIt */
+
+const Prism = require("prismjs");
+const loadLanguages = require("prismjs/components/");
+
+/**
+ *
+ * @param {MarkdownIt} md markdown-it
+ * @param {string} str code
+ * @param {string} lang code language
+ * @returns {string} highlighted result wrapped in pre
+ */
+const highlighter = function (md, str, lang) {
+ let result = "";
+ if (lang) {
+ try {
+ loadLanguages([lang]);
+ result = Prism.highlight(str, Prism.languages[lang], lang);
+ } catch (err) {
+ console.log(lang, err);
+ // we still want to wrap the result later
+ result = md.utils.escapeHtml(str);
+ }
+ } else {
+ result = md.utils.escapeHtml(str);
+ }
+
+ return `<pre class="language-${lang}"><code>${result}</code></pre>`;
+};
+
+/**
+ *
+ * modified from https://github.com/vuejs/vitepress/blob/main/src/node/markdown/plugins/lineNumbers.ts
+ * @param {MarkdownIt} md
+ * @license MIT License. See file header.
+ */
+const lineNumberPlugin = (md) => {
+ const fence = md.renderer.rules.fence;
+ md.renderer.rules.fence = (...args) => {
+ const [tokens, idx] = args;
+ const lang = tokens[idx].info.trim();
+ const rawCode = fence(...args);
+ const code = rawCode.slice(
+ rawCode.indexOf("<code>"),
+ rawCode.indexOf("</code>")
+ );
+ const lines = code.split("\n");
+ const lineNumbersCode = [...Array(lines.length - 1)]
+ .map(
+ (line, index) =>
+ `<span class="line-number">${index + 1}</span><br>`
+ )
+ .join("");
+
+ const lineNumbersWrapperCode = `<div class="line-numbers-wrapper" aria-hidden="true">${lineNumbersCode}</div>`;
+
+ const finalCode = rawCode
+ .replace(/<\/pre>\n/, `${lineNumbersWrapperCode}</pre>`)
+ .replace(/"(language-\S*?)"/, '"$1 line-numbers-mode"')
+ .replace(/<code>/, `<code class="language-${lang}">`)
+
+ return finalCode;
+ };
+};
+
+module.exports.highlighter = highlighter;
+module.exports.lineNumberPlugin = lineNumberPlugin;
---
title: About
-layout: doc
---
+(function () {
+ // for sticky table of contents
+ const tocBody = document.querySelector(".docs-aside #js-toc-panel");
+ const options = {
+ root: null,
+ rootMargin: `0px 0px -90% 0px`,
+ threshold: 1.0,
+ };
+ const activeClassName = "active";
+ const observer = new IntersectionObserver((entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ const activeAnchor = tocBody.querySelector(
+ `a.${activeClassName}`
+ );
+ if (activeAnchor) {
+ activeAnchor.parentNode.classList.remove(activeClassName);
+ activeAnchor.classList.remove(activeClassName);
+ }
+
+ const nextActiveAnchor = tocBody.querySelector(
+ `a[href="#${entry.target.id}"]`
+ );
+ if (nextActiveAnchor) {
+ nextActiveAnchor.parentNode.classList.add(activeClassName);
+ nextActiveAnchor.classList.add(activeClassName);
+ }
+ }
+ });
+ }, options);
+ if (window.matchMedia("(min-width: 1400px)").matches) {
+ document
+ .querySelectorAll(
+ "#main > div > h2[id], #main > div > h3[id], #main > div > h4[id]" // only h2, h3, h4 are shown in toc
+ )
+ .forEach((el) => observer.observe(el));
+ }
+})();
+
(function() {
var toc_trigger = document.getElementById("js-toc-label"),
toc = document.getElementById("js-toc-panel"),
document.addEventListener("DOMContentLoaded", () => {
anchors.add(".docs-content h2:not(.c-toc__label), .docs-content h3, .docs-content h4");
-});
\ No newline at end of file
+});
--- /dev/null
+(function () {
+ const scrollUpBtn = document.getElementById("scroll-up-btn");
+
+ if(window.innerWidth < 1400) {
+ window.addEventListener("scroll", function () {
+ if(document.body.scrollTop > 500 || document.documentElement.scrollTop > 500) {
+ scrollUpBtn.style.display = "flex";
+ } else {
+ scrollUpBtn.style.display = "none";
+ }
+ });
+ }
+})();
\ No newline at end of file
resultsElement.removeChild(resultsElement.firstChild);
}
resultsElement.innerHTML = "";
- searchClearBtn.setAttribute('hidden', '');
}
/**
`.trim();
list.append(listItem);
}
- searchClearBtn.removeAttribute('hidden');
} else {
resultsLiveRegion.innerHTML = "No results found.";
resultsElement.innerHTML = "No results found.";
resultsElement.setAttribute('data-results', 'false');
- searchClearBtn.setAttribute('hidden', '');
}
}
else if (isBelow) {
scrollParent.scrollTo(0, offsetTop - parentOffsetHeight + offsetHeight);
}
-
+
+}
+
+/**
+ * Debounces the provided callback with a given delay.
+ * @param {Function} callback The callback that needs to be debounced.
+ * @param {Number} delay Time in ms that the timer should wait before the callback is executed.
+ * @returns {Function} Returns the new debounced function.
+ */
+function debounce(callback, delay) {
+ let timer;
+ return (...args) => {
+ if (timer) clearTimeout(timer);
+ timer = setTimeout(() => callback.apply(this, args), delay);
+ }
}
+const debouncedFetchSearchResults = debounce((query) => {
+ fetchSearchResults(query)
+ .then(displaySearchResults)
+ .catch(clearSearchResults);
+}, 300);
//-----------------------------------------------------------------------------
// Event Handlers
//-----------------------------------------------------------------------------
// listen for input changes
-if(searchInput)
+if (searchInput)
searchInput.addEventListener('keyup', function (e) {
const query = searchInput.value;
- if(query === searchQuery) return;
+ if (query === searchQuery) return;
- if(query.length) searchClearBtn.removeAttribute('hidden');
+ if (query.length) searchClearBtn.removeAttribute('hidden');
else searchClearBtn.setAttribute('hidden', '');
if (query.length > 2) {
- fetchSearchResults(query)
- .then(displaySearchResults)
- .catch(clearSearchResults);
- document.addEventListener('click', function(e) {
- if(e.target !== resultsElement) clearSearchResults();
+ debouncedFetchSearchResults(query);
+
+ document.addEventListener('click', function (e) {
+ if (e.target !== resultsElement) clearSearchResults();
});
} else {
clearSearchResults();
}
- searchQuery = query
+ searchQuery = query
});
-if(searchClearBtn)
- searchClearBtn.addEventListener('click', function(e) {
+if (searchClearBtn)
+ searchClearBtn.addEventListener('click', function (e) {
searchInput.value = '';
searchInput.focus();
clearSearchResults();
+ searchClearBtn.setAttribute('hidden', '');
});
document.addEventListener('keydown', function (e) {
+ const searchResults = Array.from(document.querySelectorAll('.search-results__item'));
+
if (e.key === 'Escape') {
e.preventDefault();
- clearSearchResults();
- searchInput.focus();
+ if (searchResults.length) {
+ clearSearchResults();
+ searchInput.focus();
+ }
}
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
searchInput.focus();
- document.querySelector('.search').scrollIntoView({ behaviour: "smooth", block: "start" });
+ document.querySelector('.search').scrollIntoView({ behavior: "smooth", block: "start" });
}
- const searchResults = Array.from(document.querySelectorAll('.search-results__item'));
if (!searchResults.length) return;
switch (e.key) {
maintainScrollVisibility(activeSearchResult, resultsElement);
}
});
-
\ No newline at end of file
.hero-ad {
- @media all and (max-width: 800px) {
- display: none;
- }
+ @media all and (max-width: 800px) {
+ display: none;
+ }
}
#carbonads * {
padding: .6em;
font-size: 1rem;
overflow: hidden;
- border-radius: 4px;
background-color: var(--body-background-color);
border: 1px solid var(--border-color);
+ border-radius: 4px;
border-radius: var(--border-radius);
box-shadow: 0 1px 4px 1px hsla(0, 0%, 0%, 0.1);
}
.jumbotron #carbonads {
- border: solid 1px hsla(250, 20%, 50%, .6);
- background-color: hsla(0, 0%, 70%, .15);
+ border: solid 1px hsla(250, 20%, 50%, 0.6);
+ background-color: hsla(0, 0%, 70%, 0.15);
}
#carbonads a {
color: var(--color-rose-600);
[data-theme="dark"] & {
+ border: 1px solid var(--color-rose-300);
color: var(--color-rose-300);
background-color: var(--color-rose-900);
}
[data-theme="dark"] & {
color: var(--color-warning-300);
+ border: 1px solid var(--color-warning-300);
background-color: var(--color-warning-900);
}
}
[data-theme="dark"] & {
color: var(--color-success-300);
- background-color: var(--color-success-900);
- }
- }
-}
-
-
-[data-theme="dark"] {
- .alert {
- &.alert--warning {
- border: 1px solid var(--color-rose-300);
- }
-
- &.alert--important {
- border: 1px solid var(--color-warning-300);
- }
-
- &.alert--tip {
border: 1px solid var(--color-success-300);
+ background-color: var(--color-success-900);
}
}
}
}
}
-
.alert__learn-more {
display: block;
font-weight: 500;
align-items: center;
justify-content: center;
border-radius: var(--border-radius);
-
- transition: background-color .2s linear,
- border-color .2s linear;
+ transition: background-color .2s linear, border-color .2s linear;
svg {
color: inherit;
}
.index-js [aria-expanded="true"] .index-icon {
- -ms-transform: rotate(180deg);
transform: rotate(180deg);
}
}
#ham-top {
-
transform: rotate(41deg);
}
margin-bottom: 2rem;
margin-block-end: 2rem;
-
@media all and (min-width: 1024px) {
font-size: var(--step-0);
margin-top: 0;
}
}
-
.docs-nav-panel {
@media all and (min-width: 1024px) {
display: flex;
align-items: center;
margin-left: .5rem;
margin-right: -10px;
-
margin-inline-start: .5rem;
margin-inline-end: -10px;
-
svg {
width: 40px;
height: 40px;
}
#ham-top {
-
transform: rotate(41deg);
}
}
}
-
-
@media all and (min-width: 1024px) {
.docs-site-nav {
flex-direction: row;
order: 1;
}
}
-
}
padding: 0 calc(1rem + 1vw);
padding-bottom: 0;
align-items: center;
+ max-width: 1700px;
+
+ @media all and (min-width: 1700px) {
+ margin: auto;
+ }
}
}
.hero--homepage {
-
.section-title {
margin-bottom: 1.5rem;
margin-block-end: 1.5rem;
}
#ham-top {
-
transform: rotate(41deg);
}
flex: 1 0 10ch;
}
-
-.switcher--language .switcher__select {
+.switcher--language .switcher__select {
flex: 1 0 12rem;
- @media all and (max-width: 800px) {
+ @media all and (max-width: 799px) {
max-width: 250px;
}
}
overflow: hidden;
margin-bottom: .5rem;
margin-block-end: .5rem;
-
position: relative;
transition: all .2s linear;
&:hover {
background-color: var(--lighter-background-color);
}
-
}
.resource__image {
display: block;
height: 100%;
width: 100%;
- // object-fit: cover;
object-fit: contain;
}
}
align-self: center;
}
-
.resource__title { // a
text-decoration: none;
color: var(--headings-color);
left: 0;
offset-inline-start: 0;
top: 0;
- block-inline-start: 0;
+ offset-block-start: 0;
width: 100%;
height: 100%;
}
background: none;
border: none;
- @media screen and (min-width:768px){
+ @media screen and (min-width: 768px) {
&:not(:first-child)::after {
content: "";
display: block;
padding: 1px;
border-left: 1px solid var(--divider-color);
- left: 0px;
+ left: 0;
}
}
- @media screen and (min-width:768px) and (max-width:1023px), screen and (min-width:1440px){
+ @media screen and (min-width: 768px) and (max-width: 1023px), screen and (min-width: 1440px) {
&:not(:first-child)::after {
height: 70%;
position: absolute;
}
}
- @media screen and (min-width:1024px) and (max-width:1439px){
+ @media screen and (min-width: 1024px) and (max-width: 1439px) {
&:nth-child(2)::after {
height: 70%;
position: absolute;
}
}
-.rule {
+.rule:not(.token) {
border-radius: var(--border-radius);
background-color: var(--lightest-background-color);
display: flex;
}
.related-rules__list__item {
-
svg {
color: inherit;
}
}
}
-a.rule-list-item+a.rule-list-item::before {
+a.rule-list-item + a.rule-list-item::before {
content: ",";
display: inline-block;
margin-left: 5px;
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
appearance: none;
}
-[type=search]::-ms-clear,
-[type=search]::-ms-reveal {
+[type="search"]::-ms-clear,
+[type="search"]::-ms-reveal {
display: none;
width: 0;
height: 0;
.search .search-results {
font-size: .875rem;
background-color: var(--body-background-color);
- position: relative;
z-index: 10;
width: 100%;
border-radius: 0 0 var(--border-radius) var(--border-radius);
border: 1px solid var(--divider-color);
- position: rekative;
+ position: relative;
top: .25rem;
max-height: 400px;
overflow-y: auto;
&[data-results="true"] {
padding: 0;
}
+
&[data-results="false"] {
padding: 1rem;
}
background-color: var(--lightest-background-color);
}
- &:focus-within{
+ &:focus-within {
background-color: var(--lightest-background-color);
}
}
margin-bottom: 0;
font-family: var(--text-font);
-
a {
display: block;
text-decoration: none;
li {
margin: 0;
- display: inline-flex;
align-items: center;
a {
align-items: center;
justify-content: center;
border-radius: var(--border-radius) var(--border-radius) 0 0;
-
- transition: background-color .2s linear,
- border-color .2s linear;
-
-
+ transition: background-color .2s linear, border-color .2s linear;
&:hover {
color: var(--link-color);
}
}
-
.c-tabs__tabpanel__title {
margin-bottom: 1.5rem;
margin-block-end: 1.5rem;
}
.theme-switcher-label.theme-switcher-label {
- font-size: inherit;
color: inherit;
font: inherit;
font-family: var(--text-font);
}
.theme-switcher__button {
- flex: 0;
+ flex-wrap: wrap;
box-shadow: var(--shadow-xs);
padding: .625rem .875rem;
display: inline-flex;
}
}
}
-
-.theme-switcher__button:hover {
- .theme-switcher__icon {
- color: var(--link-color);
- }
-}
.docs-toc {
margin: 2rem 0;
-}
-
-.docs-toc {
- .docs-aside & {
- display: none;
- }
@media all and (min-width: 1400px) {
display: none;
}
.docs-aside & {
+ display: none;
+
@media all and (min-width: 1400px) {
display: block;
}
}
}
+.docs-aside {
+ // for sticky table of contents in sidebar
+ .docs-toc.c-toc {
+ background-color: var(--body-background-color);
+ @media all and (min-width: 1400px) {
+ position: sticky;
+ top: 20px;
+ overflow-y: auto; // show scrollbar when toc is higher than viewport
+ padding-right: 5px; // push scrollbar away from content
+ max-height: calc(100vh - 32px); // minus element's margin-top
+ a.active {
+ color: var(--link-color);
+ font-weight: 500;
+ }
+ }
+ }
+
+ .c-toc ol li.active::before {
+ @media all and (min-width: 1400px) {
+ color: var(--link-color);
+ }
+ }
+}
+
.c-toc {
ol {
margin: 0;
color: var(--color-neutral-400);
[aria-expanded="true"] & {
- -ms-transform: rotate(180deg);
transform: rotate(180deg);
}
}
-
-
.c-toc__panel {
&[data-open="false"] {
display: none;
align-items: start;
padding-top: 0;
padding-bottom: 0;
-
padding-block-start: 0;
padding-block-end: 0;
+ max-width: 1700px;
@media all and (min-width: 1024px) {
justify-content: space-between;
}
+ @media all and (min-width: 1700px) {
+ margin: auto;
+ }
}
}
scroll-behavior: smooth;
}
-.docs {
- max-width: 1700px;
- margin: 0 auto;
-}
-
.docs-aside__content {
flex: 1;
}
flex: 1;
display: flex;
flex-direction: column;
+ max-width: 1700px;
@media all and (min-width: 1024px) {
display: grid;
grid-template-columns: minmax(250px, 1fr) minmax(0, 3.5fr);
align-items: stretch;
}
+ @media all and (min-width: 1700px) {
+ margin: auto;
+ }
}
.docs-nav {
grid-row: 1 / 2;
padding-top: var(--space-l-xl);
padding-block-start: var(--space-l-xl);
- font-size: .875rem;
-
+ font-size: 0.875rem;
display: grid;
grid-auto-rows: max-content;
align-items: start;
padding: var(--space-l-xl) 0;
padding-right: var(--space-s-l);
padding-inline-end: var(--space-s-l);
-
border-right: 1px solid var(--divider-color);
border-inline-end: 1px solid var(--divider-color);
}
@media all and (min-width: 800px) {
padding-right: var(--space-s-l);
padding-inline-end: var(--space-s-l);
-
border-right: 1px solid var(--divider-color);
border-inline-end: 1px solid var(--divider-color);
}
}
}
-
.docs-aside {
grid-column: 2 / 3;
display: flex;
}
}
+div.img-container {
+ background-color: var(--img-background-color);
+ border-radius: var(--border-radius);
+
+ img {
+ margin: 0 auto;
+ }
+}
+
pre[class*="language-"] {
position: relative;
}
.c-btn.c-btn--playground {
position: absolute;
font-size: var(--step--1);
- bottom: .5rem;
- right: .5rem;
- offset-block-end: .5rem;
- offset-inline-end: .5rem;
+ bottom: 0.5rem;
+ right: 0.5rem;
+ offset-block-end: 0.5rem;
+ offset-inline-end: 0.5rem;
@media all and (max-width: 768px) {
display: none;
opacity: 1;
}
}
+
+#scroll-up-btn {
+ width: 50px;
+ height: 50px;
+ display: none;
+ position: fixed;
+ right: 50px;
+ bottom: 35px;
+ font-size: 1.5rem;
+ border-radius: 50%;
+ color: var(--body-background-color);
+ text-decoration: none;
+ justify-content: center;
+ align-items: center;
+ background-color: var(--link-color);
+
+ @media (max-width: 800px) {
+ right: 35px;
+ }
+
+ @media (max-width: 600px) {
+ right: 25px;
+ }
+}
.c-custom-select {
- -moz-appearance: none;
- -webkit-appearance: none;
appearance: none;
box-sizing: border-box;
display: block;
width: 100%;
max-width: 100%;
- min-width: 0px;
+ min-width: 0;
padding: .625rem .875rem;
padding-right: calc(.875rem * 2.5);
padding-inline-end: calc(.875rem * 2.5);
background-color: var(--body-background-color);
background-image: url("data:image/svg+xml,%3Csvg width='20' height='21' viewBox='0 0 20 21' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M5 7.60938L10 12.6094L15 7.60938' stroke='%23667085' stroke-width='1.66667' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A"), linear-gradient(to bottom, var(--body-background-color) 0%, var(--body-background-color) 100%);
background-repeat: no-repeat, repeat;
- background-position: right .875rem top 50%,
- 0 0;
+ background-position: right .875rem top 50%, 0 0;
background-size: 1em auto, 100%;
}
.label__text.label__text {
display: flex;
- font-size: .875rem;
align-items: center;
gap: .5rem;
font-size: .875rem;
font: inherit;
font-size: 1rem;
display: block;
- line-height: 1.3;
min-width: 0;
line-height: 1.3;
max-width: 100%;
box-shadow: 0 0 0 2px var(--link-color);
}
-
*,
*::before,
*::after {
}
body {
+ font-size: var(--step-0);
position: relative;
margin: 0 auto;
line-height: 1.5;
offset-block-start: -30em;
offset-inline-start: 0;
offset-inline-end: auto;
-
z-index: 999;
transition: top .1s linear;
width: 100%;
margin: 0 auto;
padding: var(--space-xl-3xl) calc(1rem + 1vw);
-}
+ max-width: 1700px;
+ @media all and (min-width: 1700px) {
+ margin: auto;
+ }
+}
.section-head {
.section-supporting-text {
font-size: var(--step-1);
}
-
code,
pre {
font-family: var(--mono-font);
}
}
-p:empty {
- display: none;
- margin: 0;
-}
-
.c-icon {
color: var(--icon-color);
flex: none;
}
}
-
a {
color: var(--link-color);
transition: color .1s linear;
overflow-wrap: break-word;
}
-
ul,
ol {
margin-top: 0;
margin: 0 0 .75em;
}
- .person__bio & {
+ .person__bio & {
padding-left: 1.5rem;
padding-inline-start: 1.5rem;
}
}
}
-
.video {
width: 90%;
max-width: 1400px;
}
}
-
/* typography */
-body {
- font-size: var(--step-0);
- line-height: 1.5;
-}
.eyebrow {
color: var(--link-color);
font-weight: 500;
margin-top: 0;
margin-block-start: 0;
-
}
h2,
h4,
h5,
h6 {
-
.docs-main &,
.components-main & {
margin-top: 3rem;
}
}
-
small,
caption,
cite,
a {
color: inherit;
- display: block;
width: 100%;
padding: .75rem .1rem;
text-decoration: none;
+ display: block;
display: flex;
align-items: center;
border-bottom: 1px solid var(--divider-color);
color: var(--link-color);
&::after {
- content: "✔️";
+ content: " ✔️";
+ white-space: pre;
+ color: rgba(100%, 0%, 0%, 0);
+ text-shadow: 0 0 0 var(--headings-color);
}
}
*,
-*:before,
-*:after,
-*:first-letter,
-p:first-line,
-div:first-line,
-blockquote:first-line,
-li:first-line {
+*::before,
+*::after,
+*::first-letter,
+p::first-line,
+div::first-line,
+blockquote::first-line,
+li::first-line {
background: transparent !important;
color: #000 !important;
box-shadow: none !important;
font-size: 14pt;
}
-
p,
h2,
h3 {
// font-size: 90%;
// }
-abbr[title]:after {
+abbr[title]::after {
content: " ("attr(title) ")";
}
color: #000;
}
-a[href$=".jpg"]:after,
-a[href$=".jpeg"]:after,
-a[href$=".gif"]:after,
-a[href$=".png"]:after {
+a[href$=".jpg"]::after,
+a[href$=".jpeg"]::after,
+a[href$=".gif"]::after,
+a[href$=".png"]::after {
content: " ("attr(href) ") ";
display: none;
}
/* Don't show links that are fragment identifiers, or use the `javascript:` pseudo protocol .. taken from html5boilerplate */
-a[href^="#"]:after,
-a[href^="javascript:"]:after {
+a[href^="#"]::after,
+a[href^="javascript:"]::after {
content: "";
}
page-break-inside: avoid;
}
-body>*:not(main),
+body > *:not(main),
aside,
*[class*="sidebar"] {
display: none;
display: none;
}
-a[href^='http']:not([href*='mywebsite.com'])::after {
- content: ' ('attr(href) ')';
+a[href^="http"]:not([href*="eslint.org"])::after {
+ content: " ("attr(href) ")";
}
.resource a::after {
page-break-inside: avoid;
}
-.docs-toc, .docs-index, .docs-aside, #skip-link{
+.docs-toc,
+.docs-index,
+.docs-aside,
+#skip-link {
display: none;
}
margin: 1cm;
}
}
+
+#scroll-up-btn {
+ display: none;
+}
+@import "tokens/themes";
+@import "tokens/spacing";
+@import "tokens/typography";
+@import "tokens/ui";
-@import "tokens/themes.scss";
-@import "tokens/spacing.scss";
-@import "tokens/typography.scss";
-@import "tokens/ui.scss";
+@import "foundations";
+@import "syntax-highlighter";
+@import "docs-header";
+@import "docs-footer";
+@import "eslint-site-footer";
+@import "eslint-site-header";
+@import "forms";
+@import "docs";
+@import "versions";
+@import "languages";
-@import "foundations.scss";
-@import "syntax-highlighter.scss";
-@import "docs-header.scss";
-@import "docs-footer.scss";
-@import "eslint-site-footer.scss";
-@import "eslint-site-header.scss";
-@import "forms.scss";
-@import "docs.scss";
-@import "versions.scss";
-@import "languages.scss";
+@import "components/buttons";
+@import "components/docs-navigation";
+@import "components/toc";
+@import "components/search";
+@import "components/alert";
+@import "components/rules";
+@import "components/social-icons";
+@import "components/hero";
+@import "components/theme-switcher";
+@import "components/version-switcher";
+@import "components/language-switcher";
+@import "components/docs-index"; // docs index on the main docs pages
+@import "components/index"; // used in component library
+@import "components/tabs";
+@import "components/resources";
-@import "components/buttons.scss";
-@import "components/docs-navigation.scss";
-@import "components/toc.scss";
-@import "components/search.scss";
-@import "components/alert.scss";
-@import "components/rules.scss";
-@import "components/social-icons.scss";
-@import "components/hero.scss";
-@import "components/theme-switcher.scss";
-@import "components/version-switcher.scss";
-@import "components/language-switcher.scss";
-@import "components/docs-index.scss"; // docs index on the main docs pages
-@import "components/index.scss"; // used in component library
-@import "components/tabs.scss";
-@import "components/index.scss";
-@import "components/resources.scss";
+@import "carbon-ads";
-@import "carbon-ads.scss";
-
-@import "utilities.scss";
+@import "utilities";
code[class*="language-"],
pre[class*="language-"] {
- font-family: var(--mono-font), Consolas,
+ font-family:
+ var(--mono-font),
+ Consolas,
Monaco,
- 'Andale Mono',
- 'Ubuntu Mono',
+ "Andale Mono",
+ "Ubuntu Mono",
monospace;
font-size: 1em;
text-align: left;
word-wrap: normal;
line-height: 1.5;
font-variant-ligatures: none;
-
- -moz-tab-size: 4;
- -o-tab-size: 4;
tab-size: 4;
-
- -webkit-hyphens: none;
- -moz-hyphens: none;
- -ms-hyphens: none;
hyphens: none;
}
@media print {
-
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
padding: 1.5rem;
margin: 1.5rem 0;
overflow: auto;
- background-color: var(--color-neutral-50);
border-radius: var(--border-radius);
-
background-color: var(--lightest-background-color);
color: var(--color-neutral-900);
[data-theme="dark"] & {
color: var(--color-neutral-100);
}
+
+ &.line-numbers-mode {
+ padding-left: calc(1.5rem + 2.4em + 1.2rem);
+ }
}
-:not(pre)>code[class*="language-"],
+:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background-color: var(--lightest-background-color);
}
/* Inline code */
-:not(pre)>code[class*="language-"] {
- padding: .1em;
- border-radius: .3em;
+:not(pre) > code[class*="language-"] {
+ padding: 0.1em;
+ border-radius: 0.3em;
white-space: normal;
}
.token.prolog,
.token.doctype,
.token.cdata {
- color: #6E7F8E;
+ color: #6e7f8e;
[data-theme="dark"] & {
- color: #8E9FAE;
+ color: #8e9fae;
}
}
-
.token.namespace {
- opacity: .7;
+ opacity: 0.7;
}
-
.token.selector,
.token.attr-name,
.token.string,
color: var(--link-color);
}
-
.token.atrule,
.token.attr-value,
.token.keyword {
cursor: help;
}
-pre {
- counter-reset: lineNumber;
-}
-
-code .highlight-line {
+.line-numbers-wrapper {
+ position: absolute;
+ top: 0;
+ left: 1.5rem;
+ text-align: right;
+ padding-top: 1.5rem;
+ font-size: 1em;
+ font-family: var(--mono-font), Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
+ line-height: 1.5;
+ color: var(--icon-color);
font-variant-ligatures: none;
-}
-code .highlight-line:before {
- -webkit-user-select: none;
- color: var(--icon-color);
- content: counter(lineNumber);
- counter-increment: lineNumber;
- display: inline-block;
- font-variant-numeric: tabular-nums;
- margin-right: 1.2em;
- padding-right: 1.2em;
- margin-inline-end: 1.2em;
- padding-inline-end: 1.2em;
- text-align: right;
- width: 2.4em;
+ .line-number {
+ user-select: none;
+ color: var(--icon-color);
+ display: inline-block;
+ font-variant-numeric: tabular-nums;
+ text-align: right;
+ width: 1.2em;
+ }
}
--fluid-screen: 100vw;
--fluid-bp: calc((var(--fluid-screen) - var(--fluid-min-width) / 16 * 1rem) / (var(--fluid-max-width) - var(--fluid-min-width)));
-}
-
-@media screen and (min-width: 1024px) {
- :root {
- --fluid-screen: calc(var(--fluid-max-width) * 1px);
- }
-}
-:root {
--fc-3xs-min: (var(--fc-s-min) * 0.25);
--fc-3xs-max: (var(--fc-s-max) * 0.25);
:root {
/* Tier 1 variables */
// colors
- --color-neutral-25: #FCFCFD;
- --color-neutral-50: #F9FAFB;
- --color-neutral-100: #F2F4F7;
- --color-neutral-200: #E4E7EC;
- --color-neutral-300: #D0D5DD;
- --color-neutral-400: #98A2B3;
+ --color-neutral-25: #fcfcfd;
+ --color-neutral-50: #f9fafb;
+ --color-neutral-100: #f2f4f7;
+ --color-neutral-200: #e4e7ec;
+ --color-neutral-300: #d0d5dd;
+ --color-neutral-400: #98a2b3;
--color-neutral-500: #667085;
--color-neutral-600: #475467;
--color-neutral-700: #344054;
- --color-neutral-800: #1D2939;
+ --color-neutral-800: #1d2939;
--color-neutral-900: #101828;
- --color-primary-25: #FBFBFF;
- --color-primary-50: #F6F6FE;
- --color-primary-100: #ECECFD;
- --color-primary-200: #DEDEFF;
- --color-primary-300: #CCCCFA;
- --color-primary-400: #B7B7FF;
- --color-primary-500: #A0A0F5;
- --color-primary-600: #8080F2;
- --color-primary-700: #6358D4;
- --color-primary-800: #4B32C3;
- --color-primary-900: #341BAB;
-
- --color-warning-25: #FFFCF5;
- --color-warning-50: #FFFAEB;
- --color-warning-100: #FEF0C7;
- --color-warning-200: #FEDF89;
- --color-warning-300: #FEC84B;
- --color-warning-400: #FDB022;
- --color-warning-500: #F79009;
- --color-warning-600: #DC6803;
- --color-warning-700: #B54708;
- --color-warning-800: #93370D;
- --color-warning-900: #7A2E0E;
-
- --color-success-25: #F6FEF9;
- --color-success-50: #ECFDF3;
- --color-success-100: #D1FADF;
- --color-success-200: #A6F4C5;
- --color-success-300: #6CE9A6;
- --color-success-400: #32D583;
- --color-success-500: #12B76A;
+ --color-primary-25: #fbfbff;
+ --color-primary-50: #f6f6fe;
+ --color-primary-100: #ececfd;
+ --color-primary-200: #dedeff;
+ --color-primary-300: #ccccfa;
+ --color-primary-400: #b7b7ff;
+ --color-primary-500: #a0a0f5;
+ --color-primary-600: #8080f2;
+ --color-primary-700: #6358d4;
+ --color-primary-800: #4b32c3;
+ --color-primary-900: #341bab;
+
+ --color-warning-25: #fffcf5;
+ --color-warning-50: #fffaeb;
+ --color-warning-100: #fef0c7;
+ --color-warning-200: #fedf89;
+ --color-warning-300: #fec84b;
+ --color-warning-400: #fdb022;
+ --color-warning-500: #f79009;
+ --color-warning-600: #dc6803;
+ --color-warning-700: #b54708;
+ --color-warning-800: #93370d;
+ --color-warning-900: #7a2e0e;
+
+ --color-success-25: #f6fef9;
+ --color-success-50: #ecfdf3;
+ --color-success-100: #d1fadf;
+ --color-success-200: #a6f4c5;
+ --color-success-300: #6ce9a6;
+ --color-success-400: #32d583;
+ --color-success-500: #12b76a;
--color-success-600: #039855;
- --color-success-700: #027A48;
- --color-success-800: #05603A;
- --color-success-900: #054F31;
-
- --color-rose-25: #FFF5F6;
- --color-rose-50: #FFF1F3;
- --color-rose-100: #FFE4E8;
- --color-rose-200: #FECDD6;
- --color-rose-300: #FEA3B4;
- --color-rose-400: #FD6F8E;
- --color-rose-500: #F63D68;
- --color-rose-600: #E31B54;
- --color-rose-700: #C01048;
- --color-rose-800: #A11043;
- --color-rose-900: #89123E;
+ --color-success-700: #027a48;
+ --color-success-800: #05603a;
+ --color-success-900: #054f31;
+
+ --color-rose-25: #fff5f6;
+ --color-rose-50: #fff1f3;
+ --color-rose-100: #ffe4e8;
+ --color-rose-200: #fecdd6;
+ --color-rose-300: #fea3b4;
+ --color-rose-400: #fd6f8e;
+ --color-rose-500: #f63d68;
+ --color-rose-600: #e31b54;
+ --color-rose-700: #c01048;
+ --color-rose-800: #a11043;
+ --color-rose-900: #89123e;
/* Tier 2 variables */
--primary-button-background-color: var(--color-primary-800);
--border-color: var(--color-neutral-300);
--divider-color: var(--color-neutral-200);
-
--icon-color: var(--color-neutral-400);
--dark-icon-color: var(--color-neutral-500);
--link-color: var(--color-primary-800);
--body-background-color: var(--color-neutral-900);
--body-text-color: var(--color-neutral-300);
--headings-color: #fff;
-
+
--divider-color: var(--color-neutral-600);
--border-color: var(--color-neutral-500);
-
+
--icon-color: var(--body-text-color);
--dark-icon-color: #fff;
--link-color: var(--color-primary-400);
-
+
--lighter-background-color: var(--color-neutral-800);
--lightest-background-color: var(--color-neutral-800);
--docs-lightest-background-color: var(--color-neutral-800);
}
}
-
-
html[data-theme="light"] {
--body-background-color: #fff;
--body-text-color: var(--color-neutral-500);
--border-color: var(--color-neutral-300);
--divider-color: var(--color-neutral-200);
-
--icon-color: var(--color-neutral-400);
--dark-icon-color: var(--color-neutral-500);
--link-color: var(--color-primary-800);
--hero-background-color: var(--color-neutral-25);
--footer-background-color: var(--color-neutral-25);
--outline-color: var(--color-brand);
+ --img-background-color: #fff;
}
html[data-theme="dark"] {
--hero-background-color: var(--color-neutral-800);
--footer-background-color: var(--color-neutral-800);
--outline-color: #fff;
+ --img-background-color: var(--color-neutral-300);
}
/* @link https://utopia.fyi/type/calculator?c=320,16,1.125,1280,16,1.25,6,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l */
-:root {
- --fluid-min-width: 320;
- --fluid-max-width: 1280;
-
- --fluid-screen: 100vw;
- --fluid-bp: calc((var(--fluid-screen) - var(--fluid-min-width) / 16 * 1rem) / (var(--fluid-max-width) - var(--fluid-min-width)));
-}
-
@media screen and (min-width: 1280px) {
:root {
--fluid-screen: calc(var(--fluid-max-width) * 1px);
}
:root {
+ --fluid-min-width: 320;
+ --fluid-max-width: 1280;
+
+ --fluid-screen: 100vw;
+ --fluid-bp: calc((var(--fluid-screen) - var(--fluid-min-width) / 16 * 1rem) / (var(--fluid-max-width) - var(--fluid-min-width)));
+
--f--2-min: 12.64;
--f--2-max: 10.24;
--step--2: calc(((var(--f--2-min) / 16) * 1rem) + (var(--f--2-max) - var(--f--2-min)) * var(--fluid-bp));
--f-6-min: 32.44;
--f-6-max: 61.04;
--step-6: calc(((var(--f-6-min) / 16) * 1rem) + (var(--f-6-max) - var(--f-6-min)) * var(--fluid-bp));
-}
-:root {
--mono-font: "Mono Punctuators", "Space Mono", monospace;
- --text-font: "Inter",
- -apple-system,
- BlinkMacSystemFont,
- "Segoe UI",
- Roboto,
- Helvetica,
- Arial,
- sans-serif,
- "Apple Color Emoji",
- "Segoe UI Emoji",
- "Segoe UI Symbol";
- --display-font: "Space Grotesk",
- -apple-system,
- BlinkMacSystemFont,
- "Segoe UI",
- Roboto,
- Helvetica,
- Arial,
- sans-serif,
- "Apple Color Emoji",
- "Segoe UI Emoji",
- "Segoe UI Symbol";
+ --text-font:
+ "Inter",
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ Roboto,
+ Helvetica,
+ Arial,
+ sans-serif,
+ "Apple Color Emoji",
+ "Twemoji Country Flags",
+ "Segoe UI Emoji",
+ "Segoe UI Symbol";
+ --display-font:
+ "Space Grotesk",
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ Roboto,
+ Helvetica,
+ Arial,
+ sans-serif,
+ "Apple Color Emoji",
+ "Segoe UI Emoji",
+ "Segoe UI Symbol";
}
:root {
// elevations
- --shadow-lg: 0px 12px 16px -4px rgba(16, 24, 40, 0.1),
- 0px 4px 6px -2px rgba(16, 24, 40, 0.05);
- --shadow-xs: 0px 1px 2px rgba(16, 24, 40, 0.05);
+ --shadow-lg:
+ 0 12px 16px -4px rgba(16, 24, 40, 0.1),
+ 0 4px 6px -2px rgba(16, 24, 40, 0.05);
+ --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.05);
--border-radius: .5rem;
}
clip: rect(0 0 0 0);
clip-path: inset(100%);
height: 1px;
- overflow:
- hidden;
+ overflow: hidden;
position: absolute;
width: 1px;
white-space: nowrap;
}
.text.text {
- font-size: inherit;
color: inherit;
font: inherit;
font-family: var(--text-font);
grid-column: 1 / 8;
}
-
.span-1-12 {
grid-column: 1 / -1;
}
a {
color: var(--link-color);
- display: block;
width: 100%;
padding: 1rem .5rem;
text-decoration: none;
+ display: block;
display: flex;
align-items: center;
border-bottom: 1px solid var(--divider-color);
color: var(--link-color);
&::after {
- content: "✔️";
+ content: " ✔️";
+ white-space: pre;
+ color: rgba(100%, 0%, 0%, 0);
+ text-shadow: 0 0 0 var(--headings-color);
}
}
--- /dev/null
+---
+title: Architecture
+eleventyNavigation:
+ key: architecture
+ parent: contribute to eslint
+ title: Architecture
+ order: 5
+---
+
+:::img-container
+<img alt="dependency graph" src="../../assets/images/architecture/dependency.svg">
+:::
+
+At a high level, there are a few key parts to ESLint:
+
+* `bin/eslint.js` - this is the file that actually gets executed with the command line utility. It's a dumb wrapper that does nothing more than bootstrap ESLint, passing the command line arguments to `cli`. This is intentionally small so as not to require heavy testing.
+* `lib/api.js` - this is the entry point of `require("eslint")`. This file exposes an object that contains public classes `Linter`, `ESLint`, `RuleTester`, and `SourceCode`.
+* `lib/cli.js` - this is the heart of the ESLint CLI. It takes an array of arguments and then uses `eslint` to execute the commands. By keeping this as a separate utility, it allows others to effectively call ESLint from within another Node.js program as if it were done on the command line. The main call is `cli.execute()`. This is also the part that does all the file reading, directory traversing, input, and output.
+* `lib/cli-engine/` - this module is `CLIEngine` class that finds source code files and configuration files then does code verifying with the `Linter` class. This includes the loading logic of configuration files, parsers, plugins, and formatters.
+* `lib/linter/` - this module is the core `Linter` class that does code verifying based on configuration options. This file does no file I/O and does not interact with the `console` at all. For other Node.js programs that have JavaScript text to verify, they would be able to use this interface directly.
+* `lib/rule-tester/` - this module is `RuleTester` class that is a wrapper around Mocha so that rules can be unit tested. This class lets us write consistently formatted tests for each rule that is implemented and be confident that each of the rules work. The RuleTester interface was modeled after Mocha and works with Mocha's global testing methods. RuleTester can also be modified to work with other testing frameworks.
+* `lib/source-code/` - this module is `SourceCode` class that is used to represent the parsed source code. It takes in source code and the Program node of the AST representing the code.
+* `lib/rules/` - this contains built-in rules that verify source code.
+
+## The `cli` object
+
+The `cli` object is the API for the command line interface. Literally, the `bin/eslint.js` file simply passes arguments to the `cli` object and then sets `process.exitCode` to the returned exit code.
+
+The main method is `cli.execute()`, which accepts an array of strings that represent the command line options (as if `process.argv` were passed without the first two arguments). If you want to run ESLint from inside of another program and have it act like the CLI, then `cli` is the object to use.
+
+This object's responsibilities include:
+
+* Interpreting command line arguments
+* Reading from the file system
+* Outputting to the console
+* Outputting to the filesystem
+* Use a formatter
+* Returning the correct exit code
+
+This object may not:
+
+* Call `process.exit()` directly
+* Perform any asynchronous operations
+
+## The `CLIEngine` object
+
+The `CLIEngine` type represents the core functionality of the CLI except that it reads nothing from the command line and doesn't output anything by default. Instead, it accepts many (but not all) of the arguments that are passed into the CLI. It reads both configuration and source files as well as managing the environment that is passed into the `Linter` object.
+
+The main method of the `CLIEngine` is `executeOnFiles()`, which accepts an array of file and directory names to run the linter on.
+
+This object's responsibilities include:
+
+* Managing the execution environment for `Linter`
+* Reading from the file system
+* Reading configuration information from config files (including `.eslintrc` and `package.json`)
+
+This object may not:
+
+* Call `process.exit()` directly
+* Perform any asynchronous operations
+* Output to the console
+* Use formatters
+
+## The `Linter` object
+
+The main method of the `Linter` object is `verify()` and accepts two arguments: the source text to verify and a configuration object (the baked configuration of the given configuration file plus command line options). The method first parses the given text with `espree` (or whatever the configured parser is) and retrieves the AST. The AST is produced with both line/column and range locations which are useful for reporting location of issues and retrieving the source text related to an AST node, respectively.
+
+Once the AST is available, `estraverse` is used to traverse the AST from top to bottom. At each node, the `Linter` object emits an event that has the same name as the node type (i.e., "Identifier", "WithStatement", etc.). On the way back up the subtree, an event is emitted with the AST type name and suffixed with ":exit", such as "Identifier:exit" - this allows rules to take action both on the way down and on the way up in the traversal. Each event is emitted with the appropriate AST node available.
+
+This object's responsibilities include:
+
+* Inspecting JavaScript code strings
+* Creating an AST for the code
+* Executing rules on the AST
+* Reporting back the results of the execution
+
+This object may not:
+
+* Call `process.exit()` directly
+* Perform any asynchronous operations
+* Use Node.js-specific features
+* Access the file system
+* Call `console.log()` or any other similar method
+
+## Rules
+
+Individual rules are the most specialized part of the ESLint architecture. Rules can do very little, they are simply a set of instructions executed against an AST that is provided. They do get some context information passed in, but the primary responsibility of a rule is to inspect the AST and report warnings.
+
+These objects' responsibilities are:
+
+* Inspect the AST for specific patterns
+* Reporting warnings when certain patterns are found
+
+These objects may not:
+
+* Call `process.exit()` directly
+* Perform any asynchronous operations
+* Use Node.js-specific features
+* Access the file system
+* Call `console.log()` or any other similar method
--- /dev/null
+---
+title: Code Conventions
+---
+
+Code conventions for ESLint are determined by
+[eslint-config-eslint](https://www.npmjs.com/package/eslint-config-eslint).
+
+The rationales for the specific rules in use can be found by looking to the
+project documentation for any given rule. If the rule is one of our own, see
+our own [rule documentation](../rules/) and otherwise, see
+the documentation of the plugin in which the rule can be found.
+
+If you need to make changes to a `package.json` file, please see the
+[package.json conventions](./package-json-conventions).
--- /dev/null
+---
+title: Code of Conduct
+eleventyNavigation:
+ key: code of conduct
+ parent: contribute to eslint
+ title: Code of Conduct
+ order: 0
+---
+
+ESLint welcomes contributions from everyone and adheres to the [OpenJS Foundation Code of Conduct](https://eslint.org/conduct). We kindly request that you read over this code of conduct before contributing.
--- /dev/null
+---
+title: Contribute to Core Rules
+eleventyNavigation:
+ key: contribute core rule
+ parent: contribute to eslint
+ title: Contribute to Core Rules
+ order: 10
+---
+
+The ESLint core rules are the rules included in the ESLint package.
+
+## Rule Writing Documentation
+
+For full reference information on writing rules, refer to [Custom Rules](../extend/custom-rules). Both custom rules and core rules have the same API. The primary difference between core and custom rules are:
+
+1. Core rules are included in the `eslint` package.
+1. Core rules must adhere to the conventions documented on this page.
+
+## File Structure
+
+Each core rule in ESLint has three files named with its identifier (for example, `no-extra-semi`).
+
+* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`)
+* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`)
+* in the `docs/src/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`)
+
+**Important:** If you submit a core rule to the ESLint repository, you **must** follow the conventions explained below.
+
+Here is the basic format of the source file for a rule:
+
+```js
+/**
+ * @fileoverview Rule to disallow unnecessary semicolons
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+/** @type {import('../shared/types').Rule} */
+module.exports = {
+ meta: {
+ type: "suggestion",
+
+ docs: {
+ description: "disallow unnecessary semicolons",
+ recommended: true,
+ url: "https://eslint.org/docs/rules/no-extra-semi"
+ },
+ fixable: "code",
+ schema: [] // no options
+ },
+ create: function(context) {
+ return {
+ // callback functions
+ };
+ }
+};
+```
+
+## Rule Unit Tests
+
+Each bundled rule for ESLint core must have a set of unit tests submitted with it to be accepted. The test file is named the same as the source file but lives in `tests/lib/`. For example, if the rule source file is `lib/rules/foo.js` then the test file should be `tests/lib/rules/foo.js`.
+
+ESLint provides the [`RuleTester`](../integrate/nodejs-api#ruletester) utility to make it easy to write tests for rules.
+
+## Performance Testing
+
+To keep the linting process efficient and unobtrusive, it is useful to verify the performance impact of new rules or modifications to existing rules.
+
+To learn how to profile the performance of individual rules, refer to [Profile Rule Performance](../extend/custom-rules#profile-rule-performance) in the custom rules documentation.
+
+When developing in the ESLint core repository, the `npm run perf` command gives a high-level overview of ESLint running time with all core rules enabled.
+
+```bash
+$ git checkout main
+Switched to branch 'main'
+
+$ npm run perf
+CPU Speed is 2200 with multiplier 7500000
+Performance Run #1: 1394.689313ms
+Performance Run #2: 1423.295351ms
+Performance Run #3: 1385.09515ms
+Performance Run #4: 1382.406982ms
+Performance Run #5: 1409.68566ms
+Performance budget ok: 1394.689313ms (limit: 3409.090909090909ms)
+
+$ git checkout my-rule-branch
+Switched to branch 'my-rule-branch'
+
+$ npm run perf
+CPU Speed is 2200 with multiplier 7500000
+Performance Run #1: 1443.736547ms
+Performance Run #2: 1419.193291ms
+Performance Run #3: 1436.018228ms
+Performance Run #4: 1473.605485ms
+Performance Run #5: 1457.455283ms
+Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms)
+```
+
+## Rule Naming Conventions
+
+The rule naming conventions for ESLint are as follows:
+
+* Use dashes between words.
+* If your rule only disallows something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`.
+* If your rule is enforcing the inclusion of something, use a short name without a special prefix.
--- /dev/null
+---
+title: Set up a Development Environment
+eleventyNavigation:
+ key: development environment
+ parent: contribute to eslint
+ title: Set up a Development Environment
+ order: 6
+---
+
+ESLint has a very lightweight development environment that makes updating code fast and easy. This is a step-by-step guide to setting up a local development environment that will let you contribute back to the project.
+
+## Step 1: Install Node.js
+
+Go to <https://nodejs.org/> to download and install the latest stable version for your operating system.
+
+Most of the installers already come with [npm](https://www.npmjs.com/) but if for some reason npm doesn't work on your system, you can install it manually using the instructions on the site.
+
+## Step 2: Fork and Checkout Your Own ESLint Repository
+
+Go to <https://github.com/eslint/eslint> and click the "Fork" button. Follow the [GitHub documentation](https://help.github.com/articles/fork-a-repo) for forking and cloning.
+
+Clone your fork:
+
+```shell
+git clone https://github.com/<Your Github Username>/eslint
+```
+
+Once you've cloned the repository, run `npm install` to get all the necessary dependencies:
+
+```shell
+cd eslint
+npm install
+```
+
+You must be connected to the Internet for this step to work. You'll see a lot of utilities being downloaded.
+
+**Note:** It's a good idea to re-run `npm install` whenever you pull from the main repository to ensure you have the latest development dependencies.
+
+## Step 3: Add the Upstream Source
+
+The *upstream source* is the main ESLint repository where active development happens. While you won't have push access to upstream, you will have pull access, allowing you to pull in the latest code whenever you want.
+
+To add the upstream source for ESLint, run the following in your repository:
+
+```shell
+git remote add upstream git@github.com:eslint/eslint.git
+```
+
+Now, the remote `upstream` points to the upstream source.
+
+## Step 4: Install the Yeoman Generator
+
+[Yeoman](https://yeoman.io) is a scaffold generator that ESLint uses to help streamline development of new rules. If you don't already have Yeoman installed, you can install it via npm:
+
+```shell
+npm install -g yo
+```
+
+Then, you can install the ESLint Yeoman generator:
+
+```shell
+npm install -g generator-eslint
+```
+
+Please see the [generator documentation](https://github.com/eslint/generator-eslint) for instructions on how to use it.
+
+## Step 5: Run the Tests
+
+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:
+
+```shell
+npm test
+```
+
+The testing takes a few minutes to complete. If any tests fail, that likely means one or more parts of the environment setup didn't complete correctly. The upstream tests always pass.
+
+## Reference Information
+
+### Directory Structure
+
+The ESLint directory and file structure is as follows:
+
+* `bin` - executable files that are available when ESLint is installed
+* `conf` - default configuration information
+* `docs` - documentation for the project
+* `lib` - contains the source code
+ * `formatters` - all source files defining formatters
+ * `rules` - all source files defining rules
+* `tests` - the main unit test folder
+ * `lib` - tests for the source code
+ * `formatters` - tests for the formatters
+ * `rules` - tests for the rules
+
+### Workflow
+
+Once you have your development environment installed, you can make and submit changes to the ESLint source files. Doing this successfully requires careful adherence to our [pull-request submission workflow](./pull-requests).
+
+### Build Scripts
+
+ESLint has several build scripts that help with various parts of development.
+
+#### npm test
+
+The primary script to use is `npm test`, which does several things:
+
+1. Lints all JavaScript (including tests) and JSON
+1. Runs all tests on Node.js
+1. Checks code coverage targets
+1. Generates `build/eslint.js` for use in a browser
+1. Runs a subset of tests in PhantomJS
+
+Be sure to run this after making changes and before sending a pull request with your changes.
+
+**Note:** The full code coverage report is output into `/coverage`.
+
+#### npm run lint
+
+Runs just the JavaScript and JSON linting on the repository.
+
+#### npm run webpack
+
+Generates `build/eslint.js`, a version of ESLint for use in the browser.
--- /dev/null
+---
+title: Governance
+eleventyNavigation:
+ key: governance
+ parent: contribute to eslint
+ title: Governance
+ order: 11
+
+---
+
+ESLint is an open source project that depends on contributions from the community. Anyone may contribute to the project at any time by submitting code, participating in discussions, making suggestions, or any other contribution they see fit. This document describes how various types of contributors work within the ESLint project.
+
+## Roles and Responsibilities
+
+### Users
+
+Users are community members who have a need for the project. Anyone can be a User; there are no special requirements. Common User contributions include evangelizing the project (e.g., display a link on a website and raise awareness through word-of-mouth), informing developers of strengths and weaknesses from a new user perspective, or providing moral support (a "thank you" goes a long way).
+
+Users who continue to engage with the project and its community will often become more and more involved. Such Users may find themselves becoming Contributors, as described in the next section.
+
+### Contributors
+
+Contributors are community members who contribute in concrete ways to the project, most often in the form of code and/or documentation. Anyone can become a Contributor, and contributions can take many forms. There is no expectation of commitment to the project, no specific skill requirements, and no selection process.
+
+Contributors have read-only access to source code and so submit changes via pull requests. Contributor pull requests have their contribution reviewed and merged by a TSC member. TSC members and Committers work with Contributors to review their code and prepare it for merging.
+
+As Contributors gain experience and familiarity with the project, their profile within, and commitment to, the community will increase. At some stage, they may find themselves being nominated as either a Website Team Member or Committer by an existing Website Team Member or Committer.
+
+### Website Team Member
+
+Website Team Members are community members who have shown that they are committed to the continued maintenance of [eslint.org](https://eslint.org/) through ongoing engagement with the community. Website Team Members are given push access to the `eslint.org` GitHub repository and must abide by the project's [Contribution Guidelines](../contribute/).
+
+ Website Team Members:
+
+* Are expected to work on public branches of the source repository and submit pull requests from that branch to the master branch.
+* Are expected to delete their public branches when they are no longer necessary.
+* Must submit pull requests for all changes.
+* Have their work reviewed by Reviewers and TSC members before acceptance into the repository.
+* May label and close website-related issues (see [Manage Issues](../maintain/manage-issues))
+* May merge some pull requests (see [Review Pull Requests](../maintain/review-pull-requests))
+
+To become a Website Team Member:
+
+* One must have shown a willingness and ability to participate in the maintenance of [eslint.org](https://eslint.org/) as a team player. Typically, a potential Website Team Member will need to show that they have an understanding of the structure of the website and how it fits into the larger ESLint project's objectives and strategy.
+* Website Team Members are expected to be respectful of every community member and to work collaboratively in the spirit of inclusion.
+* Have submitted a minimum of 10 website-related pull requests. What's a website-related pull request? One that is made to the `eslint.org` repository or the `docs` directory in the `eslint` repository and requires little effort to accept because it's well documented and tested.
+
+New Website Team Members can be nominated by any existing Website Team Member or Committer. Once they have been nominated, there will be a vote by the TSC members.
+
+It is important to recognize that membership on the website team is a privilege, not a right. That privilege must be earned and once earned it can be removed by the TSC members by a standard TSC motion. However, under normal circumstances Website Team Members remain for as long as they wish to continue engaging with the project.
+
+### Committers
+
+Committers are community members who have shown that they are committed to the continued development of the project through ongoing engagement with the community. Committers are given push access to the project's GitHub repos and must abide by the project's [Contribution Guidelines](../contribute/).
+
+Committers:
+
+* Are expected to work on public branches of the source repository and submit pull requests from that branch to the master branch.
+* Are expected to delete their public branches when they are no longer necessary.
+* Must submit pull requests for all changes.
+* Have their work reviewed by TSC members before acceptance into the repository.
+* May label and close issues (see [Manage Issues](../maintain/manage-issues))
+* May merge some pull requests (see [Review Pull Requests](../maintain/review-pull-requests))
+
+To become a Committer:
+
+* One must have shown a willingness and ability to participate in the project as a team player. Typically, a potential Committer will need to show that they have an understanding of and alignment with the project, its objectives, and its strategy.
+* Committers are expected to be respectful of every community member and to work collaboratively in the spirit of inclusion.
+* Have submitted a minimum of 10 qualifying pull requests. What's a qualifying pull request? One that carries significant technical weight and requires little effort to accept because it's well documented and tested.
+
+New Committers can be nominated by any existing Committer. Once they have been nominated, there will be a vote by the TSC members.
+
+It is important to recognize that committership is a privilege, not a right. That privilege must be earned and once earned it can be removed by the TSC members by a standard TSC motion. However, under normal circumstances committership exists for as long as the Committer wishes to continue engaging with the project.
+
+A Committer who shows an above-average level of contribution to the project, particularly with respect to its strategic direction and long-term health, may be nominated to become a reviewer, described below.
+
+#### Process for Adding Committers
+
+1. Send email congratulating the new committer and confirming that they would like to accept. This should also outline the responsibilities of a committer with a link to the maintainer guide.
+1. Add the GitHub user to the "ESLint Team" team
+1. Add committer email to the ESLint team mailing list
+1. Invite to Discord team channel
+1. Tweet congratulations to the new committer from the ESLint Twitter account
+
+### Reviewers
+
+Reviewers are community members who have contributed a significant amount of time to the project through triaging of issues, fixing bugs, implementing enhancements/features, and are trusted community leaders.
+
+Reviewers may perform all of the duties of Committers, and also:
+
+* May merge external pull requests for accepted issues upon reviewing and approving the changes.
+* May merge their own pull requests once they have collected the feedback they deem necessary. (No pull request should be merged without at least one Committer/Reviewer/TSC member comment stating they've looked at the code.)
+
+To become a Reviewer:
+
+* Work in a helpful and collaborative way with the community.
+* Have given good feedback on others' submissions and displayed an overall understanding of the code quality standards for the project.
+* Commit to being a part of the community for the long-term.
+* Have submitted a minimum of 50 qualifying pull requests.
+
+A Committer is invited to become a Reviewer by existing Reviewers and TSC members. A nomination will result in discussion and then a decision by the TSC.
+
+#### Process for Adding Reviewers
+
+1. Add the GitHub user to the "ESLint Reviewers" GitHub team
+1. Tweet congratulations to the new Reviewer from the ESLint Twitter account
+
+### Technical Steering Committee (TSC)
+
+The ESLint project is jointly governed by a Technical Steering Committee (TSC) which is responsible for high-level guidance of the project.
+
+The TSC has final authority over this project including:
+
+* Technical direction
+* Project governance and process (including this policy)
+* Contribution policy
+* GitHub repository hosting
+
+TSC seats are not time-limited. The size of the TSC can not be larger than five members. This size ensures adequate coverage of important areas of expertise balanced with the ability to make decisions efficiently.
+
+The TSC may add additional members to the TSC by a standard TSC motion.
+
+A TSC member may be removed from the TSC by voluntary resignation, by a standard TSC motion, or by missing four consecutive TSC meetings. In all cases, the TSC member will revert to Reviewer status unless they prefer Alumni status.
+
+Changes to TSC membership should be posted in the agenda, and may be suggested as any other agenda item (see "TSC Meetings" below).
+
+No more than 1/3 of the TSC members may be affiliated with the same employer. If removal or resignation of a TSC member, or a change of employment by a TSC member, creates a situation where more than 1/3 of the TSC membership shares an employer, then the situation must be immediately remedied by the resignation or removal of one or more TSC members affiliated with the over-represented employer(s).
+
+TSC members have additional responsibilities over and above those of a Reviewer. These responsibilities ensure the smooth running of the project. TSC members are expected to review code contributions, approve changes to this document, manage the copyrights within the project outputs, and attend regular TSC meetings.
+
+TSC members may perform all of the duties of Reviewers, and also:
+
+* May release new versions of all ESLint projects.
+* May participate in TSC meetings.
+* May propose budget items.
+* May propose new ESLint projects.
+
+There is no specific set of requirements or qualifications for TSC members beyond those that are expected of Reviewers.
+
+A Reviewer is invited to become a TSC member by existing TSC members. A nomination will result in discussion and then a decision by the TSC.
+
+#### Process for Adding TSC Members
+
+1. Add the GitHub user to the "ESLint TSC" GitHub team
+1. Set the GitHub user to be have the "Owner" role for the ESLint organization
+1. Send a welcome email with a link to the [Maintain ESLint documentation](../maintain/) and instructions for npm 2FA.
+1. Invite to the Discord TSC channel
+1. Make the TSC member an admin on the ESLint team mailing list
+1. Add the TSC member to the recurring TSC meeting event on Google Calendar
+1. Add the TSC member as an admin to ESLint Twitter Account on Tweetdeck
+1. Add the TSC member to the ESLint TSC mailing list as an "Owner"
+1. Tweet congratulations to the new TSC member from the ESLint Twitter account
+
+#### TSC Meetings
+
+The TSC meets every other week in the TSC Meeting [Discord](https://eslint.org/chat) channel. The meeting is run by a designated moderator approved by the TSC.
+
+Items are added to the TSC agenda which are considered contentious or
+are modifications of governance, contribution policy, TSC membership,
+or release process.
+
+The intention of the agenda is not to approve or review all patches.
+That should happen continuously on GitHub and be handled by the larger
+group of Committers.
+
+Any community member, Committer, or Reviewer can ask that something be added to
+the next meeting's agenda by logging a GitHub Issue. Anyone can add the item to the agenda by adding
+the "tsc agenda" tag to the issue.
+
+Prior to each TSC meeting, the moderator will share the Agenda with
+members of the TSC. TSC members can add any items they like to the
+agenda at the beginning of each meeting. The moderator and the TSC
+cannot veto or remove items.
+
+No binding votes on TSC agenda items can take place without a quorum of
+TSC members present in the meeting. Quorum is achieved when more than
+half of the TSC members (minus non-attending members) are present.
+
+The TSC may invite persons or representatives from certain projects to
+participate in a non-voting capacity.
+
+The moderator is responsible for summarizing the discussion of each
+agenda item and sending it as a pull request after the meeting.
+
+## Consensus Seeking Process
+
+The TSC follows a
+[Consensus Seeking](https://en.wikipedia.org/wiki/Consensus-seeking_decision-making)
+decision making model.
+
+When an agenda item has appeared to reach a consensus, the moderator
+will ask "Does anyone object?" as a final call for dissent from the
+consensus.
+
+If an agenda item cannot reach a consensus, a TSC member can call for
+either a closing vote or a vote to table the issue to the next
+meeting. The call for a vote must be approved by a majority of the TSC
+or else the discussion will continue. Simple majority wins.
+
+----
+
+This work is a derivative of [YUI Contributor Model](https://github.com/yui/yui3/wiki/Contributor-Model) and the [Node.js Project Governance Model](https://github.com/nodejs/node/blob/master/GOVERNANCE.md).
+
+This work is licensed under a [Creative Commons Attribution-ShareAlike 2.0 UK: England & Wales License](https://creativecommons.org/licenses/by-sa/2.0/uk/).
--- /dev/null
+---
+title: Contribute to ESLint
+eleventyNavigation:
+ key: contribute to eslint
+ title: Contribute to ESLint
+ order: 3
+---
+
+One of the great things about open source projects is that anyone can contribute in any number of meaningful ways. ESLint couldn't exist without the help of the many contributors it's had since the project began, and we want you to feel like you can contribute and make a difference as well.
+
+This guide is intended for anyone who wants to contribute to an ESLint project. Please read it carefully as it answers a lot of the questions many newcomers have when first working with our projects.
+
+## Read the [Code of Conduct](https://eslint.org/conduct)
+
+ESLint welcomes contributions from everyone and adheres to the [OpenJS Foundation Code of Conduct](https://eslint.org/conduct). We kindly request that you read over our code of conduct before contributing.
+
+## [Report Bugs](report-bugs)
+
+Think you found a problem? We'd love to hear about it. This section explains how to submit a bug, the type of information we need to properly verify it, and the overall process.
+
+## [Propose a New Rule](propose-new-rule)
+
+We get a lot of proposals for new rules in ESLint. This section explains how we determine which rules are accepted and what information you should provide to help us evaluate your proposal.
+
+## [Propose a Rule Change](propose-rule-change)
+
+Want to make a change to an existing rule? This section explains the process and how we evaluate such proposals.
+
+## [Request a Change](request-change)
+
+If you'd like to request a change other than a bug fix or new rule, this section explains that process.
+
+## [Architecture](architecture)
+
+Learn about the architecture of the ESLint project.
+
+## [Set up a Development Environment](development-environment)
+
+Developing for ESLint is a bit different than running it on the command line. This section shows you how to set up a development environment and get you ready to write code.
+
+## [Run the Tests](tests)
+
+There are a lot of unit tests included with ESLint to make sure that we're keeping on top of code quality. This section explains how to run the unit tests.
+
+## [Work on Issues](work-on-issue)
+
+Have some extra time and want to contribute? This section talks about the process of working on issues.
+
+## [Submit a Pull Request](pull-requests)
+
+We're always looking for contributions from the community. This section explains the requirements for pull requests and the process of contributing code.
+
+## [Contribute to Core Rules](core-rules)
+
+This section explains how to add to the core rules of ESLint.
+
+## [Governance](governance)
+
+Describes the governance policy for ESLint, including the rights and privileges of individuals inside the project.
+
+## [Report a Security Vulnerability](report-security-vulnerability)
+
+To report a security vulnerability in ESLint, please create an advisory on Github.
+
+## Sign the CLA
+
+In order to submit code or documentation to an ESLint project, you will need to electronically sign our Contributor License Agreement. The CLA is the commonly used Apache-style template, and is you giving us permission to use your contribution. You only need to sign the CLA once for any OpenJS Foundation projects that use EasyCLA. You will be asked to sign the CLA in the first pull request you open.
--- /dev/null
+---
+title: Package.json Conventions
+edit_link: https://github.com/eslint/eslint/edit/main/docs/src/contribute/package-json-conventions.md
+---
+
+The following applies to the "scripts" section of `package.json` files.
+
+## Names
+
+npm script names MUST contain only lower case letters, `:` to separate parts, `-` to separate words, and `+` to separate file extensions. Each part name SHOULD be either a full English word (e.g. `coverage` not `cov`) or a well-known initialism in all lowercase (e.g. `wasm`).
+
+Here is a summary of the proposal in ABNF.
+
+```abnf
+name = life-cycle / main target? option* ":watch"?
+life-cycle = "prepare" / "preinstall" / "install" / "postinstall" / "prepublish" / "preprepare" / "prepare" / "postprepare" / "prepack" / "postpack" / "prepublishOnly"
+main = "build" / "lint" ":fix"? / "release" / "start" / "test"
+target = ":" word ("-" word)* / extension ("+" extension)*
+option = ":" word ("-" word)*
+word = ALPHA +
+extension = ( ALPHA / DIGIT )+
+```
+
+## Order
+
+The script names MUST appear in the package.json file in alphabetical order. The other conventions outlined in this document ensure that alphabetical order will coincide with logical groupings.
+
+## Main Script Names
+
+With the exception of [npm life cycle scripts](https://docs.npmjs.com/cli/v8/using-npm/scripts#life-cycle-scripts) all script names MUST begin with one of the following names.
+
+### Build
+
+Scripts that generate a set of files from source code and / or data MUST have names that begin with `build`.
+
+If a package contains any `build:*` scripts, there MAY be a script named `build`. If so, SHOULD produce the same output as running each of the `build` scripts individually. It MUST produce a subset of the output from running those scripts.
+
+### Release
+
+Scripts that have public side effects (publishing the web site, committing to Git, etc.) MUST begin with `release`.
+
+### Lint
+
+Scripts that statically analyze files (mostly, but not limited to running `eslint` itself) MUST have names that begin with `lint`.
+
+If a package contains any `lint:*` scripts, there SHOULD be a script named `lint` and it MUST run all of the checks that would have been run if each `lint:*` script was called individually.
+
+If fixing is available, a linter MUST NOT apply fixes UNLESS the script contains the `:fix` modifier (see below).
+
+### Start
+
+A `start` script is used to start a server. As of this writing, no ESLint package has more than one `start` script, so there's no need `start` to have any modifiers.
+
+### Test
+
+Scripts that execute code in order to ensure the actual behavior matches expected behavior MUST have names that begin with `test`.
+
+If a package contains any `test:*` scripts, there SHOULD be a script named `test` and it MUST run of all of the tests that would have been run if each `test:*` script was called individually.
+
+A test script SHOULD NOT include linting.
+
+A test script SHOULD report test coverage when possible.
+
+## Modifiers
+
+One or more of the following modifiers MAY be appended to the standard script names above. If a target has modifiers, they MUST be in the order in which they appear below (e.g. `lint:fix:js:watch` not `lint:watch:js:fix`)
+
+### Fix
+
+If it's possible for a linter to fix problems that it finds, add a copy of the script with `:fix` appended to the end that also fixes.
+
+### Target
+
+The name of the target of the action being run. In the case of a `build` script, it SHOULD identify the build artifact(s), e.g. "javascript" or "css" or "website". In the case of a `lint` or `test` script, it SHOULD identify the item(s) being linted or tested. In the case of a `start` script, it SHOULD identify which server is starting.
+
+A target MAY refer to a list of affected file extensions (such as `cjs` or `less`) delimited by a `+`. If there is more than one extension, the list SHOULD be alphabetized. When a file extension has variants (such as `cjs` for CommonJS and `mjs` for ESM), the common part of the extension MAY be used instead of explicitly listing out all of the variants (e.g. `js` instead of `cjs+jsx+mjs`).
+
+The target SHOULD NOT refer to name of the name of the tool that's performing the action (`eleventy`, `webpack`, etc.)
+
+### Options
+
+Additional options that don't fit under the other modifiers.
+
+### Watch
+
+If a script watches the filesystem and responds to changes, add `:watch` to the script name.
--- /dev/null
+---
+title: Propose a New Rule
+eleventyNavigation:
+ key: propose rule
+ parent: contribute to eslint
+ title: Propose a New Rule
+ order: 2
+---
+
+ESLint is all about rules. For most of the project's lifetime, we've had over 200 rules, and that list continues to grow. However, we can't just accept any proposed rule because all rules need to work cohesively together. As such, we have some guidelines around which rules can be part of the ESLint core and which are better off as custom rules and plugins.
+
+**Note:** As of 2020, we only accept rules related to new ECMAScript features. We prefer that new rules be implemented in plugins.
+
+## Core Rule Guidelines
+
+In general, ESLint core rules must be:
+
+1. **Widely applicable.** The rules we distribute need to be of importance to a large number of developers. Individual preferences for uncommon patterns are not supported.
+1. **Generic.** Rules cannot be so specific that users will have trouble understanding when to use them. A rule is typically too specific if describing what it does requires more than two "and"s (if a and b and c and d, then this rule warns).
+1. **Atomic.** Rules must function completely on their own. Rules are expressly forbidden from knowing about the state or presence of other rules.
+1. **Unique.** No two rules can produce the same warning. Overlapping rules confuse end users and there is an expectation that core ESLint rules do not overlap.
+1. **Library agnostic.** Rules must be based solely on JavaScript runtime environments and not on specific libraries or frameworks. For example, core rules shouldn't only apply if you're using jQuery but we may have some rules that apply only if you're using Node.js (a runtime).
+1. **No conflicts.** No rule must directly conflict with another rule. For example, if we have a rule requiring semicolons, we cannot also have a rule disallowing semicolons (which is why we have one rule, `semi`, that does both).
+
+Even though these are the formal criteria for inclusion, each rule is evaluated on its own basis.
+
+## Proposing a Rule
+
+If you want to propose a new rule, please see how to [create a pull request](pull-requests) or submit an issue by filling out a [new rule template](https://github.com/eslint/eslint/issues/new/choose).
+
+We need all of this information in order to determine whether or not the rule is a good core rule candidate.
+
+## Accepting a Rule
+
+In order for a rule to be accepted in the ESLint core, it must:
+
+1. Fulfill all the criteria listed in the "Core Rule Guidelines" section
+1. Have an ESLint team member champion inclusion of the rule
+1. Be related to an ECMAScript feature that has reached stage 4 in the preceding 12 months
+
+Keep in mind that we have over 200 rules, and that is daunting both for end users and the ESLint team (who has to maintain them). As such, any new rules must be deemed of high importance to be considered for inclusion in ESLint.
+
+## Implementation is Your Responsibility
+
+The ESLint team doesn't implement new rules that are suggested by users because we have a limited number of people and need to focus on the overall roadmap. Once a rule is accepted, you are responsible for implementing and documenting the rule. You may, alternately, recruit another person to help you implement the rule. The ESLint team member who championed the rule is your resource to help guide you through the rest of this process.
+
+## Alternative: Creating Your Own Rules
+
+Remember that ESLint is completely pluggable, which means you can create your own rules and distribute them using plugins. We did this on purpose because we don't want to be the gatekeepers for all possible rules. Even if we don't accept a rule into the core, that doesn't mean you can't have the exact rule that you want. See the [Custom Rules](../extend/custom-rules) and [Create Plugins](../extend/plugins) documentation for more information.
--- /dev/null
+---
+title: Propose a Rule Change
+eleventyNavigation:
+ key: propose rule change
+ parent: contribute to eslint
+ title: Propose a Rule Change
+ order: 3
+---
+
+Occasionally, a core ESLint rule needs to be changed. This is not necessarily a bug, but rather, an enhancement that makes a rule more configurable. In those situations, we will consider making changes to rules.
+
+## Proposing a Rule Change
+
+To propose a change to an existing rule, [create a pull request](pull-requests) or [new issue](https://github.com/eslint/eslint/issues/new/choose) and fill out the template.
+
+We need all of this information in order to determine whether or not the change is a good candidate for inclusion.
+
+## Accepting a Rule Change
+
+In order for a rule change to be accepted into ESLint, it must:
+
+1. Adhere to the [Core Rule Guidelines](propose-new-rule#core-rule-guidelines)
+1. Have an ESLint team member champion the change
+1. Be important enough that rule is deemed incomplete without this change
+
+## Implementation is Your Responsibility
+
+The ESLint team doesn't implement rule changes that are suggested by users because we have a limited number of people and need to focus on the overall roadmap. Once a rule change is accepted, you are responsible for implementing and documenting it. You may, alternately, recruit another person to help you. The ESLint team member who championed the rule is your resource to help guide you through the rest of this process.
--- /dev/null
+---
+title: Submit a Pull Request
+eleventyNavigation:
+ key: submit pull request
+ parent: contribute to eslint
+ title: Submit a Pull Request
+ order: 9
+---
+
+If you want to contribute to an ESLint repo, please use a GitHub pull request. This is the fastest way for us to evaluate your code and to merge it into the code base. Please don't file an issue with snippets of code. Doing so means that we need to manually merge the changes in and update any appropriate tests. That decreases the likelihood that your code is going to get included in a timely manner. Please use pull requests.
+
+## Getting Started
+
+If you'd like to work on a pull request and you've never submitted code before, follow these steps:
+
+1. Set up a [development environment](./development-environment).
+1. If you want to implement a breaking change or a change to the core, ensure there's an issue that describes what you're doing and the issue has been accepted. You can create a new issue or just indicate you're [working on an existing issue](./work-on-issue). Bug fixes, documentation changes, and other pull requests do not require an issue.
+
+After that, you're ready to start working on code.
+
+## Working with Code
+
+The process of submitting a pull request is fairly straightforward and generally follows the same pattern each time:
+
+1. [Create a new branch](#step1)
+2. [Make your changes](#step2)
+3. [Rebase onto upstream](#step3)
+4. [Run the tests](#step4)
+5. [Double check your submission](#step5)
+6. [Push your changes](#step6)
+7. [Submit the pull request](#step7)
+
+Details about each step are found below.
+
+### Step 1: Create a new branch<a name="step1"></a>
+
+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:
+
+```shell
+git checkout -b issue1234
+```
+
+You should do all of your development for the issue in this branch.
+
+**Note:** Do not combine fixes for multiple issues into one branch. Use a separate branch for each issue you're working on.
+
+### Step 2: Make your changes<a name="step2"></a>
+
+Make the changes to the code and tests, following the [code conventions](./code-conventions) as you go. Once you have finished, commit the changes to your branch:
+
+```shell
+git add -A
+git commit
+```
+
+All ESLint projects follow [Conventional Commits](https://www.conventionalcommits.org/) for our commit messages. (Note: we don’t support the optional scope in messages.) Here's an example commit message:
+
+```txt
+tag: Short description of what you did
+
+Longer description here if necessary
+
+Fixes #1234
+```
+
+The first line of the commit message (the summary) must have a specific format. This format is checked by our build tools.
+
+The `tag` is one of the following:
+
+* `fix` - for a bug fix.
+* `feat` - either for a backwards-compatible enhancement or for a rule change that adds reported problems.
+* `fix!` - for a backwards-incompatible bug fix.
+* `feat!` - for a backwards-incompatible enhancement or feature.
+* `docs` - changes to documentation only.
+* `chore` - for changes that aren't user-facing.
+* `build` - changes to build process only.
+* `refactor` - a change that doesn't affect APIs or user experience.
+* `test` - just changes to test files.
+* `ci` - changes to our CI configuration files and scripts.
+* `perf` - a code change that improves performance.
+
+Use the [labels of the issue you are working on](work-on-issue#issue-labels) to determine the best tag.
+
+The message summary should be a one-sentence description of the change, and it must be 72 characters in length or shorter. If the pull request addresses an issue, then the issue number should be mentioned in the body of the commit message in the format `Fixes #1234`. If the commit doesn't completely fix the issue, then use `Refs #1234` instead of `Fixes #1234`.
+
+Here are some good commit message summary examples:
+
+```txt
+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
+```
+
+The commit message format is important because these messages are used to create a changelog for each release. The tag and issue number help to create more consistent and useful changelogs.
+
+### Step 3: Rebase onto upstream<a name="step3"></a>
+
+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.
+
+```shell
+git fetch upstream
+git rebase upstream/main
+```
+
+### Step 4: Run the tests<a name="step4"></a>
+
+After rebasing, be sure to run all of the tests once again to make sure nothing broke:
+
+```shell
+npm test
+```
+
+If there are any failing tests, update your code until all tests pass.
+
+### Step 5: Double check your submission<a name="step5"></a>
+
+With your code ready to go, this is a good time to double-check your submission to make sure it follows our conventions. Here are the things to check:
+
+* Make sure your commit is formatted correctly.
+* The pull request must have a description. The description should explain what you did and how its effects can be seen.
+* The commit message is properly formatted.
+* The change introduces no functional regression. Be sure to run `npm test` to verify your changes before submitting a pull request.
+* Make separate pull requests for unrelated changes. Large pull requests with multiple unrelated changes may be closed without merging.
+* All changes must be accompanied by tests, even if the feature you're working on previously had no tests.
+* All user-facing changes must be accompanied by appropriate documentation.
+* Follow the [Code Conventions](./code-conventions).
+
+### Step 6: Push your changes<a name="step6"></a>
+
+Next, push your changes to your clone:
+
+```shell
+git push origin issue1234
+```
+
+If you are unable to push because some references are old, do a forced push instead:
+
+```shell
+git push -f origin issue1234
+```
+
+### Step 7: Send the pull request<a name="step7"></a>
+
+Now you're ready to send the pull request. Go to your ESLint fork and then follow the [GitHub documentation](https://help.github.com/articles/creating-a-pull-request) on how to send a pull request.
+
+In order to submit code or documentation to an ESLint project, you’ll be asked to sign our CLA when you send your first pull request. (Read more about the Open JS Foundation CLA process at <https://cla.openjsf.org/>.)
+
+## Following Up
+
+Once your pull request is sent, it's time for the team to review it. As such, please make sure to:
+
+1. Monitor the status of the Travis CI build for your pull request. If it fails, please investigate why. We cannot merge pull requests that fail Travis for any reason.
+1. Respond to comments left on the pull request from team members. Remember, we want to help you land your code, so please be receptive to our feedback.
+1. We may ask you to make changes, rebase, or squash your commits.
+
+### Updating the Commit Message
+
+If your commit message is in the incorrect format, you'll be asked to update it. You can do so via:
+
+```shell
+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:
+
+```shell
+git push origin issue1234 -f
+```
+
+### Updating the Code
+
+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:
+
+```shell
+git add -A
+git commit
+git push origin issue1234
+```
+
+When updating the code, it's usually better to add additional commits to your branch rather than amending the original commit, because reviewers can easily tell which changes were made in response to a particular review. When we merge pull requests, we will squash all the commits from your branch into a single commit on the `main` branch.
+
+The commit messages in subsequent commits do not need to be in any specific format because these commits do not show up in the changelog.
+
+### Rebasing
+
+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) and then you can rebase using these commands:
+
+```shell
+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:
+
+```shell
+git push origin issue1234 -f
+```
--- /dev/null
+---
+title: Report Bugs
+eleventyNavigation:
+ key: report bugs
+ parent: contribute to eslint
+ title: Report Bugs
+ order: 1
+---
+
+If you think you've found a bug in ESLint, please [create a new issue](https://github.com/eslint/eslint/issues/new/choose) or a [pull request](pull-requests) on GitHub.
+
+Please include as much detail as possible to help us properly address your issue. If we need to triage issues and constantly ask people for more detail, that's time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues.
+
+**Note:** If you just have a question that won't necessarily result in a change to ESLint, such as asking how something works or how to contribute, please open a [discussion](https://github.com/eslint/eslint/discussions) or stop by our [Discord server](https://eslint.org/chat) instead of filing an issue.
--- /dev/null
+---
+title: Report a Security Vulnerability
+eleventyNavigation:
+ key: report security vulnerability
+ parent: contribute to eslint
+ title: Report a Security Vulnerability
+ order: 11
+---
+
+To report a security vulnerability in ESLint, please use our [create an advisory form](https://github.com/eslint/eslint/security/advisories/new) on GitHub.
--- /dev/null
+---
+title: Request a Change
+eleventyNavigation:
+ key: request change
+ parent: contribute to eslint
+ title: Request a Change
+ order: 4
+---
+
+If you'd like to request a change to ESLint, please [create a new issue](https://github.com/eslint/eslint/issues/new/choose) on GitHub. Be sure to include the following information:
+
+1. The version of ESLint you are using.
+2. The problem you want to solve.
+3. Your take on the correct solution to problem.
+
+If you're requesting a change to a rule, it's helpful to include this information as well:
+
+1. What you did.
+1. What you would like to happen.
+1. What actually happened.
+
+Please include as much detail as possible to help us properly address your issue. If we need to triage issues and constantly ask people for more detail, that's time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues.
+
+**Note:** If you just have a question that won't necessarily result in a change to ESLint, such as asking how something works or how to contribute, please open a [discussion](https://github.com/eslint/eslint/discussions) or stop by our [Discord server](https://eslint.org/chat) instead of filing an issue.
--- /dev/null
+---
+title: Run the Tests
+eleventyNavigation:
+ key: run tests
+ parent: contribute to eslint
+ title: Run the Tests
+ order: 7
+---
+
+Most parts of ESLint have unit tests associated with them. Unit tests are written using [Mocha](https://mochajs.org/) and are required when making contributions to ESLint. You'll find all of the unit tests in the `tests` directory.
+
+When you first get the source code, you need to run `npm install` once initially to set ESLint for development. Once you've done that, you can run the tests via:
+
+```shell
+npm test
+```
+
+This automatically starts Mocha and runs all tests in the `tests` directory. You need only add yours and it will automatically be picked up when running tests.
+
+## Running Individual Tests
+
+If you want to quickly run just one test file, you can do so by running Mocha directly and passing in the filename. For example:
+
+```shell
+npm run test:cli tests/lib/rules/no-undef.js
+```
+
+If you want to run just one or a subset of `RuleTester` test cases, add `only: true` to each test case or wrap the test case in `RuleTester.only(...)` to add it automatically:
+
+```js
+ruleTester.run("my-rule", myRule, {
+ valid: [
+ RuleTester.only("const valid = 42;"),
+ // Other valid cases
+ ],
+ invalid: [
+ {
+ code: "const invalid = 42;",
+ only: true,
+ },
+ // Other invalid cases
+ ]
+})
+```
+
+Running individual tests is useful when you're working on a specific bug and iterating on the solution. You should be sure to run `npm test` before submitting a pull request. `npm test` uses Mocha's `--forbid-only` option to prevent `only` tests from passing full test runs.
+
+## More Control on Unit Testing
+
+`npm run test:cli` is an alias of the Mocha cli in `./node_modules/.bin/mocha`. [Options](https://mochajs.org/#command-line-usage) are available to be provided to help to better control the test to run.
+
+The default timeout for tests in `npm test` is 10000ms. You may change the timeout by providing `ESLINT_MOCHA_TIMEOUT` environment variable, for example:
+
+```shell
+ESLINT_MOCHA_TIMEOUT=20000 npm test
+```
--- /dev/null
+---
+title: Work on Issues
+eleventyNavigation:
+ key: work on issues
+ parent: contribute to eslint
+ title: Work on Issues
+ order: 8
+---
+
+Our public [issues tracker](https://github.com/eslint/eslint/issues) lists all of the things we plan on doing as well as suggestions from the community. Before starting to work on an issue, be sure you read through the rest of this page.
+
+## Issue Labels
+
+We use labels to indicate the status of issues. The most complete documentation on the labels is found in the [Maintain ESLint documentation](../maintain/manage-issues#when-an-issue-is-opened), but most contributors should find the information on this page sufficient. The most important questions that labels can help you, as a contributor, answer are:
+
+1. Is this issue available for me to work on? If you have little or no experience contributing to ESLint, the [`good first issue`](https://github.com/eslint/eslint/labels/good%20first%20issue) label marks appropriate issues. Otherwise, the [`help wanted`](https://github.com/eslint/eslint/labels/help%20wanted) label is an invitation to work on the issue. If you have more experience, you can try working on other issues labeled [`accepted`](https://github.com/eslint/eslint/labels/accepted). Conversely, issues not yet ready to work on are labeled `triage`, `evaluating`, and/or `needs bikeshedding`, and issues that cannot currently be worked on because of something else, such as a bug in a dependency, are labeled `blocked`.
+1. What is this issue about? Labels describing the nature of issues include `bug`, `enhancement`, `feature`, `question`, `rule`, `documentation`, `core`, `build`, `cli`, `infrastructure`, `breaking`, and `chore`. These are documented in [Maintain ESLint](../maintain/manage-issues#types-of-issues).
+1. What is the priority of this issue? Because we have a lot of issues, we prioritize certain issues above others. The following is the list of priorities, from highest to lowest:
+
+ 1. **Bugs** - problems with the project are actively affecting users. We want to get these resolved as quickly as possible.
+ 1. **Documentation** - documentation issues are a type of bug in that they actively affect current users. As such, we want to address documentation issues as quickly as possible.
+ 1. **Features** - new functionality that will aid users in the future.
+ 1. **Enhancements** - requested improvements for existing functionality.
+ 1. **Other** - anything else.
+
+ Some issues have had monetary rewards attached to them. Those are labeled `bounty`. Bounties are assigned via [BountySource](https://www.bountysource.com/teams/eslint/issues).
+
+## Starting Work
+
+If you're going to work on an issue, please add a comment to that issue saying so and indicating when you think you will complete it. It will help us to avoid duplication of effort. Some examples of good comments are:
+
+* "I'll take a look at this over the weekend."
+* "I'm going to do this, give me two weeks."
+* "Working on this" (as in, I'm working on it right now)
+
+If an issue has already been claimed by someone, please be respectful of that person's desire to complete the work and don't work on it unless you verify that they are no longer interested.
+
+If you find you can't finish the work, then simply add a comment letting people know, for example:
+
+* "Sorry, it looks like I don't have time to do this."
+* "I thought I knew enough to fix this, but it turns out I don't."
+
+No one will blame you for backing out of an issue if you are unable to complete it. We just want to keep the process moving along as efficiently as possible.
+++ /dev/null
----
-title: Architecture
-layout: doc
-eleventyNavigation:
- key: architecture
- parent: developer guide
- title: Architecture
- order: 1
----
-
-<center><img alt="dependency graph" src="../../assets/images/architecture/dependency.svg"></center>
-
-At a high level, there are a few key parts to ESLint:
-
-* `bin/eslint.js` - this is the file that actually gets executed with the command line utility. It's a dumb wrapper that does nothing more than bootstrap ESLint, passing the command line arguments to `cli`. This is intentionally small so as not to require heavy testing.
-* `lib/api.js` - this is the entry point of `require("eslint")`. This file exposes an object that contains public classes `Linter`, `ESLint`, `RuleTester`, and `SourceCode`.
-* `lib/cli.js` - this is the heart of the ESLint CLI. It takes an array of arguments and then uses `eslint` to execute the commands. By keeping this as a separate utility, it allows others to effectively call ESLint from within another Node.js program as if it were done on the command line. The main call is `cli.execute()`. This is also the part that does all the file reading, directory traversing, input, and output.
-* `lib/cli-engine/` - this module is `CLIEngine` class that finds source code files and configuration files then does code verifying with the `Linter` class. This includes the loading logic of configuration files, parsers, plugins, and formatters.
-* `lib/linter/` - this module is the core `Linter` class that does code verifying based on configuration options. This file does no file I/O and does not interact with the `console` at all. For other Node.js programs that have JavaScript text to verify, they would be able to use this interface directly.
-* `lib/rule-tester/` - this module is `RuleTester` class that is a wrapper around Mocha so that rules can be unit tested. This class lets us write consistently formatted tests for each rule that is implemented and be confident that each of the rules work. The RuleTester interface was modeled after Mocha and works with Mocha's global testing methods. RuleTester can also be modified to work with other testing frameworks.
-* `lib/source-code/` - this module is `SourceCode` class that is used to represent the parsed source code. It takes in source code and the Program node of the AST representing the code.
-* `lib/rules/` - this contains built-in rules that verify source code.
-
-## The `cli` object
-
-The `cli` object is the API for the command line interface. Literally, the `bin/eslint.js` file simply passes arguments to the `cli` object and then sets `process.exitCode` to the returned exit code.
-
-The main method is `cli.execute()`, which accepts an array of strings that represent the command line options (as if `process.argv` were passed without the first two arguments). If you want to run ESLint from inside of another program and have it act like the CLI, then `cli` is the object to use.
-
-This object's responsibilities include:
-
-* Interpreting command line arguments
-* Reading from the file system
-* Outputting to the console
-* Outputting to the filesystem
-* Use a formatter
-* Returning the correct exit code
-
-This object may not:
-
-* Call `process.exit()` directly
-* Perform any asynchronous operations
-
-## The `CLIEngine` object
-
-The `CLIEngine` type represents the core functionality of the CLI except that it reads nothing from the command line and doesn't output anything by default. Instead, it accepts many (but not all) of the arguments that are passed into the CLI. It reads both configuration and source files as well as managing the environment that is passed into the `Linter` object.
-
-The main method of the `CLIEngine` is `executeOnFiles()`, which accepts an array of file and directory names to run the linter on.
-
-This object's responsibilities include:
-
-* Managing the execution environment for `Linter`
-* Reading from the file system
-* Reading configuration information from config files (including `.eslintrc` and `package.json`)
-
-This object may not:
-
-* Call `process.exit()` directly
-* Perform any asynchronous operations
-* Output to the console
-* Use formatters
-
-## The `Linter` object
-
-The main method of the `Linter` object is `verify()` and accepts two arguments: the source text to verify and a configuration object (the baked configuration of the given configuration file plus command line options). The method first parses the given text with `espree` (or whatever the configured parser is) and retrieves the AST. The AST is produced with both line/column and range locations which are useful for reporting location of issues and retrieving the source text related to an AST node, respectively.
-
-Once the AST is available, `estraverse` is used to traverse the AST from top to bottom. At each node, the `Linter` object emits an event that has the same name as the node type (i.e., "Identifier", "WithStatement", etc.). On the way back up the subtree, an event is emitted with the AST type name and suffixed with ":exit", such as "Identifier:exit" - this allows rules to take action both on the way down and on the way up in the traversal. Each event is emitted with the appropriate AST node available.
-
-This object's responsibilities include:
-
-* Inspecting JavaScript code strings
-* Creating an AST for the code
-* Executing rules on the AST
-* Reporting back the results of the execution
-
-This object may not:
-
-* Call `process.exit()` directly
-* Perform any asynchronous operations
-* Use Node.js-specific features
-* Access the file system
-* Call `console.log()` or any other similar method
-
-## Rules
-
-Individual rules are the most specialized part of the ESLint architecture. Rules can do very little, they are simply a set of instructions executed against an AST that is provided. They do get some context information passed in, but the primary responsibility of a rule is to inspect the AST and report warnings.
-
-These objects' responsibilities are:
-
-* Inspect the AST for specific patterns
-* Reporting warnings when certain patterns are found
-
-These objects may not:
-
-* Call `process.exit()` directly
-* Perform any asynchronous operations
-* Use Node.js-specific features
-* Access the file system
-* Call `console.log()` or any other similar method
+++ /dev/null
----
-title: Code Conventions
-layout: doc
----
-
-Code conventions for ESLint are determined by
-[eslint-config-eslint](https://www.npmjs.com/package/eslint-config-eslint).
-
-The rationales for the specific rules in use can be found by looking to the
-project documentation for any given rule. If the rule is one of our own, see
-our own [rule documentation](https://eslint.org/docs/rules/) and otherwise, see
-the documentation of the plugin in which the rule can be found.
-
-If you need to make changes to a `package.json` file, please see the
-[package.json conventions](./package-json-conventions).
+++ /dev/null
----
-title: Code Path Analysis Details
-layout: doc
-
----
-
-ESLint's rules can use code paths.
-The code path is execution routes of programs.
-It forks/joins at such as `if` statements.
-
-```js
-if (a && b) {
- foo();
-}
-bar();
-```
-
-![Code Path Example](../assets/images/code-path-analysis/helo.svg)
-
-## Objects
-
-Program is expressed with several code paths.
-A code path is expressed with objects of two kinds: `CodePath` and `CodePathSegment`.
-
-### `CodePath`
-
-`CodePath` expresses whole of one code path.
-This object exists for each function and the global.
-This has references of both the initial segment and the final segments of a code path.
-
-`CodePath` has the following properties:
-
-* `id` (`string`) - A unique string. Respective rules can use `id` to save additional information for each code path.
-* `origin` (`string`) - The reason that the code path was started. May be `"program"`, `"function"`, `"class-field-initializer"`, or `"class-static-block"`.
-* `initialSegment` (`CodePathSegment`) - The initial segment of this code path.
-* `finalSegments` (`CodePathSegment[]`) - The final segments which includes both returned and thrown.
-* `returnedSegments` (`CodePathSegment[]`) - The final segments which includes only returned.
-* `thrownSegments` (`CodePathSegment[]`) - The final segments which includes only thrown.
-* `currentSegments` (`CodePathSegment[]`) - Segments of the current position.
-* `upper` (`CodePath|null`) - The code path of the upper function/global scope.
-* `childCodePaths` (`CodePath[]`) - Code paths of functions this code path contains.
-
-### `CodePathSegment`
-
-`CodePathSegment` is a part of a code path.
-A code path is expressed with plural `CodePathSegment` objects, it's similar to doubly linked list.
-Difference from doubly linked list is what there are forking and merging (the next/prev are plural).
-
-`CodePathSegment` has the following properties:
-
-* `id` (`string`) - A unique string. Respective rules can use `id` to save additional information for each segment.
-* `nextSegments` (`CodePathSegment[]`) - The next segments. If forking, there are two or more. If final, there is nothing.
-* `prevSegments` (`CodePathSegment[]`) - The previous segments. If merging, there are two or more. If initial, there is nothing.
-* `reachable` (`boolean`) - A flag which shows whether or not it's reachable. This becomes `false` when preceded by `return`, `throw`, `break`, or `continue`.
-
-## Events
-
-There are five events related to code paths, and you can define event handlers in rules.
-
-```js
-module.exports = function(context) {
- return {
- /**
- * This is called at the start of analyzing a code path.
- * In this time, the code path object has only the initial segment.
- *
- * @param {CodePath} codePath - The new code path.
- * @param {ASTNode} node - The current node.
- * @returns {void}
- */
- "onCodePathStart": function(codePath, node) {
- // do something with codePath
- },
-
- /**
- * This is called at the end of analyzing a code path.
- * In this time, the code path object is complete.
- *
- * @param {CodePath} codePath - The completed code path.
- * @param {ASTNode} node - The current node.
- * @returns {void}
- */
- "onCodePathEnd": function(codePath, node) {
- // do something with codePath
- },
-
- /**
- * This is called when a code path segment was created.
- * It meant the code path is forked or merged.
- * In this time, the segment has the previous segments and has been
- * judged reachable or not.
- *
- * @param {CodePathSegment} segment - The new code path segment.
- * @param {ASTNode} node - The current node.
- * @returns {void}
- */
- "onCodePathSegmentStart": function(segment, node) {
- // do something with segment
- },
-
- /**
- * This is called when a code path segment was left.
- * In this time, the segment does not have the next segments yet.
- *
- * @param {CodePathSegment} segment - The left code path segment.
- * @param {ASTNode} node - The current node.
- * @returns {void}
- */
- "onCodePathSegmentEnd": function(segment, node) {
- // do something with segment
- },
-
- /**
- * This is called when a code path segment was looped.
- * Usually segments have each previous segments when created,
- * but when looped, a segment is added as a new previous segment into a
- * existing segment.
- *
- * @param {CodePathSegment} fromSegment - A code path segment of source.
- * @param {CodePathSegment} toSegment - A code path segment of destination.
- * @param {ASTNode} node - The current node.
- * @returns {void}
- */
- "onCodePathSegmentLoop": function(fromSegment, toSegment, node) {
- // do something with segment
- }
- };
-};
-```
-
-### About `onCodePathSegmentLoop`
-
-This event is always fired when the next segment has existed already.
-That timing is the end of loops mainly.
-
-For Example 1:
-
-```js
-while (a) {
- a = foo();
-}
-bar();
-```
-
-1. First, the analysis advances to the end of loop.
-
- ![Loop Event's Example 1](../assets/images/code-path-analysis/loop-event-example-while-1.svg)
-
-2. Second, it creates the looping path.
- At this time, the next segment has existed already, so the `onCodePathSegmentStart` event is not fired.
- It fires `onCodePathSegmentLoop` instead.
-
- ![Loop Event's Example 2](../assets/images/code-path-analysis/loop-event-example-while-2.svg)
-
-3. Last, it advances to the end.
-
- ![Loop Event's Example 3](../assets/images/code-path-analysis/loop-event-example-while-3.svg)
-
-For example 2:
-
-```js
-for (let i = 0; i < 10; ++i) {
- foo(i);
-}
-bar();
-```
-
-1. `for` statements are more complex.
- First, the analysis advances to `ForStatement.update`.
- The `update` segment is hovered at first.
-
- ![Loop Event's Example 1](../assets/images/code-path-analysis/loop-event-example-for-1.svg)
-
-2. Second, it advances to `ForStatement.body`.
- Of course the `body` segment is preceded by the `test` segment.
- It keeps the `update` segment hovering.
-
- ![Loop Event's Example 2](../assets/images/code-path-analysis/loop-event-example-for-2.svg)
-
-3. Third, it creates the looping path from `body` segment to `update` segment.
- At this time, the next segment has existed already, so the `onCodePathSegmentStart` event is not fired.
- It fires `onCodePathSegmentLoop` instead.
-
- ![Loop Event's Example 3](../assets/images/code-path-analysis/loop-event-example-for-3.svg)
-
-4. Fourth, also it creates the looping path from `update` segment to `test` segment.
- At this time, the next segment has existed already, so the `onCodePathSegmentStart` event is not fired.
- It fires `onCodePathSegmentLoop` instead.
-
- ![Loop Event's Example 4](../assets/images/code-path-analysis/loop-event-example-for-4.svg)
-
-5. Last, it advances to the end.
-
- ![Loop Event's Example 5](../assets/images/code-path-analysis/loop-event-example-for-5.svg)
-
-## Usage Examples
-
-### To check whether or not this is reachable
-
-```js
-function isReachable(segment) {
- return segment.reachable;
-}
-
-module.exports = function(context) {
- var codePathStack = [];
-
- return {
- // Stores CodePath objects.
- "onCodePathStart": function(codePath) {
- codePathStack.push(codePath);
- },
- "onCodePathEnd": function(codePath) {
- codePathStack.pop();
- },
-
- // Checks reachable or not.
- "ExpressionStatement": function(node) {
- var codePath = codePathStack[codePathStack.length - 1];
-
- // Checks the current code path segments.
- if (!codePath.currentSegments.some(isReachable)) {
- context.report({message: "Unreachable!", node: node});
- }
- }
- };
-};
-```
-
-See Also:
-[no-unreachable](https://github.com/eslint/eslint/blob/HEAD/lib/rules/no-unreachable.js),
-[no-fallthrough](https://github.com/eslint/eslint/blob/HEAD/lib/rules/no-fallthrough.js),
-[consistent-return](https://github.com/eslint/eslint/blob/HEAD/lib/rules/consistent-return.js)
-
-### To check state of a code path
-
-This example is checking whether or not the parameter `cb` is called in every path.
-Instances of `CodePath` and `CodePathSegment` are shared to every rule.
-So a rule must not modify those instances.
-Please use a map of information instead.
-
-```js
-function hasCb(node, context) {
- if (node.type.indexOf("Function") !== -1) {
- return context.getDeclaredVariables(node).some(function(v) {
- return v.type === "Parameter" && v.name === "cb";
- });
- }
- return false;
-}
-
-function isCbCalled(info) {
- return info.cbCalled;
-}
-
-module.exports = function(context) {
- var funcInfoStack = [];
- var segmentInfoMap = Object.create(null);
-
- return {
- // Checks `cb`.
- "onCodePathStart": function(codePath, node) {
- funcInfoStack.push({
- codePath: codePath,
- hasCb: hasCb(node, context)
- });
- },
- "onCodePathEnd": function(codePath, node) {
- funcInfoStack.pop();
-
- // Checks `cb` was called in every paths.
- var cbCalled = codePath.finalSegments.every(function(segment) {
- var info = segmentInfoMap[segment.id];
- return info.cbCalled;
- });
-
- if (!cbCalled) {
- context.report({
- message: "`cb` should be called in every path.",
- node: node
- });
- }
- },
-
- // Manages state of code paths.
- "onCodePathSegmentStart": function(segment) {
- var funcInfo = funcInfoStack[funcInfoStack.length - 1];
-
- // Ignores if `cb` doesn't exist.
- if (!funcInfo.hasCb) {
- return;
- }
-
- // Initialize state of this path.
- var info = segmentInfoMap[segment.id] = {
- cbCalled: false
- };
-
- // If there are the previous paths, merges state.
- // Checks `cb` was called in every previous path.
- if (segment.prevSegments.length > 0) {
- info.cbCalled = segment.prevSegments.every(isCbCalled);
- }
- },
-
- // Checks reachable or not.
- "CallExpression": function(node) {
- var funcInfo = funcInfoStack[funcInfoStack.length - 1];
-
- // Ignores if `cb` doesn't exist.
- if (!funcInfo.hasCb) {
- return;
- }
-
- // Sets marks that `cb` was called.
- var callee = node.callee;
- if (callee.type === "Identifier" && callee.name === "cb") {
- funcInfo.codePath.currentSegments.forEach(function(segment) {
- var info = segmentInfoMap[segment.id];
- info.cbCalled = true;
- });
- }
- }
- };
-};
-```
-
-See Also:
-[constructor-super](https://github.com/eslint/eslint/blob/HEAD/lib/rules/constructor-super.js),
-[no-this-before-super](https://github.com/eslint/eslint/blob/HEAD/lib/rules/no-this-before-super.js)
-
-## Code Path Examples
-
-### Hello World
-
-```js
-console.log("Hello world!");
-```
-
-![Hello World](../assets/images/code-path-analysis/example-hello-world.svg)
-
-### `IfStatement`
-
-```js
-if (a) {
- foo();
-} else {
- bar();
-}
-```
-
-![`IfStatement`](../assets/images/code-path-analysis/example-ifstatement.svg)
-
-### `IfStatement` (chain)
-
-```js
-if (a) {
- foo();
-} else if (b) {
- bar();
-} else if (c) {
- hoge();
-}
-```
-
-![`IfStatement` (chain)](../assets/images/code-path-analysis/example-ifstatement-chain.svg)
-
-### `SwitchStatement`
-
-```js
-switch (a) {
- case 0:
- foo();
- break;
-
- case 1:
- case 2:
- bar();
- // fallthrough
-
- case 3:
- hoge();
- break;
-}
-```
-
-![`SwitchStatement`](../assets/images/code-path-analysis/example-switchstatement.svg)
-
-### `SwitchStatement` (has `default`)
-
-```js
-switch (a) {
- case 0:
- foo();
- break;
-
- case 1:
- case 2:
- bar();
- // fallthrough
-
- case 3:
- hoge();
- break;
-
- default:
- fuga();
- break;
-}
-```
-
-![`SwitchStatement` (has `default`)](../assets/images/code-path-analysis/example-switchstatement-has-default.svg)
-
-### `TryStatement` (try-catch)
-
-```js
-try {
- foo();
- if (a) {
- throw new Error();
- }
- bar();
-} catch (err) {
- hoge(err);
-}
-last();
-```
-
-It creates the paths from `try` block to `catch` block at:
-
-* `throw` statements.
-* The first throwable node (e.g. a function call) in the `try` block.
-* The end of the `try` block.
-
-![`TryStatement` (try-catch)](../assets/images/code-path-analysis/example-trystatement-try-catch.svg)
-
-### `TryStatement` (try-finally)
-
-```js
-try {
- foo();
- bar();
-} finally {
- fuga();
-}
-last();
-```
-
-If there is not `catch` block, `finally` block has two current segments.
-At this time, `CodePath.currentSegments.length` is `2`.
-One is the normal path, and another is the leaving path (`throw` or `return`).
-
-![`TryStatement` (try-finally)](../assets/images/code-path-analysis/example-trystatement-try-finally.svg)
-
-### `TryStatement` (try-catch-finally)
-
-```js
-try {
- foo();
- bar();
-} catch (err) {
- hoge(err);
-} finally {
- fuga();
-}
-last();
-```
-
-![`TryStatement` (try-catch-finally)](../assets/images/code-path-analysis/example-trystatement-try-catch-finally.svg)
-
-### `WhileStatement`
-
-```js
-while (a) {
- foo();
- if (b) {
- continue;
- }
- bar();
-}
-```
-
-![`WhileStatement`](../assets/images/code-path-analysis/example-whilestatement.svg)
-
-### `DoWhileStatement`
-
-```js
-do {
- foo();
- bar();
-} while (a);
-```
-
-![`DoWhileStatement`](../assets/images/code-path-analysis/example-dowhilestatement.svg)
-
-### `ForStatement`
-
-```js
-for (let i = 0; i < 10; ++i) {
- foo();
- if (b) {
- break;
- }
- bar();
-}
-```
-
-![`ForStatement`](../assets/images/code-path-analysis/example-forstatement.svg)
-
-### `ForStatement` (for ever)
-
-```js
-for (;;) {
- foo();
-}
-bar();
-```
-
-![`ForStatement` (for ever)](../assets/images/code-path-analysis/example-forstatement-for-ever.svg)
-
-### `ForInStatement`
-
-```js
-for (let key in obj) {
- foo(key);
-}
-```
-
-![`ForInStatement`](../assets/images/code-path-analysis/example-forinstatement.svg)
-
-### When there is a function
-
-```js
-function foo(a) {
- if (a) {
- return;
- }
- bar();
-}
-
-foo(false);
-```
-
-It creates two code paths.
-
-* The global's
-
- ![When there is a function](../assets/images/code-path-analysis/example-when-there-is-a-function-g.svg)
-
-* The function's
-
- ![When there is a function](../assets/images/code-path-analysis/example-when-there-is-a-function-f.svg)
+++ /dev/null
----
-title: Change Requests
-layout: doc
-
----
-
-If you'd like to request a change to ESLint, please [create a new issue](https://github.com/eslint/eslint/issues/new/choose) on GitHub. Be sure to include the following information:
-
-1. The version of ESLint you are using.
-2. The problem you want to solve.
-3. Your take on the correct solution to problem.
-
-If you're requesting a change to a rule, it's helpful to include this information as well:
-
-1. What you did.
-1. What you would like to happen.
-1. What actually happened.
-
-Please include as much detail as possible to help us properly address your issue. If we need to triage issues and constantly ask people for more detail, that's time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues.
-
-**Note:** If you just have a question that won't necessarily result in a change to ESLint, such as asking how something works or how to contribute, please use the [mailing list](https://groups.google.com/group/eslint) or [chat](https://eslint.org/chat) instead of filing an issue.
+++ /dev/null
----
-title: Contributing
-layout: doc
-eleventyNavigation:
- key: contributing
- parent: developer guide
- title: Contributing
- order: 10
-
----
-
-One of the great things about open source projects is that anyone can contribute in any number of meaningful ways. ESLint couldn't exist without the help of the many contributors it's had since the project began, and we want you to feel like you can contribute and make a difference as well.
-
-This guide is intended for anyone who wants to contribute to an ESLint project. Please read it carefully as it answers a lot of the questions many newcomers have when first working with our projects.
-
-## Read the [Code of Conduct](https://eslint.org/conduct)
-
-ESLint welcomes contributions from everyone and adheres to the [OpenJS Foundation Code of Conduct](https://eslint.org/conduct). We kindly request that you read over our code of conduct before contributing.
-
-## [Bug Reporting](reporting-bugs)
-
-Think you found a problem? We'd love to hear about it. This section explains how to submit a bug, the type of information we need to properly verify it, and the overall process.
-
-## Proposing a [New Rule](new-rules)
-
-We get a lot of proposals for new rules in ESLint. This section explains how we determine which rules are accepted and what information you should provide to help us evaluate your proposal.
-
-## Proposing a [Rule Change](rule-changes)
-
-Want to make a change to an existing rule? This section explains the process and how we evaluate such proposals.
-
-## Requesting a [Change](changes)
-
-If you'd like to request a change other than a bug fix or new rule, this section explains that process.
-
-## Reporting a security vulnerability
-
-To report a security vulnerability in ESLint, please use our [HackerOne program](https://hackerone.com/eslint).
-
-## [Working on Issues](working-on-issues)
-
-Have some extra time and want to contribute? This section talks about the process of working on issues.
-
-## Submitting a [Pull Request](pull-requests)
-
-We're always looking for contributions from the community. This section explains the requirements for pull requests and the process of contributing code.
-
-## Signing the CLA
-
-In order to submit code or documentation to an ESLint project, you will need to electronically sign our Contributor License Agreement. The CLA is the commonly used Apache-style template, and is you giving us permission to use your contribution. You only need to sign the CLA once for any OpenJS Foundation projects that use EasyCLA. You will be asked to sign the CLA in the first pull request you open.
+++ /dev/null
----
-title: New Rules
-layout: doc
-
----
-
-ESLint is all about rules. For most of the project's lifetime, we've had over 200 rules, and that list continues to grow. However, we can't just accept any proposed rule because all rules need to work cohesively together. As such, we have some guidelines around which rules can be part of the ESLint core and which are better off as custom rules and plugins.
-
-**Note:** As of 2020, we only accept rules related to new ECMAScript features. We prefer that new rules be implemented in plugins.
-
-## Core Rule Guidelines
-
-In general, ESLint core rules must be:
-
-1. **Widely applicable.** The rules we distribute need to be of importance to a large number of developers. Individual preferences for uncommon patterns are not supported.
-1. **Generic.** Rules cannot be so specific that users will have trouble understanding when to use them. A rule is typically too specific if describing what it does requires more than two "and"s (if a and b and c and d, then this rule warns).
-1. **Atomic.** Rules must function completely on their own. Rules are expressly forbidden from knowing about the state or presence of other rules.
-1. **Unique.** No two rules can produce the same warning. Overlapping rules confuse end users and there is an expectation that core ESLint rules do not overlap.
-1. **Library agnostic.** Rules must be based solely on JavaScript runtime environments and not on specific libraries or frameworks. For example, core rules shouldn't only apply if you're using jQuery but we may have some rules that apply only if you're using Node.js (a runtime).
-1. **No conflicts.** No rule must directly conflict with another rule. For example, if we have a rule requiring semicolons, we cannot also have a rule disallowing semicolons (which is why we have one rule, `semi`, that does both).
-
-Even though these are the formal criteria for inclusion, each rule is evaluated on its own basis.
-
-## Proposing a Rule
-
-If you want to propose a new rule, please see how to [create a pull request](/docs/developer-guide/contributing/pull-requests) or submit an issue by filling out a [new rule template](https://github.com/eslint/eslint/issues/new/choose).
-
-We need all of this information in order to determine whether or not the rule is a good core rule candidate.
-
-## Accepting a Rule
-
-In order for a rule to be accepted in the ESLint core, it must:
-
-1. Fulfill all the criteria listed in the "Core Rule Guidelines" section
-1. Have an ESLint team member champion inclusion of the rule
-1. Be related to an ECMAScript feature that has reached stage 4 in the preceding 12 months
-
-Keep in mind that we have over 200 rules, and that is daunting both for end users and the ESLint team (who has to maintain them). As such, any new rules must be deemed of high importance to be considered for inclusion in ESLint.
-
-## Implementation is Your Responsibility
-
-The ESLint team doesn't implement new rules that are suggested by users because we have a limited number of people and need to focus on the overall roadmap. Once a rule is accepted, you are responsible for implementing and documenting the rule. You may, alternately, recruit another person to help you implement the rule. The ESLint team member who championed the rule is your resource to help guide you through the rest of this process.
-
-## Alternative: Creating Your Own Rules
-
-Remember that ESLint is completely pluggable, which means you can create your own rules and distribute them using plugins. We did this on purpose because we don't want to be the gatekeepers for all possible rules. Even if we don't accept a rule into the core, that doesn't mean you can't have the exact rule that you want. See the [working with rules](../working-with-rules) and [working with plugins](../working-with-plugins) documentation for more information.
+++ /dev/null
----
-title: Pull Requests
-layout: doc
-
----
-
-If you want to contribute to an ESLint repo, please use a GitHub pull request. This is the fastest way for us to evaluate your code and to merge it into the code base. Please don't file an issue with snippets of code. Doing so means that we need to manually merge the changes in and update any appropriate tests. That decreases the likelihood that your code is going to get included in a timely manner. Please use pull requests.
-
-## Getting Started
-
-If you'd like to work on a pull request and you've never submitted code before, follow these steps:
-
-1. Set up a [development environment](../development-environment).
-1. If you want to implement a breaking change or a change to the core, ensure there's an issue that describes what you're doing and the issue has been accepted. You can create a new issue or just indicate you're [working on an existing issue](working-on-issues). Bug fixes, documentation changes, and other pull requests do not require an issue.
-
-After that, you're ready to start working on code.
-
-## Working with Code
-
-The process of submitting a pull request is fairly straightforward and generally follows the same pattern each time:
-
-1. [Create a new branch](#step1)
-2. [Make your changes](#step2)
-3. [Rebase onto upstream](#step3)
-4. [Run the tests](#step4)
-5. [Double check your submission](#step5)
-6. [Push your changes](#step6)
-7. [Submit the pull request](#step7)
-
-Details about each step are found below.
-
-### Step 1: Create a new branch<a name="step1"></a>
-
-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:
-
-```shell
-git checkout -b issue1234
-```
-
-You should do all of your development for the issue in this branch.
-
-**Note:** Do not combine fixes for multiple issues into one branch. Use a separate branch for each issue you're working on.
-
-### Step 2: Make your changes<a name="step2"></a>
-
-Make the changes to the code and tests, following the [code conventions](../code-conventions) as you go. Once you have finished, commit the changes to your branch:
-
-```shell
-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:
-
-```txt
-tag: Short description of what you did
-
-Longer description here if necessary
-
-Fixes #1234
-```
-
-The first line of the commit message (the summary) must have a specific format. This format is checked by our build tools.
-
-The `tag` is one of the following:
-
-* `fix` - for a bug fix.
-* `feat` - either for a backwards-compatible enhancement or for a rule change that adds reported problems.
-* `fix!` - for a backwards-incompatible bug fix.
-* `feat!` - for a backwards-incompatible enhancement or feature.
-* `docs` - changes to documentation only.
-* `chore` - for changes that aren't user-facing.
-* `build` - changes to build process only.
-* `refactor` - a change that doesn't affect APIs or user experience.
-* `test` - just changes to test files.
-* `ci` - changes to our CI configuration files and scripts.
-* `perf` - a code change that improves performance.
-
-Use the [labels of the issue you are working on](working-on-issues#issue-labels) to determine the best tag.
-
-The message summary should be a one-sentence description of the change, and it must be 72 characters in length or shorter. If the pull request addresses an issue, then the issue number should be mentioned in the body of the commit message in the format `Fixes #1234`. If the commit doesn't completely fix the issue, then use `Refs #1234` instead of `Fixes #1234`.
-
-Here are some good commit message summary examples:
-
-```txt
-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
-```
-
-The commit message format is important because these messages are used to create a changelog for each release. The tag and issue number help to create more consistent and useful changelogs.
-
-### Step 3: Rebase onto upstream<a name="step3"></a>
-
-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.
-
-```shell
-git fetch upstream
-git rebase upstream/main
-```
-
-### Step 4: Run the tests<a name="step4"></a>
-
-After rebasing, be sure to run all of the tests once again to make sure nothing broke:
-
-```shell
-npm test
-```
-
-If there are any failing tests, update your code until all tests pass.
-
-### Step 5: Double check your submission<a name="step5"></a>
-
-With your code ready to go, this is a good time to double-check your submission to make sure it follows our conventions. Here are the things to check:
-
-* Make sure your commit is formatted correctly.
-* The pull request must have a description. The description should explain what you did and how its effects can be seen.
-* The commit message is properly formatted.
-* The change introduces no functional regression. Be sure to run `npm test` to verify your changes before submitting a pull request.
-* Make separate pull requests for unrelated changes. Large pull requests with multiple unrelated changes may be closed without merging.
-* All changes must be accompanied by tests, even if the feature you're working on previously had no tests.
-* All user-facing changes must be accompanied by appropriate documentation.
-* Follow the [Code Conventions](../code-conventions).
-
-### Step 6: Push your changes<a name="step6"></a>
-
-Next, push your changes to your clone:
-
-```shell
-git push origin issue1234
-```
-
-If you are unable to push because some references are old, do a forced push instead:
-
-```shell
-git push -f origin issue1234
-```
-
-### Step 7: Send the pull request<a name="step7"></a>
-
-Now you're ready to send the pull request. Go to your ESLint fork and then follow the [GitHub documentation](https://help.github.com/articles/creating-a-pull-request) on how to send a pull request.
-
-In order to submit code or documentation to an ESLint project, you’ll be asked to sign our CLA when you send your first pull request. (Read more about the Open JS Foundation CLA process at <https://cla.openjsf.org/>.)
-
-## Following Up
-
-Once your pull request is sent, it's time for the team to review it. As such, please make sure to:
-
-1. Monitor the status of the Travis CI build for your pull request. If it fails, please investigate why. We cannot merge pull requests that fail Travis for any reason.
-1. Respond to comments left on the pull request from team members. Remember, we want to help you land your code, so please be receptive to our feedback.
-1. We may ask you to make changes, rebase, or squash your commits.
-
-### Updating the Commit Message
-
-If your commit message is in the incorrect format, you'll be asked to update it. You can do so via:
-
-```shell
-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:
-
-```shell
-git push origin issue1234 -f
-```
-
-### Updating the Code
-
-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:
-
-```shell
-git add -A
-git commit
-git push origin issue1234
-```
-
-When updating the code, it's usually better to add additional commits to your branch rather than amending the original commit, because reviewers can easily tell which changes were made in response to a particular review. When we merge pull requests, we will squash all the commits from your branch into a single commit on the `main` branch.
-
-The commit messages in subsequent commits do not need to be in any specific format because these commits do not show up in the changelog.
-
-### Rebasing
-
-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) and then you can rebase using these commands:
-
-```shell
-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:
-
-```shell
-git push origin issue1234 -f
-```
+++ /dev/null
----
-title: Reporting Bugs
-layout: doc
-
----
-
-If you think you've found a bug in ESLint, please [create a new issue](https://github.com/eslint/eslint/issues/new/choose) or a [pull request](/docs/developer-guide/contributing/pull-requests) on GitHub.
-
-Please include as much detail as possible to help us properly address your issue. If we need to triage issues and constantly ask people for more detail, that's time taken away from actually fixing issues. Help us be as efficient as possible by including a lot of detail in your issues.
-
-**Note:** If you just have a question that won't necessarily result in a change to ESLint, such as asking how something works or how to contribute, please use the [mailing list](https://groups.google.com/group/eslint) or [chat](https://eslint.org/chat) instead of filing an issue.
+++ /dev/null
----
-title: Rule Changes
-layout: doc
-
----
-
-Occasionally, a core ESLint rule needs to be changed. This is not necessarily a bug, but rather, an enhancement that makes a rule more configurable. In those situations, we will consider making changes to rules.
-
-## Proposing a Rule Change
-
-To propose a change to an existing rule, [create a pull request](/docs/developer-guide/contributing/pull-requests) or [new issue](https://github.com/eslint/eslint/issues/new/choose) and fill out the template.
-
-We need all of this information in order to determine whether or not the change is a good candidate for inclusion.
-
-## Accepting a Rule Change
-
-In order for a rule change to be accepted into ESLint, it must:
-
-1. Adhere to the [Core Rule Guidelines](new-rules#core-rule-guidelines)
-1. Have an ESLint team member champion the change
-1. Be important enough that rule is deemed incomplete without this change
-
-## Implementation is Your Responsibility
-
-The ESLint team doesn't implement rule changes that are suggested by users because we have a limited number of people and need to focus on the overall roadmap. Once a rule change is accepted, you are responsible for implementing and documenting it. You may, alternately, recruit another person to help you. The ESLint team member who championed the rule is your resource to help guide you through the rest of this process.
+++ /dev/null
----
-title: Working on Issues
-layout: doc
-
----
-
-Our public [issues tracker](https://github.com/eslint/eslint/issues) lists all of the things we plan on doing as well as suggestions from the community. Before starting to work on an issue, be sure you read through the rest of this page.
-
-## Issue Labels
-
-We use labels to indicate the status of issues. The most complete documentation on the labels is found in the [Maintainer Guide](https://eslint.org/docs/maintainer-guide/issues.html#when-an-issue-is-opened), but most contributors should find the information on this page sufficient. The most important questions that labels can help you, as a contributor, answer are:
-
-1. Is this issue available for me to work on? If you have little or no experience contributing to ESLint, the [`good first issue`](https://github.com/eslint/eslint/labels/good%20first%20issue) label marks appropriate issues. Otherwise, the [`help wanted`](https://github.com/eslint/eslint/labels/help%20wanted) label is an invitation to work on the issue. If you have more experience, you can try working on other issues labeled [`accepted`](https://github.com/eslint/eslint/labels/accepted). Conversely, issues not yet ready to work on are labeled `triage`, `evaluating`, and/or `needs bikeshedding`, and issues that cannot currently be worked on because of something else, such as a bug in a dependency, are labeled `blocked`.
-1. What is this issue about? Labels describing the nature of issues include `bug`, `enhancement`, `feature`, `question`, `rule`, `documentation`, `core`, `build`, `cli`, `infrastructure`, `breaking`, and `chore`. These are documented in the [Maintainer Guide](https://eslint.org/docs/maintainer-guide/issues.html#types-of-issues).
-1. What is the priority of this issue? Because we have a lot of issues, we prioritize certain issues above others. The following is the list of priorities, from highest to lowest:
-
- 1. **Bugs** - problems with the project are actively affecting users. We want to get these resolved as quickly as possible.
- 1. **Documentation** - documentation issues are a type of bug in that they actively affect current users. As such, we want to address documentation issues as quickly as possible.
- 1. **Features** - new functionality that will aid users in the future.
- 1. **Enhancements** - requested improvements for existing functionality.
- 1. **Other** - anything else.
-
- Some issues have had monetary rewards attached to them. Those are labeled `bounty`. Bounties are assigned via [BountySource](https://www.bountysource.com/teams/eslint/issues).
-
-## Starting Work
-
-If you're going to work on an issue, please add a comment to that issue saying so and indicating when you think you will complete it. It will help us to avoid duplication of effort. Some examples of good comments are:
-
-* "I'll take a look at this over the weekend."
-* "I'm going to do this, give me two weeks."
-* "Working on this" (as in, I'm working on it right now)
-
-If an issue has already been claimed by someone, please be respectful of that person's desire to complete the work and don't work on it unless you verify that they are no longer interested.
-
-If you find you can't finish the work, then simply add a comment letting people know, for example:
-
-* "Sorry, it looks like I don't have time to do this."
-* "I thought I knew enough to fix this, but it turns out I don't."
-
-No one will blame you for backing out of an issue if you are unable to complete it. We just want to keep the process moving along as efficiently as possible.
+++ /dev/null
----
-title: Development Environment
-layout: doc
-eleventyNavigation:
- key: set up a development environment
- parent: developer guide
- title: Set Up a Development Environment
- order: 2
-
----
-
-ESLint has a very lightweight development environment that makes updating code fast and easy. This is a step-by-step guide to setting up a local development environment that will let you contribute back to the project.
-
-## Step 1: Install Node.js
-
-Go to <https://nodejs.org/> to download and install the latest stable version for your operating system.
-
-Most of the installers already come with [npm](https://www.npmjs.com/) but if for some reason npm doesn't work on your system, you can install it manually using the instructions on the site.
-
-## Step 2: Fork and checkout your own ESLint repository
-
-Go to <https://github.com/eslint/eslint> and click the "Fork" button. Follow the [GitHub documentation](https://help.github.com/articles/fork-a-repo) for forking and cloning.
-
-Once you've cloned the repository, run `npm install` to get all the necessary dependencies:
-
-```shell
-cd eslint
-npm install
-```
-
-You must be connected to the Internet for this step to work. You'll see a lot of utilities being downloaded.
-
-## Step 3: Add the upstream source
-
-The *upstream source* is the main ESLint repository where active development happens. While you won't have push access to upstream, you will have pull access, allowing you to pull in the latest code whenever you want.
-
-To add the upstream source for ESLint, run the following in your repository:
-
-```shell
-git remote add upstream git@github.com:eslint/eslint.git
-```
-
-Now, the remote `upstream` points to the upstream source.
-
-## Step 4: Install the Yeoman Generator
-
-[Yeoman](http://yeoman.io) is a scaffold generator that ESLint uses to help streamline development of new rules. If you don't already have Yeoman installed, you can install it via npm:
-
-```shell
-npm install -g yo
-```
-
-Then, you can install the ESLint Yeoman generator:
-
-```shell
-npm install -g generator-eslint
-```
-
-Please see the [generator documentation](https://github.com/eslint/generator-eslint) for instructions on how to use it.
-
-## Step 5: Run the tests
-
-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:
-
-```shell
-npm test
-```
-
-The testing takes a few minutes to complete. If any tests fail, that likely means one or more parts of the environment setup didn't complete correctly. The upstream tests always pass.
-
-## Reference Information
-
-### Workflow
-
-Once you have your development environment installed, you can make and submit changes to the ESLint source files. Doing this successfully requires careful adherence to our [pull-request submission workflow](contributing/pull-requests).
-
-### Build Scripts
-
-ESLint has several build scripts that help with various parts of development.
-
-#### npm test
-
-The primary script to use is `npm test`, which does several things:
-
-1. Lints all JavaScript (including tests) and JSON
-1. Runs all tests on Node.js
-1. Checks code coverage targets
-1. Generates `build/eslint.js` for use in a browser
-1. Runs a subset of tests in PhantomJS
-
-Be sure to run this after making changes and before sending a pull request with your changes.
-
-**Note:** The full code coverage report is output into `/coverage`.
-
-#### npm run lint
-
-Runs just the JavaScript and JSON linting on the repository.
-
-#### npm run webpack
-
-Generates `build/eslint.js`, a version of ESLint for use in the browser.
+++ /dev/null
----
-title: Developer Guide
-layout: doc
-eleventyNavigation:
- key: developer guide
- title: Developer Guide
- order: 2
-
----
-
-This guide is intended for those who wish to:
-
-* Contribute code to ESLint
-* Create their own rules for ESLint
-
-In order to work with ESLint as a developer, it's recommended that:
-
-* You know JavaScript, since ESLint is written in JavaScript.
-* You have some familiarity with Node.js, since ESLint runs on it.
-* You're comfortable with command-line programs.
-* You understand unit tests and why they're important.
-
-If that sounds like you, then continue reading to get started.
-
-## Section 1: Get the [Source Code](source-code)
-
-Before you can get started, you'll need to get a copy of the ESLint source code. This section explains how to do that and a little about the source code structure.
-
-## Section 2: Set up a [Development Environment](development-environment)
-
-Developing for ESLint is a bit different than running it on the command line. This section shows you how to set up a development environment and get you ready to write code.
-
-## Section 3: Run the [Unit Tests](unit-tests)
-
-There are a lot of unit tests included with ESLint to make sure that we're keeping on top of code quality. This section explains how to run the unit tests.
-
-## Section 4: [Working with Rules](working-with-rules)
-
-You're finally ready to start working with rules. You may want to fix an existing rule or create a new one. This section explains how to do all of that.
-
-## Section 5: [Working with Plugins](working-with-plugins)
-
-You've developed library-specific rules for ESLint and you want to share them with the community. You can publish an ESLint plugin on npm.
-
-## Section 6: [Working with Custom Parsers](working-with-custom-parsers)
-
-If you aren't going to use the default parser of ESLint, this section explains about using custom parsers.
-
-## Section 7: [Node.js API](nodejs-api)
-
-If you're interested in writing a tool that uses ESLint, then you can use the Node.js API to get programmatic access to functionality.
-
-## Section 8: [Contributing](contributing/)
-
-Once you've made changes that you want to share with the community, the next step is to submit those changes back via a pull request.
+++ /dev/null
----
-title: Node.js API
-layout: doc
-eleventyNavigation:
- key: node.js api
- parent: developer guide
- title: Node.js API
- order: 9
-
----
-
-While ESLint is designed to be run on the command line, it's possible to use ESLint programmatically through the Node.js API. The purpose of the Node.js API is to allow plugin and tool authors to use the ESLint functionality directly, without going through the command line interface.
-
-**Note:** Use undocumented parts of the API at your own risk. Only those parts that are specifically mentioned in this document are approved for use and will remain stable and reliable. Anything left undocumented is unstable and may change or be removed at any point.
-
-## ESLint class
-
-The `ESLint` class is the primary class to use in Node.js applications.
-
-This class depends on the Node.js `fs` module and the file system, so you cannot use it in browsers. If you want to lint code on browsers, use the [Linter](#linter) class instead.
-
-Here's a simple example of using the `ESLint` class:
-
-```js
-const { ESLint } = require("eslint");
-
-(async function main() {
- // 1. Create an instance.
- const eslint = new ESLint();
-
- // 2. Lint files.
- const results = await eslint.lintFiles(["lib/**/*.js"]);
-
- // 3. Format the results.
- const formatter = await eslint.loadFormatter("stylish");
- const resultText = formatter.format(results);
-
- // 4. Output it.
- console.log(resultText);
-})().catch((error) => {
- process.exitCode = 1;
- console.error(error);
-});
-```
-
-And here is an example that autofixes lint problems:
-
-```js
-const { ESLint } = require("eslint");
-
-(async function main() {
- // 1. Create an instance with the `fix` option.
- const eslint = new ESLint({ fix: true });
-
- // 2. Lint files. This doesn't modify target files.
- const results = await eslint.lintFiles(["lib/**/*.js"]);
-
- // 3. Modify the files with the fixed code.
- await ESLint.outputFixes(results);
-
- // 4. Format the results.
- const formatter = await eslint.loadFormatter("stylish");
- const resultText = formatter.format(results);
-
- // 5. Output it.
- console.log(resultText);
-})().catch((error) => {
- process.exitCode = 1;
- console.error(error);
-});
-```
-
-### ◆ new ESLint(options)
-
-```js
-const eslint = new ESLint(options);
-```
-
-Create a new `ESLint` instance.
-
-#### Parameters
-
-The `ESLint` constructor takes an `options` object. If you omit the `options` object then it uses default values for all options. The `options` object has the following properties.
-
-##### File Enumeration
-
-* `options.cwd` (`string`)<br>
- Default is `process.cwd()`. The working directory. This must be an absolute path.
-* `options.errorOnUnmatchedPattern` (`boolean`)<br>
- Default is `true`. Unless set to `false`, the [`eslint.lintFiles()`][eslint-lintfiles] method will throw an error when no target files are found.
-* `options.extensions` (`string[] | null`)<br>
- Default is `null`. If you pass directory paths to the [`eslint.lintFiles()`][eslint-lintfiles] method, ESLint checks the files in those directories that have the given extensions. For example, when passing the `src/` directory and `extensions` is `[".js", ".ts"]`, ESLint will lint `*.js` and `*.ts` files in `src/`. If `extensions` is `null`, ESLint checks `*.js` files and files that match `overrides[].files` patterns in your configuration.<br>**Note:** This option only applies when you pass directory paths to the [`eslint.lintFiles()`][eslint-lintfiles] method. If you pass glob patterns like `lib/**/*`, ESLint will lint all files matching the glob pattern regardless of extension.
-* `options.globInputPaths` (`boolean`)<br>
- Default is `true`. If `false` is present, the [`eslint.lintFiles()`][eslint-lintfiles] method doesn't interpret glob patterns.
-* `options.ignore` (`boolean`)<br>
- Default is `true`. If `false` is present, the [`eslint.lintFiles()`][eslint-lintfiles] method doesn't respect `.eslintignore` files or `ignorePatterns` in your configuration.
-* `options.ignorePath` (`string | null`)<br>
- Default is `null`. The path to a file ESLint uses instead of `$CWD/.eslintignore`. If a path is present and the file doesn't exist, this constructor will throw an error.
-
-##### Linting
-
-* `options.allowInlineConfig` (`boolean`)<br>
- Default is `true`. If `false` is present, ESLint suppresses directive comments in source code. If this option is `false`, it overrides the `noInlineConfig` setting in your configurations.
-* `options.baseConfig` (`ConfigData | null`)<br>
- Default is `null`. [Configuration object], extended by all configurations used with this instance. You can use this option to define the default settings that will be used if your configuration files don't configure it.
-* `options.overrideConfig` (`ConfigData | null`)<br>
- Default is `null`. [Configuration object], overrides all configurations used with this instance. You can use this option to define the settings that will be used even if your configuration files configure it.
-* `options.overrideConfigFile` (`string | null`)<br>
- Default is `null`. The path to a configuration file, overrides all configurations used with this instance. The `options.overrideConfig` option is applied after this option is applied.
-* `options.plugins` (`Record<string, Plugin> | null`)<br>
- Default is `null`. The plugin implementations that ESLint uses for the `plugins` setting of your configuration. This is a map-like object. Those keys are plugin IDs and each value is implementation.
-* `options.reportUnusedDisableDirectives` (`"error" | "warn" | "off" | null`)<br>
- Default is `null`. The severity to report unused eslint-disable directives. If this option is a severity, it overrides the `reportUnusedDisableDirectives` setting in your configurations.
-* `options.resolvePluginsRelativeTo` (`string` | `null`)<br>
- Default is `null`. The path to a directory where plugins should be resolved from. If `null` is present, ESLint loads plugins from the location of the configuration file that contains the plugin setting. If a path is present, ESLint loads all plugins from there.
-* `options.rulePaths` (`string[]`)<br>
- Default is `[]`. An array of paths to directories to load custom rules from.
-* `options.useEslintrc` (`boolean`)<br>
- Default is `true`. If `false` is present, ESLint doesn't load configuration files (`.eslintrc.*` files). Only the configuration of the constructor options is valid.
-
-##### Autofix
-
-* `options.fix` (`boolean | (message: LintMessage) => boolean`)<br>
- Default is `false`. If `true` is present, the [`eslint.lintFiles()`][eslint-lintfiles] and [`eslint.lintText()`][eslint-linttext] methods work in autofix mode. If a predicate function is present, the methods pass each lint message to the function, then use only the lint messages for which the function returned `true`.
-* `options.fixTypes` (`("directive" | "problem" | "suggestion" | "layout")[] | null`)<br>
- Default is `null`. The types of the rules that the [`eslint.lintFiles()`][eslint-lintfiles] and [`eslint.lintText()`][eslint-linttext] methods use for autofix.
-
-##### Cache-related
-
-* `options.cache` (`boolean`)<br>
- Default is `false`. If `true` is present, the [`eslint.lintFiles()`][eslint-lintfiles] method caches lint results and uses it if each target file is not changed. Please mind that ESLint doesn't clear the cache when you upgrade ESLint plugins. In that case, you have to remove the cache file manually. The [`eslint.lintText()`][eslint-linttext] method doesn't use caches even if you pass the `options.filePath` to the method.
-* `options.cacheLocation` (`string`)<br>
- Default is `.eslintcache`. The [`eslint.lintFiles()`][eslint-lintfiles] method writes caches into this file.
-* `options.cacheStrategy` (`string`)<br>
- Default is `"metadata"`. Strategy for the cache to use for detecting changed files. Can be either `"metadata"` or `"content"`.
-
-### ◆ eslint.lintFiles(patterns)
-
-```js
-const results = await eslint.lintFiles(patterns);
-```
-
-This method lints the files that match the glob patterns and then returns the results.
-
-#### Parameters
-
-* `patterns` (`string | string[]`)<br>
- The lint target files. This can contain any of file paths, directory paths, and glob patterns.
-
-#### Return Value
-
-* (`Promise<LintResult[]>`)<br>
- The promise that will be fulfilled with an array of [LintResult] objects.
-
-### ◆ eslint.lintText(code, options)
-
-```js
-const results = await eslint.lintText(code, options);
-```
-
-This method lints the given source code text and then returns the results.
-
-By default, this method uses the configuration that applies to files in the current working directory (the `cwd` constructor option). If you want to use a different configuration, pass `options.filePath`, and ESLint will load the same configuration that [`eslint.lintFiles()`][eslint-lintfiles] would use for a file at `options.filePath`.
-
-If the `options.filePath` value is configured to be ignored, this method returns an empty array. If the `options.warnIgnored` option is set along with the `options.filePath` option, this method returns a [LintResult] object. In that case, the result may contain a warning that indicates the file was ignored.
-
-#### Parameters
-
-The second parameter `options` is omittable.
-
-* `code` (`string`)<br>
- The source code text to check.
-* `options.filePath` (`string`)<br>
- Optional. The path to the file of the source code text. If omitted, the `result.filePath` becomes the string `"<text>"`.
-* `options.warnIgnored` (`boolean`)<br>
- Optional. If `true` is present and the `options.filePath` is a file ESLint should ignore, this method returns a lint result contains a warning message.
-
-#### Return Value
-
-* (`Promise<LintResult[]>`)<br>
- The promise that will be fulfilled with an array of [LintResult] objects. This is an array (despite there being only one lint result) in order to keep the interfaces between this and the [`eslint.lintFiles()`][eslint-lintfiles] method similar.
-
-### ◆ eslint.getRulesMetaForResults(results)
-
-```js
-const results = await eslint.lintFiles(patterns);
-const rulesMeta = eslint.getRulesMetaForResults(results);
-```
-
-This method returns an object containing meta information for each rule that triggered a lint error in the given `results`.
-
-#### Parameters
-
-* `results` (`LintResult[]`)<br>
- An array of [LintResult] objects returned from a call to `ESLint#lintFiles()` or `ESLint#lintText()`.
-
-#### Return Value
-
-* (`Object`)<br>
- An object whose property names are the rule IDs from the `results` and whose property values are the rule's meta information (if available).
-
-### ◆ eslint.calculateConfigForFile(filePath)
-
-```js
-const config = await eslint.calculateConfigForFile(filePath);
-```
-
-This method calculates the configuration for a given file, which can be useful for debugging purposes.
-
-* It resolves and merges `extends` and `overrides` settings into the top level configuration.
-* It resolves the `parser` setting to absolute paths.
-* It normalizes the `plugins` setting to align short names. (e.g., `eslint-plugin-foo` → `foo`)
-* It adds the `processor` setting if a legacy file extension processor is matched.
-* It doesn't interpret the `env` setting to the `globals` and `parserOptions` settings, so the result object contains the `env` setting as is.
-
-#### Parameters
-
-* `filePath` (`string`)<br>
- The path to the file whose configuration you would like to calculate. Directory paths are forbidden because ESLint cannot handle the `overrides` setting.
-
-#### Return Value
-
-* (`Promise<Object>`)<br>
- The promise that will be fulfilled with a configuration object.
-
-### ◆ eslint.isPathIgnored(filePath)
-
-```js
-const isPathIgnored = await eslint.isPathIgnored(filePath);
-```
-
-This method checks if a given file is ignored by your configuration.
-
-#### Parameters
-
-* `filePath` (`string`)<br>
- The path to the file you want to check.
-
-#### Return Value
-
-* (`Promise<boolean>`)<br>
- The promise that will be fulfilled with whether the file is ignored or not. If the file is ignored, then it will return `true`.
-
-### ◆ eslint.loadFormatter(nameOrPath)
-
-```js
-const formatter = await eslint.loadFormatter(nameOrPath);
-```
-
-This method loads a formatter. Formatters convert lint results to a human- or machine-readable string.
-
-#### Parameters
-
-* `nameOrPath` (`string | undefined`)<br>
- The path to the file you want to check. The following values are allowed:
- * `undefined`. In this case, loads the `"stylish"` built-in formatter.
- * A name of [built-in formatters][builtin-formatters].
- * A name of [third-party formatters][third-party-formatters]. For examples:
- * `"foo"` will load `eslint-formatter-foo`.
- * `"@foo"` will load `@foo/eslint-formatter`.
- * `"@foo/bar"` will load `@foo/eslint-formatter-bar`.
- * A path to the file that defines a formatter. The path must contain one or more path separators (`/`) in order to distinguish if it's a path or not. For example, start with `./`.
-
-#### Return Value
-
-* (`Promise<LoadedFormatter>`)<br>
- The promise that will be fulfilled with a [LoadedFormatter] object.
-
-### ◆ ESLint.version
-
-```js
-const version = ESLint.version;
-```
-
-The version string of ESLint. E.g. `"7.0.0"`.
-
-This is a static property.
-
-### ◆ ESLint.outputFixes(results)
-
-```js
-await ESLint.outputFixes(results);
-```
-
-This method writes code modified by ESLint's autofix feature into its respective file. If any of the modified files don't exist, this method does nothing.
-
-This is a static method.
-
-#### Parameters
-
-* `results` (`LintResult[]`)<br>
- The [LintResult] objects to write.
-
-#### Return Value
-
-* (`Promise<void>`)<br>
- The promise that will be fulfilled after all files are written.
-
-### ◆ ESLint.getErrorResults(results)
-
-```js
-const filteredResults = ESLint.getErrorResults(results);
-```
-
-This method copies the given results and removes warnings. The returned value contains only errors.
-
-This is a static method.
-
-#### Parameters
-
-* `results` (`LintResult[]`)<br>
- The [LintResult] objects to filter.
-
-#### Return Value
-
-* (`LintResult[]`)<br>
- The filtered [LintResult] objects.
-
-### ◆ LintResult type
-
-The `LintResult` value is the information of the linting result of each file. The [`eslint.lintFiles()`][eslint-lintfiles] and [`eslint.lintText()`][eslint-linttext] methods return it. It has the following properties:
-
-* `filePath` (`string`)<br>
- The absolute path to the file of this result. This is the string `"<text>"` if the file path is unknown (when you didn't pass the `options.filePath` option to the [`eslint.lintText()`][eslint-linttext] method).
-* `messages` (`LintMessage[]`)<br>
- The array of [LintMessage] objects.
-* `suppressedMessages` (`SuppressedLintMessage[]`)<br>
- The array of [SuppressedLintMessage] objects.
-* `fixableErrorCount` (`number`)<br>
- The number of errors that can be fixed automatically by the `fix` constructor option.
-* `fixableWarningCount` (`number`)<br>
- The number of warnings that can be fixed automatically by the `fix` constructor option.
-* `errorCount` (`number`)<br>
- The number of errors. This includes fixable errors and fatal errors.
-* `fatalErrorCount` (`number`)<br>
- The number of fatal errors.
-* `warningCount` (`number`)<br>
- The number of warnings. This includes fixable warnings.
-* `output` (`string | undefined`)<br>
- The modified source code text. This property is undefined if any fixable messages didn't exist.
-* `source` (`string | undefined`)<br>
- The original source code text. This property is undefined if any messages didn't exist or the `output` property exists.
-* `usedDeprecatedRules` (`{ ruleId: string; replacedBy: string[] }[]`)<br>
- The information about the deprecated rules that were used to check this file.
-
-### ◆ LintMessage type
-
-The `LintMessage` value is the information of each linting error. The `messages` property of the [LintResult] type contains it. It has the following properties:
-
-* `ruleId` (`string` | `null`)<br>
- The rule name that generates this lint message. If this message is generated by the ESLint core rather than rules, this is `null`.
-* `severity` (`1 | 2`)<br>
- The severity of this message. `1` means warning and `2` means error.
-* `fatal` (`boolean | undefined`)<br>
- `true` if this is a fatal error unrelated to a rule, like a parsing error.
-* `message` (`string`)<br>
- The error message.
-* `line` (`number | undefined`)<br>
- The 1-based line number of the begin point of this message.
-* `column` (`number | undefined`)<br>
- The 1-based column number of the begin point of this message.
-* `endLine` (`number | undefined`)<br>
- The 1-based line number of the end point of this message. This property is undefined if this message is not a range.
-* `endColumn` (`number | undefined`)<br>
- The 1-based column number of the end point of this message. This property is undefined if this message is not a range.
-* `fix` (`EditInfo | undefined`)<br>
- The [EditInfo] object of autofix. This property is undefined if this message is not fixable.
-* `suggestions` (`{ desc: string; fix: EditInfo }[] | undefined`)<br>
- The list of suggestions. Each suggestion is the pair of a description and an [EditInfo] object to fix code. API users such as editor integrations can choose one of them to fix the problem of this message. This property is undefined if this message doesn't have any suggestions.
-
-### ◆ SuppressedLintMessage type
-
-The `SuppressedLintMessage` value is the information of each suppressed linting error. The `suppressedMessages` property of the [LintResult] type contains it. It has the following properties:
-
-* `ruleId` (`string` | `null`)<br>
- Same as `ruleId` in [LintMessage] type.
-* `severity` (`1 | 2`)<br>
- Same as `severity` in [LintMessage] type.
-* `fatal` (`boolean | undefined`)<br>
- Same as `fatal` in [LintMessage] type.
-* `message` (`string`)<br>
- Same as `message` in [LintMessage] type.
-* `line` (`number | undefined`)<br>
- Same as `line` in [LintMessage] type.
-* `column` (`number | undefined`)<br>
- Same as `column` in [LintMessage] type.
-* `endLine` (`number | undefined`)<br>
- Same as `endLine` in [LintMessage] type.
-* `endColumn` (`number | undefined`)<br>
- Same as `endColumn` in [LintMessage] type.
-* `fix` (`EditInfo | undefined`)<br>
- Same as `fix` in [LintMessage] type.
-* `suggestions` (`{ desc: string; fix: EditInfo }[] | undefined`)<br>
- Same as `suggestions` in [LintMessage] type.
-* `suppressions` (`{ kind: string; justification: string}[]`)<br>
- The list of suppressions. Each suppression is the pair of a kind and a justification.
-
-### ◆ EditInfo type
-
-The `EditInfo` value is information to edit text. The `fix` and `suggestions` properties of [LintMessage] type contain it. It has following properties:
-
-* `range` (`[number, number]`)<br>
- The pair of 0-based indices in source code text to remove.
-* `text` (`string`)<br>
- The text to add.
-
-This edit information means replacing the range of the `range` property by the `text` property value. It's like `sourceCodeText.slice(0, edit.range[0]) + edit.text + sourceCodeText.slice(edit.range[1])`. Therefore, it's an add if the `range[0]` and `range[1]` property values are the same value, and it's removal if the `text` property value is empty string.
-
-### ◆ LoadedFormatter type
-
-The `LoadedFormatter` 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 | Promise<string>`)<br>
- The method to convert the [LintResult] objects to text.
-
----
-
-## SourceCode
-
-The `SourceCode` type represents the parsed source code that ESLint executes on. It's used internally in ESLint and is also available so that already-parsed code can be used. You can create a new instance of `SourceCode` by passing in the text string representing the code and an abstract syntax tree (AST) in [ESTree](https://github.com/estree/estree) format (including location information, range information, comments, and tokens):
-
-```js
-const SourceCode = require("eslint").SourceCode;
-
-const code = new SourceCode("var foo = bar;", ast);
-```
-
-The `SourceCode` constructor throws an error if the AST is missing any of the required information.
-
-The `SourceCode` constructor strips Unicode BOM.
-Please note the AST also should be parsed from stripped text.
-
-```js
-const SourceCode = require("eslint").SourceCode;
-
-const code = new SourceCode("\uFEFFvar foo = bar;", ast);
-
-assert(code.hasBOM === true);
-assert(code.text === "var foo = bar;");
-```
-
-### SourceCode#splitLines()
-
-This is a static function on `SourceCode` that is used to split the source code text into an array of lines.
-
-```js
-const SourceCode = require("eslint").SourceCode;
-
-const code = "var a = 1;\nvar b = 2;"
-
-// split code into an array
-const codeLines = SourceCode.splitLines(code);
-
-/*
- Value of codeLines will be
- [
- "var a = 1;",
- "var b = 2;"
- ]
- */
-```
-
----
-
-## Linter
-
-The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files. Unless you are working in the browser, you probably want to use the [ESLint class](#eslint-class) class instead.
-
-The `Linter` is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:
-
-* `cwd` - Path to a directory that should be considered as the current working directory. It is accessible to rules by calling `context.getCwd()` (see [The Context Object](./working-with-rules#the-context-object)). If `cwd` is `undefined`, it will be normalized to `process.cwd()` if the global `process` object is defined (for example, in the Node.js runtime) , or `undefined` otherwise.
-
-For example:
-
-```js
-const Linter = require("eslint").Linter;
-const linter1 = new Linter({ cwd: 'path/to/project' });
-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>).
-
-### Linter#verify
-
-The most important method on `Linter` is `verify()`, which initiates linting of the given text. This method accepts three arguments:
-
-* `code` - the source code to lint (a string or instance of `SourceCode`).
-* `config` - a configuration object that has been processed and normalized by `ESLint` using eslintrc files and/or other configuration arguments.
- * **Note**: If you want to lint text and have your configuration be read and processed, use [`ESLint#lintFiles()`][eslint-lintfiles] or [`ESLint#lintText()`][eslint-linttext] instead.
-* `options` - (optional) Additional options for this run.
- * `filename` - (optional) the filename to associate with the source code.
- * `preprocess` - (optional) A function that [Processors in Plugins](/docs/developer-guide/working-with-plugins#processors-in-plugins) documentation describes as the `preprocess` method.
- * `postprocess` - (optional) A function that [Processors in Plugins](/docs/developer-guide/working-with-plugins#processors-in-plugins) documentation describes as the `postprocess` method.
- * `filterCodeBlock` - (optional) A function that decides which code blocks the linter should adopt. The function receives two arguments. The first argument is the virtual filename of a code block. The second argument is the text of the code block. If the function returned `true` then the linter adopts the code block. If the function was omitted, the linter adopts only `*.js` code blocks. If you provided a `filterCodeBlock` function, it overrides this default behavior, so the linter doesn't adopt `*.js` code blocks automatically.
- * `disableFixes` - (optional) when set to `true`, the linter doesn't make either the `fix` or `suggestions` property of the lint result.
- * `allowInlineConfig` - (optional) set to `false` to disable inline comments from changing ESLint rules.
- * `reportUnusedDisableDirectives` - (optional) when set to `true`, adds reported errors for unused `eslint-disable` directives when no problems would be reported in the disabled area anyway.
-
-If the third argument is a string, it is interpreted as the `filename`.
-
-You can call `verify()` like this:
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-const messages = linter.verify("var foo;", {
- rules: {
- semi: 2
- }
-}, { filename: "foo.js" });
-
-// or using SourceCode
-
-const Linter = require("eslint").Linter,
- linter = new Linter(),
- SourceCode = require("eslint").SourceCode;
-
-const code = new SourceCode("var foo = bar;", ast);
-
-const messages = linter.verify(code, {
- rules: {
- semi: 2
- }
-}, { filename: "foo.js" });
-```
-
-The `verify()` method returns an array of objects containing information about the linting warnings and errors. Here's an example:
-
-```js
-{
- fatal: false,
- ruleId: "semi",
- severity: 2,
- line: 1,
- column: 23,
- message: "Expected a semicolon.",
- fix: {
- range: [1, 15],
- text: ";"
- }
-}
-```
-
-The information available for each linting message is:
-
-* `column` - the column on which the error occurred.
-* `fatal` - usually omitted, but will be set to true if there's a parsing error (not related to a rule).
-* `line` - the line on which the error occurred.
-* `message` - the message that should be output.
-* `nodeType` - the node or token type that was reported with the problem.
-* `ruleId` - the ID of the rule that triggered the messages (or null if `fatal` is true).
-* `severity` - either 1 or 2, depending on your configuration.
-* `endColumn` - the end column of the range on which the error occurred (this property is omitted if it's not range).
-* `endLine` - the end line of the range on which the error occurred (this property is omitted if it's not range).
-* `fix` - an object describing the fix for the problem (this property is omitted if no fix is available).
-* `suggestions` - an array of objects describing possible lint fixes for editors to programmatically enable (see details in the [Working with Rules docs](./working-with-rules#providing-suggestions)).
-
-You can get the suppressed messages from the previous run by `getSuppressedMessages()` method. If there is not a previous run, `getSuppressedMessage()` will return an empty list.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-const messages = linter.verify("var foo = bar; // eslint-disable-line -- Need to suppress", {
- rules: {
- semi: ["error", "never"]
- }
-}, { filename: "foo.js" });
-const suppressedMessages = linter.getSuppressedMessages();
-
-console.log(suppressedMessages[0].suppressions); // [{ "kind": "directive", "justification": "Need to suppress" }]
-```
-
-Linting message objects have a deprecated `source` property. This property **will be removed** from linting messages in an upcoming breaking release. If you depend on this property, you should now use the `SourceCode` instance provided by the linter.
-
-You can also get an instance of the `SourceCode` object used inside of `linter` by using the `getSourceCode()` method:
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-const messages = linter.verify("var foo = bar;", {
- rules: {
- semi: 2
- }
-}, { filename: "foo.js" });
-
-const code = linter.getSourceCode();
-
-console.log(code.text); // "var foo = bar;"
-```
-
-In this way, you can retrieve the text and AST used for the last run of `linter.verify()`.
-
-### Linter#verifyAndFix()
-
-This method is similar to verify except that it also runs autofixing logic, similar to the `--fix` flag on the command line. The result object will contain the autofixed code, along with any remaining linting messages for the code that were not autofixed.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-const messages = linter.verifyAndFix("var foo", {
- rules: {
- semi: 2
- }
-});
-```
-
-Output object from this method:
-
-```js
-{
- fixed: true,
- output: "var foo;",
- messages: []
-}
-```
-
-The information available is:
-
-* `fixed` - True, if the code was fixed.
-* `output` - Fixed code text (might be the same as input if no fixes were applied).
-* `messages` - Collection of all messages for the given code (It has the same information as explained above under `verify` block).
-
-### Linter#defineRule
-
-Each `Linter` instance holds a map of rule names to loaded rule objects. By default, all ESLint core rules are loaded. If you want to use `Linter` with custom rules, you should use the `defineRule` method to register your rules by ID.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-linter.defineRule("my-custom-rule", {
- // (an ESLint rule)
-
- create(context) {
- // ...
- }
-});
-
-const results = linter.verify("// some source text", { rules: { "my-custom-rule": "error" } });
-```
-
-### Linter#defineRules
-
-This is a convenience method similar to `Linter#defineRule`, except that it allows you to define many rules at once using an object.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-linter.defineRules({
- "my-custom-rule": { /* an ESLint rule */ create() {} },
- "another-custom-rule": { /* an ESLint rule */ create() {} }
-});
-
-const results = linter.verify("// some source text", {
- rules: {
- "my-custom-rule": "error",
- "another-custom-rule": "warn"
- }
-});
-```
-
-### Linter#getRules
-
-This method returns a map of all loaded rules.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-linter.getRules();
-
-/*
-Map {
- 'accessor-pairs' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
- 'array-bracket-newline' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
- ...
-}
-*/
-```
-
-### Linter#defineParser
-
-Each instance of `Linter` holds a map of custom parsers. If you want to define a parser programmatically, you can add this function
-with the name of the parser as first argument and the [parser object](/docs/developer-guide/working-with-custom-parsers) as second argument. The default `"espree"` parser will already be loaded for every `Linter` instance.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-linter.defineParser("my-custom-parser", {
- parse(code, options) {
- // ...
- }
-});
-
-const results = linter.verify("// some source text", { parser: "my-custom-parser" });
-```
-
-### Linter#version/Linter.version
-
-Each instance of `Linter` has a `version` property containing the semantic version number of ESLint that the `Linter` instance is from.
-
-```js
-const Linter = require("eslint").Linter;
-const linter = new Linter();
-
-linter.version; // => '4.5.0'
-```
-
-There is also a `Linter.version` property that you can read without instantiating `Linter`:
-
-```js
-const Linter = require("eslint").Linter;
-
-Linter.version; // => '4.5.0'
-```
-
----
-
-## RuleTester
-
-`eslint.RuleTester` is a utility to write tests for ESLint rules. It is used internally for the bundled rules that come with ESLint, and it can also be used by plugins.
-
-Example usage:
-
-```js
-"use strict";
-
-const rule = require("../../../lib/rules/my-rule"),
- RuleTester = require("eslint").RuleTester;
-
-const ruleTester = new RuleTester();
-
-ruleTester.run("my-rule", rule, {
- valid: [
- {
- code: "var foo = true",
- options: [{ allowFoo: true }]
- }
- ],
-
- invalid: [
- {
- code: "var invalidVariable = true",
- errors: [{ message: "Unexpected invalid variable." }]
- },
- {
- code: "var invalidVariable = true",
- errors: [{ message: /^Unexpected.+variable/ }]
- }
- ]
-});
-```
-
-The `RuleTester` constructor accepts an optional object argument, which can be used to specify defaults for your test cases. For example, if all of your test cases use ES2015, you can set it as a default:
-
-```js
-const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } });
-```
-
-The `RuleTester#run()` method is used to run the tests. It should be passed the following arguments:
-
-* The name of the rule (string)
-* The rule object itself (see ["working with rules"](./working-with-rules))
-* An object containing `valid` and `invalid` properties, each of which is an array containing test cases.
-
-A test case is an object with the following properties:
-
-* `name` (string, optional): The name to use for the test case, to make it easier to find
-* `code` (string, required): The source code that the rule should be run on
-* `options` (array, optional): The options passed to the rule. The rule severity should not be included in this list.
-* `filename` (string, optional): The filename for the given case (useful for rules that make assertions about filenames).
-* `only` (boolean, optional): Run this case exclusively for debugging in supported test frameworks.
-
-In addition to the properties above, invalid test cases can also have the following properties:
-
-* `errors` (number or array, required): Asserts some properties of the errors that the rule is expected to produce when run on this code. If this is a number, asserts the number of errors produced. Otherwise, this should be a list of objects, each containing information about a single reported error. The following properties can be used for an error (all are optional):
- * `message` (string/regexp): The message for the error
- * `messageId` (string): The Id for the error. See [testing errors with messageId](#testing-errors-with-messageid) for details
- * `data` (object): Placeholder data which can be used in combination with `messageId`
- * `type` (string): The type of the reported AST node
- * `line` (number): The 1-based line number of the reported location
- * `column` (number): The 1-based column number of the reported location
- * `endLine` (number): The 1-based line number of the end of the reported location
- * `endColumn` (number): The 1-based column number of the end of the reported location
- * `suggestions` (array): An array of objects with suggestion details to check. See [Testing Suggestions](#testing-suggestions) for details
-
- If a string is provided as an error instead of an object, the string is used to assert the `message` of the error.
-* `output` (string, required if the rule fixes code): Asserts the output that will be produced when using this rule for a single pass of autofixing (e.g. with the `--fix` command line flag). If this is `null`, asserts that none of the reported problems suggest autofixes.
-
-Any additional properties of a test case will be passed directly to the linter as config options. For example, a test case can have a `parserOptions` property to configure parser behavior:
-
-```js
-{
- code: "let foo;",
- parserOptions: { ecmaVersion: 2015 }
-}
-```
-
-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`
-
-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`.
-
-```js
-{
- code: "let foo;",
- errors: [{ messageId: "unexpected" }]
-}
-```
-
-For messages with placeholders, a test case can also use `data` property to additionally assert reported error's `message`.
-
-```js
-{
- code: "let foo;",
- errors: [{ messageId: "unexpected", data: { name: "foo" } }]
-}
-```
-
-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
-
-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):
-
-* `desc` (string): The suggestion `desc` value
-* `messageId` (string): The suggestion `messageId` value for suggestions that use `messageId`s
-* `data` (object): Placeholder data which can be used in combination with `messageId`
-* `output` (string): A code string representing the result of applying the suggestion fix to the input code
-
-Example:
-
-```js
-ruleTester.run("my-rule-for-no-foo", rule, {
- valid: [],
- invalid: [{
- code: "var foo;",
- errors: [{
- suggestions: [{
- desc: "Rename identifier 'foo' to 'bar'",
- output: "var bar;"
- }]
- }]
- }]
-})
-```
-
-`messageId` and `data` properties in suggestion test objects work the same way as in error test objects. See [testing errors with messageId](#testing-errors-with-messageid) for details.
-
-```js
-ruleTester.run("my-rule-for-no-foo", rule, {
- valid: [],
- invalid: [{
- code: "var foo;",
- errors: [{
- suggestions: [{
- messageId: "renameFoo",
- data: { newName: "bar" },
- output: "var bar;"
- }]
- }]
- }]
-})
-```
-
-### Customizing RuleTester
-
-`RuleTester` depends on two functions to run tests: `describe` and `it`. These functions can come from various places:
-
-1. If `RuleTester.describe` and `RuleTester.it` have been set to function values, `RuleTester` will use `RuleTester.describe` and `RuleTester.it` to run tests. You can use this to customize the behavior of `RuleTester` to match a test framework that you're using.
-
- If `RuleTester.itOnly` has been set to a function value, `RuleTester` will call `RuleTester.itOnly` instead of `RuleTester.it` to run cases with `only: true`. If `RuleTester.itOnly` is not set but `RuleTester.it` has an `only` function property, `RuleTester` will fall back to `RuleTester.it.only`.
-
-2. Otherwise, if `describe` and `it` are present as globals, `RuleTester` will use `global.describe` and `global.it` to run tests and `global.it.only` to run cases with `only: true`. This allows `RuleTester` to work when using frameworks like [Mocha](https://mochajs.org/) without any additional configuration.
-3. Otherwise, `RuleTester#run` will simply execute all of the tests in sequence, and will throw an error if one of them fails. This means you can simply execute a test file that calls `RuleTester.run` using `Node.js`, without needing a testing framework.
-
-`RuleTester#run` calls the `describe` function with two arguments: a string describing the rule, and a callback function. The callback calls the `it` function with a string describing the test case, and a test function. The test function will return successfully if the test passes, and throw an error if the test fails. The signature for `only` is the same as `it`. `RuleTester` calls either `it` or `only` for every case even when some cases have `only: true`, and the test framework is responsible for implementing test case exclusivity. (Note that this is the standard behavior for test suites when using frameworks like [Mocha](https://mochajs.org/); this information is only relevant if you plan to customize `RuleTester.describe`, `RuleTester.it`, or `RuleTester.itOnly`.)
-
-Example of customizing `RuleTester`:
-
-```js
-"use strict";
-
-const RuleTester = require("eslint").RuleTester,
- test = require("my-test-runner"),
- myRule = require("../../../lib/rules/my-rule");
-
-RuleTester.describe = function(text, method) {
- RuleTester.it.title = text;
- return method.call(this);
-};
-
-RuleTester.it = function(text, method) {
- test(RuleTester.it.title + ": " + text, method);
-};
-
-// then use RuleTester as documented
-
-const ruleTester = new RuleTester();
-
-ruleTester.run("my-rule", myRule, {
- valid: [
- // valid test cases
- ],
- invalid: [
- // invalid test cases
- ]
-})
-```
-
----
-
-[configuration object]: ../user-guide/configuring/
-[builtin-formatters]: https://eslint.org/docs/user-guide/formatters/
-[third-party-formatters]: https://www.npmjs.com/search?q=eslintformatter
-[eslint]: #eslint-class
-[eslint-constructor]: #-new-eslintoptions
-[eslint-lintfiles]: #-eslintlintfilespatterns
-[eslint-linttext]: #-eslintlinttextcode-options
-[eslint-getrulesmetaforresults]: #-eslintgetrulesmetaforresultsresults
-[eslint-calculateconfigforfile]: #-eslintcalculateconfigforfilefilepath
-[eslint-ispathignored]: #-eslintispathignoredfilepath
-[eslint-loadformatter]: #-eslintloadformatternameorpath
-[eslint-version]: #-eslintversion
-[eslint-outputfixes]: #-eslintoutputfixesresults
-[eslint-geterrorresults]: #-eslintgeterrorresultsresults
-[lintresult]: #-lintresult-type
-[lintmessage]: #-lintmessage-type
-[suppressedlintmessage]: #-suppressedlintmessage-type
-[editinfo]: #-editinfo-type
-[loadedformatter]: #-loadedformatter-type
-[linter]: #linter
+++ /dev/null
----
-title: Package.json Conventions
-layout: doc
-edit_link: https://github.com/eslint/eslint/edit/main/docs/src/developer-guide/package-json-conventions.md
----
-
-The following applies to the "scripts" section of `package.json` files.
-
-## Names
-
-npm script names MUST contain only lower case letters, `:` to separate parts, `-` to separate words, and `+` to separate file extensions. Each part name SHOULD be either a full English word (e.g. `coverage` not `cov`) or a well-known initialism in all lowercase (e.g. `wasm`).
-
-Here is a summary of the proposal in EBNF.
-
-```ebnf
-name = life-cycle | main ":fix"? target? option* ":watch"?
-
-life-cycle = prepare | preinstall | install | postinstall | prepublish | preprepare | prepare | postprepare | prepack | postpack | prepublishOnly;
-
-main = "build" | "lint" | "start" | "test";
-
-target = ":" word ("-" word)* | extension ("+" extension)*;
-
-option = ":" word ("-" word)*;
-
-word = [a-z]+;
-
-extension = [a-z0-9]+;
-```
-
-## Order
-
-The script names MUST appear in the package.json file in alphabetical order. The other conventions outlined in this document ensure that alphabetical order will coincide with logical groupings.
-
-## Main Script Names
-
-With the exception of [npm life cycle scripts](https://docs.npmjs.com/cli/v8/using-npm/scripts#life-cycle-scripts) all script names MUST begin with one of the following names.
-
-### Build
-
-Scripts that generate a set of files from source code and / or data MUST have names that begin with `build`.
-
-If a package contains any `build:*` scripts, there MAY be a script named `build`. If so, SHOULD produce the same output as running each of the `build` scripts individually. It MUST produce a subset of the output from running those scripts.
-
-### Lint
-
-Scripts that statically analyze files (mostly, but not limited to running `eslint` itself) MUST have names that begin with `lint`.
-
-If a package contains any `lint:*` scripts, there SHOULD be a script named `lint` and it MUST run all of the checks that would have been run if each `lint:*` script was called individually.
-
-If fixing is available, a linter MUST NOT apply fixes UNLESS the script contains the `:fix` modifier (see below).
-
-### Start
-
-A `start` script is used to start a server. As of this writing, no ESLint package has more than one `start` script, so there's no need `start` to have any modifiers.
-
-### Test
-
-Scripts that execute code in order to ensure the actual behavior matches expected behavior MUST have names that begin with `test`.
-
-If a package contains any `test:*` scripts, there SHOULD be a script named `test` and it MUST run of all of the tests that would have been run if each `test:*` script was called individually.
-
-A test script SHOULD NOT include linting.
-
-A test script SHOULD report test coverage when possible.
-
-## Modifiers
-
-One or more of the following modifiers MAY be appended to the standard script names above. If a target has modifiers, they MUST be in the order in which they appear below (e.g. `lint:fix:js:watch` not `lint:watch:js:fix`)
-
-### Fix
-
-If it's possible for a linter to fix problems that it finds, add a copy of the script with `:fix` appended to the end that also fixes.
-
-### Target
-
-The name of the target of the action being run. In the case of a `build` script, it SHOULD identify the build artifact(s), e.g. "javascript" or "css" or "website". In the case of a `lint` or `test` script, it SHOULD identify the item(s) being linted or tested. In the case of a `start` script, it SHOULD identify which server is starting.
-
-A target MAY refer to a list of affected file extensions (such as `cjs` or `less`) delimited by a `+`. If there is more than one extension, the list SHOULD be alphabetized. When a file extension has variants (such as `cjs` for CommonJS and `mjs` for ESM), the common part of the extension MAY be used instead of explicitly listing out all of the variants (e.g. `js` instead of `cjs+jsx+mjs`).
-
-The target SHOULD NOT refer to name of the name of the tool that's performing the action (`eleventy`, `webpack`, etc.)
-
-### Options
-
-Additional options that don't fit under the other modifiers.
-
-### Watch
-
-If a script watches the filesystem and responds to changes, add `:watch` to the script name.
+++ /dev/null
----
-title: ScopeManager
-layout: doc
-
----
-
-This document was written based on the implementation of [eslint-scope](https://github.com/eslint/eslint-scope), a fork of [escope](https://github.com/estools/escope), and deprecates some members ESLint is not using.
-
-----
-
-## ScopeManager interface
-
-`ScopeManager` object has all variable scopes.
-
-### Fields
-
-#### scopes
-
-* **Type:** `Scope[]`
-* **Description:** All scopes.
-
-#### globalScope
-
-* **Type:** `Scope`
-* **Description:** The root scope.
-
-### Methods
-
-#### acquire(node, inner = false)
-
-* **Parameters:**
- * `node` (`ASTNode`) ... An AST node to get their scope.
- * `inner` (`boolean`) ... If the node has multiple scope, this returns the outermost scope normally. If `inner` is `true` then this returns the innermost scope. Default is `false`.
-* **Return type:** `Scope | null`
-* **Description:** Get the scope of a given AST node. The gotten scope's `block` property is the node. This method never returns `function-expression-name` scope. If the node does not have their scope, this returns `null`.
-
-#### getDeclaredVariables(node)
-
-* **Parameters:**
- * `node` (`ASTNode`) ... An AST node to get their variables.
-* **Return type:** `Variable[]`
-* **Description:** Get the variables that a given AST node defines. The gotten variables' `def[].node`/`def[].parent` property is the node. If the node does not define any variable, this returns an empty array.
-
-### Deprecated members
-
-Those members are defined but not used in ESLint.
-
-#### isModule()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this program is module.
-
-#### isImpliedStrict()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this program is strict mode implicitly. I.e., `options.impliedStrict === true`.
-
-#### isStrictModeSupported()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this program supports strict mode. I.e., `options.ecmaVersion >= 5`.
-
-#### acquireAll(node)
-
-* **Parameters:**
- * `node` (`ASTNode`) ... An AST node to get their scope.
-* **Return type:** `Scope[] | null`
-* **Description:** Get the scopes of a given AST node. The gotten scopes' `block` property is the node. If the node does not have their scope, this returns `null`.
-
-----
-
-## Scope interface
-
-`Scope` object has all variables and references in the scope.
-
-### Fields
-
-#### type
-
-* **Type:** `string`
-* **Description:** The type of this scope. This is one of `"block"`, `"catch"`, `"class"`, `"class-field-initializer"`, `"class-static-block"`, `"for"`, `"function"`, `"function-expression-name"`, `"global"`, `"module"`, `"switch"`, `"with"`.
-
-#### isStrict
-
-* **Type:** `boolean`
-* **Description:** `true` if this scope is strict mode.
-
-#### upper
-
-* **Type:** `Scope | null`
-* **Description:** The parent scope. If this is the global scope then this property is `null`.
-
-#### childScopes
-
-* **Type:** `Scope[]`
-* **Description:** The array of child scopes. This does not include grandchild scopes.
-
-#### variableScope
-
-* **Type:** `Scope`
-* **Description:** The nearest ancestor whose `type` is one of `"class-field-initializer"`, `"class-static-block"`, `"function"`, `"global"`, or `"module"`. For the aforementioned scopes this is a self-reference.
-
-> This represents the lowest enclosing function or top-level scope. Class field initializers and class static blocks are implicit functions. Historically, this was the scope which hosts variables that are defined by `var` declarations, and thus the name `variableScope`.
-
-#### block
-
-* **Type:** `ASTNode`
-* **Description:** The AST node which created this scope.
-
-#### variables
-
-* **Type:** `Variable[]`
-* **Description:** The array of all variables which are defined on this scope. This does not include variables which are defined in child scopes.
-
-#### set
-
-* **Type:** `Map<string, Variable>`
-* **Description:** The map from variable names to variable objects.
-
-> I hope to rename `set` field or replace by a method.
-
-#### references
-
-* **Type:** `Reference[]`
-* **Description:** The array of all references on this scope. This does not include references in child scopes.
-
-#### through
-
-* **Type:** `Reference[]`
-* **Description:** The array of references which could not be resolved in this scope.
-
-#### functionExpressionScope
-
-* **Type:** `boolean`
-* **Description:** `true` if this scope is `"function-expression-name"` scope.
-
-> I hope to deprecate `functionExpressionScope` field as replacing by `scope.type === "function-expression-name"`.
-
-### Deprecated members
-
-Those members are defined but not used in ESLint.
-
-#### taints
-
-* **Type:** `Map<string, boolean>`
-* **Description:** The map from variable names to `tainted` flag.
-
-#### dynamic
-
-* **Type:** `boolean`
-* **Description:** `true` if this scope is dynamic. I.e., the type of this scope is `"global"` or `"with"`.
-
-#### directCallToEvalScope
-
-* **Type:** `boolean`
-* **Description:** `true` if this scope contains `eval()` invocations.
-
-#### thisFound
-
-* **Type:** `boolean`
-* **Description:** `true` if this scope contains `this`.
-
-#### resolve(node)
-
-* **Parameters:**
- * `node` (`ASTNode`) ... An AST node to get their reference object. The type of the node must be `"Identifier"`.
-* **Return type:** `Reference | null`
-* **Description:** Returns `this.references.find(r => r.identifier === node)`.
-
-#### isStatic()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** Returns `!this.dynamic`.
-
-#### isArgumentsMaterialized()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this is a `"function"` scope which has used `arguments` variable.
-
-#### isThisMaterialized()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** Returns `this.thisFound`.
-
-#### isUsedName(name)
-
-* **Parameters:**
- * `name` (`string`) ... The name to check.
-* **Return type:** `boolean`
-* **Description:** `true` if a given name is used in variable names or reference names.
-
-----
-
-## Variable interface
-
-`Variable` object is variable's information.
-
-### Fields
-
-#### name
-
-* **Type:** `string`
-* **Description:** The name of this variable.
-
-#### scope
-
-* **Type:** `Scope`
-* **Description:** The scope in which this variable is defined.
-
-#### identifiers
-
-* **Type:** `ASTNode[]`
-* **Description:** The array of `Identifier` nodes which define this variable. If this variable is redeclared, this array includes two or more nodes.
-
-> I hope to deprecate `identifiers` field as replacing by `defs[].name` field.
-
-#### references
-
-* **Type:** `Reference[]`
-* **Description:** The array of the references of this variable.
-
-#### defs
-
-* **Type:** `Definition[]`
-* **Description:** The array of the definitions of this variable.
-
-### Deprecated members
-
-Those members are defined but not used in ESLint.
-
-#### tainted
-
-* **Type:** `boolean`
-* **Description:** The `tainted` flag. (always `false`)
-
-#### stack
-
-* **Type:** `boolean`
-* **Description:** The `stack` flag. (I'm not sure what this means.)
-
-----
-
-## Reference interface
-
-`Reference` object is reference's information.
-
-### Fields
-
-#### identifier
-
-* **Type:** `ASTNode`
-* **Description:** The `Identifier` node of this reference.
-
-#### from
-
-* **Type:** `Scope`
-* **Description:** The `Scope` object that this reference is on.
-
-#### resolved
-
-* **Type:** `Variable | null`
-* **Description:** The `Variable` object that this reference refers. If such variable was not defined, this is `null`.
-
-#### writeExpr
-
-* **Type:** `ASTNode | null`
-* **Description:** The ASTNode object which is right-hand side.
-
-#### init
-
-* **Type:** `boolean`
-* **Description:** `true` if this writing reference is a variable initializer or a default value.
-
-### Methods
-
-#### isWrite()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this reference is writing.
-
-#### isRead()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this reference is reading.
-
-#### isWriteOnly()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this reference is writing but not reading.
-
-#### isReadOnly()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this reference is reading but not writing.
-
-#### isReadWrite()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this reference is reading and writing.
-
-### Deprecated members
-
-Those members are defined but not used in ESLint.
-
-#### tainted
-
-* **Type:** `boolean`
-* **Description:** The `tainted` flag. (always `false`)
-
-#### flag
-
-* **Type:** `number`
-* **Description:** `1` is reading, `2` is writing, `3` is reading/writing.
-
-#### partial
-
-* **Type:** `boolean`
-* **Description:** The `partial` flag.
-
-#### isStatic()
-
-* **Parameters:**
-* **Return type:** `boolean`
-* **Description:** `true` if this reference is resolved statically.
-
-----
-
-## Definition interface
-
-`Definition` object is variable definition's information.
-
-### Fields
-
-#### type
-
-* **Type:** `string`
-* **Description:** The type of this definition. One of `"CatchClause"`, `"ClassName"`, `"FunctionName"`, `"ImplicitGlobalVariable"`, `"ImportBinding"`, `"Parameter"`, and `"Variable"`.
-
-#### name
-
-* **Type:** `ASTNode`
-* **Description:** The `Identifier` node of this definition.
-
-#### node
-
-* **Type:** `ASTNode`
-* **Description:** The enclosing node of the name.
-
-| type | node |
-|:---------------------------|:-----|
-| `"CatchClause"` | `CatchClause`
-| `"ClassName"` | `ClassDeclaration` or `ClassExpression`
-| `"FunctionName"` | `FunctionDeclaration` or `FunctionExpression`
-| `"ImplicitGlobalVariable"` | `Program`
-| `"ImportBinding"` | `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`
-| `"Parameter"` | `FunctionDeclaration`, `FunctionExpression`, or `ArrowFunctionExpression`
-| `"Variable"` | `VariableDeclarator`
-
-#### parent
-
-* **Type:** `ASTNode | undefined | null`
-* **Description:** The enclosing statement node of the name.
-
-| type | parent |
-|:---------------------------|:-------|
-| `"CatchClause"` | `null`
-| `"ClassName"` | `null`
-| `"FunctionName"` | `null`
-| `"ImplicitGlobalVariable"` | `null`
-| `"ImportBinding"` | `ImportDeclaration`
-| `"Parameter"` | `null`
-| `"Variable"` | `VariableDeclaration`
-
-### Deprecated members
-
-Those members are defined but not used in ESLint.
-
-#### index
-
-* **Type:** `number | undefined | null`
-* **Description:** The index in the declaration statement.
-
-#### kind
-
-* **Type:** `string | undefined | null`
-* **Description:** The kind of the declaration statement.
+++ /dev/null
----
-title: Selectors
-layout: doc
-
----
-
-Some rules and APIs allow the use of selectors to query an AST. This page is intended to:
-
-1. Explain what selectors are
-2. Describe the syntax for creating selectors
-3. Describe what selectors can be used for
-
-## What is a selector?
-
-A selector is a string that can be used to match nodes in an Abstract Syntax Tree (AST). This is useful for describing a particular syntax pattern in your code.
-
-The syntax for AST selectors is similar to the syntax for [CSS selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors). If you've used CSS selectors before, the syntax for AST selectors should be easy to understand.
-
-The simplest selector is just a node type. A node type selector will match all nodes with the given type. For example, consider the following program:
-
-```js
-var foo = 1;
-bar.baz();
-```
-
-The selector "`Identifier`" will match all `Identifier` nodes in the program. In this case, the selector will match the nodes for `foo`, `bar`, and `baz`.
-
-Selectors are not limited to matching against single node types. For example, the selector `VariableDeclarator > Identifier` will match all `Identifier` nodes that have a `VariableDeclarator` as a direct parent. In the program above, this will match the node for `foo`, but not the nodes for `bar` and `baz`.
-
-## What syntax can selectors have?
-
-The following selectors are supported:
-
-* AST node type: `ForStatement`
-* wildcard (matches all nodes): `*`
-* attribute existence: `[attr]`
-* attribute value: `[attr="foo"]` or `[attr=123]`
-* attribute regex: `[attr=/foo.*/]` <sub>(with some [known issues](#known-issues))</sub>
-* attribute conditions: `[attr!="foo"]`, `[attr>2]`, `[attr<3]`, `[attr>=2]`, or `[attr<=3]`
-* nested attribute: `[attr.level2="foo"]`
-* field: `FunctionDeclaration > Identifier.id`
-* First or last child: `:first-child` or `:last-child`
-* nth-child (no ax+b support): `:nth-child(2)`
-* nth-last-child (no ax+b support): `:nth-last-child(1)`
-* descendant: `FunctionExpression ReturnStatement`
-* child: `UnaryExpression > Literal`
-* following sibling: `VariableDeclaration ~ VariableDeclaration`
-* adjacent sibling: `ArrayExpression > Literal + SpreadElement`
-* negation: `:not(ForStatement)`
-* matches-any: `:matches([attr] > :first-child, :last-child)`
-* class of AST node: `:statement`, `:expression`, `:declaration`, `:function`, or `:pattern`
-
-This syntax is very powerful, and can be used to precisely select many syntactic patterns in your code.
-
-<sup>The examples in this section were adapted from the [esquery](https://github.com/estools/esquery) documentation.</sup>
-
-## What can selectors be used for?
-
-If you're writing custom ESLint rules, you might be interested in using selectors to examine specific parts of the AST. If you're configuring ESLint for your codebase, you might be interested in restricting particular syntax patterns with selectors.
-
-### Listening for selectors in rules
-
-When writing a custom ESLint rule, you can listen for nodes that match a particular selector as the AST is traversed.
-
-```js
-module.exports = {
- create(context) {
- // ...
-
- return {
-
- // This listener will be called for all IfStatement nodes with blocks.
- "IfStatement > BlockStatement": function(blockStatementNode) {
- // ...your logic here
- },
-
- // This listener will be called for all function declarations with more than 3 parameters.
- "FunctionDeclaration[params.length>3]": function(functionDeclarationNode) {
- // ...your logic here
- }
- };
- }
-};
-```
-
-Adding `:exit` to the end of a selector will cause the listener to be called when the matching nodes are exited during traversal, rather than when they are entered.
-
-If two or more selectors match the same node, their listeners will be called in order of increasing specificity. The specificity of an AST selector is similar to the specificity of a CSS selector:
-
-* When comparing two selectors, the selector that contains more class selectors, attribute selectors, and pseudo-class selectors (excluding `:not()`) has higher specificity.
-* If the class/attribute/pseudo-class count is tied, the selector that contains more node type selectors has higher specificity.
-
-If multiple selectors have equal specificity, their listeners will be called in alphabetical order for that node.
-
-### Restricting syntax with selectors
-
-With the [no-restricted-syntax](/docs/rules/no-restricted-syntax) rule, you can restrict the usage of particular syntax in your code. For example, you can use the following configuration to disallow using `if` statements that do not have block statements as their body:
-
-```json
-{
- "rules": {
- "no-restricted-syntax": ["error", "IfStatement > :not(BlockStatement).consequent"]
- }
-}
-```
-
-...or equivalently, you can use this configuration:
-
-```json
-{
- "rules": {
- "no-restricted-syntax": ["error", "IfStatement[consequent.type!='BlockStatement']"]
- }
-}
-```
-
-As another example, you can disallow calls to `require()`:
-
-```json
-{
- "rules": {
- "no-restricted-syntax": ["error", "CallExpression[callee.name='require']"]
- }
-}
-```
-
-Or you can enforce that calls to `setTimeout` always have two arguments:
-
-```json
-{
- "rules": {
- "no-restricted-syntax": ["error", "CallExpression[callee.name='setTimeout'][arguments.length!=2]"]
- }
-}
-```
-
-Using selectors in the `no-restricted-syntax` rule can give you a lot of control over problematic patterns in your codebase, without needing to write custom rules to detect each pattern.
-
-### Known issues
-
-Due to a [bug](https://github.com/estools/esquery/issues/68) in [esquery](https://github.com/estools/esquery), regular expressions that contain a forward-slash character `/` aren't properly parsed, so `[value=/some\/path/]` will be a syntax error. As a [workaround](https://github.com/estools/esquery/issues/68), you can replace the `/` character with its unicode counterpart, like so: `[value=/some\\u002Fpath/]`.
+++ /dev/null
----
-title: Shareable Configs
-layout: doc
-eleventyNavigation:
- key: shareable configs
- parent: developer guide
- title: Shareable Configs
- order: 8
-
----
-
-The configuration that you have in your `.eslintrc` file is an important part of your project, and as such, you may want to share it with other projects or people. Shareable configs allow you to publish your configuration settings on [npm](https://www.npmjs.com/) and have others download and use it in their ESLint projects.
-
-## Creating a Shareable Config
-
-Shareable configs are simply npm packages that export a configuration object. To start, [create a Node.js module](https://docs.npmjs.com/getting-started/creating-node-modules) like you normally would. Make sure the module name begins with `eslint-config-`, such as `eslint-config-myconfig`.
-
-npm [scoped modules](https://docs.npmjs.com/misc/scope) are also supported, by naming or prefixing the module with `@scope/eslint-config`, such as `@scope/eslint-config` or `@scope/eslint-config-myconfig`.
-
-Create a new `index.js` file and export an object containing your settings:
-
-```js
-module.exports = {
-
- globals: {
- MyGlobal: true
- },
-
- rules: {
- semi: [2, "always"]
- }
-
-};
-```
-
-Since `index.js` is just JavaScript, you can optionally read these settings from a file or generate them dynamically.
-
-## Publishing a Shareable Config
-
-Once your shareable config is ready, you can [publish to npm](https://docs.npmjs.com/getting-started/publishing-npm-packages) to share with others. We recommend using the `eslint` and `eslintconfig` keywords so others can easily find your module.
-
-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:
-
-```json
-{
- "peerDependencies": {
- "eslint": ">= 3"
- }
-}
-```
-
-If your shareable config depends on a plugin, you should also specify it as a `peerDependency` (plugins will be loaded relative to the end user's project, so the end user is required to install the plugins they need). However, if your shareable config depends on a third-party parser or another shareable config, you can specify these packages as `dependencies`.
-
-You can also test your shareable config on your computer before publishing by linking your module globally. Type:
-
-```bash
-npm link
-```
-
-Then, in your project that wants to use your shareable config, type:
-
-```bash
-npm link eslint-config-myconfig
-```
-
-Be sure to replace `eslint-config-myconfig` with the actual name of your module.
-
-## Using a Shareable Config
-
-Shareable configs are designed to work with the `extends` feature of `.eslintrc` files. Instead of using a file path for the value of `extends`, use your module name. For example:
-
-```json
-{
- "extends": "eslint-config-myconfig"
-}
-```
-
-You can also omit the `eslint-config-` and it will be automatically assumed by ESLint:
-
-```json
-{
- "extends": "myconfig"
-}
-```
-
-### npm scoped modules
-
-npm [scoped modules](https://docs.npmjs.com/misc/scope) are also supported in a number of ways.
-
-By using the module name:
-
-```json
-{
- "extends": "@scope/eslint-config"
-}
-```
-
-You can also omit the `eslint-config` and it will be automatically assumed by ESLint:
-
-```json
-{
- "extends": "@scope"
-}
-```
-
-The module name can also be customized, just note that when using [scoped modules](https://docs.npmjs.com/misc/scope) it is not possible to omit the `eslint-config-` prefix. Doing so would result in package naming conflicts, and thus in resolution errors in most of cases. For example a package named `@scope/eslint-config-myconfig` vs `@scope/myconfig`, since both are valid scoped package names, the configuration should be specified as:
-
-```json
-{
- "extends": "@scope/eslint-config-myconfig"
-}
-```
-
-You can override settings from the shareable config by adding them directly into your `.eslintrc` file.
-
-## Sharing Multiple Configs
-
-It's possible to share multiple configs in the same npm package. You can specify a default config for the package by following the directions in the first section. You can specify additional configs by simply adding a new file to your npm package and then referencing it from your ESLint config.
-
-As an example, you can create a file called `my-special-config.js` in the root of your npm package and export a config, such as:
-
-```js
-module.exports = {
- rules: {
- quotes: [2, "double"]
- }
-};
-```
-
-Then, assuming you're using the package name `eslint-config-myconfig`, you can access the additional config via:
-
-```json
-{
- "extends": "myconfig/my-special-config"
-}
-```
-
-When using [scoped modules](https://docs.npmjs.com/misc/scope) it is not possible to omit the `eslint-config` namespace. Doing so would result in resolution errors as explained above. Assuming the package name is `@scope/eslint-config`, the additional config can be accessed as:
-
-```json
-{
- "extends": "@scope/eslint-config/my-special-config"
-}
-```
-
-Note that you can leave off the `.js` from the filename. In this way, you can add as many additional configs to your package as you'd like.
-
-**Important:** We strongly recommend always including a default config for your plugin to avoid errors.
-
-## Local Config File Resolution
-
-If you need to make multiple configs that can extend from each other and live in different directories, you can create a single shareable config that handles this scenario.
-
-As an example, let's assume you're using the package name `eslint-config-myconfig` and your package looks something like this:
-
-```text
-myconfig
-├── index.js
-└─┬ lib
- ├── defaults.js
- ├── dev.js
- ├── ci.js
- └─┬ ci
- ├── frontend.js
- ├── backend.js
- └── common.js
-```
-
-In your `index.js` you can do something like this:
-
-```js
-module.exports = require('./lib/ci.js');
-```
-
-Now inside your package you have `/lib/defaults.js`, which contains:
-
-```js
-module.exports = {
- rules: {
- 'no-console': 1
- }
-};
-```
-
-Inside your `/lib/ci.js` you have
-
-```js
-module.exports = require('./ci/backend');
-```
-
-Inside your `/lib/ci/common.js`
-
-```js
-module.exports = {
- rules: {
- 'no-alert': 2
- },
- extends: 'myconfig/lib/defaults'
-};
-```
-
-Despite being in an entirely different directory, you'll see that all `extends` must use the full package path to the config file you wish to extend.
-
-Now inside your `/lib/ci/backend.js`
-
-```js
-module.exports = {
- rules: {
- 'no-console': 1
- },
- extends: 'myconfig/lib/ci/common'
-};
-```
-
-In the last file, you'll once again see that to properly resolve your config, you'll need include the full package path.
-
-## Further Reading
-
-* [npm Developer Guide](https://docs.npmjs.com/misc/developers)
+++ /dev/null
----
-title: Source Code
-layout: doc
-eleventyNavigation:
- key: getting the source code
- parent: developer guide
- title: Getting the Source Code
- order: 1
-
----
-
-ESLint is hosted at [GitHub](https://github.com/eslint/eslint) and uses [Git](https://git-scm.com/) for source control. In order to obtain the source code, you must first install Git on your system. Instructions for installing and setting up Git can be found at [https://help.github.com/articles/set-up-git/](https://help.github.com/articles/set-up-git/).
-
-If you simply want to create a local copy of the source to play with, you can clone the main repository using this command:
-
-```shell
-git clone git://github.com/eslint/eslint.git
-```
-
-If you're planning on contributing to ESLint, then it's a good idea to fork the repository. You can find instructions for forking a repository at [https://help.github.com/articles/fork-a-repo/](https://help.github.com/articles/fork-a-repo/). After forking the ESLint repository, you'll want to create a local copy of your fork.
-
-## Start Developing
-
-Before you can get started developing, you'll need to have a couple of things installed:
-
-* [Node.JS](https://nodejs.org)
-* [npm](https://www.npmjs.com/)
-
-Once you have a local copy and have Node.JS and npm installed, you'll need to install the ESLint dependencies:
-
-```shell
-cd eslint
-npm install
-```
-
-Now when you run `eslint`, it will be running your local copy and showing your changes.
-
-**Note:** It's a good idea to re-run `npm install` whenever you pull from the main repository to ensure you have the latest development dependencies.
-
-## Directory structure
-
-The ESLint directory and file structure is as follows:
-
-* `bin` - executable files that are available when ESLint is installed
-* `conf` - default configuration information
-* `docs` - documentation for the project
-* `lib` - contains the source code
- * `formatters` - all source files defining formatters
- * `rules` - all source files defining rules
-* `tests` - the main unit test folder
- * `lib` - tests for the source code
- * `formatters` - tests for the formatters
- * `rules` - tests for the rules
+++ /dev/null
----
-title: Unit Tests
-layout: doc
-eleventyNavigation:
- key: run the tests
- parent: developer guide
- title: Run the Tests
- order: 3
-
----
-
-Most parts of ESLint have unit tests associated with them. Unit tests are written using [Mocha](https://mochajs.org/) and are required when making contributions to ESLint. You'll find all of the unit tests in the `tests` directory.
-
-When you first get the source code, you need to run `npm install` once initially to set ESLint for development. Once you've done that, you can run the tests via:
-
-```shell
-npm test
-```
-
-This automatically starts Mocha and runs all tests in the `tests` directory. You need only add yours and it will automatically be picked up when running tests.
-
-## Running Individual Tests
-
-If you want to quickly run just one test file, you can do so by running Mocha directly and passing in the filename. For example:
-
-```shell
-npm run test:cli tests/lib/rules/no-undef.js
-```
-
-If you want to run just one or a subset of `RuleTester` test cases, add `only: true` to each test case or wrap the test case in `RuleTester.only(...)` to add it automatically:
-
-```js
-ruleTester.run("my-rule", myRule, {
- valid: [
- RuleTester.only("const valid = 42;"),
- // Other valid cases
- ],
- invalid: [
- {
- code: "const invalid = 42;",
- only: true,
- },
- // Other invalid cases
- ]
-})
-```
-
-Running individual tests is useful when you're working on a specific bug and iterating on the solution. You should be sure to run `npm test` before submitting a pull request. `npm test` uses Mocha's `--forbid-only` option to prevent `only` tests from passing full test runs.
-
-## More Control on Unit Testing
-
-`npm run test:cli` is an alias of the Mocha cli in `./node_modules/.bin/mocha`. [Options](https://mochajs.org/#command-line-usage) are available to be provided to help to better control the test to run.
-
-The default timeout for tests in `npm test` is 10000ms. You may change the timeout by providing `ESLINT_MOCHA_TIMEOUT` environment variable, for example:
-
-```shell
-ESLINT_MOCHA_TIMEOUT=20000 npm test
-```
+++ /dev/null
----
-title: Working with Custom Formatters
-layout: doc
-eleventyNavigation:
- key: working with custom formatters
- parent: developer guide
- title: Working with Custom Formatters
- order: 6
-
----
-
-While ESLint has some built-in formatters available to format the linting results, it's also possible to create and distribute your own custom formatters. You can include custom formatters in your project directly or create an npm package to distribute them separately.
-
-Each formatter is just a function that receives a `results` object and a `context` and returns a string. For example, the following is how the `json` built-in formatter is implemented:
-
-```js
-//my-awesome-formatter.js
-module.exports = function(results, context) {
- return JSON.stringify(results, null, 2);
-};
-```
-
-A 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
-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`).
-
-## 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:
-
-```bash
-eslint -f awesome src/
-```
-
-Because ESLint knows to look for packages beginning with `eslint-formatter-` when the specified formatter doesn't begin with a dot, there is no need to type `eslint-formatter-` when using a packaged custom formatter.
-
-Tips for `package.json`:
-
-* The `main` entry should be the JavaScript file implementing your custom formatter.
-* Add these `keywords` to help users find your formatter:
- * `"eslint"`
- * `"eslint-formatter"`
- * `"eslintformatter"`
-
-See all [formatters on npm](https://www.npmjs.com/search?q=eslint-formatter);
-
-## 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/a/file.js",
- messages: [
- {
- ruleId: "curly",
- severity: 2,
- message: "Expected { after 'if' condition.",
- line: 2,
- column: 1,
- nodeType: "IfStatement"
- },
- {
- ruleId: "no-process-exit",
- severity: 2,
- message: "Don't use process.exit(); throw an error instead.",
- line: 3,
- column: 1,
- nodeType: "CallExpression"
- }
- ],
- errorCount: 2,
- warningCount: 0,
- fixableErrorCount: 0,
- fixableWarningCount: 0,
- source:
- "var err = doStuff();\nif (err) console.log('failed tests: ' + err);\nprocess.exit(1);\n"
- },
- {
- filePath: "/path/to/Gruntfile.js",
- messages: [],
- errorCount: 0,
- warningCount: 0,
- fixableErrorCount: 0,
- fixableWarningCount: 0
- }
-]
-```
-
-### The `result` Object
-
-<!-- This section is copied from the "Node.js API" page. Changes to this section should
-also be manually applied to that page. -->
-
-Each object in the `results` array is a `result` object. Each `result` object contains the path of the file that was linted and information about linting issues that were encountered. Here are the properties available on each `result` object:
-
-* **filePath**: The absolute path to the file that was linted.
-* **messages**: An array of `message` objects. See below for more info about messages.
-* **errorCount**: The number of errors for the given file.
-* **warningCount**: The number of warnings for the given file.
-* **source**: The source code for the given file. This property is omitted if this file has no errors/warnings or if the `output` property is present.
-* **output**: The source code for the given file with as many fixes applied as possible. This property is omitted if no fix is available.
-
-### The `message` Object
-
-Each `message` object contains information about the ESLint rule that was triggered by some source code. The properties available on each `message` object are:
-
-* **ruleId**: the ID of the rule that produced the error or warning.
-* **severity**: the severity of the failure, `1` for warnings and `2` for errors.
-* **message**: the human readable description of the error.
-* **line**: the line where the issue is located.
-* **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#-new-eslintoptions) class.
-* `rulesMeta` ... The `meta` property values of rules. See the [Working with Rules](working-with-rules) 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
-
-A formatter that only cares about the total count of errors and warnings will look like this:
-
-```javascript
-module.exports = function(results, context) {
- // accumulate the errors and warnings
- var summary = results.reduce(
- function(seq, current) {
- seq.errors += current.errorCount;
- seq.warnings += current.warningCount;
- return seq;
- },
- { errors: 0, warnings: 0 }
- );
-
- if (summary.errors > 0 || summary.warnings > 0) {
- return (
- "Errors: " +
- summary.errors +
- ", Warnings: " +
- summary.warnings +
- "\n"
- );
- }
-
- return "";
-};
-```
-
-Running `eslint` with the previous custom formatter,
-
-```bash
-eslint -f ./my-awesome-formatter.js src/
-```
-
-Will produce the following output:
-
-```bash
-Errors: 2, Warnings: 4
-```
-
-### Detailed formatter
-
-A more complex report will look something like this:
-
-```javascript
-module.exports = function(results, context) {
- var results = results || [];
-
- var summary = results.reduce(
- function(seq, current) {
- current.messages.forEach(function(msg) {
- var logMessage = {
- filePath: current.filePath,
- ruleId: msg.ruleId,
- ruleUrl: context.rulesMeta[msg.ruleId].docs.url,
- message: msg.message,
- line: msg.line,
- column: msg.column
- };
-
- if (msg.severity === 1) {
- logMessage.type = "warning";
- seq.warnings.push(logMessage);
- }
- if (msg.severity === 2) {
- logMessage.type = "error";
- seq.errors.push(logMessage);
- }
- });
- return seq;
- },
- {
- errors: [],
- warnings: []
- }
- );
-
- if (summary.errors.length > 0 || summary.warnings.length > 0) {
- var lines = summary.errors
- .concat(summary.warnings)
- .map(function(msg) {
- return (
- "\n" +
- msg.type +
- " " +
- msg.ruleId + (msg.ruleUrl ? " (" + msg.ruleUrl + ")" : "") +
- "\n " +
- msg.filePath +
- ":" +
- msg.line +
- ":" +
- msg.column
- );
- })
- .join("\n");
-
- return lines + "\n";
- }
-};
-```
-
-So running `eslint` with this custom formatter:
-
-```bash
-eslint -f ./my-awesome-formatter.js src/
-```
-
-The output will be
-
-```bash
-error space-infix-ops (https://eslint.org/docs/rules/space-infix-ops)
- src/configs/bundler.js:6:8
-error semi (https://eslint.org/docs/rules/semi)
- src/configs/bundler.js:6:10
-warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
- src/configs/bundler.js:5:6
-warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
- src/configs/bundler.js:6:6
-warning no-shadow (https://eslint.org/docs/rules/no-shadow)
- src/configs/bundler.js:65:32
-warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
- src/configs/clean.js:3:6
-```
-
-## Passing Arguments to Formatters
-
-While formatter functions do not receive arguments in addition to the results object and the context, it is possible to pass additional data into custom formatters using the methods described below.
-
-## Using Environment Variables
-
-Custom formatters have access to environment variables and so can change their behavior based on environment variable data. Here's an example that uses a `AF_SKIP_WARNINGS` environment variable to determine whether or not to show warnings in the results:
-
-```js
-module.exports = function(results) {
- var skipWarnings = process.env.AF_SKIP_WARNINGS === "true"; //af stands for awesome-formatter
-
- var results = results || [];
- var summary = results.reduce(
- function(seq, current) {
- current.messages.forEach(function(msg) {
- var logMessage = {
- filePath: current.filePath,
- ruleId: msg.ruleId,
- message: msg.message,
- line: msg.line,
- column: msg.column
- };
-
- if (msg.severity === 1) {
- logMessage.type = "warning";
- seq.warnings.push(logMessage);
- }
- if (msg.severity === 2) {
- logMessage.type = "error";
- seq.errors.push(logMessage);
- }
- });
- return seq;
- },
- {
- errors: [],
- warnings: []
- }
- );
-
- if (summary.errors.length > 0 || summary.warnings.length > 0) {
- var warnings = !skipWarnings ? summary.warnings : []; // skip the warnings in that case
-
- var lines = summary.errors
- .concat(warnings)
- .map(function(msg) {
- return (
- "\n" +
- msg.type +
- " " +
- msg.ruleId +
- "\n " +
- msg.filePath +
- ":" +
- msg.line +
- ":" +
- msg.column
- );
- })
- .join("\n");
-
- return lines + "\n";
- }
-};
-```
-
-You would run ESLint with this custom formatter and an environment variable set like this:
-
-```bash
-AF_SKIP_WARNINGS=true eslint -f ./my-awesome-formatter.js src/
-```
-
-The output would be:
-
-```bash
-error space-infix-ops
- src/configs/bundler.js:6:8
-
-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:
-
-```bash
-eslint -f json src/ | your-program-that-reads-JSON --option
-```
-
-In this example, the `your-program-that-reads-json` program can accept the raw JSON of ESLint results and process it before outputting its own format of the results. You can pass as many command line arguments to that program as are necessary to customize the output.
-
-## Note: Formatting for Terminals
-
-Modern terminals like [iTerm2](https://www.iterm2.com/) or [Guake](http://guake-project.org/) expect a specific results format to automatically open filenames when they are clicked. Most terminals support this format for that purpose:
-
-```bash
-file:line:column
-```
+++ /dev/null
----
-title: Working with Custom Parsers
-layout: doc
-eleventyNavigation:
- key: working with custom parsers
- parent: developer guide
- title: Working with Custom Parsers
- order: 7
-
----
-
-If you want to use your own parser and provide additional capabilities for your rules, you can specify your own custom parser. If a `parseForESLint` method is exposed on the parser, this method will be used to parse the code. Otherwise, the `parse` method will be used. Both methods should take in the source code as the first argument, and an optional configuration object as the second argument (provided as `parserOptions` in a config file). The `parse` method should simply return the AST. The `parseForESLint` method should return an object that contains the required property `ast` and optional properties `services`, `scopeManager`, and `visitorKeys`.
-
-* `ast` should contain the AST.
-* `services` can contain any parser-dependent services (such as type checkers for nodes). The value of the `services` property is available to rules as `context.parserServices`. Default is an empty object.
-* `scopeManager` can be a [ScopeManager](./scope-manager-interface) object. Custom parsers can use customized scope analysis for experimental/enhancement syntaxes. Default is the `ScopeManager` object which is created by [eslint-scope](https://github.com/eslint/eslint-scope).
- * Support for `scopeManager` was added in ESLint v4.14.0. ESLint versions which support `scopeManager` will provide an `eslintScopeManager: true` property in `parserOptions`, which can be used for feature detection.
-* `visitorKeys` can be an object to customize AST traversal. The keys of the object are the type of AST nodes. Each value is an array of the property names which should be traversed. Default is [KEYS of `eslint-visitor-keys`](https://github.com/eslint/eslint-visitor-keys#evkkeys).
- * Support for `visitorKeys` was added in ESLint v4.14.0. ESLint versions which support `visitorKeys` will provide an `eslintVisitorKeys: true` property in `parserOptions`, which can be used for feature detection.
-
-You can find an ESLint parser project [here](https://github.com/typescript-eslint/typescript-eslint).
-
-```json
-{
- "parser": "./path/to/awesome-custom-parser.js"
-}
-```
-
-```javascript
-var espree = require("espree");
-// awesome-custom-parser.js
-exports.parseForESLint = function(code, options) {
- return {
- ast: espree.parse(code, options),
- services: {
- foo: function() {
- console.log("foo");
- }
- },
- scopeManager: null,
- visitorKeys: null
- };
-};
-
-```
-
-## The AST specification
-
-The AST that custom parsers should create is based on [ESTree](https://github.com/estree/estree). The AST requires some additional properties about detail information of the source code.
-
-### All nodes:
-
-All nodes must have `range` property.
-
-* `range` (`number[]`) is an array of two numbers. Both numbers are a 0-based index which is the position in the array of source code characters. The first is the start position of the node, the second is the end position of the node. `code.slice(node.range[0], node.range[1])` must be the text of the node. This range does not include spaces/parentheses which are around the node.
-* `loc` (`SourceLocation`) must not be `null`. [The `loc` property is defined as nullable by ESTree](https://github.com/estree/estree/blob/25834f7247d44d3156030f8e8a2d07644d771fdb/es5.md#node-objects), but ESLint requires this property. On the other hand, `SourceLocation#source` property can be `undefined`. ESLint does not use the `SourceLocation#source` property.
-
-The `parent` property of all nodes must be rewritable. ESLint sets each node's `parent` property to its parent node while traversing, before any rules have access to the AST.
-
-### The `Program` node:
-
-The `Program` node must have `tokens` and `comments` properties. Both properties are an array of the below Token interface.
-
-```ts
-interface Token {
- type: string;
- loc: SourceLocation;
- range: [number, number]; // See "All nodes:" section for details of `range` property.
- value: string;
-}
-```
-
-* `tokens` (`Token[]`) is the array of tokens which affect the behavior of programs. Arbitrary spaces can exist between tokens, so rules check the `Token#range` to detect spaces between tokens. This must be sorted by `Token#range[0]`.
-* `comments` (`Token[]`) is the array of comment tokens. This must be sorted by `Token#range[0]`.
-
-The range indexes of all tokens and comments must not overlap with the range of other tokens and comments.
-
-### The `Literal` node:
-
-The `Literal` node must have `raw` property.
-
-* `raw` (`string`) is the source code of this literal. This is the same as `code.slice(node.range[0], node.range[1])`.
+++ /dev/null
----
-title: Working with Plugins
-layout: doc
-eleventyNavigation:
- key: working with plugings
- parent: developer guide
- title: Working with Plugins
- order: 5
-
----
-
-Each plugin is an npm module with a name in the format of `eslint-plugin-<plugin-name>`, such as `eslint-plugin-jquery`. You can also use scoped packages in the format of `@<scope>/eslint-plugin-<plugin-name>` such as `@jquery/eslint-plugin-jquery` or even `@<scope>/eslint-plugin` such as `@jquery/eslint-plugin`.
-
-## Create a Plugin
-
-The easiest way to start creating a plugin is to use the [Yeoman generator](https://www.npmjs.com/package/generator-eslint). The generator will guide you through setting up the skeleton of a plugin.
-
-### Rules in Plugins
-
-Plugins can expose additional rules for use in ESLint. To do so, the plugin must export a `rules` object containing a key-value mapping of rule ID to rule. The rule ID does not have to follow any naming convention (so it can just be `dollar-sign`, for instance).
-
-```js
-module.exports = {
- rules: {
- "dollar-sign": {
- create: function (context) {
- // rule implementation ...
- }
- }
- }
-};
-```
-
-To use the rule in ESLint, you would use the unprefixed plugin name, followed by a slash, followed by the rule name. So if this plugin were named `eslint-plugin-myplugin`, then in your configuration you'd refer to the rule by the name `myplugin/dollar-sign`. Example: `"rules": {"myplugin/dollar-sign": 2}`.
-
-### Environments in Plugins
-
-Plugins can expose additional environments for use in ESLint. To do so, the plugin must export an `environments` object. The keys of the `environments` object are the names of the different environments provided and the values are the environment settings. For example:
-
-```js
-module.exports = {
- environments: {
- jquery: {
- globals: {
- $: false
- }
- }
- }
-};
-```
-
-There's a `jquery` environment defined in this plugin. To use the environment in ESLint, you would use the unprefixed plugin name, followed by a slash, followed by the environment name. So if this plugin were named `eslint-plugin-myplugin`, then you would set the environment in your configuration to be `"myplugin/jquery"`.
-
-Plugin environments can define the following objects:
-
-1. `globals` - acts the same `globals` in a configuration file. The keys are the names of the globals and the values are `true` to allow the global to be overwritten and `false` to disallow.
-1. `parserOptions` - acts the same as `parserOptions` in a configuration file.
-
-### Processors in Plugins
-
-You can also create plugins that would tell ESLint how to process files other than JavaScript. In order to create a processor, the object that is exported from your module has to conform to the following interface:
-
-```js
-module.exports = {
- processors: {
- "processor-name": {
- // takes text of the file and filename
- preprocess: function(text, filename) {
- // here, you can strip out any non-JS content
- // and split into multiple strings to lint
-
- return [ // return an array of code blocks to lint
- { text: code1, filename: "0.js" },
- { text: code2, filename: "1.js" },
- ];
- },
-
- // takes a Message[][] and filename
- postprocess: function(messages, filename) {
- // `messages` argument contains two-dimensional array of Message objects
- // where each top-level array item contains array of lint messages related
- // to the text that was returned in array from preprocess() method
-
- // you need to return a one-dimensional array of the messages you want to keep
- return [].concat(...messages);
- },
-
- supportsAutofix: true // (optional, defaults to false)
- }
- }
-};
-```
-
-**The `preprocess` method** takes the file contents and filename as arguments, and returns an array of code blocks to lint. The code blocks will be linted separately but still be registered to the filename.
-
-A code block has two properties `text` and `filename`; the `text` property is the content of the block and the `filename` property is the name of the block. Name of the block can be anything, but should include the file extension, that would tell the linter how to process the current block. The linter will check [`--ext` CLI option](../user-guide/command-line-interface#--ext) to see if the current block should be linted, and resolve `overrides` configs to check how to process the current block.
-
-It's up to the plugin to decide if it needs to return just one part, or multiple pieces. For example in the case of processing `.html` files, you might want to return just one item in the array by combining all scripts, but for `.md` file where each JavaScript block might be independent, you can return multiple items.
-
-**The `postprocess` method** takes a two-dimensional array of arrays of lint messages and the filename. Each item in the input array corresponds to the part that was returned from the `preprocess` method. The `postprocess` method must adjust the locations of all errors to correspond to locations in the original, unprocessed code, and aggregate them into a single flat array and return it.
-
-Reported problems have the following location information:
-
-```typescript
-{
- line: number,
- column: number,
-
- endLine?: number,
- endColumn?: number
-}
-```
-
-By default, ESLint will not perform autofixes when a processor is used, even when the `--fix` flag is enabled on the command line. To allow ESLint to autofix code when using your processor, you should take the following additional steps:
-
-1. Update the `postprocess` method to additionally transform the `fix` property of reported problems. All autofixable problems will have a `fix` property, which is an object with the following schema:
-
- ```js
- {
- range: [number, number],
- text: string
- }
- ```
-
- The `range` property contains two indexes in the code, referring to the start and end location of a contiguous section of text that will be replaced. The `text` property refers to the text that will replace the given range.
-
- In the initial list of problems, the `fix` property will refer to a fix in the processed JavaScript. The `postprocess` method should transform the object to refer to a fix in the original, unprocessed file.
-
-2. Add a `supportsAutofix: true` property to the processor.
-
-You can have both rules and processors in a single plugin. You can also have multiple processors in one plugin.
-To support multiple extensions, add each one to the `processors` element and point them to the same object.
-
-#### Specifying Processor in Config Files
-
-To use a processor, add its ID to a `processor` section in the config file. Processor ID is a concatenated string of plugin name and processor name with a slash as a separator. This can also be added to a `overrides` section of the config, to specify which processors should handle which files.
-
-For example:
-
-```yml
-plugins:
- - a-plugin
-overrides:
- - files: "*.md"
- processor: a-plugin/markdown
-```
-
-See [Specifying Processor](../user-guide/configuring/plugins#specifying-processor) for details.
-
-#### File Extension-named Processor
-
-If a processor name starts with `.`, ESLint handles the processor as a **file extension-named processor** especially and applies the processor to the kind of files automatically. People don't need to specify the file extension-named processors in their config files.
-
-For example:
-
-```js
-module.exports = {
- processors: {
- // This processor will be applied to `*.md` files automatically.
- // Also, people can use this processor as "plugin-id/.md" explicitly.
- ".md": {
- preprocess(text, filename) { /* ... */ },
- postprocess(messageLists, filename) { /* ... */ }
- }
- }
-}
-```
-
-### Configs in Plugins
-
-You can bundle configurations inside a plugin by specifying them under the `configs` key. This can be useful when you want to provide not just code style, but also some custom rules to support it. Multiple configurations are supported per plugin. Note that it is not possible to specify a default configuration for a given plugin and that users must specify in their configuration file when they want to use one.
-
-```js
-// eslint-plugin-myPlugin
-
-module.exports = {
- configs: {
- myConfig: {
- plugins: ["myPlugin"],
- env: ["browser"],
- rules: {
- semi: "error",
- "myPlugin/my-rule": "error",
- "eslint-plugin-myPlugin/another-rule": "error"
- }
- },
- myOtherConfig: {
- plugins: ["myPlugin"],
- env: ["node"],
- rules: {
- "myPlugin/my-rule": "off",
- "eslint-plugin-myPlugin/another-rule": "off",
- "eslint-plugin-myPlugin/yet-another-rule": "error"
- }
- }
- }
-};
-```
-
-If the example plugin above were called `eslint-plugin-myPlugin`, the `myConfig` and `myOtherConfig` configurations would then be usable by extending off of `"plugin:myPlugin/myConfig"` and `"plugin:myPlugin/myOtherConfig"`, respectively.
-
-```json
-{
- "extends": ["plugin:myPlugin/myConfig"]
-}
-
-```
-
-**Note:** Please note that configuration will not enable any of the plugin's rules by default, and instead should be treated as a standalone config. This means that you must specify your plugin name in the `plugins` array as well as any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name. See [Configuring Plugins](../user-guide/configuring/plugins#configuring-plugins) for more information.
-
-### Peer Dependency
-
-To make clear that the plugin requires ESLint to work correctly you have to declare ESLint as a `peerDependency` in your `package.json`.
-The plugin support was introduced in ESLint version `0.8.0`. Ensure the `peerDependency` points to ESLint `0.8.0` or later.
-
-```json
-{
- "peerDependencies": {
- "eslint": ">=0.8.0"
- }
-}
-```
-
-### Testing
-
-ESLint provides the [`RuleTester`](/docs/developer-guide/nodejs-api#ruletester) utility to make it easy to test the rules of your plugin.
-
-### Linting
-
-ESLint plugins should be linted too! It's suggested to lint your plugin with the `recommended` configurations of:
-
-* [eslint](https://www.npmjs.com/package/eslint)
-* [eslint-plugin-eslint-plugin](https://www.npmjs.com/package/eslint-plugin-eslint-plugin)
-* [eslint-plugin-node](https://www.npmjs.com/package/eslint-plugin-node)
-
-## Share Plugins
-
-In order to make your plugin available to the community you have to publish it on npm.
-
-Recommended keywords:
-
-* `eslint`
-* `eslintplugin`
-
-Add these keywords into your `package.json` file to make it easy for others to find.
-
-## Further Reading
-
-* [npm Developer Guide](https://docs.npmjs.com/misc/developers)
+++ /dev/null
----
-title: Working with Rules (Deprecated)
-layout: doc
-
----
-
-**Note:** This page covers the deprecated rule format for ESLint <= 2.13.1. [This is the most recent rule format](./working-with-rules).
-
-Each rule in ESLint has two files named with its identifier (for example, `no-extra-semi`).
-
-* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`)
-* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`)
-
-**Important:** If you submit a **core** rule to the ESLint repository, you **must** follow some conventions explained below.
-
-Here is the basic format of the source file for a rule:
-
-```js
-/**
- * @fileoverview Rule to disallow unnecessary semicolons
- * @author Nicholas C. Zakas
- */
-
-"use strict";
-
-//------------------------------------------------------------------------------
-// Rule Definition
-//------------------------------------------------------------------------------
-
-module.exports = function(context) {
- return {
- // callback functions
- };
-};
-
-module.exports.schema = []; // no options
-```
-
-## Rule Basics
-
-`schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../user-guide/configuring/rules#configuring-rules)
-
-`create` (function) returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code:
-
-* if a key is a node type, ESLint calls that **visitor** function while going **down** the tree
-* if a key is a node type plus `:exit`, ESLint calls that **visitor** function while going **up** the tree
-* if a key is an event name, ESLint calls that **handler** function for [code path analysis](./code-path-analysis)
-
-A rule can use the current node and its surrounding tree to report or fix problems.
-
-Here are methods for the [array-callback-return](../rules/array-callback-return) rule:
-
-```js
-function checkLastSegment (node) {
- // report problem for function if last code path segment is reachable
-}
-
-module.exports = function(context) {
- // declare the state of the rule
- return {
- ReturnStatement: function(node) {
- // at a ReturnStatement node while going down
- },
- // at a function expression node while going up:
- "FunctionExpression:exit": checkLastSegment,
- "ArrowFunctionExpression:exit": checkLastSegment,
- onCodePathStart: function (codePath, node) {
- // at the start of analyzing a code path
- },
- onCodePathEnd: function(codePath, node) {
- // at the end of analyzing a code path
- }
- };
-};
-```
-
-## The Context Object
-
-The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. The `context` object has the following properties:
-
-* `parserOptions` - the parser options configured for this run (more details [here](../user-guide/configuring/language-options#specifying-parser-options)).
-* `id` - the rule ID.
-* `options` - an array of rule options.
-* `settings` - the `settings` from configuration.
-* `parserPath` - the full path to the `parser` from configuration.
-
-Additionally, the `context` object has the following methods:
-
-* `getAncestors()` - returns an array of ancestor nodes based on the current traversal.
-* `getDeclaredVariables(node)` - returns the declared variables on the given node.
-* `getFilename()` - returns the filename associated with the source.
-* `getScope()` - returns the current scope.
-* `getSourceCode()` - returns a `SourceCode` object that you can use to work with the source that was passed to ESLint
-* `markVariableAsUsed(name)` - marks the named variable in scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule.
-* `report(descriptor)` - reports a problem in the code.
-
-**Deprecated:** The following methods on the `context` object are deprecated. Please use the corresponding methods on `SourceCode` instead:
-
-* `getAllComments()` - returns an array of all comments in the source. Use `sourceCode.getAllComments()` instead.
-* `getComments(node)` - returns the leading and trailing comments arrays for the given node. Use `sourceCode.getComments(node)` instead.
-* `getFirstToken(node)` - returns the first token representing the given node. Use `sourceCode.getFirstToken(node)` instead.
-* `getFirstTokens(node, count)` - returns the first `count` tokens representing the given node. Use `sourceCode.getFirstTokens(node, count)` instead.
-* `getJSDocComment(node)` - returns the JSDoc comment for a given node or `null` if there is none. Use `sourceCode.getJSDocComment(node)` instead.
-* `getLastToken(node)` - returns the last token representing the given node. Use `sourceCode.getLastToken(node)` instead.
-* `getLastTokens(node, count)` - returns the last `count` tokens representing the given node. Use `sourceCode.getLastTokens(node, count)` instead.
-* `getNodeByRangeIndex(index)` - returns the deepest node in the AST containing the given source index. Use `sourceCode.getNodeByRangeIndex(index)` instead.
-* `getSource(node)` - returns the source code for the given node. Omit `node` to get the whole source. Use `sourceCode.getText(node)` instead.
-* `getSourceLines()` - returns the entire source code split into an array of string lines. Use `sourceCode.lines` instead.
-* `getTokenAfter(nodeOrToken)` - returns the first token after the given node or token. Use `sourceCode.getTokenAfter(nodeOrToken)` instead.
-* `getTokenBefore(nodeOrToken)` - returns the first token before the given node or token. Use `sourceCode.getTokenBefore(nodeOrToken)` instead.
-* `getTokenByRangeStart(index)` - returns the token whose range starts at the given index in the source. Use `sourceCode.getTokenByRangeStart(index)` instead.
-* `getTokens(node)` - returns all tokens for the given node. Use `sourceCode.getTokens(node)` instead.
-* `getTokensAfter(nodeOrToken, count)` - returns `count` tokens after the given node or token. Use `sourceCode.getTokensAfter(nodeOrToken, count)` instead.
-* `getTokensBefore(nodeOrToken, count)` - returns `count` tokens before the given node or token. Use `sourceCode.getTokensBefore(nodeOrToken, count)` instead.
-* `getTokensBetween(node1, node2)` - returns the tokens between two nodes. Use `sourceCode.getTokensBetween(node1, node2)` instead.
-* `report(node, [location], message)` - reports a problem in the code.
-
-### context.report()
-
-The main method you'll use is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties:
-
-* `message` - the problem message.
-* `node` - (optional) the AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem.
-* `loc` - (optional) an object specifying the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`.
- * `line` - the 1-based line number at which the problem occurred.
- * `column` - the 0-based column number at which the problem occurred.
-* `data` - (optional) placeholder data for `message`.
-* `fix` - (optional) a function that applies a fix to resolve the problem.
-
-Note that at least one of `node` or `loc` is required.
-
-The simplest example is to use just `node` and `message`:
-
-```js
-context.report({
- node: node,
- message: "Unexpected identifier"
-});
-```
-
-The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node.
-
-You can also use placeholders in the message and provide `data`:
-
-```js
-{% raw %}
-context.report({
- node: node,
- message: "Unexpected identifier: {{ identifier }}",
- data: {
- identifier: node.name
- }
-});
-{% endraw %}
-```
-
-Note that leading and trailing whitespace is optional in message parameters.
-
-The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node.
-
-### Applying Fixes
-
-If you'd like ESLint to attempt to fix the problem you're reporting, you can do so by specifying the `fix` function when using `context.report()`. The `fix` function receives a single argument, a `fixer` object, that you can use to apply a fix. For example:
-
-```js
-context.report({
- node: node,
- message: "Missing semicolon".
- fix: function(fixer) {
- return fixer.insertTextAfter(node, ";");
- }
-});
-```
-
-Here, the `fix()` function is used to insert a semicolon after the node. Note that the fix is not immediately applied and may not be applied at all if there are conflicts with other fixes. If the fix cannot be applied, then the problem message is reported as usual; if the fix can be applied, then the problem message is not reported.
-
-The `fixer` object has the following methods:
-
-* `insertTextAfter(nodeOrToken, text)` - inserts text after the given node or token
-* `insertTextAfterRange(range, text)` - inserts text after the given range
-* `insertTextBefore(nodeOrToken, text)` - inserts text before the given node or token
-* `insertTextBeforeRange(range, text)` - inserts text before the given range
-* `remove(nodeOrToken)` - removes the given node or token
-* `removeRange(range)` - removes text in the given range
-* `replaceText(nodeOrToken, text)` - replaces the text in the given node or token
-* `replaceTextRange(range, text)` - replaces the text in the given range
-
-Best practices for fixes:
-
-1. Make fixes that are as small as possible. Anything more than a single character is risky and could prevent other, simpler fixes from being made.
-1. Only make one fix per message. This is enforced because you must return the result of the fixer operation from `fix()`.
-1. Fixes should not introduce clashes with other rules. You can accidentally introduce a new problem that won't be reported until ESLint is run again. Another good reason to make as small a fix as possible.
-
-### context.options
-
-Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line, or in comments). For example:
-
-```json
-{
- "quotes": [2, "double"]
-}
-```
-
-The `quotes` rule in this example has one option, `"double"` (the `2` is the error level). You can retrieve the options for a rule by using `context.options`, which is an array containing every configured option for the rule. In this case, `context.options[0]` would contain `"double"`:
-
-```js
-module.exports = function(context) {
-
- var isDouble = (context.options[0] === "double");
-
- // ...
-}
-```
-
-Since `context.options` is just an array, you can use it to determine how many options have been passed as well as retrieving the actual options themselves. Keep in mind that the error level is not part of `context.options`, as the error level cannot be known or modified from inside a rule.
-
-When using options, make sure that your rule has some logic defaults in case the options are not provided.
-
-### context.getSourceCode()
-
-The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `getSourceCode()` method:
-
-```js
-module.exports = function(context) {
-
- var sourceCode = context.getSourceCode();
-
- // ...
-}
-```
-
-Once you have an instance of `SourceCode`, you can use the methods on it to work with the code:
-
-* `getAllComments()` - returns an array of all comments in the source.
-* `getComments(node)` - returns the leading and trailing comments arrays for the given node.
-* `getFirstToken(node)` - returns the first token representing the given node.
-* `getFirstTokens(node, count)` - returns the first `count` tokens representing the given node.
-* `getJSDocComment(node)` - returns the JSDoc comment for a given node or `null` if there is none.
-* `getLastToken(node)` - returns the last token representing the given node.
-* `getLastTokens(node, count)` - returns the last `count` tokens representing the given node.
-* `getNodeByRangeIndex(index)` - returns the deepest node in the AST containing the given source index.
-* `isSpaceBetweenTokens(first, second)` - returns true if there is a whitespace character between the two tokens.
-* `getText(node)` - returns the source code for the given node. Omit `node` to get the whole source.
-* `getTokenAfter(nodeOrToken)` - returns the first token after the given node or token.
-* `getTokenBefore(nodeOrToken)` - returns the first token before the given node or token.
-* `getTokenByRangeStart(index)` - returns the token whose range starts at the given index in the source.
-* `getTokens(node)` - returns all tokens for the given node.
-* `getTokensAfter(nodeOrToken, count)` - returns `count` tokens after the given node or token.
-* `getTokensBefore(nodeOrToken, count)` - returns `count` tokens before the given node or token.
-* `getTokensBetween(node1, node2)` - returns the tokens between two nodes.
-
-There are also some properties you can access:
-
-* `hasBOM` - the flag to indicate whether or not the source code has Unicode BOM.
-* `text` - the full text of the code being linted. Unicode BOM has been stripped from this text.
-* `ast` - the `Program` node of the AST for the code being linted.
-* `lines` - an array of lines, split according to the specification's definition of line breaks.
-
-You should use a `SourceCode` object whenever you need to get more information about the code being linted.
-
-### Options Schemas
-
-Rules may export a `schema` property, which is a [JSON schema](http://json-schema.org/) format description of a rule's options which will be used by ESLint to validate configuration options and prevent invalid or unexpected inputs before they are passed to the rule in `context.options`.
-
-There are two formats for a rule's exported `schema`. The first is a full JSON Schema object describing all possible options the rule accepts, including the rule's error level as the first argument and any optional arguments thereafter.
-
-However, to simplify schema creation, rules may also export an array of schemas for each optional positional argument, and ESLint will automatically validate the required error level first. For example, the `yoda` rule accepts a primary mode argument, as well as an extra options object with named properties.
-
-```js
-// "yoda": [2, "never", { "exceptRange": true }]
-module.exports.schema = [
- {
- "enum": ["always", "never"]
- },
- {
- "type": "object",
- "properties": {
- "exceptRange": {
- "type": "boolean"
- }
- },
- "additionalProperties": false
- }
-];
-```
-
-In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a Boolean property named `exceptRange`.
-
-To learn more about JSON Schema, we recommend looking at some [examples](http://json-schema.org/examples.html) to start, and also reading [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/) (a free ebook).
-
-### Getting the Source
-
-If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows:
-
-```js
-
-// get all source
-var source = sourceCode.getText();
-
-// get source for just this AST node
-var nodeSource = sourceCode.getText(node);
-
-// get source for AST node plus previous two characters
-var nodeSourceWithPrev = sourceCode.getText(node, 2);
-
-// get source for AST node plus following two characters
-var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2);
-```
-
-In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.).
-
-### Accessing comments
-
-If you need to access comments for a specific node you can use `sourceCode.getComments(node)`:
-
-```js
-// the "comments" variable has a "leading" and "trailing" property containing
-// its leading and trailing comments, respectively
-var comments = sourceCode.getComments(node);
-```
-
-Keep in mind that comments are technically not a part of the AST and are only attached to it on demand, i.e. when you call `getComments()`.
-
-**Note:** One of the libraries adds AST node properties for comments - do not use these properties. Always use `sourceCode.getComments()` as this is the only guaranteed API for accessing comments (we will likely change how comments are handled later).
-
-### Accessing Code Paths
-
-ESLint analyzes code paths while traversing AST.
-You can access that code path objects with five events related to code paths.
-
-[details here](./code-path-analysis)
-
-## Rule Unit Tests
-
-Each rule must have a set of unit tests submitted with it to be accepted. The test file is named the same as the source file but lives in `tests/lib/`. For example, if your rule source file is `lib/rules/foo.js` then your test file should be `tests/lib/rules/foo.js`.
-
-For your rule, be sure to test:
-
-1. All instances that should be flagged as warnings.
-1. At least one pattern that should **not** be flagged as a warning.
-
-The basic pattern for a rule unit test file is:
-
-```js
-/**
- * @fileoverview Tests for no-with rule.
- * @author Nicholas C. Zakas
- */
-
-"use strict";
-
-//------------------------------------------------------------------------------
-// Requirements
-//------------------------------------------------------------------------------
-
-var rule = require("../../../lib/rules/no-with"),
- RuleTester = require("../../../lib/testers/rule-tester");
-
-//------------------------------------------------------------------------------
-// Tests
-//------------------------------------------------------------------------------
-
-var ruleTester = new RuleTester();
-ruleTester.run("no-with", rule, {
- valid: [
- "foo.bar()"
- ],
- invalid: [
- {
- code: "with(foo) { bar() }",
- errors: [{ message: "Unexpected use of 'with' statement.", type: "WithStatement"}]
- }
- ]
-});
-```
-
-Be sure to replace the value of `"no-with"` with your rule's ID. There are plenty of examples in the `tests/lib/rules/` directory.
-
-### Valid Code
-
-Each valid case can be either a string or an object. The object form is used when you need to specify additional global variables or arguments for the rule. For example, the following defines `window` as a global variable for code that should not trigger the rule being tested:
-
-```js
-valid: [
- {
- code: "window.alert()",
- globals: [ "window" ]
- }
-]
-```
-
-You can also pass options to the rule (if it accepts them). These arguments are equivalent to how people can configure rules in their `.eslintrc` file. For example:
-
-```js
-valid: [
- {
- code: "var msg = 'Hello';",
- options: [ "single" ]
- }
-]
-```
-
-The `options` property must be an array of options. This gets passed through to `context.options` in the rule.
-
-### Invalid Code
-
-Each invalid case must be an object containing the code to test and at least one message that is produced by the rule. The `errors` key specifies an array of objects, each containing a message (your rule may trigger multiple messages for the same code). You should also specify the type of AST node you expect to receive back using the `type` key. The AST node should represent the actual spot in the code where there is a problem. For example:
-
-```js
-invalid: [
- {
- code: "function doSomething() { var f; if (true) { var build = true; } f = build; }",
- errors: [
- { message: "build used outside of binding context.", type: "Identifier" }
- ]
- }
-]
-```
-
-In this case, the message is specific to the variable being used and the AST node type is `Identifier`.
-
-Similar to the valid cases, you can also specify `options` to be passed to the rule:
-
-```js
-invalid: [
- {
- code: "function doSomething() { var f; if (true) { var build = true; } f = build; }",
- options: [ "double" ],
- errors: [
- { message: "build used outside of binding context.", type: "Identifier" }
- ]
- }
-]
-```
-
-For simpler cases where the only thing that really matters is the error message, you can also specify any `errors` as strings. You can also have some strings and some objects, if you like.
-
-```js
-invalid: [
- {
- code: "'single quotes'",
- options: ["double"],
- errors: ["Strings must use doublequote."]
- }
-]
-```
-
-### Specifying Parser Options
-
-Some tests require that a certain parser configuration must be used. This can be specified in test specifications via the `parserOptions` setting.
-
-For example, to set `ecmaVersion` to 6 (in order to use constructs like `for ... of`):
-
-```js
-valid: [
- {
- code: "for (x of a) doSomething();",
- parserOptions: { ecmaVersion: 6 }
- }
-]
-```
-
-If you are working with ES6 modules:
-
-```js
-valid: [
- {
- code: "export default function () {};",
- parserOptions: { ecmaVersion: 6, sourceType: "module" }
- }
-]
-```
-
-For non-version specific features such as JSX:
-
-```js
-valid: [
- {
- code: "var foo = <div>{bar}</div>",
- parserOptions: { ecmaFeatures: { jsx: true } }
- }
-]
-```
-
-The options available and the expected syntax for `parserOptions` is the same as those used in [configuration](../user-guide/configuring/language-options#specifying-parser-options).
-
-### Write Several Tests
-
-Provide as many unit tests as possible. Your pull request will never be turned down for having too many tests submitted with it!
-
-## Performance Testing
-
-To keep the linting process efficient and unobtrusive, it is useful to verify the performance impact of new rules or modifications to existing rules.
-
-### Overall Performance
-
-The `npm run perf` command gives a high-level overview of ESLint running time with default rules (`eslint:recommended`) enabled.
-
-```bash
-$ git checkout main
-Switched to branch 'main'
-
-$ npm run perf
-CPU Speed is 2200 with multiplier 7500000
-Performance Run #1: 1394.689313ms
-Performance Run #2: 1423.295351ms
-Performance Run #3: 1385.09515ms
-Performance Run #4: 1382.406982ms
-Performance Run #5: 1409.68566ms
-Performance budget ok: 1394.689313ms (limit: 3409.090909090909ms)
-
-$ git checkout my-rule-branch
-Switched to branch 'my-rule-branch'
-
-$ npm run perf
-CPU Speed is 2200 with multiplier 7500000
-Performance Run #1: 1443.736547ms
-Performance Run #2: 1419.193291ms
-Performance Run #3: 1436.018228ms
-Performance Run #4: 1473.605485ms
-Performance Run #5: 1457.455283ms
-Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms)
-```
-
-### Per-rule Performance
-
-ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time and relative performance impact as a percentage of total rule processing time.
-
-```bash
-$ TIMING=1 eslint lib
-Rule | Time (ms) | Relative
-:-----------------------|----------:|--------:
-no-multi-spaces | 52.472 | 6.1%
-camelcase | 48.684 | 5.7%
-no-irregular-whitespace | 43.847 | 5.1%
-valid-jsdoc | 40.346 | 4.7%
-handle-callback-err | 39.153 | 4.6%
-space-infix-ops | 35.444 | 4.1%
-no-undefined | 25.693 | 3.0%
-no-shadow | 22.759 | 2.7%
-no-empty-class | 21.976 | 2.6%
-semi | 19.359 | 2.3%
-```
-
-To test one rule explicitly, combine the `--no-eslintrc`, and `--rule` options:
-
-```bash
-$ TIMING=1 eslint --no-eslintrc --rule "quotes: [2, 'double']" lib
-Rule | Time (ms) | Relative
-:------|----------:|--------:
-quotes | 18.066 | 100.0%
-```
-
-## Rule Naming Conventions
-
-The rule naming conventions for ESLint are fairly simple:
-
-* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`.
-* If your rule is enforcing the inclusion of something, use a short name without a special prefix.
-* Keep your rule names as short as possible, use abbreviations where appropriate, and no more than four words.
-* Use dashes between words.
-
-## Rule Acceptance Criteria
-
-Because rules are highly personal (and therefore very contentious), accepted rules should:
-
-* Not be library-specific.
-* Demonstrate a possible issue that can be resolved by rewriting the code.
-* Be general enough so as to apply for a large number of developers.
-* Not be the opposite of an existing rule.
-* Not overlap with an existing rule.
-
-## Runtime Rules
-
-The thing that makes ESLint different from other linters is the ability to define custom rules at runtime. This is perfect for rules that are specific to your project or company and wouldn't make sense for ESLint to ship with. With runtime rules, you don't have to wait for the next version of ESLint or be disappointed that your rule isn't general enough to apply to the larger JavaScript community, just write your rules and include them at runtime.
-
-Runtime rules are written in the same format as all other rules. Create your rule as you would any other and then follow these steps:
-
-1. Place all of your runtime rules in the same directory (i.e., `eslint_rules`).
-2. Create a [configuration file](../user-guide/configuring/) and specify your rule ID error level under the `rules` key. Your rule will not run unless it has a value of `1` or `2` in the configuration file.
-3. Run the [command line interface](../user-guide/command-line-interface) using the `--rulesdir` option to specify the location of your runtime rules.
+++ /dev/null
----
-title: Working with Rules
-layout: doc
-eleventyNavigation:
- key: working with rules
- parent: developer guide
- title: Working with Rules
- order: 4
-
----
-
-**Note:** This page covers the most recent rule format for ESLint >= 3.0.0. There is also a [deprecated rule format](./working-with-rules-deprecated).
-
-Each rule in ESLint has three files named with its identifier (for example, `no-extra-semi`).
-
-* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`)
-* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`)
-* in the `docs/src/rules` directory: a Markdown documentation file (for example, `no-extra-semi.md`)
-
-**Important:** If you submit a **core** rule to the ESLint repository, you **must** follow some conventions explained below.
-
-Here is the basic format of the source file for a rule:
-
-```js
-/**
- * @fileoverview Rule to disallow unnecessary semicolons
- * @author Nicholas C. Zakas
- */
-
-"use strict";
-
-//------------------------------------------------------------------------------
-// Rule Definition
-//------------------------------------------------------------------------------
-
-/** @type {import('eslint').Rule.RuleModule} */
-module.exports = {
- meta: {
- type: "suggestion",
-
- docs: {
- description: "disallow unnecessary semicolons",
- recommended: true,
- url: "https://eslint.org/docs/rules/no-extra-semi"
- },
- fixable: "code",
- schema: [] // no options
- },
- create: function(context) {
- return {
- // callback functions
- };
- }
-};
-```
-
-## Rule Basics
-
-The source file for a rule exports an object with the following properties.
-
-`meta` (object) contains metadata for the rule:
-
-* `type` (string) indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`:
- * `"problem"` means the rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve.
- * `"suggestion"` means the rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed.
- * `"layout"` means the rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST.
-
-* `docs` (object) is required for core rules of ESLint:
-
- * `description` (string) provides the short description of the rule in the [rules index](../rules/)
- * `recommended` (boolean) is whether the `"extends": "eslint:recommended"` property in a [configuration file](../user-guide/configuring/configuration-files#extending-configuration-files) enables the rule
- * `url` (string) specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations)
-
- In a custom rule or plugin, you can omit `docs` or include any properties that you need in it.
-
-* `fixable` (string) is either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../user-guide/command-line-interface#--fix) automatically fixes problems reported by the rule
-
- **Important:** the `fixable` property is mandatory for fixable rules. If this property isn't specified, ESLint will throw an error whenever the rule attempts to produce a fix. Omit the `fixable` property if the rule is not fixable.
-
-* `hasSuggestions` (boolean) specifies whether rules can return suggestions (defaults to `false` if omitted)
-
- **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions.
-
-* `schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../user-guide/configuring/rules#configuring-rules)
-
-* `deprecated` (boolean) indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated.
-
-* `replacedBy` (array) in the case of a deprecated rule, specifies replacement rule(s)
-
-`create` (function) returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code:
-
-* if a key is a node type or a [selector](./selectors), ESLint calls that **visitor** function while going **down** the tree
-* if a key is a node type or a [selector](./selectors) plus `:exit`, ESLint calls that **visitor** function while going **up** the tree
-* if a key is an event name, ESLint calls that **handler** function for [code path analysis](./code-path-analysis)
-
-A rule can use the current node and its surrounding tree to report or fix problems.
-
-Here are methods for the [array-callback-return](../rules/array-callback-return) rule:
-
-```js
-function checkLastSegment (node) {
- // report problem for function if last code path segment is reachable
-}
-
-module.exports = {
- meta: { ... },
- create: function(context) {
- // declare the state of the rule
- return {
- ReturnStatement: function(node) {
- // at a ReturnStatement node while going down
- },
- // at a function expression node while going up:
- "FunctionExpression:exit": checkLastSegment,
- "ArrowFunctionExpression:exit": checkLastSegment,
- onCodePathStart: function (codePath, node) {
- // at the start of analyzing a code path
- },
- onCodePathEnd: function(codePath, node) {
- // at the end of analyzing a code path
- }
- };
- }
-};
-```
-
-## The Context Object
-
-The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. The `context` object has the following properties:
-
-* `parserOptions` - the parser options configured for this run (more details [here](../user-guide/configuring/language-options#specifying-parser-options)).
-* `id` - the rule ID.
-* `options` - an array of the [configured options](/docs/user-guide/configuring/rules#configuring-rules) for this rule. This array does not include the rule severity. For more information, see [here](#contextoptions).
-* `settings` - the [shared settings](/docs/user-guide/configuring/configuration-files#adding-shared-settings) from configuration.
-* `parserPath` - the name of the `parser` from configuration.
-* `parserServices` - an object containing parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.)
-
-Additionally, the `context` object has the following methods:
-
-* `getAncestors()` - returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself.
-* `getCwd()` - returns the `cwd` passed to [Linter](./nodejs-api#linter). It is a path to a directory that should be considered as the current working directory.
-* `getDeclaredVariables(node)` - returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables.
- * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned.
- * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned.
- * If the node is a `FunctionDeclaration` or `FunctionExpression`, the variable for the function name is returned, in addition to variables for the function parameters.
- * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned.
- * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned.
- * If the node is a `CatchClause`, the variable for the exception is returned.
- * If the node is an `ImportDeclaration`, variables for all of its specifiers are returned.
- * If the node is an `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`, the declared variable is returned.
- * Otherwise, if the node does not declare any variables, an empty array is returned.
-* `getFilename()` - returns the filename associated with the source.
-* `getPhysicalFilename()` - when linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `<text>` if not specified.
-* `getScope()` - returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables.
-* `getSourceCode()` - returns a [`SourceCode`](#contextgetsourcecode) object that you can use to work with the source that was passed to ESLint.
-* `markVariableAsUsed(name)` - marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`.
-* `report(descriptor)` - reports a problem in the code (see the [dedicated section](#contextreport)).
-
-**Note:** Earlier versions of ESLint supported additional methods on the `context` object. Those methods were removed in the new format and should not be relied upon.
-
-### context.getScope()
-
-This method returns the scope which has the following types:
-
-| AST Node Type | Scope Type |
-|:--------------------------|:-----------|
-| `Program` | `global` |
-| `FunctionDeclaration` | `function` |
-| `FunctionExpression` | `function` |
-| `ArrowFunctionExpression` | `function` |
-| `ClassDeclaration` | `class` |
-| `ClassExpression` | `class` |
-| `BlockStatement` ※1 | `block` |
-| `SwitchStatement` ※1 | `switch` |
-| `ForStatement` ※2 | `for` |
-| `ForInStatement` ※2 | `for` |
-| `ForOfStatement` ※2 | `for` |
-| `WithStatement` | `with` |
-| `CatchClause` | `catch` |
-| others | ※3 |
-
-**※1** Only if the configured parser provided the block-scope feature. The default parser provides the block-scope feature if `parserOptions.ecmaVersion` is not less than `6`.<br>
-**※2** Only if the `for` statement defines the iteration variable as a block-scoped variable (E.g., `for (let i = 0;;) {}`).<br>
-**※3** The scope of the closest ancestor node which has own scope. If the closest ancestor node has multiple scopes then it chooses the innermost scope (E.g., the `Program` node has a `global` scope and a `module` scope if `Program#sourceType` is `"module"`. The innermost scope is the `module` scope.).
-
-The returned value is a [`Scope` object](scope-manager-interface) defined by the `eslint-scope` package. The `Variable` objects of global variables have some additional properties.
-
-* `variable.writeable` (`boolean | undefined`) ... If `true`, this global variable can be assigned arbitrary value. If `false`, this global variable is read-only.
-* `variable.eslintExplicitGlobal` (`boolean | undefined`) ... If `true`, this global variable was defined by a `/* globals */` directive comment in the source code file.
-* `variable.eslintExplicitGlobalComments` (`Comment[] | undefined`) ... The array of `/* globals */` directive comments which defined this global variable in the source code file. This property is `undefined` if there are no `/* globals */` directive comments.
-* `variable.eslintImplicitGlobalSetting` (`"readonly" | "writable" | undefined`) ... The configured value in config files. This can be different from `variable.writeable` if there are `/* globals */` directive comments.
-
-### context.report()
-
-The main method you'll use is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties:
-
-* `message` - the problem message.
-* `node` - (optional) the AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem.
-* `loc` - (optional) an object specifying the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`.
- * `start` - An object of the start location.
- * `line` - the 1-based line number at which the problem occurred.
- * `column` - the 0-based column number at which the problem occurred.
- * `end` - An object of the end location.
- * `line` - the 1-based line number at which the problem occurred.
- * `column` - the 0-based column number at which the problem occurred.
-* `data` - (optional) [placeholder](#using-message-placeholders) data for `message`.
-* `fix` - (optional) a function that applies a [fix](#applying-fixes) to resolve the problem.
-
-Note that at least one of `node` or `loc` is required.
-
-The simplest example is to use just `node` and `message`:
-
-```js
-context.report({
- node: node,
- message: "Unexpected identifier"
-});
-```
-
-The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node.
-
-### Using message placeholders
-
-You can also use placeholders in the message and provide `data`:
-
-```js
-{% raw %}
-context.report({
- node: node,
- message: "Unexpected identifier: {{ identifier }}",
- data: {
- identifier: node.name
- }
-});
-{% endraw %}
-```
-
-Note that leading and trailing whitespace is optional in message parameters.
-
-The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node.
-
-### `messageId`s
-
-Instead of typing out messages in both the `context.report()` call and your tests, you can use `messageId`s instead.
-
-This allows you to avoid retyping error messages. It also prevents errors reported in different sections of your rule from having out-of-date messages.
-
-```js
-{% raw %}
-// in your rule
-module.exports = {
- meta: {
- messages: {
- avoidName: "Avoid using variables named '{{ name }}'"
- }
- },
- create(context) {
- return {
- Identifier(node) {
- if (node.name === "foo") {
- context.report({
- node,
- messageId: "avoidName",
- data: {
- name: "foo",
- }
- });
- }
- }
- };
- }
-};
-
-// in the file to lint:
-
-var foo = 2;
-// ^ error: Avoid using variables named 'foo'
-
-// In your tests:
-var rule = require("../../../lib/rules/my-rule");
-var RuleTester = require("eslint").RuleTester;
-
-var ruleTester = new RuleTester();
-ruleTester.run("my-rule", rule, {
- valid: ["bar", "baz"],
- invalid: [
- {
- code: "foo",
- errors: [
- {
- messageId: "avoidName"
- }
- ]
- }
- ]
-});
-{% endraw %}
-```
-
-### Applying Fixes
-
-If you'd like ESLint to attempt to fix the problem you're reporting, you can do so by specifying the `fix` function when using `context.report()`. The `fix` function receives a single argument, a `fixer` object, that you can use to apply a fix. For example:
-
-```js
-context.report({
- node: node,
- message: "Missing semicolon",
- fix: function(fixer) {
- return fixer.insertTextAfter(node, ";");
- }
-});
-```
-
-Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all of the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterwards, any remaining problems will be reported as usual.
-
-**Important:** The `meta.fixable` property is mandatory for fixable rules. ESLint will throw an error if a rule that implements `fix` functions does not [export](#rule-basics) the `meta.fixable` property.
-
-The `fixer` object has the following methods:
-
-* `insertTextAfter(nodeOrToken, text)` - inserts text after the given node or token
-* `insertTextAfterRange(range, text)` - inserts text after the given range
-* `insertTextBefore(nodeOrToken, text)` - inserts text before the given node or token
-* `insertTextBeforeRange(range, text)` - inserts text before the given range
-* `remove(nodeOrToken)` - removes the given node or token
-* `removeRange(range)` - removes text in the given range
-* `replaceText(nodeOrToken, text)` - replaces the text in the given node or token
-* `replaceTextRange(range, text)` - replaces the text in the given range
-
-A range is a two-item array containing character indices inside of the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent.
-
-The above methods return a `fixing` object.
-The `fix()` function can return the following values:
-
-* A `fixing` object.
-* An array which includes `fixing` objects.
-* An iterable object which enumerates `fixing` objects. Especially, the `fix()` function can be a generator.
-
-If you make a `fix()` function which returns multiple `fixing` objects, those `fixing` objects must not be overlapped.
-
-Best practices for fixes:
-
-1. Avoid any fixes that could change the runtime behavior of code and cause it to stop working.
-1. Make fixes as small as possible. Fixes that are unnecessarily large could conflict with other fixes, and prevent them from being applied.
-1. Only make one fix per message. This is enforced because you must return the result of the fixer operation from `fix()`.
-1. Since all rules are run again after the initial round of fixes is applied, it's not necessary for a rule to check whether the code style of a fix will cause errors to be reported by another rule.
- * For example, suppose a fixer would like to surround an object key with quotes, but it's not sure whether the user would prefer single or double quotes.
-
- ```js
- ({ foo : 1 })
-
- // should get fixed to either
-
- ({ 'foo': 1 })
-
- // or
-
- ({ "foo": 1 })
- ```
-
- * This fixer can just select a quote type arbitrarily. If it guesses wrong, the resulting code will be automatically reported and fixed by the [`quotes`](/docs/rules/quotes) rule.
-
-Note: Making fixes as small as possible is a best practice, but in some cases it may be correct to extend the range of the fix in order to intentionally prevent other rules from making fixes in a surrounding range in the same pass. For instance, if replacement text declares a new variable, it can be useful to prevent other changes in the scope of the variable as they might cause name collisions.
-
-The following example replaces `node` and also ensures that no other fixes will be applied in the range of `node.parent` in the same pass:
-
-```js
-context.report({
- node,
- message,
- *fix(fixer) {
- yield fixer.replaceText(node, replacementText);
-
- // extend range of the fix to the range of `node.parent`
- yield fixer.insertTextBefore(node.parent, "");
- yield fixer.insertTextAfter(node.parent, "");
- }
-});
-```
-
-### Providing Suggestions
-
-In some cases fixes aren't appropriate to be automatically applied, for example, if a fix potentially changes functionality or if there are multiple valid ways to fix a rule depending on the implementation intent (see the best practices for [applying fixes](#applying-fixes) listed above). In these cases, there is an alternative `suggest` option on `context.report()` that allows other tools, such as editors, to expose helpers for users to manually apply a suggestion.
-
-In order to provide suggestions, use the `suggest` key in the report argument with an array of suggestion objects. The suggestion objects represent individual suggestions that could be applied and require either a `desc` key string that describes what applying the suggestion would do or a `messageId` key (see [below](#suggestion-messageids)), and a `fix` key that is a function defining the suggestion result. This `fix` function follows the same API as regular fixes (described above in [applying fixes](#applying-fixes)).
-
-```js
-{% raw %}
-context.report({
- node: node,
- message: "Unnecessary escape character: \\{{character}}.",
- data: { character },
- suggest: [
- {
- desc: "Remove the `\\`. This maintains the current functionality.",
- fix: function(fixer) {
- return fixer.removeRange(range);
- }
- },
- {
- desc: "Replace the `\\` with `\\\\` to include the actual backslash character.",
- fix: function(fixer) {
- return fixer.insertTextBeforeRange(range, "\\");
- }
- }
- ]
-});
-{% endraw %}
-```
-
-**Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-basics) this property.
-
-Note: Suggestions will be applied as a stand-alone change, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation, or conform to user preferences on presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it.
-
-Best practices for suggestions:
-
-1. Don't try to do too much and suggest large refactors that could introduce a lot of breaking changes.
-1. As noted above, don't try to conform to user-defined styles.
-
-Suggestions are intended to provide fixes. ESLint will automatically remove the whole suggestion from the linting output if the suggestion's `fix` function returned `null` or an empty array/sequence.
-
-#### Suggestion `messageId`s
-
-Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use it in a rule:
-
-```js
-{% raw %}
-module.exports = {
- meta: {
- messages: {
- unnecessaryEscape: "Unnecessary escape character: \\{{character}}.",
- removeEscape: "Remove the `\\`. This maintains the current functionality.",
- escapeBackslash: "Replace the `\\` with `\\\\` to include the actual backslash character."
- },
- hasSuggestions: true
- },
- create: function(context) {
- // ...
- context.report({
- node: node,
- messageId: 'unnecessaryEscape',
- data: { character },
- suggest: [
- {
- messageId: "removeEscape",
- fix: function(fixer) {
- return fixer.removeRange(range);
- }
- },
- {
- messageId: "escapeBackslash",
- fix: function(fixer) {
- return fixer.insertTextBeforeRange(range, "\\");
- }
- }
- ]
- });
- }
-};
-{% endraw %}
-```
-
-#### Placeholders in suggestion messages
-
-You can also use placeholders in the suggestion message. This works the same way as placeholders for the overall error (see [using message placeholders](#using-message-placeholders)).
-
-Please note that you have to provide `data` on the suggestion's object. Suggestion messages cannot use properties from the overall error's `data`.
-
-```js
-{% raw %}
-module.exports = {
- meta: {
- messages: {
- unnecessaryEscape: "Unnecessary escape character: \\{{character}}.",
- removeEscape: "Remove `\\` before {{character}}.",
- },
- hasSuggestions: true
- },
- create: function(context) {
- // ...
- context.report({
- node: node,
- messageId: "unnecessaryEscape",
- data: { character }, // data for the unnecessaryEscape overall message
- suggest: [
- {
- messageId: "removeEscape",
- data: { character }, // data for the removeEscape suggestion message
- fix: function(fixer) {
- return fixer.removeRange(range);
- }
- }
- ]
- });
- }
-};
-{% endraw %}
-```
-
-### context.options
-
-Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line, or in comments). For example:
-
-```json
-{
- "quotes": ["error", "double"]
-}
-```
-
-The `quotes` rule in this example has one option, `"double"` (the `error` is the error level). You can retrieve the options for a rule by using `context.options`, which is an array containing every configured option for the rule. In this case, `context.options[0]` would contain `"double"`:
-
-```js
-module.exports = {
- create: function(context) {
- var isDouble = (context.options[0] === "double");
-
- // ...
- }
-};
-```
-
-Since `context.options` is just an array, you can use it to determine how many options have been passed as well as retrieving the actual options themselves. Keep in mind that the error level is not part of `context.options`, as the error level cannot be known or modified from inside a rule.
-
-When using options, make sure that your rule has some logical defaults in case the options are not provided.
-
-### context.getSourceCode()
-
-The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `getSourceCode()` method:
-
-```js
-module.exports = {
- create: function(context) {
- var sourceCode = context.getSourceCode();
-
- // ...
- }
-};
-```
-
-Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code:
-
-* `getText(node)` - returns the source code for the given node. Omit `node` to get the whole source.
-* `getAllComments()` - returns an array of all comments in the source.
-* `getCommentsBefore(nodeOrToken)` - returns an array of comment tokens that occur directly before the given node or token.
-* `getCommentsAfter(nodeOrToken)` - returns an array of comment tokens that occur directly after the given node or token.
-* `getCommentsInside(node)` - returns an array of all comment tokens inside a given node.
-* `isSpaceBetween(nodeOrToken, nodeOrToken)` - returns true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node.
-* `getFirstToken(node, skipOptions)` - returns the first token representing the given node.
-* `getFirstTokens(node, countOptions)` - returns the first `count` tokens representing the given node.
-* `getLastToken(node, skipOptions)` - returns the last token representing the given node.
-* `getLastTokens(node, countOptions)` - returns the last `count` tokens representing the given node.
-* `getTokenAfter(nodeOrToken, skipOptions)` - returns the first token after the given node or token.
-* `getTokensAfter(nodeOrToken, countOptions)` - returns `count` tokens after the given node or token.
-* `getTokenBefore(nodeOrToken, skipOptions)` - returns the first token before the given node or token.
-* `getTokensBefore(nodeOrToken, countOptions)` - returns `count` tokens before the given node or token.
-* `getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)` - returns the first token between two nodes or tokens.
-* `getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)` - returns the first `count` tokens between two nodes or tokens.
-* `getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)` - returns the last token between two nodes or tokens.
-* `getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)` - returns the last `count` tokens between two nodes or tokens.
-* `getTokens(node)` - returns all tokens for the given node.
-* `getTokensBetween(nodeOrToken1, nodeOrToken2)` - returns all tokens between two nodes.
-* `getTokenByRangeStart(index, rangeOptions)` - returns the token whose range starts at the given index in the source.
-* `getNodeByRangeIndex(index)` - returns the deepest node in the AST containing the given source index.
-* `getLocFromIndex(index)` - returns an object with `line` and `column` properties, corresponding to the location of the given source index. `line` is 1-based and `column` is 0-based.
-* `getIndexFromLoc(loc)` - returns the index of a given location in the source code, where `loc` is an object with a 1-based `line` key and a 0-based `column` key.
-* `commentsExistBetween(nodeOrToken1, nodeOrToken2)` - returns `true` if comments exist between two nodes.
-
-`skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`.
-
-* `skip` is a positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped.
-* `includeComments` is a boolean value, the flag to include comment tokens into the result.
-* `filter` is a function which gets a token as the first argument, if the function returns `false` then the result excludes the token.
-
-`countOptions` is an object which has 3 properties; `count`, `includeComments`, and `filter`. Default is `{count: 0, includeComments: false, filter: null}`.
-
-* `count` is a positive integer, the maximum number of returning tokens.
-* `includeComments` is a boolean value, the flag to include comment tokens into the result.
-* `filter` is a function which gets a token as the first argument, if the function returns `false` then the result excludes the token.
-
-`rangeOptions` is an object which has 1 property: `includeComments`.
-
-* `includeComments` is a boolean value, the flag to include comment tokens into the result.
-
-There are also some properties you can access:
-
-* `hasBOM` - the flag to indicate whether or not the source code has Unicode BOM.
-* `text` - the full text of the code being linted. Unicode BOM has been stripped from this text.
-* `ast` - the `Program` node of the AST for the code being linted.
-* `scopeManager` - the [ScopeManager](./scope-manager-interface#scopemanager-interface) object of the code.
-* `visitorKeys` - the visitor keys to traverse this AST.
-* `lines` - an array of lines, split according to the specification's definition of line breaks.
-
-You should use a `SourceCode` object whenever you need to get more information about the code being linted.
-
-#### Deprecated
-
-Please note that the following methods have been deprecated and will be removed in a future version of ESLint:
-
-* `getComments()` - replaced by `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()`
-* `getTokenOrCommentBefore()` - replaced by `getTokenBefore()` with the `{ includeComments: true }` option
-* `getTokenOrCommentAfter()` - replaced by `getTokenAfter()` with the `{ includeComments: true }` option
-* `isSpaceBetweenTokens()` - replaced by `isSpaceBetween()`
-* `getJSDocComment()`
-
-### Options Schemas
-
-Rules may export a `schema` property, which is a [JSON schema](https://json-schema.org/) format description of a rule's options which will be used by ESLint to validate configuration options and prevent invalid or unexpected inputs before they are passed to the rule in `context.options`.
-
-There are two formats for a rule's exported `schema`. The first is a full JSON Schema object describing all possible options the rule accepts, including the rule's error level as the first argument and any optional arguments thereafter.
-
-However, to simplify schema creation, rules may also export an array of schemas for each optional positional argument, and ESLint will automatically validate the required error level first. For example, the `yoda` rule accepts a primary mode argument, as well as an extra options object with named properties.
-
-```js
-// "yoda": [2, "never", { "exceptRange": true }]
-module.exports = {
- meta: {
- schema: [
- {
- "enum": ["always", "never"]
- },
- {
- "type": "object",
- "properties": {
- "exceptRange": {
- "type": "boolean"
- }
- },
- "additionalProperties": false
- }
- ]
- },
-};
-```
-
-In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a Boolean property named `exceptRange`.
-
-To learn more about JSON Schema, we recommend looking at some examples in [website](https://json-schema.org/learn/) to start, and also reading [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) (a free ebook).
-
-**Note:** Currently you need to use full JSON Schema object rather than array in case your schema has references ($ref), because in case of array format ESLint transforms this array into a single schema without updating references that makes them incorrect (they are ignored).
-
-### Getting the Source
-
-If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows:
-
-```js
-
-// get all source
-var source = sourceCode.getText();
-
-// get source for just this AST node
-var nodeSource = sourceCode.getText(node);
-
-// get source for AST node plus previous two characters
-var nodeSourceWithPrev = sourceCode.getText(node, 2);
-
-// get source for AST node plus following two characters
-var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2);
-```
-
-In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.).
-
-### Accessing Comments
-
-While comments are not technically part of the AST, ESLint provides a few ways for rules to access them:
-
-#### sourceCode.getAllComments()
-
-This method returns an array of all the comments found in the program. This is useful for rules that need to check all comments regardless of location.
-
-#### sourceCode.getCommentsBefore(), sourceCode.getCommentsAfter(), and sourceCode.getCommentsInside()
-
-These methods return an array of comments that appear directly before, directly after, and inside nodes, respectively. They are useful for rules that need to check comments in relation to a given node or token.
-
-Keep in mind that the results of this method are calculated on demand.
-
-#### Token traversal methods
-
-Finally, comments can be accessed through many of `sourceCode`'s methods using the `includeComments` option.
-
-### Accessing Shebangs
-
-Shebangs are represented by tokens of type `"Shebang"`. They are treated as comments and can be accessed by the methods outlined above.
-
-### Accessing Code Paths
-
-ESLint analyzes code paths while traversing AST.
-You can access that code path objects with five events related to code paths.
-
-[details here](./code-path-analysis)
-
-## Rule Unit Tests
-
-Each bundled rule for ESLint core must have a set of unit tests submitted with it to be accepted. The test file is named the same as the source file but lives in `tests/lib/`. For example, if the rule source file is `lib/rules/foo.js` then the test file should be `tests/lib/rules/foo.js`.
-
-ESLint provides the [`RuleTester`](/docs/developer-guide/nodejs-api#ruletester) utility to make it easy to write tests for rules.
-
-## Performance Testing
-
-To keep the linting process efficient and unobtrusive, it is useful to verify the performance impact of new rules or modifications to existing rules.
-
-### Overall Performance
-
-When developing in the ESLint core repository, the `npm run perf` command gives a high-level overview of ESLint running time with all core rules enabled.
-
-```bash
-$ git checkout main
-Switched to branch 'main'
-
-$ npm run perf
-CPU Speed is 2200 with multiplier 7500000
-Performance Run #1: 1394.689313ms
-Performance Run #2: 1423.295351ms
-Performance Run #3: 1385.09515ms
-Performance Run #4: 1382.406982ms
-Performance Run #5: 1409.68566ms
-Performance budget ok: 1394.689313ms (limit: 3409.090909090909ms)
-
-$ git checkout my-rule-branch
-Switched to branch 'my-rule-branch'
-
-$ npm run perf
-CPU Speed is 2200 with multiplier 7500000
-Performance Run #1: 1443.736547ms
-Performance Run #2: 1419.193291ms
-Performance Run #3: 1436.018228ms
-Performance Run #4: 1473.605485ms
-Performance Run #5: 1457.455283ms
-Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms)
-```
-
-### Per-rule Performance
-
-ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time (rule creation + rule execution) and relative performance impact as a percentage of total rule processing time (rule creation + rule execution).
-
-```bash
-$ TIMING=1 eslint lib
-Rule | Time (ms) | Relative
-:-----------------------|----------:|--------:
-no-multi-spaces | 52.472 | 6.1%
-camelcase | 48.684 | 5.7%
-no-irregular-whitespace | 43.847 | 5.1%
-valid-jsdoc | 40.346 | 4.7%
-handle-callback-err | 39.153 | 4.6%
-space-infix-ops | 35.444 | 4.1%
-no-undefined | 25.693 | 3.0%
-no-shadow | 22.759 | 2.7%
-no-empty-class | 21.976 | 2.6%
-semi | 19.359 | 2.3%
-```
-
-To test one rule explicitly, combine the `--no-eslintrc`, and `--rule` options:
-
-```bash
-$ TIMING=1 eslint --no-eslintrc --rule "quotes: [2, 'double']" lib
-Rule | Time (ms) | Relative
-:------|----------:|--------:
-quotes | 18.066 | 100.0%
-```
-
-To see a longer list of results (more than 10), set the environment variable to another value such as `TIMING=50` or `TIMING=all`.
-
-## Rule Naming Conventions
-
-The rule naming conventions for ESLint are fairly simple:
-
-* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`.
-* If your rule is enforcing the inclusion of something, use a short name without a special prefix.
-* Use dashes between words.
-
-## Runtime Rules
-
-The thing that makes ESLint different from other linters is the ability to define custom rules at runtime. This is perfect for rules that are specific to your project or company and wouldn't make sense for ESLint to ship with. With runtime rules, you don't have to wait for the next version of ESLint or be disappointed that your rule isn't general enough to apply to the larger JavaScript community, just write your rules and include them at runtime.
-
-Runtime rules are written in the same format as all other rules. Create your rule as you would any other and then follow these steps:
-
-1. Place all of your runtime rules in the same directory (e.g., `eslint_rules`).
-2. Create a [configuration file](../user-guide/configuring/) and specify your rule ID error level under the `rules` key. Your rule will not run unless it has a value of `"warn"` or `"error"` in the configuration file.
-3. Run the [command line interface](../user-guide/command-line-interface) using the `--rulesdir` option to specify the location of your runtime rules.
--- /dev/null
+---
+title: Code Path Analysis Details
+
+---
+
+ESLint's rules can use code paths.
+The code path is execution routes of programs.
+It forks/joins at such as `if` statements.
+
+```js
+if (a && b) {
+ foo();
+}
+bar();
+```
+
+:::img-container
+![Code Path Example](../assets/images/code-path-analysis/helo.svg)
+:::
+
+## Objects
+
+Program is expressed with several code paths.
+A code path is expressed with objects of two kinds: `CodePath` and `CodePathSegment`.
+
+### `CodePath`
+
+`CodePath` expresses whole of one code path.
+This object exists for each function and the global.
+This has references of both the initial segment and the final segments of a code path.
+
+`CodePath` has the following properties:
+
+* `id` (`string`) - A unique string. Respective rules can use `id` to save additional information for each code path.
+* `origin` (`string`) - The reason that the code path was started. May be `"program"`, `"function"`, `"class-field-initializer"`, or `"class-static-block"`.
+* `initialSegment` (`CodePathSegment`) - The initial segment of this code path.
+* `finalSegments` (`CodePathSegment[]`) - The final segments which includes both returned and thrown.
+* `returnedSegments` (`CodePathSegment[]`) - The final segments which includes only returned.
+* `thrownSegments` (`CodePathSegment[]`) - The final segments which includes only thrown.
+* `currentSegments` (`CodePathSegment[]`) - Segments of the current position.
+* `upper` (`CodePath|null`) - The code path of the upper function/global scope.
+* `childCodePaths` (`CodePath[]`) - Code paths of functions this code path contains.
+
+### `CodePathSegment`
+
+`CodePathSegment` is a part of a code path.
+A code path is expressed with plural `CodePathSegment` objects, it's similar to doubly linked list.
+Difference from doubly linked list is what there are forking and merging (the next/prev are plural).
+
+`CodePathSegment` has the following properties:
+
+* `id` (`string`) - A unique string. Respective rules can use `id` to save additional information for each segment.
+* `nextSegments` (`CodePathSegment[]`) - The next segments. If forking, there are two or more. If final, there is nothing.
+* `prevSegments` (`CodePathSegment[]`) - The previous segments. If merging, there are two or more. If initial, there is nothing.
+* `reachable` (`boolean`) - A flag which shows whether or not it's reachable. This becomes `false` when preceded by `return`, `throw`, `break`, or `continue`.
+
+## Events
+
+There are five events related to code paths, and you can define event handlers in rules.
+
+```js
+module.exports = function(context) {
+ return {
+ /**
+ * This is called at the start of analyzing a code path.
+ * In this time, the code path object has only the initial segment.
+ *
+ * @param {CodePath} codePath - The new code path.
+ * @param {ASTNode} node - The current node.
+ * @returns {void}
+ */
+ "onCodePathStart": function(codePath, node) {
+ // do something with codePath
+ },
+
+ /**
+ * This is called at the end of analyzing a code path.
+ * In this time, the code path object is complete.
+ *
+ * @param {CodePath} codePath - The completed code path.
+ * @param {ASTNode} node - The current node.
+ * @returns {void}
+ */
+ "onCodePathEnd": function(codePath, node) {
+ // do something with codePath
+ },
+
+ /**
+ * This is called when a code path segment was created.
+ * It meant the code path is forked or merged.
+ * In this time, the segment has the previous segments and has been
+ * judged reachable or not.
+ *
+ * @param {CodePathSegment} segment - The new code path segment.
+ * @param {ASTNode} node - The current node.
+ * @returns {void}
+ */
+ "onCodePathSegmentStart": function(segment, node) {
+ // do something with segment
+ },
+
+ /**
+ * This is called when a code path segment was left.
+ * In this time, the segment does not have the next segments yet.
+ *
+ * @param {CodePathSegment} segment - The left code path segment.
+ * @param {ASTNode} node - The current node.
+ * @returns {void}
+ */
+ "onCodePathSegmentEnd": function(segment, node) {
+ // do something with segment
+ },
+
+ /**
+ * This is called when a code path segment was looped.
+ * Usually segments have each previous segments when created,
+ * but when looped, a segment is added as a new previous segment into a
+ * existing segment.
+ *
+ * @param {CodePathSegment} fromSegment - A code path segment of source.
+ * @param {CodePathSegment} toSegment - A code path segment of destination.
+ * @param {ASTNode} node - The current node.
+ * @returns {void}
+ */
+ "onCodePathSegmentLoop": function(fromSegment, toSegment, node) {
+ // do something with segment
+ }
+ };
+};
+```
+
+### About `onCodePathSegmentLoop`
+
+This event is always fired when the next segment has existed already.
+That timing is the end of loops mainly.
+
+For Example 1:
+
+```js
+while (a) {
+ a = foo();
+}
+bar();
+```
+
+1. First, the analysis advances to the end of loop.
+
+:::img-container
+ ![Loop Event's Example 1](../assets/images/code-path-analysis/loop-event-example-while-1.svg)
+:::
+
+2. Second, it creates the looping path.
+ At this time, the next segment has existed already, so the `onCodePathSegmentStart` event is not fired.
+ It fires `onCodePathSegmentLoop` instead.
+
+:::img-container
+ ![Loop Event's Example 2](../assets/images/code-path-analysis/loop-event-example-while-2.svg)
+:::
+
+3. Last, it advances to the end.
+
+:::img-container
+ ![Loop Event's Example 3](../assets/images/code-path-analysis/loop-event-example-while-3.svg)
+:::
+
+For example 2:
+
+```js
+for (let i = 0; i < 10; ++i) {
+ foo(i);
+}
+bar();
+```
+
+1. `for` statements are more complex.
+ First, the analysis advances to `ForStatement.update`.
+ The `update` segment is hovered at first.
+
+:::img-container
+ ![Loop Event's Example 1](../assets/images/code-path-analysis/loop-event-example-for-1.svg)
+:::
+
+2. Second, it advances to `ForStatement.body`.
+ Of course the `body` segment is preceded by the `test` segment.
+ It keeps the `update` segment hovering.
+
+:::img-container
+ ![Loop Event's Example 2](../assets/images/code-path-analysis/loop-event-example-for-2.svg)
+:::
+
+3. Third, it creates the looping path from `body` segment to `update` segment.
+ At this time, the next segment has existed already, so the `onCodePathSegmentStart` event is not fired.
+ It fires `onCodePathSegmentLoop` instead.
+
+:::img-container
+ ![Loop Event's Example 3](../assets/images/code-path-analysis/loop-event-example-for-3.svg)
+:::
+
+4. Fourth, also it creates the looping path from `update` segment to `test` segment.
+ At this time, the next segment has existed already, so the `onCodePathSegmentStart` event is not fired.
+ It fires `onCodePathSegmentLoop` instead.
+
+:::img-container
+ ![Loop Event's Example 4](../assets/images/code-path-analysis/loop-event-example-for-4.svg)
+:::
+
+5. Last, it advances to the end.
+
+:::img-container
+ ![Loop Event's Example 5](../assets/images/code-path-analysis/loop-event-example-for-5.svg)
+:::
+
+## Usage Examples
+
+### To check whether or not this is reachable
+
+```js
+function isReachable(segment) {
+ return segment.reachable;
+}
+
+module.exports = function(context) {
+ var codePathStack = [];
+
+ return {
+ // Stores CodePath objects.
+ "onCodePathStart": function(codePath) {
+ codePathStack.push(codePath);
+ },
+ "onCodePathEnd": function(codePath) {
+ codePathStack.pop();
+ },
+
+ // Checks reachable or not.
+ "ExpressionStatement": function(node) {
+ var codePath = codePathStack[codePathStack.length - 1];
+
+ // Checks the current code path segments.
+ if (!codePath.currentSegments.some(isReachable)) {
+ context.report({message: "Unreachable!", node: node});
+ }
+ }
+ };
+};
+```
+
+See Also:
+[no-unreachable](https://github.com/eslint/eslint/blob/HEAD/lib/rules/no-unreachable.js),
+[no-fallthrough](https://github.com/eslint/eslint/blob/HEAD/lib/rules/no-fallthrough.js),
+[consistent-return](https://github.com/eslint/eslint/blob/HEAD/lib/rules/consistent-return.js)
+
+### To check state of a code path
+
+This example is checking whether or not the parameter `cb` is called in every path.
+Instances of `CodePath` and `CodePathSegment` are shared to every rule.
+So a rule must not modify those instances.
+Please use a map of information instead.
+
+```js
+function hasCb(node, context) {
+ if (node.type.indexOf("Function") !== -1) {
+ const sourceCode = context.sourceCode;
+ return sourceCode.getDeclaredVariables(node).some(function(v) {
+ return v.type === "Parameter" && v.name === "cb";
+ });
+ }
+ return false;
+}
+
+function isCbCalled(info) {
+ return info.cbCalled;
+}
+
+module.exports = function(context) {
+ var funcInfoStack = [];
+ var segmentInfoMap = Object.create(null);
+
+ return {
+ // Checks `cb`.
+ "onCodePathStart": function(codePath, node) {
+ funcInfoStack.push({
+ codePath: codePath,
+ hasCb: hasCb(node, context)
+ });
+ },
+ "onCodePathEnd": function(codePath, node) {
+ funcInfoStack.pop();
+
+ // Checks `cb` was called in every paths.
+ var cbCalled = codePath.finalSegments.every(function(segment) {
+ var info = segmentInfoMap[segment.id];
+ return info.cbCalled;
+ });
+
+ if (!cbCalled) {
+ context.report({
+ message: "`cb` should be called in every path.",
+ node: node
+ });
+ }
+ },
+
+ // Manages state of code paths.
+ "onCodePathSegmentStart": function(segment) {
+ var funcInfo = funcInfoStack[funcInfoStack.length - 1];
+
+ // Ignores if `cb` doesn't exist.
+ if (!funcInfo.hasCb) {
+ return;
+ }
+
+ // Initialize state of this path.
+ var info = segmentInfoMap[segment.id] = {
+ cbCalled: false
+ };
+
+ // If there are the previous paths, merges state.
+ // Checks `cb` was called in every previous path.
+ if (segment.prevSegments.length > 0) {
+ info.cbCalled = segment.prevSegments.every(isCbCalled);
+ }
+ },
+
+ // Checks reachable or not.
+ "CallExpression": function(node) {
+ var funcInfo = funcInfoStack[funcInfoStack.length - 1];
+
+ // Ignores if `cb` doesn't exist.
+ if (!funcInfo.hasCb) {
+ return;
+ }
+
+ // Sets marks that `cb` was called.
+ var callee = node.callee;
+ if (callee.type === "Identifier" && callee.name === "cb") {
+ funcInfo.codePath.currentSegments.forEach(function(segment) {
+ var info = segmentInfoMap[segment.id];
+ info.cbCalled = true;
+ });
+ }
+ }
+ };
+};
+```
+
+See Also:
+[constructor-super](https://github.com/eslint/eslint/blob/HEAD/lib/rules/constructor-super.js),
+[no-this-before-super](https://github.com/eslint/eslint/blob/HEAD/lib/rules/no-this-before-super.js)
+
+## Code Path Examples
+
+### Hello World
+
+```js
+console.log("Hello world!");
+```
+
+:::img-container
+![Hello World](../assets/images/code-path-analysis/example-hello-world.svg)
+:::
+
+### `IfStatement`
+
+```js
+if (a) {
+ foo();
+} else {
+ bar();
+}
+```
+
+:::img-container
+![`IfStatement`](../assets/images/code-path-analysis/example-ifstatement.svg)
+:::
+
+### `IfStatement` (chain)
+
+```js
+if (a) {
+ foo();
+} else if (b) {
+ bar();
+} else if (c) {
+ hoge();
+}
+```
+
+:::img-container
+![`IfStatement` (chain)](../assets/images/code-path-analysis/example-ifstatement-chain.svg)
+:::
+
+### `SwitchStatement`
+
+```js
+switch (a) {
+ case 0:
+ foo();
+ break;
+
+ case 1:
+ case 2:
+ bar();
+ // fallthrough
+
+ case 3:
+ hoge();
+ break;
+}
+```
+
+:::img-container
+![`SwitchStatement`](../assets/images/code-path-analysis/example-switchstatement.svg)
+:::
+
+### `SwitchStatement` (has `default`)
+
+```js
+switch (a) {
+ case 0:
+ foo();
+ break;
+
+ case 1:
+ case 2:
+ bar();
+ // fallthrough
+
+ case 3:
+ hoge();
+ break;
+
+ default:
+ fuga();
+ break;
+}
+```
+
+:::img-container
+![`SwitchStatement` (has `default`)](../assets/images/code-path-analysis/example-switchstatement-has-default.svg)
+:::
+
+### `TryStatement` (try-catch)
+
+```js
+try {
+ foo();
+ if (a) {
+ throw new Error();
+ }
+ bar();
+} catch (err) {
+ hoge(err);
+}
+last();
+```
+
+It creates the paths from `try` block to `catch` block at:
+
+* `throw` statements.
+* The first throwable node (e.g. a function call) in the `try` block.
+* The end of the `try` block.
+
+:::img-container
+![`TryStatement` (try-catch)](../assets/images/code-path-analysis/example-trystatement-try-catch.svg)
+:::
+
+### `TryStatement` (try-finally)
+
+```js
+try {
+ foo();
+ bar();
+} finally {
+ fuga();
+}
+last();
+```
+
+If there is not `catch` block, `finally` block has two current segments.
+At this time, `CodePath.currentSegments.length` is `2`.
+One is the normal path, and another is the leaving path (`throw` or `return`).
+
+:::img-container
+![`TryStatement` (try-finally)](../assets/images/code-path-analysis/example-trystatement-try-finally.svg)
+:::
+
+### `TryStatement` (try-catch-finally)
+
+```js
+try {
+ foo();
+ bar();
+} catch (err) {
+ hoge(err);
+} finally {
+ fuga();
+}
+last();
+```
+
+:::img-container
+![`TryStatement` (try-catch-finally)](../assets/images/code-path-analysis/example-trystatement-try-catch-finally.svg)
+:::
+
+### `WhileStatement`
+
+```js
+while (a) {
+ foo();
+ if (b) {
+ continue;
+ }
+ bar();
+}
+```
+
+:::img-container
+![`WhileStatement`](../assets/images/code-path-analysis/example-whilestatement.svg)
+:::
+
+### `DoWhileStatement`
+
+```js
+do {
+ foo();
+ bar();
+} while (a);
+```
+
+:::img-container
+![`DoWhileStatement`](../assets/images/code-path-analysis/example-dowhilestatement.svg)
+:::
+
+### `ForStatement`
+
+```js
+for (let i = 0; i < 10; ++i) {
+ foo();
+ if (b) {
+ break;
+ }
+ bar();
+}
+```
+
+:::img-container
+![`ForStatement`](../assets/images/code-path-analysis/example-forstatement.svg)
+:::
+
+### `ForStatement` (for ever)
+
+```js
+for (;;) {
+ foo();
+}
+bar();
+```
+
+:::img-container
+![`ForStatement` (for ever)](../assets/images/code-path-analysis/example-forstatement-for-ever.svg)
+:::
+
+### `ForInStatement`
+
+```js
+for (let key in obj) {
+ foo(key);
+}
+```
+
+:::img-container
+![`ForInStatement`](../assets/images/code-path-analysis/example-forinstatement.svg)
+:::
+
+### When there is a function
+
+```js
+function foo(a) {
+ if (a) {
+ return;
+ }
+ bar();
+}
+
+foo(false);
+```
+
+It creates two code paths.
+
+* The global's
+
+:::img-container
+ ![When there is a function](../assets/images/code-path-analysis/example-when-there-is-a-function-g.svg)
+:::
+
+* The function's
+
+:::img-container
+ ![When there is a function](../assets/images/code-path-analysis/example-when-there-is-a-function-f.svg)
+:::
--- /dev/null
+---
+title: Custom Formatters
+eleventyNavigation:
+ key: custom formatters
+ parent: extend eslint
+ title: Custom Formatters
+ order: 4
+
+---
+
+Custom formatters let you display linting results in a format that best fits your needs, whether that's in a specific file format, a certain display style, or a format optimized for a particular tool.
+
+ESLint also has [built-in formatters](../use/formatters/) that you can use.
+
+You can include custom formatters in your project directly or create an npm package to distribute them separately.
+
+## Creating a Custom Formatter
+
+Each formatter is a function that receives a `results` object and a `context` as arguments and returns a string. For example, the following is how the built-in [JSON formatter](../use/formatters/#json) is implemented:
+
+```js
+//my-awesome-formatter.js
+module.exports = function(results, context) {
+ return JSON.stringify(results, null, 2);
+};
+```
+
+A 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`)](../use/command-line-interface#-f---format) command line flag. You must begin the path to a locally defined custom formatter with a period (`.`), such as `./my-awesome-formatter.js` or `../formatters/my-awesome-formatter.js`.
+
+```bash
+eslint -f ./my-awesome-formatter.js src/
+```
+
+The remainder of this section contains reference information on how to work with custom formatter functions.
+
+### The `results` Argument
+
+The `results` object passed into a formatter is an array of [`result`](#the-result-object) objects containing the linting results for individual files. Here's an example output:
+
+```js
+[
+ {
+ filePath: "/path/to/a/file.js",
+ messages: [
+ {
+ ruleId: "curly",
+ severity: 2,
+ message: "Expected { after 'if' condition.",
+ line: 2,
+ column: 1,
+ nodeType: "IfStatement"
+ },
+ {
+ ruleId: "no-process-exit",
+ severity: 2,
+ message: "Don't use process.exit(); throw an error instead.",
+ line: 3,
+ column: 1,
+ nodeType: "CallExpression"
+ }
+ ],
+ errorCount: 2,
+ warningCount: 0,
+ fixableErrorCount: 0,
+ fixableWarningCount: 0,
+ source:
+ "var err = doStuff();\nif (err) console.log('failed tests: ' + err);\nprocess.exit(1);\n"
+ },
+ {
+ filePath: "/path/to/Gruntfile.js",
+ messages: [],
+ errorCount: 0,
+ warningCount: 0,
+ fixableErrorCount: 0,
+ fixableWarningCount: 0
+ }
+]
+```
+
+#### The `result` Object
+
+<!-- This section is copied from the "Node.js API" page. Changes to this section should
+also be manually applied to that page. -->
+
+Each object in the `results` array is a `result` object. Each `result` object contains the path of the file that was linted and information about linting issues that were encountered. Here are the properties available on each `result` object:
+
+* **filePath**: The absolute path to the file that was linted.
+* **messages**: An array of [`message`](#the-message-object) objects. See below for more info about messages.
+* **errorCount**: The number of errors for the given file.
+* **warningCount**: The number of warnings for the given file.
+* **source**: The source code for the given file. This property is omitted if this file has no errors/warnings or if the `output` property is present.
+* **output**: The source code for the given file with as many fixes applied as possible. This property is omitted if no fix is available.
+
+##### The `message` Object
+
+Each `message` object contains information about the ESLint rule that was triggered by some source code. The properties available on each `message` object are:
+
+* **ruleId**: the ID of the rule that produced the error or warning.
+* **severity**: the severity of the failure, `1` for warnings and `2` for errors.
+* **message**: the human readable description of the error.
+* **line**: the line where the issue is located.
+* **column**: the column where the issue is located.
+* **nodeType**: the type of the node in the [AST](https://github.com/estree/estree/blob/master/es5.md#node-objects)
+
+### The `context` Argument
+
+The formatter function receives a `context` object as its second argument. The object has the following properties:
+
+* `cwd`: The current working directory. This value comes from the `cwd` constructor option of the [ESLint](../integrate/nodejs-api#-new-eslintoptions) class.
+* `maxWarningsExceeded` (optional): If `--max-warnings` was set and the number of warnings exceeded the limit, this property's value is an object containing two properties:
+ * `maxWarnings`: the value of the `--max-warnings` option
+ * `foundWarnings`: the number of lint warnings
+* `rulesMeta`: The `meta` property values of rules. See the [Custom Rules](custom-rules) page for more information about rules.
+
+For example, here's what the object would look like if the rule `no-extra-semi` had been run:
+
+```js
+{
+ cwd: "/path/to/cwd",
+ maxWarningsExceeded: {
+ maxWarnings: 5,
+ foundWarnings: 6
+ },
+ 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 the 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.
+
+### Passing Arguments to Formatters
+
+While formatter functions do not receive arguments in addition to the results object and the context, it is possible to pass additional data into custom formatters using the methods described below.
+
+#### Using Environment Variables
+
+Custom formatters have access to environment variables and so can change their behavior based on environment variable data.
+
+Here's an example that uses a `FORMATTER_SKIP_WARNINGS` environment variable to determine whether to show warnings in the results:
+
+```js
+module.exports = function(results) {
+ var skipWarnings = process.env.FORMATTER_SKIP_WARNINGS === "true";
+
+ var results = results || [];
+ var summary = results.reduce(
+ function(seq, current) {
+ current.messages.forEach(function(msg) {
+ var logMessage = {
+ filePath: current.filePath,
+ ruleId: msg.ruleId,
+ message: msg.message,
+ line: msg.line,
+ column: msg.column
+ };
+
+ if (msg.severity === 1) {
+ logMessage.type = "warning";
+ seq.warnings.push(logMessage);
+ }
+ if (msg.severity === 2) {
+ logMessage.type = "error";
+ seq.errors.push(logMessage);
+ }
+ });
+ return seq;
+ },
+ {
+ errors: [],
+ warnings: []
+ }
+ );
+
+ if (summary.errors.length > 0 || summary.warnings.length > 0) {
+ var warnings = !skipWarnings ? summary.warnings : []; // skip the warnings in that case
+
+ var lines = summary.errors
+ .concat(warnings)
+ .map(function(msg) {
+ return (
+ "\n" +
+ msg.type +
+ " " +
+ msg.ruleId +
+ "\n " +
+ msg.filePath +
+ ":" +
+ msg.line +
+ ":" +
+ msg.column
+ );
+ })
+ .join("\n");
+
+ return lines + "\n";
+ }
+};
+```
+
+You would run ESLint with this custom formatter and an environment variable set like this:
+
+```bash
+FORMATTER_SKIP_WARNINGS=true eslint -f ./my-awesome-formatter.js src/
+```
+
+The output would be:
+
+```bash
+error space-infix-ops
+ src/configs/bundler.js:6:8
+
+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](../use/formatters/#json) and pipe the output to a second program. For example:
+
+```bash
+eslint -f json src/ | your-program-that-reads-JSON --option
+```
+
+In this example, the `your-program-that-reads-json` program can accept the raw JSON of ESLint results and process it before outputting its own format of the results. You can pass as many command line arguments to that program as are necessary to customize the output.
+
+### Formatting for Terminals
+
+Modern terminals like [iTerm2](https://www.iterm2.com/) or [Guake](http://guake-project.org/) expect a specific results format to automatically open filenames when they are clicked. Most terminals support this format for that purpose:
+
+```bash
+file:line:column
+```
+
+## Packaging a Custom Formatter
+
+Custom formatters can be distributed through npm packages. To do so, create an npm package with a name in the format `eslint-formatter-*`, where `*` is the name of your formatter (such as `eslint-formatter-awesome`). Projects should then install the package and use the custom formatter with the [`-f` (or `--format`)](../use/command-line-interface#-f---format) flag like this:
+
+```bash
+eslint -f awesome src/
+```
+
+Because ESLint knows to look for packages beginning with `eslint-formatter-` when the specified formatter doesn't begin with a period, you do not need to type `eslint-formatter-` when using a packaged custom formatter.
+
+Tips for the `package.json` of a custom formatter:
+
+* The [`main`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#main) entry point must be the JavaScript file implementing your custom formatter.
+* Add these [`keywords`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords) to help users find your formatter:
+ * `"eslint"`
+ * `"eslint-formatter"`
+ * `"eslintformatter"`
+
+See all [custom formatters on npm](https://www.npmjs.com/search?q=eslint-formatter).
+
+## Examples
+
+### Summary Formatter
+
+A formatter that only reports on the total count of errors and warnings will look like this:
+
+```javascript
+module.exports = function(results, context) {
+ // accumulate the errors and warnings
+ var summary = results.reduce(
+ function(seq, current) {
+ seq.errors += current.errorCount;
+ seq.warnings += current.warningCount;
+ return seq;
+ },
+ { errors: 0, warnings: 0 }
+ );
+
+ if (summary.errors > 0 || summary.warnings > 0) {
+ return (
+ "Errors: " +
+ summary.errors +
+ ", Warnings: " +
+ summary.warnings +
+ "\n"
+ );
+ }
+
+ return "";
+};
+```
+
+Run `eslint` with the above summary formatter:
+
+```bash
+eslint -f ./my-awesome-formatter.js src/
+```
+
+Will produce the following output:
+
+```bash
+Errors: 2, Warnings: 4
+```
+
+### Detailed Formatter
+
+A more complex report could look like this:
+
+```javascript
+module.exports = function(results, context) {
+ var results = results || [];
+
+ var summary = results.reduce(
+ function(seq, current) {
+ current.messages.forEach(function(msg) {
+ var logMessage = {
+ filePath: current.filePath,
+ ruleId: msg.ruleId,
+ ruleUrl: context.rulesMeta[msg.ruleId].docs.url,
+ message: msg.message,
+ line: msg.line,
+ column: msg.column
+ };
+
+ if (msg.severity === 1) {
+ logMessage.type = "warning";
+ seq.warnings.push(logMessage);
+ }
+ if (msg.severity === 2) {
+ logMessage.type = "error";
+ seq.errors.push(logMessage);
+ }
+ });
+ return seq;
+ },
+ {
+ errors: [],
+ warnings: []
+ }
+ );
+
+ if (summary.errors.length > 0 || summary.warnings.length > 0) {
+ var lines = summary.errors
+ .concat(summary.warnings)
+ .map(function(msg) {
+ return (
+ "\n" +
+ msg.type +
+ " " +
+ msg.ruleId + (msg.ruleUrl ? " (" + msg.ruleUrl + ")" : "") +
+ "\n " +
+ msg.filePath +
+ ":" +
+ msg.line +
+ ":" +
+ msg.column
+ );
+ })
+ .join("\n");
+
+ return lines + "\n";
+ }
+};
+```
+
+When you run ESLint with this custom formatter:
+
+```bash
+eslint -f ./my-awesome-formatter.js src/
+```
+
+The output is:
+
+```bash
+error space-infix-ops (https://eslint.org/docs/rules/space-infix-ops)
+ src/configs/bundler.js:6:8
+error semi (https://eslint.org/docs/rules/semi)
+ src/configs/bundler.js:6:10
+warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
+ src/configs/bundler.js:5:6
+warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
+ src/configs/bundler.js:6:6
+warning no-shadow (https://eslint.org/docs/rules/no-shadow)
+ src/configs/bundler.js:65:32
+warning no-unused-vars (https://eslint.org/docs/rules/no-unused-vars)
+ src/configs/clean.js:3:6
+```
--- /dev/null
+---
+title: Custom Parsers
+eleventyNavigation:
+ key: custom parsers
+ parent: extend eslint
+ title: Custom Parsers
+ order: 5
+
+---
+
+ESLint custom parsers let you extend ESLint to support linting new non-standard JavaScript language features or custom syntax in your code. A parser is responsible for taking your code and transforming it into an abstract syntax tree (AST) that ESLint can then analyze and lint.
+
+## Creating a Custom Parser
+
+A custom parser is a JavaScript object with either a `parse` or `parseForESLint` method. The `parse` method only returns the AST, whereas `parseForESLint` also returns additional values that let the parser customize the behavior of ESLint even more.
+
+Both methods should take in the source code as the first argument, and an optional configuration object as the second argument, which is provided as [`parserOptions`](../use/configure/language-options#specifying-parser-options) in a configuration file.
+
+```javascript
+// customParser.js
+
+const espree = require("espree");
+
+// Logs the duration it takes to parse each file.
+function parse(code, options) {
+ const label = `Parsing file "${options.filePath}"`;
+ console.time(label);
+ const ast = espree.parse(code, options);
+ console.timeEnd(label);
+ return ast; // Only the AST is returned.
+};
+
+module.exports = { parse };
+```
+
+## `parse` Return Object
+
+The `parse` method should simply return the [AST](#ast-specification) object.
+
+## `parseForESLint` Return Object
+
+The `parseForESLint` method should return an object that contains the required property `ast` and optional properties `services`, `scopeManager`, and `visitorKeys`.
+
+* `ast` should contain the [AST](#ast-specification) object.
+* `services` can contain any parser-dependent services (such as type checkers for nodes). The value of the `services` property is available to rules as `context.parserServices`. Default is an empty object.
+* `scopeManager` can be a [ScopeManager](./scope-manager-interface) object. Custom parsers can use customized scope analysis for experimental/enhancement syntaxes. The default is the `ScopeManager` object which is created by [eslint-scope](https://github.com/eslint/eslint-scope).
+ * Support for `scopeManager` was added in ESLint v4.14.0. ESLint versions that support `scopeManager` will provide an `eslintScopeManager: true` property in `parserOptions`, which can be used for feature detection.
+* `visitorKeys` can be an object to customize AST traversal. The keys of the object are the type of AST nodes. Each value is an array of the property names which should be traversed. The default is [KEYS of `eslint-visitor-keys`](https://github.com/eslint/eslint-visitor-keys#evkkeys).
+ * Support for `visitorKeys` was added in ESLint v4.14.0. ESLint versions that support `visitorKeys` will provide an `eslintVisitorKeys: true` property in `parserOptions`, which can be used for feature detection.
+
+## AST Specification
+
+The AST that custom parsers should create is based on [ESTree](https://github.com/estree/estree). The AST requires some additional properties about detail information of the source code.
+
+### All Nodes
+
+All nodes must have `range` property.
+
+* `range` (`number[]`) is an array of two numbers. Both numbers are a 0-based index which is the position in the array of source code characters. The first is the start position of the node, the second is the end position of the node. `code.slice(node.range[0], node.range[1])` must be the text of the node. This range does not include spaces/parentheses which are around the node.
+* `loc` (`SourceLocation`) must not be `null`. [The `loc` property is defined as nullable by ESTree](https://github.com/estree/estree/blob/25834f7247d44d3156030f8e8a2d07644d771fdb/es5.md#node-objects), but ESLint requires this property. The `SourceLocation#source` property can be `undefined`. ESLint does not use the `SourceLocation#source` property.
+
+The `parent` property of all nodes must be rewritable. Before any rules have access to the AST, ESLint sets each node's `parent` property to its parent node while traversing.
+
+### The `Program` Node
+
+The `Program` node must have `tokens` and `comments` properties. Both properties are an array of the below `Token` interface.
+
+```ts
+interface Token {
+ type: string;
+ loc: SourceLocation;
+ // See the "All Nodes" section for details of the `range` property.
+ range: [number, number];
+ value: string;
+}
+```
+
+* `tokens` (`Token[]`) is the array of tokens which affect the behavior of programs. Arbitrary spaces can exist between tokens, so rules check the `Token#range` to detect spaces between tokens. This must be sorted by `Token#range[0]`.
+* `comments` (`Token[]`) is the array of comment tokens. This must be sorted by `Token#range[0]`.
+
+The range indexes of all tokens and comments must not overlap with the range of other tokens and comments.
+
+### The `Literal` Node
+
+The `Literal` node must have `raw` property.
+
+* `raw` (`string`) is the source code of this literal. This is the same as `code.slice(node.range[0], node.range[1])`.
+
+## Packaging a Custom Parser
+
+To publish your custom parser to npm, perform the following:
+
+1. Create a custom parser following the [Creating a Custom Parser](#creating-a-custom-parser) section above.
+1. [Create an npm package](https://docs.npmjs.com/creating-node-js-modules) for the custom parser.
+1. In your `package.json` file, set the [`main`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#main) field as the file that exports your custom parser.
+1. [Publish the npm package.](https://docs.npmjs.com/creating-and-publishing-unscoped-public-packages)
+
+For more information on publishing an npm package, refer to the [npm documentation](https://docs.npmjs.com/).
+
+Once you've published the npm package, you can use it by adding the package to your project. For example:
+
+```shell
+npm install eslint-parser-myparser --save-dev
+```
+
+Then add the custom parser to your ESLint configuration file with the `parser` property. For example:
+
+```js
+// .eslintrc.js
+
+module.exports = {
+ parser: 'eslint-parser-myparser',
+ // ... rest of configuration
+};
+```
+
+To learn more about using ESLint parsers in your project, refer to [Configure a Parser](../use/configure/parser).
+
+## Example
+
+For a complex example of a custom parser, refer to the [`@typescript-eslint/parser`](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/parser) source code.
+
+A simple custom parser that provides a `context.parserServices.foo()` method to rules.
+
+```javascript
+// awesome-custom-parser.js
+var espree = require("espree");
+function parseForESLint(code, options) {
+ return {
+ ast: espree.parse(code, options),
+ services: {
+ foo: function() {
+ console.log("foo");
+ }
+ },
+ scopeManager: null,
+ visitorKeys: null
+ };
+};
+
+module.exports = { parseForESLint };
+```
+
+Include the custom parser in an ESLint configuration file:
+
+```js
+// .eslintrc.json
+{
+ "parser": "./path/to/awesome-custom-parser.js"
+}
+```
--- /dev/null
+---
+title: Custom Processors
+eleventyNavigation:
+ key: custom processors
+ parent: create plugins
+ title: Custom Processors
+ order: 2
+
+---
+
+You can also create custom processors that tell ESLint how to process files other than standard JavaScript. For example, you could write a custom processor to extract and process JavaScript from Markdown files ([eslint-plugin-markdown](https://www.npmjs.com/package/eslint-plugin-markdown) includes a custom processor for this).
+
+## Custom Processor Specification
+
+In order to create a custom processor, the object exported from your module has to conform to the following interface:
+
+```js
+module.exports = {
+ processors: {
+ "processor-name": {
+ // takes text of the file and filename
+ preprocess: function(text, filename) {
+ // here, you can strip out any non-JS content
+ // and split into multiple strings to lint
+
+ return [ // return an array of code blocks to lint
+ { text: code1, filename: "0.js" },
+ { text: code2, filename: "1.js" },
+ ];
+ },
+
+ // takes a Message[][] and filename
+ postprocess: function(messages, filename) {
+ // `messages` argument contains two-dimensional array of Message objects
+ // where each top-level array item contains array of lint messages related
+ // to the text that was returned in array from preprocess() method
+
+ // you need to return a one-dimensional array of the messages you want to keep
+ return [].concat(...messages);
+ },
+
+ supportsAutofix: true // (optional, defaults to false)
+ }
+ }
+};
+```
+
+**The `preprocess` method** takes the file contents and filename as arguments, and returns an array of code blocks to lint. The code blocks will be linted separately but still be registered to the filename.
+
+A code block has two properties `text` and `filename`. The `text` property is the content of the block and the `filename` property is the name of the block. The name of the block can be anything, but should include the file extension, which tells the linter how to process the current block. The linter checks the [`--ext` CLI option](../use/command-line-interface#--ext) to see if the current block should be linted and resolves `overrides` configs to check how to process the current block.
+
+It's up to the plugin to decide if it needs to return just one part of the non-JavaScript file or multiple pieces. For example in the case of processing `.html` files, you might want to return just one item in the array by combining all scripts. However, for `.md` files, you can return multiple items because each JavaScript block might be independent.
+
+**The `postprocess` method** takes a two-dimensional array of arrays of lint messages and the filename. Each item in the input array corresponds to the part that was returned from the `preprocess` method. The `postprocess` method must adjust the locations of all errors to correspond to locations in the original, unprocessed code, and aggregate them into a single flat array and return it.
+
+Reported problems have the following location information in each lint message:
+
+```typescript
+type LintMessage = {
+
+ /// The 1-based line number where the message occurs.
+ line?: number;
+
+ /// The 1-based column number where the message occurs.
+ column?: number;
+
+ /// The 1-based line number of the end location.
+ endLine?: number;
+
+ /// The 1-based column number of the end location.
+ endColumn?: number;
+
+ /// If `true`, this is a fatal error.
+ fatal?: boolean;
+
+ /// Information for an autofix.
+ fix: Fix;
+
+ /// The error message.
+ message: string;
+
+ /// The ID of the rule which generated the message, or `null` if not applicable.
+ ruleId: string | null;
+
+ /// The severity of the message.
+ severity: 0 | 1 | 2;
+
+ /// Information for suggestions.
+ suggestions?: Suggestion[];
+};
+
+type Fix = {
+ range: [number, number];
+ text: string;
+}
+
+type Suggestion = {
+ desc?: string;
+ messageId?: string;
+ fix: Fix;
+}
+
+```
+
+By default, ESLint does not perform autofixes when a custom processor is used, even when the `--fix` flag is enabled on the command line. To allow ESLint to autofix code when using your processor, you should take the following additional steps:
+
+1. Update the `postprocess` method to additionally transform the `fix` property of reported problems. All autofixable problems have a `fix` property, which is an object with the following schema:
+
+ ```typescript
+ {
+ range: [number, number],
+ text: string
+ }
+ ```
+
+ The `range` property contains two indexes in the code, referring to the start and end location of a contiguous section of text that will be replaced. The `text` property refers to the text that will replace the given range.
+
+ In the initial list of problems, the `fix` property will refer to a fix in the processed JavaScript. The `postprocess` method should transform the object to refer to a fix in the original, unprocessed file.
+
+2. Add a `supportsAutofix: true` property to the processor.
+
+You can have both rules and custom processors in a single plugin. You can also have multiple processors in one plugin. To support multiple extensions, add each one to the `processors` element and point them to the same object.
+
+## Specifying Processor in Config Files
+
+To use a processor, add its ID to a `processor` section in the config file. Processor ID is a concatenated string of plugin name and processor name with a slash as a separator. This can also be added to a `overrides` section of the config, to specify which processors should handle which files.
+
+For example:
+
+```yml
+plugins:
+ - a-plugin
+overrides:
+ - files: "*.md"
+ processor: a-plugin/markdown
+```
+
+See [Specify a Processor](../use/configure/plugins#specify-a-processor) in the Plugin Configuration documentation for more details.
+
+## File Extension-named Processor
+
+If a custom processor name starts with `.`, ESLint handles the processor as a **file extension-named processor**. ESLint applies the processor to files with that filename extension automatically. Users don't need to specify the file extension-named processors in their config files.
+
+For example:
+
+```js
+module.exports = {
+ processors: {
+ // This processor will be applied to `*.md` files automatically.
+ // Also, you can use this processor as "plugin-id/.md" explicitly.
+ ".md": {
+ preprocess(text, filename) { /* ... */ },
+ postprocess(messageLists, filename) { /* ... */ }
+ }
+ // This processor will not be applied to any files automatically.
+ // To use this processor, you must explicitly specify it
+ // in your configuration as "plugin-id/markdown".
+ "markdown": {
+ preprocess(text, filename) { /* ... */ },
+ postprocess(messageLists, filename) { /* ... */ }
+ }
+ }
+}
+```
+
+You can also use the same custom processor with multiple filename extensions. The following example shows using the same processor for both `.md` and `.mdx` files:
+
+```js
+const myCustomProcessor = { /* processor methods */ };
+
+module.exports = {
+ // The same custom processor is applied to both
+ // `.md` and `.mdx` files.
+ processors: {
+ ".md": myCustomProcessor,
+ ".mdx": myCustomProcessor
+ }
+}
+```
--- /dev/null
+---
+title: Working with Rules (Deprecated)
+
+---
+
+**Note:** This page covers the deprecated rule format for ESLint <= 2.13.1. [This is the most recent rule format](./custom-rules).
+
+Each rule in ESLint has two files named with its identifier (for example, `no-extra-semi`).
+
+* in the `lib/rules` directory: a source file (for example, `no-extra-semi.js`)
+* in the `tests/lib/rules` directory: a test file (for example, `no-extra-semi.js`)
+
+**Important:** If you submit a **core** rule to the ESLint repository, you **must** follow some conventions explained below.
+
+Here is the basic format of the source file for a rule:
+
+```js
+/**
+ * @fileoverview Rule to disallow unnecessary semicolons
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ return {
+ // callback functions
+ };
+};
+
+module.exports.schema = []; // no options
+```
+
+## Rule Basics
+
+`schema` (array) specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules)
+
+`create` (function) returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code:
+
+* if a key is a node type, ESLint calls that **visitor** function while going **down** the tree
+* if a key is a node type plus `:exit`, ESLint calls that **visitor** function while going **up** the tree
+* if a key is an event name, ESLint calls that **handler** function for [code path analysis](code-path-analysis)
+
+A rule can use the current node and its surrounding tree to report or fix problems.
+
+Here are methods for the [array-callback-return](../rules/array-callback-return) rule:
+
+```js
+function checkLastSegment (node) {
+ // report problem for function if last code path segment is reachable
+}
+
+module.exports = function(context) {
+ // declare the state of the rule
+ return {
+ ReturnStatement: function(node) {
+ // at a ReturnStatement node while going down
+ },
+ // at a function expression node while going up:
+ "FunctionExpression:exit": checkLastSegment,
+ "ArrowFunctionExpression:exit": checkLastSegment,
+ onCodePathStart: function (codePath, node) {
+ // at the start of analyzing a code path
+ },
+ onCodePathEnd: function(codePath, node) {
+ // at the end of analyzing a code path
+ }
+ };
+};
+```
+
+## The Context Object
+
+The `context` object contains additional functionality that is helpful for rules to do their jobs. As the name implies, the `context` object contains information that is relevant to the context of the rule. The `context` object has the following properties:
+
+* `parserOptions` - the parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)).
+* `id` - the rule ID.
+* `options` - an array of rule options.
+* `settings` - the `settings` from configuration.
+* `parserPath` - the full path to the `parser` from configuration.
+
+Additionally, the `context` object has the following methods:
+
+* `getAncestors()` - returns an array of ancestor nodes based on the current traversal.
+* `getDeclaredVariables(node)` - returns the declared variables on the given node.
+* `getFilename()` - returns the filename associated with the source.
+* `getScope()` - returns the current scope.
+* `getSourceCode()` - returns a `SourceCode` object that you can use to work with the source that was passed to ESLint
+* `markVariableAsUsed(name)` - marks the named variable in scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule.
+* `report(descriptor)` - reports a problem in the code.
+
+**Deprecated:** The following methods on the `context` object are deprecated. Please use the corresponding methods on `SourceCode` instead:
+
+* `getAllComments()` - returns an array of all comments in the source. Use `sourceCode.getAllComments()` instead.
+* `getComments(node)` - returns the leading and trailing comments arrays for the given node. Use `sourceCode.getComments(node)` instead.
+* `getFirstToken(node)` - returns the first token representing the given node. Use `sourceCode.getFirstToken(node)` instead.
+* `getFirstTokens(node, count)` - returns the first `count` tokens representing the given node. Use `sourceCode.getFirstTokens(node, count)` instead.
+* `getJSDocComment(node)` - returns the JSDoc comment for a given node or `null` if there is none. Use `sourceCode.getJSDocComment(node)` instead.
+* `getLastToken(node)` - returns the last token representing the given node. Use `sourceCode.getLastToken(node)` instead.
+* `getLastTokens(node, count)` - returns the last `count` tokens representing the given node. Use `sourceCode.getLastTokens(node, count)` instead.
+* `getNodeByRangeIndex(index)` - returns the deepest node in the AST containing the given source index. Use `sourceCode.getNodeByRangeIndex(index)` instead.
+* `getSource(node)` - returns the source code for the given node. Omit `node` to get the whole source. Use `sourceCode.getText(node)` instead.
+* `getSourceLines()` - returns the entire source code split into an array of string lines. Use `sourceCode.lines` instead.
+* `getTokenAfter(nodeOrToken)` - returns the first token after the given node or token. Use `sourceCode.getTokenAfter(nodeOrToken)` instead.
+* `getTokenBefore(nodeOrToken)` - returns the first token before the given node or token. Use `sourceCode.getTokenBefore(nodeOrToken)` instead.
+* `getTokenByRangeStart(index)` - returns the token whose range starts at the given index in the source. Use `sourceCode.getTokenByRangeStart(index)` instead.
+* `getTokens(node)` - returns all tokens for the given node. Use `sourceCode.getTokens(node)` instead.
+* `getTokensAfter(nodeOrToken, count)` - returns `count` tokens after the given node or token. Use `sourceCode.getTokensAfter(nodeOrToken, count)` instead.
+* `getTokensBefore(nodeOrToken, count)` - returns `count` tokens before the given node or token. Use `sourceCode.getTokensBefore(nodeOrToken, count)` instead.
+* `getTokensBetween(node1, node2)` - returns the tokens between two nodes. Use `sourceCode.getTokensBetween(node1, node2)` instead.
+* `report(node, [location], message)` - reports a problem in the code.
+
+### context.report()
+
+The main method you'll use is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties:
+
+* `message` - the problem message.
+* `node` - (optional) the AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem.
+* `loc` - (optional) an object specifying the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`.
+ * `line` - the 1-based line number at which the problem occurred.
+ * `column` - the 0-based column number at which the problem occurred.
+* `data` - (optional) placeholder data for `message`.
+* `fix` - (optional) a function that applies a fix to resolve the problem.
+
+Note that at least one of `node` or `loc` is required.
+
+The simplest example is to use just `node` and `message`:
+
+```js
+context.report({
+ node: node,
+ message: "Unexpected identifier"
+});
+```
+
+The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node.
+
+You can also use placeholders in the message and provide `data`:
+
+```js
+{% raw %}
+context.report({
+ node: node,
+ message: "Unexpected identifier: {{ identifier }}",
+ data: {
+ identifier: node.name
+ }
+});
+{% endraw %}
+```
+
+Note that leading and trailing whitespace is optional in message parameters.
+
+The node contains all of the information necessary to figure out the line and column number of the offending text as well the source text representing the node.
+
+### Applying Fixes
+
+If you'd like ESLint to attempt to fix the problem you're reporting, you can do so by specifying the `fix` function when using `context.report()`. The `fix` function receives a single argument, a `fixer` object, that you can use to apply a fix. For example:
+
+```js
+context.report({
+ node: node,
+ message: "Missing semicolon".
+ fix: function(fixer) {
+ return fixer.insertTextAfter(node, ";");
+ }
+});
+```
+
+Here, the `fix()` function is used to insert a semicolon after the node. Note that the fix is not immediately applied and may not be applied at all if there are conflicts with other fixes. If the fix cannot be applied, then the problem message is reported as usual; if the fix can be applied, then the problem message is not reported.
+
+The `fixer` object has the following methods:
+
+* `insertTextAfter(nodeOrToken, text)` - inserts text after the given node or token
+* `insertTextAfterRange(range, text)` - inserts text after the given range
+* `insertTextBefore(nodeOrToken, text)` - inserts text before the given node or token
+* `insertTextBeforeRange(range, text)` - inserts text before the given range
+* `remove(nodeOrToken)` - removes the given node or token
+* `removeRange(range)` - removes text in the given range
+* `replaceText(nodeOrToken, text)` - replaces the text in the given node or token
+* `replaceTextRange(range, text)` - replaces the text in the given range
+
+Best practices for fixes:
+
+1. Make fixes that are as small as possible. Anything more than a single character is risky and could prevent other, simpler fixes from being made.
+1. Only make one fix per message. This is enforced because you must return the result of the fixer operation from `fix()`.
+1. Fixes should not introduce clashes with other rules. You can accidentally introduce a new problem that won't be reported until ESLint is run again. Another good reason to make as small a fix as possible.
+
+### context.options
+
+Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line, or in comments). For example:
+
+```json
+{
+ "quotes": [2, "double"]
+}
+```
+
+The `quotes` rule in this example has one option, `"double"` (the `2` is the error level). You can retrieve the options for a rule by using `context.options`, which is an array containing every configured option for the rule. In this case, `context.options[0]` would contain `"double"`:
+
+```js
+module.exports = function(context) {
+
+ var isDouble = (context.options[0] === "double");
+
+ // ...
+}
+```
+
+Since `context.options` is just an array, you can use it to determine how many options have been passed as well as retrieving the actual options themselves. Keep in mind that the error level is not part of `context.options`, as the error level cannot be known or modified from inside a rule.
+
+When using options, make sure that your rule has some logic defaults in case the options are not provided.
+
+### context.getSourceCode()
+
+The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `getSourceCode()` method:
+
+```js
+module.exports = function(context) {
+
+ var sourceCode = context.getSourceCode();
+
+ // ...
+}
+```
+
+Once you have an instance of `SourceCode`, you can use the methods on it to work with the code:
+
+* `getAllComments()` - returns an array of all comments in the source.
+* `getComments(node)` - returns the leading and trailing comments arrays for the given node.
+* `getFirstToken(node)` - returns the first token representing the given node.
+* `getFirstTokens(node, count)` - returns the first `count` tokens representing the given node.
+* `getJSDocComment(node)` - returns the JSDoc comment for a given node or `null` if there is none.
+* `getLastToken(node)` - returns the last token representing the given node.
+* `getLastTokens(node, count)` - returns the last `count` tokens representing the given node.
+* `getNodeByRangeIndex(index)` - returns the deepest node in the AST containing the given source index.
+* `isSpaceBetweenTokens(first, second)` - returns true if there is a whitespace character between the two tokens.
+* `getText(node)` - returns the source code for the given node. Omit `node` to get the whole source.
+* `getTokenAfter(nodeOrToken)` - returns the first token after the given node or token.
+* `getTokenBefore(nodeOrToken)` - returns the first token before the given node or token.
+* `getTokenByRangeStart(index)` - returns the token whose range starts at the given index in the source.
+* `getTokens(node)` - returns all tokens for the given node.
+* `getTokensAfter(nodeOrToken, count)` - returns `count` tokens after the given node or token.
+* `getTokensBefore(nodeOrToken, count)` - returns `count` tokens before the given node or token.
+* `getTokensBetween(node1, node2)` - returns the tokens between two nodes.
+
+There are also some properties you can access:
+
+* `hasBOM` - the flag to indicate whether or not the source code has Unicode BOM.
+* `text` - the full text of the code being linted. Unicode BOM has been stripped from this text.
+* `ast` - the `Program` node of the AST for the code being linted.
+* `lines` - an array of lines, split according to the specification's definition of line breaks.
+
+You should use a `SourceCode` object whenever you need to get more information about the code being linted.
+
+### Options Schemas
+
+Rules may export a `schema` property, which is a [JSON schema](http://json-schema.org/) format description of a rule's options which will be used by ESLint to validate configuration options and prevent invalid or unexpected inputs before they are passed to the rule in `context.options`.
+
+There are two formats for a rule's exported `schema`. The first is a full JSON Schema object describing all possible options the rule accepts, including the rule's error level as the first argument and any optional arguments thereafter.
+
+However, to simplify schema creation, rules may also export an array of schemas for each optional positional argument, and ESLint will automatically validate the required error level first. For example, the `yoda` rule accepts a primary mode argument, as well as an extra options object with named properties.
+
+```js
+// "yoda": [2, "never", { "exceptRange": true }]
+module.exports.schema = [
+ {
+ "enum": ["always", "never"]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "exceptRange": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+];
+```
+
+In the preceding example, the error level is assumed to be the first argument. It is followed by the first optional argument, a string which may be either `"always"` or `"never"`. The final optional argument is an object, which may have a Boolean property named `exceptRange`.
+
+To learn more about JSON Schema, we recommend looking at some [examples](http://json-schema.org/examples.html) to start, and also reading [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/) (a free ebook).
+
+### Getting the Source
+
+If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows:
+
+```js
+
+// get all source
+var source = sourceCode.getText();
+
+// get source for just this AST node
+var nodeSource = sourceCode.getText(node);
+
+// get source for AST node plus previous two characters
+var nodeSourceWithPrev = sourceCode.getText(node, 2);
+
+// get source for AST node plus following two characters
+var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2);
+```
+
+In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as location of commas, semicolons, parentheses, etc.).
+
+### Accessing comments
+
+If you need to access comments for a specific node you can use `sourceCode.getComments(node)`:
+
+```js
+// the "comments" variable has a "leading" and "trailing" property containing
+// its leading and trailing comments, respectively
+var comments = sourceCode.getComments(node);
+```
+
+Keep in mind that comments are technically not a part of the AST and are only attached to it on demand, i.e. when you call `getComments()`.
+
+**Note:** One of the libraries adds AST node properties for comments - do not use these properties. Always use `sourceCode.getComments()` as this is the only guaranteed API for accessing comments (we will likely change how comments are handled later).
+
+### Accessing Code Paths
+
+ESLint analyzes code paths while traversing AST.
+You can access that code path objects with five events related to code paths.
+
+[details here](code-path-analysis)
+
+## Rule Unit Tests
+
+Each rule must have a set of unit tests submitted with it to be accepted. The test file is named the same as the source file but lives in `tests/lib/`. For example, if your rule source file is `lib/rules/foo.js` then your test file should be `tests/lib/rules/foo.js`.
+
+For your rule, be sure to test:
+
+1. All instances that should be flagged as warnings.
+1. At least one pattern that should **not** be flagged as a warning.
+
+The basic pattern for a rule unit test file is:
+
+```js
+/**
+ * @fileoverview Tests for no-with rule.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+var rule = require("../../../lib/rules/no-with"),
+ RuleTester = require("../../../lib/testers/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+var ruleTester = new RuleTester();
+ruleTester.run("no-with", rule, {
+ valid: [
+ "foo.bar()"
+ ],
+ invalid: [
+ {
+ code: "with(foo) { bar() }",
+ errors: [{ message: "Unexpected use of 'with' statement.", type: "WithStatement"}]
+ }
+ ]
+});
+```
+
+Be sure to replace the value of `"no-with"` with your rule's ID. There are plenty of examples in the `tests/lib/rules/` directory.
+
+### Valid Code
+
+Each valid case can be either a string or an object. The object form is used when you need to specify additional global variables or arguments for the rule. For example, the following defines `window` as a global variable for code that should not trigger the rule being tested:
+
+```js
+valid: [
+ {
+ code: "window.alert()",
+ globals: [ "window" ]
+ }
+]
+```
+
+You can also pass options to the rule (if it accepts them). These arguments are equivalent to how people can configure rules in their `.eslintrc` file. For example:
+
+```js
+valid: [
+ {
+ code: "var msg = 'Hello';",
+ options: [ "single" ]
+ }
+]
+```
+
+The `options` property must be an array of options. This gets passed through to `context.options` in the rule.
+
+### Invalid Code
+
+Each invalid case must be an object containing the code to test and at least one message that is produced by the rule. The `errors` key specifies an array of objects, each containing a message (your rule may trigger multiple messages for the same code). You should also specify the type of AST node you expect to receive back using the `type` key. The AST node should represent the actual spot in the code where there is a problem. For example:
+
+```js
+invalid: [
+ {
+ code: "function doSomething() { var f; if (true) { var build = true; } f = build; }",
+ errors: [
+ { message: "build used outside of binding context.", type: "Identifier" }
+ ]
+ }
+]
+```
+
+In this case, the message is specific to the variable being used and the AST node type is `Identifier`.
+
+Similar to the valid cases, you can also specify `options` to be passed to the rule:
+
+```js
+invalid: [
+ {
+ code: "function doSomething() { var f; if (true) { var build = true; } f = build; }",
+ options: [ "double" ],
+ errors: [
+ { message: "build used outside of binding context.", type: "Identifier" }
+ ]
+ }
+]
+```
+
+For simpler cases where the only thing that really matters is the error message, you can also specify any `errors` as strings. You can also have some strings and some objects, if you like.
+
+```js
+invalid: [
+ {
+ code: "'single quotes'",
+ options: ["double"],
+ errors: ["Strings must use doublequote."]
+ }
+]
+```
+
+### Specifying Parser Options
+
+Some tests require that a certain parser configuration must be used. This can be specified in test specifications via the `parserOptions` setting.
+
+For example, to set `ecmaVersion` to 6 (in order to use constructs like `for ... of`):
+
+```js
+valid: [
+ {
+ code: "for (x of a) doSomething();",
+ parserOptions: { ecmaVersion: 6 }
+ }
+]
+```
+
+If you are working with ES6 modules:
+
+```js
+valid: [
+ {
+ code: "export default function () {};",
+ parserOptions: { ecmaVersion: 6, sourceType: "module" }
+ }
+]
+```
+
+For non-version specific features such as JSX:
+
+```js
+valid: [
+ {
+ code: "var foo = <div>{bar}</div>",
+ parserOptions: { ecmaFeatures: { jsx: true } }
+ }
+]
+```
+
+The options available and the expected syntax for `parserOptions` is the same as those used in [configuration](../use/configure/language-options#specifying-parser-options).
+
+### Write Several Tests
+
+Provide as many unit tests as possible. Your pull request will never be turned down for having too many tests submitted with it!
+
+## Performance Testing
+
+To keep the linting process efficient and unobtrusive, it is useful to verify the performance impact of new rules or modifications to existing rules.
+
+### Overall Performance
+
+The `npm run perf` command gives a high-level overview of ESLint running time with default rules (`eslint:recommended`) enabled.
+
+```bash
+$ git checkout main
+Switched to branch 'main'
+
+$ npm run perf
+CPU Speed is 2200 with multiplier 7500000
+Performance Run #1: 1394.689313ms
+Performance Run #2: 1423.295351ms
+Performance Run #3: 1385.09515ms
+Performance Run #4: 1382.406982ms
+Performance Run #5: 1409.68566ms
+Performance budget ok: 1394.689313ms (limit: 3409.090909090909ms)
+
+$ git checkout my-rule-branch
+Switched to branch 'my-rule-branch'
+
+$ npm run perf
+CPU Speed is 2200 with multiplier 7500000
+Performance Run #1: 1443.736547ms
+Performance Run #2: 1419.193291ms
+Performance Run #3: 1436.018228ms
+Performance Run #4: 1473.605485ms
+Performance Run #5: 1457.455283ms
+Performance budget ok: 1443.736547ms (limit: 3409.090909090909ms)
+```
+
+### Per-rule Performance
+
+ESLint has a built-in method to track performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time and relative performance impact as a percentage of total rule processing time.
+
+```bash
+$ TIMING=1 eslint lib
+Rule | Time (ms) | Relative
+:-----------------------|----------:|--------:
+no-multi-spaces | 52.472 | 6.1%
+camelcase | 48.684 | 5.7%
+no-irregular-whitespace | 43.847 | 5.1%
+valid-jsdoc | 40.346 | 4.7%
+handle-callback-err | 39.153 | 4.6%
+space-infix-ops | 35.444 | 4.1%
+no-undefined | 25.693 | 3.0%
+no-shadow | 22.759 | 2.7%
+no-empty-class | 21.976 | 2.6%
+semi | 19.359 | 2.3%
+```
+
+To test one rule explicitly, combine the `--no-eslintrc`, and `--rule` options:
+
+```bash
+$ TIMING=1 eslint --no-eslintrc --rule "quotes: [2, 'double']" lib
+Rule | Time (ms) | Relative
+:------|----------:|--------:
+quotes | 18.066 | 100.0%
+```
+
+## Rule Naming Conventions
+
+The rule naming conventions for ESLint are fairly simple:
+
+* If your rule is disallowing something, prefix it with `no-` such as `no-eval` for disallowing `eval()` and `no-debugger` for disallowing `debugger`.
+* If your rule is enforcing the inclusion of something, use a short name without a special prefix.
+* Keep your rule names as short as possible, use abbreviations where appropriate, and no more than four words.
+* Use dashes between words.
+
+## Rule Acceptance Criteria
+
+Because rules are highly personal (and therefore very contentious), accepted rules should:
+
+* Not be library-specific.
+* Demonstrate a possible issue that can be resolved by rewriting the code.
+* Be general enough so as to apply for a large number of developers.
+* Not be the opposite of an existing rule.
+* Not overlap with an existing rule.
+
+## Runtime Rules
+
+The thing that makes ESLint different from other linters is the ability to define custom rules at runtime. This is perfect for rules that are specific to your project or company and wouldn't make sense for ESLint to ship with. With runtime rules, you don't have to wait for the next version of ESLint or be disappointed that your rule isn't general enough to apply to the larger JavaScript community, just write your rules and include them at runtime.
+
+Runtime rules are written in the same format as all other rules. Create your rule as you would any other and then follow these steps:
+
+1. Place all of your runtime rules in the same directory (i.e., `eslint_rules`).
+2. Create a [configuration file](../use/configure/) and specify your rule ID error level under the `rules` key. Your rule will not run unless it has a value of `1` or `2` in the configuration file.
+3. Run the [command line interface](../use/command-line-interface) using the `--rulesdir` option to specify the location of your runtime rules.
--- /dev/null
+---
+title: Custom Rules
+eleventyNavigation:
+ key: custom rules
+ parent: create plugins
+ title: Custom Rules
+ order: 1
+
+---
+
+You can create custom rules to use with ESLint. You might want to create a custom rule if the [core rules](../rules/) do not cover your use case.
+
+**Note:** This page covers the most recent rule format for ESLint >= 3.0.0. There is also a [deprecated rule format](./custom-rules-deprecated).
+
+Here's the basic format of a custom rule:
+
+```js
+// customRule.js
+
+module.exports = {
+ meta: {
+ type: "suggestion",
+ docs: {
+ description: "Description of the rule",
+ },
+ fixable: "code",
+ schema: [] // no options
+ },
+ create: function(context) {
+ return {
+ // callback functions
+ };
+ }
+};
+```
+
+## Rule Structure
+
+The source file for a rule exports an object with the following properties. Both custom rules and core rules follow this format.
+
+`meta`: (`object`) Contains metadata for the rule:
+
+* `type`: (`string`) Indicates the type of rule, which is one of `"problem"`, `"suggestion"`, or `"layout"`:
+
+ * `"problem"`: The rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve.
+ * `"suggestion"`: The rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed.
+ * `"layout"`: The rule cares primarily about whitespace, semicolons, commas, and parentheses, all the parts of the program that determine how the code looks rather than how it executes. These rules work on parts of the code that aren't specified in the AST.
+
+* `docs`: (`object`) Required for core rules and optional for custom rules. Core rules have specific entries inside of `docs` while custom rules can include any properties that you need. The following properties are only relevant when working on core rules.
+
+ * `description`: (`string`) Provides the short description of the rule in the [rules index](../rules/).
+ * `recommended`: (`boolean`) Specifies whether the `"extends": "eslint:recommended"` property in a [configuration file](../use/configure/configuration-files#extending-configuration-files) enables the rule.
+ * `url`: (`string`) Specifies the URL at which the full documentation can be accessed (enabling code editors to provide a helpful link on highlighted rule violations).
+
+* `fixable`: (`string`) Either `"code"` or `"whitespace"` if the `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixes problems reported by the rule.
+
+ **Important:** the `fixable` property is mandatory for fixable rules. If this property isn't specified, ESLint will throw an error whenever the rule attempts to produce a fix. Omit the `fixable` property if the rule is not fixable.
+
+* `hasSuggestions`: (`boolean`) Specifies whether rules can return suggestions (defaults to `false` if omitted).
+
+ **Important:** the `hasSuggestions` property is mandatory for rules that provide suggestions. If this property isn't set to `true`, ESLint will throw an error whenever the rule attempts to produce a suggestion. Omit the `hasSuggestions` property if the rule does not provide suggestions.
+
+* `schema`: (`object | array`) Specifies the [options](#options-schemas) so ESLint can prevent invalid [rule configurations](../use/configure/rules).
+
+* `deprecated`: (`boolean`) Indicates whether the rule has been deprecated. You may omit the `deprecated` property if the rule has not been deprecated.
+
+* `replacedBy`: (`array`) In the case of a deprecated rule, specify replacement rule(s).
+
+`create()`: Returns an object with methods that ESLint calls to "visit" nodes while traversing the abstract syntax tree (AST as defined by [ESTree](https://github.com/estree/estree)) of JavaScript code:
+
+* If a key is a node type or a [selector](./selectors), ESLint calls that **visitor** function while going **down** the tree.
+* If a key is a node type or a [selector](./selectors) plus `:exit`, ESLint calls that **visitor** function while going **up** the tree.
+* If a key is an event name, ESLint calls that **handler** function for [code path analysis](code-path-analysis).
+
+A rule can use the current node and its surrounding tree to report or fix problems.
+
+Here are methods for the [array-callback-return](../rules/array-callback-return) rule:
+
+```js
+function checkLastSegment (node) {
+ // report problem for function if last code path segment is reachable
+}
+
+module.exports = {
+ meta: { ... },
+ create: function(context) {
+ // declare the state of the rule
+ return {
+ ReturnStatement: function(node) {
+ // at a ReturnStatement node while going down
+ },
+ // at a function expression node while going up:
+ "FunctionExpression:exit": checkLastSegment,
+ "ArrowFunctionExpression:exit": checkLastSegment,
+ onCodePathStart: function (codePath, node) {
+ // at the start of analyzing a code path
+ },
+ onCodePathEnd: function(codePath, node) {
+ // at the end of analyzing a code path
+ }
+ };
+ }
+};
+```
+
+## The Context Object
+
+The `context` object is the only argument of the `create` method in a rule. For example:
+
+```js
+// customRule.js
+
+module.exports = {
+ meta: { ... },
+ // `context` object is the argument
+ create(context) {
+ // ...
+ }
+};
+```
+
+As the name implies, the `context` object contains information that is relevant to the context of the rule.
+
+The `context` object has the following properties:
+
+* `id`: (`string`) The rule ID.
+* `filename`: (`string`) The filename associated with the source.
+* `physicalFilename`: (`string`) When linting a file, it provides the full path of the file on disk without any code block information. When linting text, it provides the value passed to `—stdin-filename` or `<text>` if not specified.
+* `cwd`: (`string`) The `cwd` option passed to the [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered the current working directory.
+* `options`: (`array`) An array of the [configured options](../use/configure/rules) for this rule. This array does not include the rule severity (see the [dedicated section](#accessing-options-passed-to-a-rule)).
+* `sourceCode`: (`object`) A `SourceCode` object that you can use to work with the source that was passed to ESLint (see [Accessing the Source Code](#accessing-the-source-code)).
+* `settings`: (`object`) The [shared settings](../use/configure/configuration-files#adding-shared-settings) from the configuration.
+* `parserPath`: (`string`) The name of the `parser` from the configuration.
+* `parserServices`: (`object`) Contains parser-provided services for rules. The default parser does not provide any services. However, if a rule is intended to be used with a custom parser, it could use `parserServices` to access anything provided by that parser. (For example, a TypeScript parser could provide the ability to get the computed type of a given node.)
+* `parserOptions`: The parser options configured for this run (more details [here](../use/configure/language-options#specifying-parser-options)).
+
+Additionally, the `context` object has the following methods:
+
+* `getAncestors()`: (**Deprecated:** Use `SourceCode#getAncestors(node)` instead.) Returns an array of the ancestors of the currently-traversed node, starting at the root of the AST and continuing through the direct parent of the current node. This array does not include the currently-traversed node itself.
+* `getCwd()`: (**Deprecated:** Use `context.cwd` instead.) Returns the `cwd` option passed to the [Linter](../integrate/nodejs-api#linter). It is a path to a directory that should be considered the current working directory.
+* `getDeclaredVariables(node)`: (**Deprecated:** Use `SourceCode#getDeclaredVariables(node)` instead.) Returns a list of [variables](./scope-manager-interface#variable-interface) declared by the given node. This information can be used to track references to variables.
+ * If the node is a `VariableDeclaration`, all variables declared in the declaration are returned.
+ * If the node is a `VariableDeclarator`, all variables declared in the declarator are returned.
+ * If the node is a `FunctionDeclaration` or `FunctionExpression`, the variable for the function name is returned, in addition to variables for the function parameters.
+ * If the node is an `ArrowFunctionExpression`, variables for the parameters are returned.
+ * If the node is a `ClassDeclaration` or a `ClassExpression`, the variable for the class name is returned.
+ * If the node is a `CatchClause`, the variable for the exception is returned.
+ * If the node is an `ImportDeclaration`, variables for all of its specifiers are returned.
+ * If the node is an `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`, the declared variable is returned.
+ * Otherwise, if the node does not declare any variables, an empty array is returned.
+* `getFilename()`: (**Deprecated:** Use `context.filename` instead.) Returns the filename associated with the source.
+* `getPhysicalFilename()`: (**Deprecated:** Use `context.physicalFilename` instead.) When linting a file, it returns the full path of the file on disk without any code block information. When linting text, it returns the value passed to `—stdin-filename` or `<text>` if not specified.
+* `getScope()`: (**Deprecated:** Use `SourceCode#getScope(node)` instead.) Returns the [scope](./scope-manager-interface#scope-interface) of the currently-traversed node. This information can be used to track references to variables.
+* `getSourceCode()`: (**Deprecated:** Use `context.sourceCode` instead.) Returns a `SourceCode` object that you can use to work with the source that was passed to ESLint (see [Accessing the Source Code](#accessing-the-source-code)).
+* `markVariableAsUsed(name)`: (**Deprecated:** Use `SourceCode#markVariableAsUsed(name, node)` instead.) Marks a variable with the given name in the current scope as used. This affects the [no-unused-vars](../rules/no-unused-vars) rule. Returns `true` if a variable with the given name was found and marked as used, otherwise `false`.
+* `report(descriptor)`. Reports a problem in the code (see the [dedicated section](#reporting-problems)).
+
+**Note:** Earlier versions of ESLint supported additional methods on the `context` object. Those methods were removed in the new format and should not be relied upon.
+
+### Reporting Problems
+
+The main method you'll use when writing custom rules is `context.report()`, which publishes a warning or error (depending on the configuration being used). This method accepts a single argument, which is an object containing the following properties:
+
+* `message`: (`string`) The problem message.
+* `node`: (optional `object`) The AST node related to the problem. If present and `loc` is not specified, then the starting location of the node is used as the location of the problem.
+* `loc`: (optional `object`) Specifies the location of the problem. If both `loc` and `node` are specified, then the location is used from `loc` instead of `node`.
+ * `start`: An object of the start location.
+ * `line`: (`number`) The 1-based line number at which the problem occurred.
+ * `column`: (`number`) The 0-based column number at which the problem occurred.
+ * `end`: An object of the end location.
+ * `line`: (`number`) The 1-based line number at which the problem occurred.
+ * `column`: (`number`) The 0-based column number at which the problem occurred.
+* `data`: (optional `object`) [Placeholder](#using-message-placeholders) data for `message`.
+* `fix(fixer)`: (optional `function`) Applies a [fix](#applying-fixes) to resolve the problem.
+
+Note that at least one of `node` or `loc` is required.
+
+The simplest example is to use just `node` and `message`:
+
+```js
+context.report({
+ node: node,
+ message: "Unexpected identifier"
+});
+```
+
+The node contains all the information necessary to figure out the line and column number of the offending text as well as the source text representing the node.
+
+#### Using Message Placeholders
+
+You can also use placeholders in the message and provide `data`:
+
+```js
+{% raw %}
+context.report({
+ node: node,
+ message: "Unexpected identifier: {{ identifier }}",
+ data: {
+ identifier: node.name
+ }
+});
+{% endraw %}
+```
+
+Note that leading and trailing whitespace is optional in message parameters.
+
+The node contains all the information necessary to figure out the line and column number of the offending text as well as the source text representing the node.
+
+#### `messageId`s
+
+Instead of typing out messages in both the `context.report()` call and your tests, you can use `messageId`s instead.
+
+This allows you to avoid retyping error messages. It also prevents errors reported in different sections of your rule from having out-of-date messages.
+
+Rule file:
+
+```js
+{% raw %}
+// avoid-name.js
+
+module.exports = {
+ meta: {
+ messages: {
+ avoidName: "Avoid using variables named '{{ name }}'"
+ }
+ },
+ create(context) {
+ return {
+ Identifier(node) {
+ if (node.name === "foo") {
+ context.report({
+ node,
+ messageId: "avoidName",
+ data: {
+ name: "foo",
+ }
+ });
+ }
+ }
+ };
+ }
+};
+{% endraw %}
+```
+
+In the file to lint:
+
+```javascript
+// someFile.js
+
+var foo = 2;
+// ^ error: Avoid using variables named 'foo'
+```
+
+In your tests:
+
+```javascript
+// avoid-name.test.js
+
+var rule = require("../../../lib/rules/avoid-name");
+var RuleTester = require("eslint").RuleTester;
+
+var ruleTester = new RuleTester();
+ruleTester.run("avoid-name", rule, {
+ valid: ["bar", "baz"],
+ invalid: [
+ {
+ code: "foo",
+ errors: [
+ {
+ messageId: "avoidName"
+ }
+ ]
+ }
+ ]
+});
+```
+
+#### Applying Fixes
+
+If you'd like ESLint to attempt to fix the problem you're reporting, you can do so by specifying the `fix` function when using `context.report()`. The `fix` function receives a single argument, a `fixer` object, that you can use to apply a fix. For example:
+
+```js
+context.report({
+ node: node,
+ message: "Missing semicolon",
+ fix(fixer) {
+ return fixer.insertTextAfter(node, ";");
+ }
+});
+```
+
+Here, the `fix()` function is used to insert a semicolon after the node. Note that a fix is not immediately applied, and may not be applied at all if there are conflicts with other fixes. After applying fixes, ESLint will run all the enabled rules again on the fixed code, potentially applying more fixes. This process will repeat up to 10 times, or until no more fixable problems are found. Afterward, any remaining problems will be reported as usual.
+
+**Important:** The `meta.fixable` property is mandatory for fixable rules. ESLint will throw an error if a rule that implements `fix` functions does not [export](#rule-structure) the `meta.fixable` property.
+
+The `fixer` object has the following methods:
+
+* `insertTextAfter(nodeOrToken, text)`: Insert text after the given node or token.
+* `insertTextAfterRange(range, text)`: Insert text after the given range.
+* `insertTextBefore(nodeOrToken, text)`: Insert text before the given node or token.
+* `insertTextBeforeRange(range, text)`: Insert text before the given range.
+* `remove(nodeOrToken)`: Remove the given node or token.
+* `removeRange(range)`: Remove text in the given range.
+* `replaceText(nodeOrToken, text)`: Replace the text in the given node or token.
+* `replaceTextRange(range, text)`: Replace the text in the given range.
+
+A `range` is a two-item array containing character indices inside the source code. The first item is the start of the range (inclusive) and the second item is the end of the range (exclusive). Every node and token has a `range` property to identify the source code range they represent.
+
+The above methods return a `fixing` object.
+The `fix()` function can return the following values:
+
+* A `fixing` object.
+* An array which includes `fixing` objects.
+* An iterable object which enumerates `fixing` objects. Especially, the `fix()` function can be a generator.
+
+If you make a `fix()` function which returns multiple `fixing` objects, those `fixing` objects must not overlap.
+
+Best practices for fixes:
+
+1. Avoid any fixes that could change the runtime behavior of code and cause it to stop working.
+1. Make fixes as small as possible. Fixes that are unnecessarily large could conflict with other fixes, and prevent them from being applied.
+1. Only make one fix per message. This is enforced because you must return the result of the fixer operation from `fix()`.
+1. Since all rules are run again after the initial round of fixes is applied, it's not necessary for a rule to check whether the code style of a fix will cause errors to be reported by another rule.
+ * For example, suppose a fixer would like to surround an object key with quotes, but it's not sure whether the user would prefer single or double quotes.
+
+ ```js
+ ({ foo : 1 })
+
+ // should get fixed to either
+
+ ({ 'foo': 1 })
+
+ // or
+
+ ({ "foo": 1 })
+ ```
+
+ * This fixer can just select a quote type arbitrarily. If it guesses wrong, the resulting code will be automatically reported and fixed by the [`quotes`](../rules/quotes) rule.
+
+Note: Making fixes as small as possible is a best practice, but in some cases it may be correct to extend the range of the fix in order to intentionally prevent other rules from making fixes in a surrounding range in the same pass. For instance, if replacement text declares a new variable, it can be useful to prevent other changes in the scope of the variable as they might cause name collisions.
+
+The following example replaces `node` and also ensures that no other fixes will be applied in the range of `node.parent` in the same pass:
+
+```js
+context.report({
+ node,
+ message,
+ *fix(fixer) {
+ yield fixer.replaceText(node, replacementText);
+
+ // extend range of the fix to the range of `node.parent`
+ yield fixer.insertTextBefore(node.parent, "");
+ yield fixer.insertTextAfter(node.parent, "");
+ }
+});
+```
+
+#### Conflicting Fixes
+
+Conflicting fixes are fixes that apply different changes to the same part of the source code.
+There is no way to specify which of the conflicting fixes is applied.
+
+For example, if two fixes want to modify characters 0 through 5, only one is applied.
+
+#### Providing Suggestions
+
+In some cases fixes aren't appropriate to be automatically applied, for example, if a fix potentially changes functionality or if there are multiple valid ways to fix a rule depending on the implementation intent (see the best practices for [applying fixes](#applying-fixes) listed above). In these cases, there is an alternative `suggest` option on `context.report()` that allows other tools, such as editors, to expose helpers for users to manually apply a suggestion.
+
+To provide suggestions, use the `suggest` key in the report argument with an array of suggestion objects. The suggestion objects represent individual suggestions that could be applied and require either a `desc` key string that describes what applying the suggestion would do or a `messageId` key (see [below](#suggestion-messageids)), and a `fix` key that is a function defining the suggestion result. This `fix` function follows the same API as regular fixes (described above in [applying fixes](#applying-fixes)).
+
+```js
+{% raw %}
+context.report({
+ node: node,
+ message: "Unnecessary escape character: \\{{character}}.",
+ data: { character },
+ suggest: [
+ {
+ desc: "Remove the `\\`. This maintains the current functionality.",
+ fix: function(fixer) {
+ return fixer.removeRange(range);
+ }
+ },
+ {
+ desc: "Replace the `\\` with `\\\\` to include the actual backslash character.",
+ fix: function(fixer) {
+ return fixer.insertTextBeforeRange(range, "\\");
+ }
+ }
+ ]
+});
+{% endraw %}
+```
+
+**Important:** The `meta.hasSuggestions` property is mandatory for rules that provide suggestions. ESLint will throw an error if a rule attempts to produce a suggestion but does not [export](#rule-structure) this property.
+
+**Note:** Suggestions are applied as stand-alone changes, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to conform to user-defined styles. For example, if a suggestion is adding a new statement into the codebase, it should not try to match correct indentation or conform to user preferences on the presence/absence of semicolons. All of those things can be corrected by multipass autofix when the user triggers it.
+
+Best practices for suggestions:
+
+1. Don't try to do too much and suggest large refactors that could introduce a lot of breaking changes.
+1. As noted above, don't try to conform to user-defined styles.
+
+Suggestions are intended to provide fixes. ESLint will automatically remove the whole suggestion from the linting output if the suggestion's `fix` function returned `null` or an empty array/sequence.
+
+#### Suggestion `messageId`s
+
+Instead of using a `desc` key for suggestions a `messageId` can be used instead. This works the same way as `messageId`s for the overall error (see [messageIds](#messageids)). Here is an example of how to use a suggestion `messageId` in a rule:
+
+```js
+{% raw %}
+module.exports = {
+ meta: {
+ messages: {
+ unnecessaryEscape: "Unnecessary escape character: \\{{character}}.",
+ removeEscape: "Remove the `\\`. This maintains the current functionality.",
+ escapeBackslash: "Replace the `\\` with `\\\\` to include the actual backslash character."
+ },
+ hasSuggestions: true
+ },
+ create: function(context) {
+ // ...
+ context.report({
+ node: node,
+ messageId: 'unnecessaryEscape',
+ data: { character },
+ suggest: [
+ {
+ messageId: "removeEscape", // suggestion messageId
+ fix: function(fixer) {
+ return fixer.removeRange(range);
+ }
+ },
+ {
+ messageId: "escapeBackslash", // suggestion messageId
+ fix: function(fixer) {
+ return fixer.insertTextBeforeRange(range, "\\");
+ }
+ }
+ ]
+ });
+ }
+};
+{% endraw %}
+```
+
+#### Placeholders in Suggestion Messages
+
+You can also use placeholders in the suggestion message. This works the same way as placeholders for the overall error (see [using message placeholders](#using-message-placeholders)).
+
+Please note that you have to provide `data` on the suggestion's object. Suggestion messages cannot use properties from the overall error's `data`.
+
+```js
+{% raw %}
+module.exports = {
+ meta: {
+ messages: {
+ unnecessaryEscape: "Unnecessary escape character: \\{{character}}.",
+ removeEscape: "Remove `\\` before {{character}}.",
+ },
+ hasSuggestions: true
+ },
+ create: function(context) {
+ // ...
+ context.report({
+ node: node,
+ messageId: "unnecessaryEscape",
+ data: { character }, // data for the unnecessaryEscape overall message
+ suggest: [
+ {
+ messageId: "removeEscape",
+ data: { character }, // data for the removeEscape suggestion message
+ fix: function(fixer) {
+ return fixer.removeRange(range);
+ }
+ }
+ ]
+ });
+ }
+};
+{% endraw %}
+```
+
+### Accessing Options Passed to a Rule
+
+Some rules require options in order to function correctly. These options appear in configuration (`.eslintrc`, command line interface, or comments). For example:
+
+```json
+{
+ "quotes": ["error", "double"]
+}
+```
+
+The `quotes` rule in this example has one option, `"double"` (the `error` is the error level). You can retrieve the options for a rule by using `context.options`, which is an array containing every configured option for the rule. In this case, `context.options[0]` would contain `"double"`:
+
+```js
+module.exports = {
+ create: function(context) {
+ var isDouble = (context.options[0] === "double");
+
+ // ...
+ }
+};
+```
+
+Since `context.options` is just an array, you can use it to determine how many options have been passed as well as retrieving the actual options themselves. Keep in mind that the error level is not part of `context.options`, as the error level cannot be known or modified from inside a rule.
+
+When using options, make sure that your rule has some logical defaults in case the options are not provided.
+
+### Accessing the Source Code
+
+The `SourceCode` object is the main object for getting more information about the source code being linted. You can retrieve the `SourceCode` object at any time by using the `context.sourceCode` property:
+
+```js
+module.exports = {
+ create: function(context) {
+ var sourceCode = context.sourceCode;
+
+ // ...
+ }
+};
+```
+
+**Deprecated:** The `context.getSourceCode()` method is deprecated; make sure to use `context.sourceCode` property instead.
+
+Once you have an instance of `SourceCode`, you can use the following methods on it to work with the code:
+
+* `getText(node)`: Returns the source code for the given node. Omit `node` to get the whole source (see the [dedicated section](#accessing-the-source-text)).
+* `getAllComments()`: Returns an array of all comments in the source (see the [dedicated section](#accessing-comments)).
+* `getCommentsBefore(nodeOrToken)`: Returns an array of comment tokens that occur directly before the given node or token (see the [dedicated section](#accessing-comments)).
+* `getCommentsAfter(nodeOrToken)`: Returns an array of comment tokens that occur directly after the given node or token (see the [dedicated section](#accessing-comments)).
+* `getCommentsInside(node)`: Returns an array of all comment tokens inside a given node (see the [dedicated section](#accessing-comments)).
+* `isSpaceBetween(nodeOrToken, nodeOrToken)`: Returns true if there is a whitespace character between the two tokens or, if given a node, the last token of the first node and the first token of the second node.
+* `getFirstToken(node, skipOptions)`: Returns the first token representing the given node.
+* `getFirstTokens(node, countOptions)`: Returns the first `count` tokens representing the given node.
+* `getLastToken(node, skipOptions)`: Returns the last token representing the given node.
+* `getLastTokens(node, countOptions)`: Returns the last `count` tokens representing the given node.
+* `getTokenAfter(nodeOrToken, skipOptions)`: Returns the first token after the given node or token.
+* `getTokensAfter(nodeOrToken, countOptions)`: Returns `count` tokens after the given node or token.
+* `getTokenBefore(nodeOrToken, skipOptions)`: Returns the first token before the given node or token.
+* `getTokensBefore(nodeOrToken, countOptions)`: Returns `count` tokens before the given node or token.
+* `getFirstTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Returns the first token between two nodes or tokens.
+* `getFirstTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Returns the first `count` tokens between two nodes or tokens.
+* `getLastTokenBetween(nodeOrToken1, nodeOrToken2, skipOptions)`: Returns the last token between two nodes or tokens.
+* `getLastTokensBetween(nodeOrToken1, nodeOrToken2, countOptions)`: Returns the last `count` tokens between two nodes or tokens.
+* `getTokens(node)`: Returns all tokens for the given node.
+* `getTokensBetween(nodeOrToken1, nodeOrToken2)`: Returns all tokens between two nodes.
+* `getTokenByRangeStart(index, rangeOptions)`: Returns the token whose range starts at the given index in the source.
+* `getNodeByRangeIndex(index)`: Returns the deepest node in the AST containing the given source index.
+* `getLocFromIndex(index)`: Returns an object with `line` and `column` properties, corresponding to the location of the given source index. `line` is 1-based and `column` is 0-based.
+* `getIndexFromLoc(loc)`: Returns the index of a given location in the source code, where `loc` is an object with a 1-based `line` key and a 0-based `column` key.
+* `commentsExistBetween(nodeOrToken1, nodeOrToken2)`: Returns `true` if comments exist between two nodes.
+
+`skipOptions` is an object which has 3 properties; `skip`, `includeComments`, and `filter`. Default is `{skip: 0, includeComments: false, filter: null}`.
+
+* `skip`: (`number`) Positive integer, the number of skipping tokens. If `filter` option is given at the same time, it doesn't count filtered tokens as skipped.
+* `includeComments`: (`boolean`) The flag to include comment tokens into the result.
+* `filter(token)`: Function which gets a token as the first argument. If the function returns `false` then the result excludes the token.
+
+`countOptions` is an object which has 3 properties; `count`, `includeComments`, and `filter`. Default is `{count: 0, includeComments: false, filter: null}`.
+
+* `count`: (`number`) Positive integer, the maximum number of returning tokens.
+* `includeComments`: (`boolean`) The flag to include comment tokens into the result.
+* `filter(token)`: Function which gets a token as the first argument, if the function returns `false` then the result excludes the token.
+
+`rangeOptions` is an object that has 1 property, `includeComments`. Default is `{includeComments: false}`.
+
+* `includeComments`: (`boolean`) The flag to include comment tokens into the result.
+
+There are also some properties you can access:
+
+* `hasBOM`: (`boolean`) The flag to indicate whether the source code has Unicode BOM.
+* `text`: (`string`) The full text of the code being linted. Unicode BOM has been stripped from this text.
+* `ast`: (`object`) `Program` node of the AST for the code being linted.
+* `scopeManager`: [ScopeManager](./scope-manager-interface#scopemanager-interface) object of the code.
+* `visitorKeys`: (`object`) Visitor keys to traverse this AST.
+* `lines`: (`array`) Array of lines, split according to the specification's definition of line breaks.
+
+You should use a `SourceCode` object whenever you need to get more information about the code being linted.
+
+#### Accessing the Source Text
+
+If your rule needs to get the actual JavaScript source to work with, then use the `sourceCode.getText()` method. This method works as follows:
+
+```js
+
+// get all source
+var source = sourceCode.getText();
+
+// get source for just this AST node
+var nodeSource = sourceCode.getText(node);
+
+// get source for AST node plus previous two characters
+var nodeSourceWithPrev = sourceCode.getText(node, 2);
+
+// get source for AST node plus following two characters
+var nodeSourceWithFollowing = sourceCode.getText(node, 0, 2);
+```
+
+In this way, you can look for patterns in the JavaScript text itself when the AST isn't providing the appropriate data (such as the location of commas, semicolons, parentheses, etc.).
+
+#### Accessing Comments
+
+While comments are not technically part of the AST, ESLint provides the `sourceCode.getAllComments()`, `sourceCode.getCommentsBefore()`, `sourceCode.getCommentsAfter()`, and `sourceCode.getCommentsInside()` to access them.
+
+`sourceCode.getCommentsBefore()`, `sourceCode.getCommentsAfter()`, and `sourceCode.getCommentsInside()` are useful for rules that need to check comments in relation to a given node or token.
+
+Keep in mind that the results of these methods are calculated on demand.
+
+You can also access comments through many of `sourceCode`'s methods using the `includeComments` option.
+
+### Options Schemas
+
+Rules may export a `schema` property, which is a [JSON Schema](https://json-schema.org/) format description of a rule's options which will be used by ESLint to validate configuration options and prevent invalid or unexpected inputs before they are passed to the rule in `context.options`.
+
+There are two formats for a rule's exported `schema`:
+
+1. A full JSON Schema object describing all possible options the rule accepts.
+2. An array of JSON Schema objects for each optional positional argument.
+
+In both cases, these should exclude the [severity](../use/configure/rules#rule-severities), as ESLint automatically validates this first.
+
+For example, the `yoda` rule accepts a primary mode argument of `"always"` or `"never"`, as well as an extra options object with an optional property `exceptRange`:
+
+```js
+// "yoda": ["error", "never", { "exceptRange": true }]
+module.exports = {
+ meta: {
+ schema: [
+ {
+ "enum": ["always", "never"]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "exceptRange": {
+ "type": "boolean"
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+};
+```
+
+**Note:** If your rule schema uses JSON schema [`$ref`](https://json-schema.org/understanding-json-schema/structuring.html#ref) properties, you must use the full JSON Schema object rather than the array of positional property schemas. This is because ESLint transforms the array shorthand into a single schema without updating references that makes them incorrect (they are ignored).
+
+To learn more about JSON Schema, we recommend looking at some examples on the [JSON Schema website](https://json-schema.org/learn/), or reading the free [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/) ebook.
+
+### Accessing Shebangs
+
+[Shebangs (#!)](https://en.wikipedia.org/wiki/Shebang_(Unix)) are represented by the unique tokens of type `"Shebang"`. They are treated as comments and can be accessed by the methods outlined in the [Accessing Comments](#accessing-comments) section, such as `sourceCode.getAllComments()`.
+
+### Accessing Variable Scopes
+
+The `SourceCode#getScope(node)` method returns the scope of the given node. It is a useful method for finding information about the variables in a given scope and how they are used in other scopes.
+
+**Deprecated:** The `context.getScope()` is deprecated; make sure to use `SourceCode#getScope(node)` instead.
+
+#### Scope types
+
+The following table contains a list of AST node types and the scope type that they correspond to. For more information about the scope types, refer to the [`Scope` object documentation](./scope-manager-interface#scope-interface).
+
+| AST Node Type | Scope Type |
+|:--------------------------|:-----------|
+| `Program` | `global` |
+| `FunctionDeclaration` | `function` |
+| `FunctionExpression` | `function` |
+| `ArrowFunctionExpression` | `function` |
+| `ClassDeclaration` | `class` |
+| `ClassExpression` | `class` |
+| `BlockStatement` ※1 | `block` |
+| `SwitchStatement` ※1 | `switch` |
+| `ForStatement` ※2 | `for` |
+| `ForInStatement` ※2 | `for` |
+| `ForOfStatement` ※2 | `for` |
+| `WithStatement` | `with` |
+| `CatchClause` | `catch` |
+| others | ※3 |
+
+**※1** Only if the configured parser provided the block-scope feature. The default parser provides the block-scope feature if `parserOptions.ecmaVersion` is not less than `6`.<br>
+**※2** Only if the `for` statement defines the iteration variable as a block-scoped variable (E.g., `for (let i = 0;;) {}`).<br>
+**※3** The scope of the closest ancestor node which has own scope. If the closest ancestor node has multiple scopes then it chooses the innermost scope (E.g., the `Program` node has a `global` scope and a `module` scope if `Program#sourceType` is `"module"`. The innermost scope is the `module` scope.).
+
+#### Scope Variables
+
+The `Scope#variables` property contains an array of [`Variable` objects](./scope-manager-interface#variable-interface). These are the variables declared in current scope. You can use these `Variable` objects to track references to a variable throughout the entire module.
+
+Inside of each `Variable`, the `Variable#references` property contains an array of [`Reference` objects](./scope-manager-interface#reference-interface). The `Reference` array contains all the locations where the variable is referenced in the module's source code.
+
+Also inside of each `Variable`, the `Variable#defs` property contains an array of [`Definition` objects](./scope-manager-interface#definition-interface). You can use the `Definitions` to find where the variable was defined.
+
+Global variables have the following additional properties:
+
+* `Variable#writeable` (`boolean | undefined`) ... If `true`, this global variable can be assigned arbitrary value. If `false`, this global variable is read-only.
+* `Variable#eslintExplicitGlobal` (`boolean | undefined`) ... If `true`, this global variable was defined by a `/* globals */` directive comment in the source code file.
+* `Variable#eslintExplicitGlobalComments` (`Comment[] | undefined`) ... The array of `/* globals */` directive comments which defined this global variable in the source code file. This property is `undefined` if there are no `/* globals */` directive comments.
+* `Variable#eslintImplicitGlobalSetting` (`"readonly" | "writable" | undefined`) ... The configured value in config files. This can be different from `variable.writeable` if there are `/* globals */` directive comments.
+
+For examples of using `SourceCode#getScope()` to track variables, refer to the source code for the following built-in rules:
+
+* [no-shadow](https://github.com/eslint/eslint/blob/main/lib/rules/no-shadow.js): Calls `sourceCode.getScope()` at the `Program` node and inspects all child scopes to make sure a variable name is not reused at a lower scope. ([no-shadow](../rules/no-shadow) documentation)
+* [no-redeclare](https://github.com/eslint/eslint/blob/main/lib/rules/no-redeclare.js): Calls `sourceCode.getScope()` at each scope to make sure that a variable is not declared twice in the same scope. ([no-redeclare](../rules/no-redeclare) documentation)
+
+### Marking Variables as Used
+
+**Deprecated:** The `context.markVariableAsUsed()` method is deprecated in favor of `sourceCode.markVariableAsUsed()`.
+
+Certain ESLint rules, such as [`no-unused-vars`](../rules/no-unused-vars), check to see if a variable has been used. ESLint itself only knows about the standard rules of variable access and so custom ways of accessing variables may not register as "used".
+
+To help with this, you can use the `sourceCode.markVariableAsUsed()` method. This method takes two arguments: the name of the variable to mark as used and an option reference node indicating the scope in which you are working. Here's an example:
+
+```js
+module.exports = {
+ create: function(context) {
+ var sourceCode = context.sourceCode;
+
+ return {
+ ReturnStatement(node) {
+
+ // look in the scope of the function for myCustomVar and mark as used
+ sourceCode.markVariableAsUsed("myCustomVar", node);
+
+ // or: look in the global scope for myCustomVar and mark as used
+ sourceCode.markVariableAsUsed("myCustomVar");
+ }
+ }
+ // ...
+ }
+};
+```
+
+Here, the `myCustomVar` variable is marked as used relative to a `ReturnStatement` node, which means ESLint will start searching from the scope closest to that node. If you omit the second argument, then the top-level scope is used. (For ESM files, the top-level scope is the module scope; for CommonJS files, the top-level scope is the first function scope.)
+
+### Accessing Code Paths
+
+ESLint analyzes code paths while traversing AST. You can access code path objects with five events related to code paths. For more information, refer to [Code Path Analysis](code-path-analysis).
+
+### Deprecated `SourceCode` Methods
+
+Please note that the following `SourceCode` methods have been deprecated and will be removed in a future version of ESLint:
+
+* `getComments()`: Replaced by `SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, and `SourceCode#getCommentsInside()`.
+* `getTokenOrCommentBefore()`: Replaced by `SourceCode#getTokenBefore()` with the `{ includeComments: true }` option.
+* `getTokenOrCommentAfter()`: Replaced by `SourceCode#getTokenAfter()` with the `{ includeComments: true }` option.
+* `isSpaceBetweenTokens()`: Replaced by `SourceCode#isSpaceBetween()`
+* `getJSDocComment()`
+
+## Rule Unit Tests
+
+ESLint provides the [`RuleTester`](../integrate/nodejs-api#ruletester) utility to make it easy to write tests for rules.
+
+## Rule Naming Conventions
+
+While you can give a custom rule any name you'd like, the core rules have naming conventions. It could be clearer to apply these same naming conventions to your custom rule. To learn more, refer to the [Core Rule Naming Conventions](../contribute/core-rules#rule-naming-conventions) documentation.
+
+## Runtime Rules
+
+The thing that makes ESLint different from other linters is the ability to define custom rules at runtime. This is perfect for rules that are specific to your project or company and wouldn't make sense for ESLint to ship with or be included in a plugin. Just write your rules and include them at runtime.
+
+Runtime rules are written in the same format as all other rules. Create your rule as you would any other and then follow these steps:
+
+1. Place all of your runtime rules in the same directory (e.g., `eslint_rules`).
+2. Create a [configuration file](../use/configure/) and specify your rule ID error level under the `rules` key. Your rule will not run unless it has a value of `"warn"` or `"error"` in the configuration file.
+3. Run the [command line interface](../use/command-line-interface) using the `--rulesdir` option to specify the location of your runtime rules.
+
+## Profile Rule Performance
+
+ESLint has a built-in method to track the performance of individual rules. Setting the `TIMING` environment variable will trigger the display, upon linting completion, of the ten longest-running rules, along with their individual running time (rule creation + rule execution) and relative performance impact as a percentage of total rule processing time (rule creation + rule execution).
+
+```bash
+$ TIMING=1 eslint lib
+Rule | Time (ms) | Relative
+:-----------------------|----------:|--------:
+no-multi-spaces | 52.472 | 6.1%
+camelcase | 48.684 | 5.7%
+no-irregular-whitespace | 43.847 | 5.1%
+valid-jsdoc | 40.346 | 4.7%
+handle-callback-err | 39.153 | 4.6%
+space-infix-ops | 35.444 | 4.1%
+no-undefined | 25.693 | 3.0%
+no-shadow | 22.759 | 2.7%
+no-empty-class | 21.976 | 2.6%
+semi | 19.359 | 2.3%
+```
+
+To test one rule explicitly, combine the `--no-eslintrc`, and `--rule` options:
+
+```bash
+$ TIMING=1 eslint --no-eslintrc --rule "quotes: [2, 'double']" lib
+Rule | Time (ms) | Relative
+:------|----------:|--------:
+quotes | 18.066 | 100.0%
+```
+
+To see a longer list of results (more than 10), set the environment variable to another value such as `TIMING=50` or `TIMING=all`.
--- /dev/null
+---
+title: Extend ESLint
+eleventyNavigation:
+ key: extend eslint
+ title: Extend ESLint
+ order: 2
+
+---
+
+This guide is intended for those who wish to extend the functionality of ESLint.
+
+In order to extend ESLint, it's recommended that:
+
+* You know JavaScript, since ESLint is written in JavaScript.
+* You have some familiarity with Node.js, since ESLint runs on it.
+* You're comfortable with command-line programs.
+
+If that sounds like you, then continue reading to get started.
+
+## [Ways to Extend ESLint](ways-to-extend)
+
+This page summarizes the various ways that you can extend ESLint and how these extensions all fit together.
+
+## [Create Plugins](plugins)
+
+You've developed custom rules for ESLint and you want to share them with the community. You can publish an ESLint plugin on npm.
+
+## [Custom Rules](custom-rules)
+
+This section explains how to create custom rules to use with ESLint.
+
+## [Custom Formatters](custom-formatters)
+
+This section explains how you can create a custom formatter to control what ESLint outputs.
+
+## [Custom Parsers](custom-parsers)
+
+If you don't want to use the default parser of ESLint, this section explains how to create custom parsers.
+
+## [Custom Processors](custom-processors)
+
+This section explains how you can use a custom processor to have ESLint process files other than JavaScript.
+
+## [Share Configurations](shareable-configs)
+
+This section explains how you can bundle and share ESLint configuration in a JavaScript package.
+
+## [Node.js API Reference](../integrate/nodejs-api)
+
+If you're interested in writing a tool that uses ESLint, then you can use the Node.js API to get programmatic access to functionality.
--- /dev/null
+---
+title: Create Plugins
+eleventyNavigation:
+ key: create plugins
+ parent: extend eslint
+ title: Create Plugins
+ order: 2
+
+---
+
+An ESLint plugin is an extension for ESLint that adds additional rules and configuration options. Plugins let you customize your ESLint configuration to enforce rules that are not included in the core ESLint package. Plugins can also provide additional environments, custom processors, and configurations.
+
+## Name a Plugin
+
+Each plugin is an npm module with a name in the format of `eslint-plugin-<plugin-name>`, such as `eslint-plugin-jquery`. You can also use scoped packages in the format of `@<scope>/eslint-plugin-<plugin-name>` such as `@jquery/eslint-plugin-jquery` or even `@<scope>/eslint-plugin` such as `@jquery/eslint-plugin`.
+
+## Create a Plugin
+
+The easiest way to start creating a plugin is to use the [Yeoman generator](https://www.npmjs.com/package/generator-eslint). The generator will guide you through setting up the skeleton of a plugin.
+
+### Metadata in Plugins
+
+For easier debugging and more effective caching of plugins, it's recommended to provide a name and version in a `meta` object at the root of your plugin, like this:
+
+```js
+// preferred location of name and version
+module.exports = {
+ meta: {
+ name: "eslint-plugin-custom",
+ version: "1.2.3"
+ }
+};
+```
+
+The `meta.name` property should match the npm package name for your plugin and the `meta.version` property should match the npm package version for your plugin. The easiest way to accomplish this is by reading this information from your `package.json`.
+
+As an alternative, you can also expose `name` and `version` properties at the root of your plugin, such as:
+
+```js
+// alternate location of name and version
+module.exports = {
+ name: "eslint-plugin-custom",
+ version: "1.2.3"
+};
+```
+
+While the `meta` object is the preferred way to provide the plugin name and version, this format is also acceptable and is provided for backward compatibility.
+
+### Rules in Plugins
+
+Plugins can expose custom rules for use in ESLint. To do so, the plugin must export a `rules` object containing a key-value mapping of rule ID to rule. The rule ID does not have to follow any naming convention (so it can just be `dollar-sign`, for instance). To learn more about creating custom rules in plugins, refer to [Custom Rules](custom-rules).
+
+```js
+module.exports = {
+ rules: {
+ "dollar-sign": {
+ create: function (context) {
+ // rule implementation ...
+ }
+ }
+ }
+};
+```
+
+To use the rule in ESLint, you would use the unprefixed plugin name, followed by a slash, followed by the rule name. So if this plugin were named `eslint-plugin-myplugin`, then in your configuration you'd refer to the rule by the name `myplugin/dollar-sign`. Example: `"rules": {"myplugin/dollar-sign": 2}`.
+
+### Environments in Plugins
+
+Plugins can expose additional environments for use in ESLint. To do so, the plugin must export an `environments` object. The keys of the `environments` object are the names of the different environments provided and the values are the environment settings. For example:
+
+```js
+module.exports = {
+ environments: {
+ jquery: {
+ globals: {
+ $: false
+ }
+ }
+ }
+};
+```
+
+There's a `jquery` environment defined in this plugin. To use the environment in ESLint, you would use the unprefixed plugin name, followed by a slash, followed by the environment name. So if this plugin were named `eslint-plugin-myplugin`, then you would set the environment in your configuration to be `"myplugin/jquery"`.
+
+Plugin environments can define the following objects:
+
+1. `globals` - acts the same `globals` in a configuration file. The keys are the names of the globals and the values are `true` to allow the global to be overwritten and `false` to disallow.
+1. `parserOptions` - acts the same as `parserOptions` in a configuration file.
+
+### Processors in Plugins
+
+You can add processors to plugins by including the processor functions in the `processors` key. For more information on defining custom processors, refer to [Custom Processors](custom-processors).
+
+```js
+module.exports = {
+ processors: {
+ // This processor will be applied to `*.md` files automatically.
+ ".md": {
+ preprocess(text, filename) { /* ... */ },
+ postprocess(messages, filename) { /* ... */ }
+ }
+ "processor-name": {
+ preprocess: function(text, filename) {/* ... */},
+
+ postprocess: function(messages, filename) { /* ... */ },
+ }
+ }
+}
+```
+
+### Configs in Plugins
+
+You can bundle configurations inside a plugin by specifying them under the `configs` key. This can be useful when you want to bundle a set of custom rules with additional configuration. Multiple configurations are supported per plugin.
+
+You can include individual rules from a plugin in a config that's also included in the plugin. In the config, you must specify your plugin name in the `plugins` array as well as any rules you want to enable that are part of the plugin. Any plugin rules must be prefixed with the short or long plugin name.
+
+```js
+// eslint-plugin-myPlugin
+
+module.exports = {
+ configs: {
+ myConfig: {
+ plugins: ["myPlugin"],
+ env: ["browser"],
+ rules: {
+ semi: "error",
+ "myPlugin/my-rule": "error",
+ "eslint-plugin-myPlugin/another-rule": "error"
+ }
+ },
+ myOtherConfig: {
+ plugins: ["myPlugin"],
+ env: ["node"],
+ rules: {
+ "myPlugin/my-rule": "off",
+ "eslint-plugin-myPlugin/another-rule": "off",
+ "eslint-plugin-myPlugin/yet-another-rule": "error"
+ }
+ }
+ },
+ rules: {
+ "my-rule": {/* rule definition */},
+ "another-rule": {/* rule definition */},
+ "yet-another-rule": {/* rule definition */}
+ }
+};
+```
+
+Plugins cannot force a specific configuration to be used. Users must manually include a plugin's configurations in their configuration file.
+
+If the example plugin above were called `eslint-plugin-myPlugin`, the `myConfig` and `myOtherConfig` configurations would then be usable in a configuration file by extending `"plugin:myPlugin/myConfig"` and `"plugin:myPlugin/myOtherConfig"`, respectively.
+
+```json
+// .eslintrc.json
+
+{
+ "extends": ["plugin:myPlugin/myConfig"]
+}
+
+```
+
+### Peer Dependency
+
+To make clear that the plugin requires ESLint to work correctly, you must declare ESLint as a peer dependency by mentioning it in the `peerDependencies` field of your plugin's `package.json`.
+
+Plugin support was introduced in ESLint version `0.8.0`. Ensure the `peerDependencies` points to ESLint `0.8.0` or later.
+
+```json
+{
+ "peerDependencies": {
+ "eslint": ">=0.8.0"
+ }
+}
+```
+
+## Testing
+
+ESLint provides the [`RuleTester`](../integrate/nodejs-api#ruletester) utility to make it easy to test the rules of your plugin.
+
+## Linting
+
+ESLint plugins should be linted too! It's suggested to lint your plugin with the `recommended` configurations of:
+
+* [eslint](https://www.npmjs.com/package/eslint)
+* [eslint-plugin-eslint-plugin](https://www.npmjs.com/package/eslint-plugin-eslint-plugin)
+* [eslint-plugin-n](https://www.npmjs.com/package/eslint-plugin-n)
+
+## Share Plugins
+
+In order to make your plugin available to the community you have to publish it on npm.
+
+To make it easy for others to find your plugin, add these [keywords](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords) to your `package.json` file:
+
+* `eslint`
+* `eslintplugin`
--- /dev/null
+---
+title: ScopeManager
+
+---
+
+This document was written based on the implementation of [eslint-scope](https://github.com/eslint/eslint-scope), a fork of [escope](https://github.com/estools/escope), and deprecates some members ESLint is not using.
+
+----
+
+## ScopeManager interface
+
+`ScopeManager` object has all variable scopes.
+
+### Fields
+
+#### scopes
+
+* **Type:** `Scope[]`
+* **Description:** All scopes.
+
+#### globalScope
+
+* **Type:** `Scope`
+* **Description:** The root scope.
+
+### Methods
+
+#### acquire(node, inner = false)
+
+* **Parameters:**
+ * `node` (`ASTNode`) ... An AST node to get their scope.
+ * `inner` (`boolean`) ... If the node has multiple scope, this returns the outermost scope normally. If `inner` is `true` then this returns the innermost scope. Default is `false`.
+* **Return type:** `Scope | null`
+* **Description:** Get the scope of a given AST node. The gotten scope's `block` property is the node. This method never returns `function-expression-name` scope. If the node does not have their scope, this returns `null`.
+
+#### getDeclaredVariables(node)
+
+* **Parameters:**
+ * `node` (`ASTNode`) ... An AST node to get their variables.
+* **Return type:** `Variable[]`
+* **Description:** Get the variables that a given AST node defines. The gotten variables' `def[].node`/`def[].parent` property is the node. If the node does not define any variable, this returns an empty array.
+
+### Deprecated members
+
+Those members are defined but not used in ESLint.
+
+#### isModule()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this program is module.
+
+#### isImpliedStrict()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this program is strict mode implicitly. I.e., `options.impliedStrict === true`.
+
+#### isStrictModeSupported()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this program supports strict mode. I.e., `options.ecmaVersion >= 5`.
+
+#### acquireAll(node)
+
+* **Parameters:**
+ * `node` (`ASTNode`) ... An AST node to get their scope.
+* **Return type:** `Scope[] | null`
+* **Description:** Get the scopes of a given AST node. The gotten scopes' `block` property is the node. If the node does not have their scope, this returns `null`.
+
+----
+
+## Scope interface
+
+`Scope` object has all variables and references in the scope.
+
+### Fields
+
+#### type
+
+* **Type:** `string`
+* **Description:** The type of this scope. This is one of `"block"`, `"catch"`, `"class"`, `"class-field-initializer"`, `"class-static-block"`, `"for"`, `"function"`, `"function-expression-name"`, `"global"`, `"module"`, `"switch"`, `"with"`.
+
+#### isStrict
+
+* **Type:** `boolean`
+* **Description:** `true` if this scope is strict mode.
+
+#### upper
+
+* **Type:** `Scope | null`
+* **Description:** The parent scope. If this is the global scope then this property is `null`.
+
+#### childScopes
+
+* **Type:** `Scope[]`
+* **Description:** The array of child scopes. This does not include grandchild scopes.
+
+#### variableScope
+
+* **Type:** `Scope`
+* **Description:** The nearest ancestor whose `type` is one of `"class-field-initializer"`, `"class-static-block"`, `"function"`, `"global"`, or `"module"`. For the aforementioned scopes this is a self-reference.
+
+> This represents the lowest enclosing function or top-level scope. Class field initializers and class static blocks are implicit functions. Historically, this was the scope which hosts variables that are defined by `var` declarations, and thus the name `variableScope`.
+
+#### block
+
+* **Type:** `ASTNode`
+* **Description:** The AST node which created this scope.
+
+#### variables
+
+* **Type:** `Variable[]`
+* **Description:** The array of all variables which are defined on this scope. This does not include variables which are defined in child scopes.
+
+#### set
+
+* **Type:** `Map<string, Variable>`
+* **Description:** The map from variable names to variable objects.
+
+> I hope to rename `set` field or replace by a method.
+
+#### references
+
+* **Type:** `Reference[]`
+* **Description:** The array of all references on this scope. This does not include references in child scopes.
+
+#### through
+
+* **Type:** `Reference[]`
+* **Description:** The array of references which could not be resolved in this scope.
+
+#### functionExpressionScope
+
+* **Type:** `boolean`
+* **Description:** `true` if this scope is `"function-expression-name"` scope.
+
+> I hope to deprecate `functionExpressionScope` field as replacing by `scope.type === "function-expression-name"`.
+
+### Deprecated members
+
+Those members are defined but not used in ESLint.
+
+#### taints
+
+* **Type:** `Map<string, boolean>`
+* **Description:** The map from variable names to `tainted` flag.
+
+#### dynamic
+
+* **Type:** `boolean`
+* **Description:** `true` if this scope is dynamic. I.e., the type of this scope is `"global"` or `"with"`.
+
+#### directCallToEvalScope
+
+* **Type:** `boolean`
+* **Description:** `true` if this scope contains `eval()` invocations.
+
+#### thisFound
+
+* **Type:** `boolean`
+* **Description:** `true` if this scope contains `this`.
+
+#### resolve(node)
+
+* **Parameters:**
+ * `node` (`ASTNode`) ... An AST node to get their reference object. The type of the node must be `"Identifier"`.
+* **Return type:** `Reference | null`
+* **Description:** Returns `this.references.find(r => r.identifier === node)`.
+
+#### isStatic()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** Returns `!this.dynamic`.
+
+#### isArgumentsMaterialized()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this is a `"function"` scope which has used `arguments` variable.
+
+#### isThisMaterialized()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** Returns `this.thisFound`.
+
+#### isUsedName(name)
+
+* **Parameters:**
+ * `name` (`string`) ... The name to check.
+* **Return type:** `boolean`
+* **Description:** `true` if a given name is used in variable names or reference names.
+
+----
+
+## Variable interface
+
+`Variable` object is variable's information.
+
+### Fields
+
+#### name
+
+* **Type:** `string`
+* **Description:** The name of this variable.
+
+#### scope
+
+* **Type:** `Scope`
+* **Description:** The scope in which this variable is defined.
+
+#### identifiers
+
+* **Type:** `ASTNode[]`
+* **Description:** The array of `Identifier` nodes which define this variable. If this variable is redeclared, this array includes two or more nodes.
+
+> I hope to deprecate `identifiers` field as replacing by `defs[].name` field.
+
+#### references
+
+* **Type:** `Reference[]`
+* **Description:** The array of the references of this variable.
+
+#### defs
+
+* **Type:** `Definition[]`
+* **Description:** The array of the definitions of this variable.
+
+### Deprecated members
+
+Those members are defined but not used in ESLint.
+
+#### tainted
+
+* **Type:** `boolean`
+* **Description:** The `tainted` flag. (always `false`)
+
+#### stack
+
+* **Type:** `boolean`
+* **Description:** The `stack` flag. (I'm not sure what this means.)
+
+----
+
+## Reference interface
+
+`Reference` object is reference's information.
+
+### Fields
+
+#### identifier
+
+* **Type:** `ASTNode`
+* **Description:** The `Identifier` node of this reference.
+
+#### from
+
+* **Type:** `Scope`
+* **Description:** The `Scope` object that this reference is on.
+
+#### resolved
+
+* **Type:** `Variable | null`
+* **Description:** The `Variable` object that this reference refers. If such variable was not defined, this is `null`.
+
+#### writeExpr
+
+* **Type:** `ASTNode | null`
+* **Description:** The ASTNode object which is right-hand side.
+
+#### init
+
+* **Type:** `boolean`
+* **Description:** `true` if this writing reference is a variable initializer or a default value.
+
+### Methods
+
+#### isWrite()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this reference is writing.
+
+#### isRead()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this reference is reading.
+
+#### isWriteOnly()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this reference is writing but not reading.
+
+#### isReadOnly()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this reference is reading but not writing.
+
+#### isReadWrite()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this reference is reading and writing.
+
+### Deprecated members
+
+Those members are defined but not used in ESLint.
+
+#### tainted
+
+* **Type:** `boolean`
+* **Description:** The `tainted` flag. (always `false`)
+
+#### flag
+
+* **Type:** `number`
+* **Description:** `1` is reading, `2` is writing, `3` is reading/writing.
+
+#### partial
+
+* **Type:** `boolean`
+* **Description:** The `partial` flag.
+
+#### isStatic()
+
+* **Parameters:**
+* **Return type:** `boolean`
+* **Description:** `true` if this reference is resolved statically.
+
+----
+
+## Definition interface
+
+`Definition` object is variable definition's information.
+
+### Fields
+
+#### type
+
+* **Type:** `string`
+* **Description:** The type of this definition. One of `"CatchClause"`, `"ClassName"`, `"FunctionName"`, `"ImplicitGlobalVariable"`, `"ImportBinding"`, `"Parameter"`, and `"Variable"`.
+
+#### name
+
+* **Type:** `ASTNode`
+* **Description:** The `Identifier` node of this definition.
+
+#### node
+
+* **Type:** `ASTNode`
+* **Description:** The enclosing node of the name.
+
+| type | node |
+|:---------------------------|:-----|
+| `"CatchClause"` | `CatchClause`
+| `"ClassName"` | `ClassDeclaration` or `ClassExpression`
+| `"FunctionName"` | `FunctionDeclaration` or `FunctionExpression`
+| `"ImplicitGlobalVariable"` | `Program`
+| `"ImportBinding"` | `ImportSpecifier`, `ImportDefaultSpecifier`, or `ImportNamespaceSpecifier`
+| `"Parameter"` | `FunctionDeclaration`, `FunctionExpression`, or `ArrowFunctionExpression`
+| `"Variable"` | `VariableDeclarator`
+
+#### parent
+
+* **Type:** `ASTNode | undefined | null`
+* **Description:** The enclosing statement node of the name.
+
+| type | parent |
+|:---------------------------|:-------|
+| `"CatchClause"` | `null`
+| `"ClassName"` | `null`
+| `"FunctionName"` | `null`
+| `"ImplicitGlobalVariable"` | `null`
+| `"ImportBinding"` | `ImportDeclaration`
+| `"Parameter"` | `null`
+| `"Variable"` | `VariableDeclaration`
+
+### Deprecated members
+
+Those members are defined but not used in ESLint.
+
+#### index
+
+* **Type:** `number | undefined | null`
+* **Description:** The index in the declaration statement.
+
+#### kind
+
+* **Type:** `string | undefined | null`
+* **Description:** The kind of the declaration statement.
--- /dev/null
+---
+title: Selectors
+
+---
+
+Some rules and APIs allow the use of selectors to query an AST. This page is intended to:
+
+1. Explain what selectors are
+2. Describe the syntax for creating selectors
+3. Describe what selectors can be used for
+
+## What is a selector?
+
+A selector is a string that can be used to match nodes in an Abstract Syntax Tree (AST). This is useful for describing a particular syntax pattern in your code.
+
+The syntax for AST selectors is similar to the syntax for [CSS selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors). If you've used CSS selectors before, the syntax for AST selectors should be easy to understand.
+
+The simplest selector is just a node type. A node type selector will match all nodes with the given type. For example, consider the following program:
+
+```js
+var foo = 1;
+bar.baz();
+```
+
+The selector "`Identifier`" will match all `Identifier` nodes in the program. In this case, the selector will match the nodes for `foo`, `bar`, and `baz`.
+
+Selectors are not limited to matching against single node types. For example, the selector `VariableDeclarator > Identifier` will match all `Identifier` nodes that have a `VariableDeclarator` as a direct parent. In the program above, this will match the node for `foo`, but not the nodes for `bar` and `baz`.
+
+## What syntax can selectors have?
+
+The following selectors are supported:
+
+* AST node type: `ForStatement`
+* wildcard (matches all nodes): `*`
+* attribute existence: `[attr]`
+* attribute value: `[attr="foo"]` or `[attr=123]`
+* attribute regex: `[attr=/foo.*/]` <sub>(with some [known issues](#known-issues))</sub>
+* attribute conditions: `[attr!="foo"]`, `[attr>2]`, `[attr<3]`, `[attr>=2]`, or `[attr<=3]`
+* nested attribute: `[attr.level2="foo"]`
+* field: `FunctionDeclaration > Identifier.id`
+* First or last child: `:first-child` or `:last-child`
+* nth-child (no ax+b support): `:nth-child(2)`
+* nth-last-child (no ax+b support): `:nth-last-child(1)`
+* descendant: `FunctionExpression ReturnStatement`
+* child: `UnaryExpression > Literal`
+* following sibling: `VariableDeclaration ~ VariableDeclaration`
+* adjacent sibling: `ArrayExpression > Literal + SpreadElement`
+* negation: `:not(ForStatement)`
+* matches-any: `:matches([attr] > :first-child, :last-child)`
+* class of AST node: `:statement`, `:expression`, `:declaration`, `:function`, or `:pattern`
+
+This syntax is very powerful, and can be used to precisely select many syntactic patterns in your code.
+
+<sup>The examples in this section were adapted from the [esquery](https://github.com/estools/esquery) documentation.</sup>
+
+## What can selectors be used for?
+
+If you're writing custom ESLint rules, you might be interested in using selectors to examine specific parts of the AST. If you're configuring ESLint for your codebase, you might be interested in restricting particular syntax patterns with selectors.
+
+### Listening for selectors in rules
+
+When writing a custom ESLint rule, you can listen for nodes that match a particular selector as the AST is traversed.
+
+```js
+module.exports = {
+ create(context) {
+ // ...
+
+ return {
+
+ // This listener will be called for all IfStatement nodes with blocks.
+ "IfStatement > BlockStatement": function(blockStatementNode) {
+ // ...your logic here
+ },
+
+ // This listener will be called for all function declarations with more than 3 parameters.
+ "FunctionDeclaration[params.length>3]": function(functionDeclarationNode) {
+ // ...your logic here
+ }
+ };
+ }
+};
+```
+
+Adding `:exit` to the end of a selector will cause the listener to be called when the matching nodes are exited during traversal, rather than when they are entered.
+
+If two or more selectors match the same node, their listeners will be called in order of increasing specificity. The specificity of an AST selector is similar to the specificity of a CSS selector:
+
+* When comparing two selectors, the selector that contains more class selectors, attribute selectors, and pseudo-class selectors (excluding `:not()`) has higher specificity.
+* If the class/attribute/pseudo-class count is tied, the selector that contains more node type selectors has higher specificity.
+
+If multiple selectors have equal specificity, their listeners will be called in alphabetical order for that node.
+
+### Restricting syntax with selectors
+
+With the [no-restricted-syntax](../rules/no-restricted-syntax) rule, you can restrict the usage of particular syntax in your code. For example, you can use the following configuration to disallow using `if` statements that do not have block statements as their body:
+
+```json
+{
+ "rules": {
+ "no-restricted-syntax": ["error", "IfStatement > :not(BlockStatement).consequent"]
+ }
+}
+```
+
+...or equivalently, you can use this configuration:
+
+```json
+{
+ "rules": {
+ "no-restricted-syntax": ["error", "IfStatement[consequent.type!='BlockStatement']"]
+ }
+}
+```
+
+As another example, you can disallow calls to `require()`:
+
+```json
+{
+ "rules": {
+ "no-restricted-syntax": ["error", "CallExpression[callee.name='require']"]
+ }
+}
+```
+
+Or you can enforce that calls to `setTimeout` always have two arguments:
+
+```json
+{
+ "rules": {
+ "no-restricted-syntax": ["error", "CallExpression[callee.name='setTimeout'][arguments.length!=2]"]
+ }
+}
+```
+
+Using selectors in the `no-restricted-syntax` rule can give you a lot of control over problematic patterns in your codebase, without needing to write custom rules to detect each pattern.
+
+### Known issues
+
+Due to a [bug](https://github.com/estools/esquery/issues/68) in [esquery](https://github.com/estools/esquery), regular expressions that contain a forward-slash character `/` aren't properly parsed, so `[value=/some\/path/]` will be a syntax error. As a [workaround](https://github.com/estools/esquery/issues/68), you can replace the `/` character with its unicode counterpart, like so: `[value=/some\u002Fpath/]`.
+
+For example, the following configuration disallows importing from `some/path`:
+
+```json
+{
+ "rules": {
+ "no-restricted-syntax": ["error", "ImportDeclaration[source.value=/^some\\u002Fpath$/]"]
+ }
+}
+```
+
+Note that the `\` character needs to be escaped (`\\`) in JSON and string literals.
--- /dev/null
+---
+title: Share Configurations
+eleventyNavigation:
+ key: share configs
+ parent: extend eslint
+ title: Share Configurations
+ order: 3
+
+---
+
+To share your ESLint configuration, create a **shareable config**. You can publish your shareable config on [npm](https://www.npmjs.com/) so that others can download and use it in their ESLint projects.
+
+This page explains how to create and publish a shareable config.
+
+## Creating a Shareable Config
+
+Shareable configs are simply npm packages that export a configuration object. To start, [create a Node.js module](https://docs.npmjs.com/getting-started/creating-node-modules) like you normally would.
+
+The module name must take one of the following forms:
+
+* Begin with `eslint-config-`, such as `eslint-config-myconfig`.
+* Be an npm [scoped module](https://docs.npmjs.com/misc/scope). To create a scoped module, name or prefix the module with `@scope/eslint-config`, such as `@scope/eslint-config` or `@scope/eslint-config-myconfig`.
+
+In your module, export the shareable config from the module's [`main`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#main) entry point file. The default main entry point is `index.js`. For example:
+
+```js
+// index.js
+module.exports = {
+
+ globals: {
+ MyGlobal: true
+ },
+
+ rules: {
+ semi: [2, "always"]
+ }
+
+};
+```
+
+Since the `index.js` file is just JavaScript, you can read these settings from a file or generate them dynamically.
+
+## Publishing a Shareable Config
+
+Once your shareable config is ready, you can [publish it to npm](https://docs.npmjs.com/getting-started/publishing-npm-packages) to share it with others. We recommend using the `eslint` and `eslintconfig` [keywords](https://docs.npmjs.com/cli/v9/configuring-npm/package-json#keywords) in the `package.json` file so others can easily find your module.
+
+You should declare your dependency on ESLint in the `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:
+
+```json
+{
+ "peerDependencies": {
+ "eslint": ">= 3"
+ }
+}
+```
+
+If your shareable config depends on a plugin, you should also specify it as a `peerDependency` (plugins will be loaded relative to the end user's project, so the end user is required to install the plugins they need). However, if your shareable config depends on a [custom parser](custom-parsers) or another shareable config, you can specify these packages as `dependencies` in the `package.json`.
+
+You can also test your shareable config on your computer before publishing by linking your module globally. Type:
+
+```bash
+npm link
+```
+
+Then, in your project that wants to use your shareable config, type:
+
+```bash
+npm link eslint-config-myconfig
+```
+
+Be sure to replace `eslint-config-myconfig` with the actual name of your module.
+
+## Using a Shareable Config
+
+To use a shareable config, include the config name in the `extends` field of a configuration file. For the value, use your module name. For example:
+
+```json
+{
+ "extends": "eslint-config-myconfig"
+}
+```
+
+You can also omit the `eslint-config-` and it is automatically assumed by ESLint:
+
+```json
+{
+ "extends": "myconfig"
+}
+```
+
+You cannot use shareable configs with the ESLint CLI [`--config`](../use/command-line-interface#-c---config) flag.
+
+### npm Scoped Modules
+
+npm [scoped modules](https://docs.npmjs.com/misc/scope) are also supported in a number of ways.
+
+You can use the module name:
+
+```json
+{
+ "extends": "@scope/eslint-config"
+}
+```
+
+You can also omit the `eslint-config` and it is automatically assumed by ESLint:
+
+```json
+{
+ "extends": "@scope"
+}
+```
+
+The module name can also be customized. For example, if you have a package named `@scope/eslint-config-myconfig`, the configuration can be specified as:
+
+```json
+{
+ "extends": "@scope/eslint-config-myconfig"
+}
+```
+
+You could also omit `eslint-config` to specify the configuration as:
+
+```json
+{
+ "extends": "@scope/myconfig"
+}
+```
+
+### Overriding Settings from Shareable Configs
+
+You can override settings from the shareable config by adding them directly into your `.eslintrc` file.
+
+## Sharing Multiple Configs
+
+You can share multiple configs in the same npm package. Specify a default config for the package by following the directions in the [Creating a Shareable Config](#creating-a-shareable-config) section. You can specify additional shareable configs by adding a new file to your npm package and then referencing it from your ESLint config.
+
+As an example, you can create a file called `my-special-config.js` in the root of your npm package and export a config, such as:
+
+```js
+// my-special-config.js
+module.exports = {
+ rules: {
+ quotes: [2, "double"]
+ }
+};
+```
+
+Then, assuming you're using the package name `eslint-config-myconfig`, you can access the additional config via:
+
+```json
+{
+ "extends": "myconfig/my-special-config"
+}
+```
+
+When using [scoped modules](https://docs.npmjs.com/misc/scope) it is not possible to omit the `eslint-config` namespace. Doing so would result in resolution errors as explained above. Assuming the package name is `@scope/eslint-config`, the additional config can be accessed as:
+
+```json
+{
+ "extends": "@scope/eslint-config/my-special-config"
+}
+```
+
+Note that you can leave off the `.js` from the filename.
+
+**Important:** We strongly recommend always including a default config for your plugin to avoid errors.
+
+## Local Config File Resolution
+
+If you need to make multiple configs that can extend each other and live in different directories, you can create a single shareable config that handles this scenario.
+
+As an example, let's assume you're using the package name `eslint-config-myconfig` and your package looks something like this:
+
+```text
+myconfig
+├── index.js
+└─┬ lib
+ ├── defaults.js
+ ├── dev.js
+ ├── ci.js
+ └─┬ ci
+ ├── frontend.js
+ ├── backend.js
+ └── common.js
+```
+
+In the `index.js` file, you can do something like this:
+
+```js
+module.exports = require('./lib/ci.js');
+```
+
+Now inside the package you have `/lib/defaults.js`, which contains:
+
+```js
+module.exports = {
+ rules: {
+ 'no-console': 1
+ }
+};
+```
+
+Inside `/lib/ci.js` you have:
+
+```js
+module.exports = require('./ci/backend');
+```
+
+Inside `/lib/ci/common.js`:
+
+```js
+module.exports = {
+ rules: {
+ 'no-alert': 2
+ },
+ extends: 'myconfig/lib/defaults'
+};
+```
+
+Despite being in an entirely different directory, you'll see that all `extends` must use the full package path to the config file you wish to extend.
+
+Now inside `/lib/ci/backend.js`:
+
+```js
+module.exports = {
+ rules: {
+ 'no-console': 1
+ },
+ extends: 'myconfig/lib/ci/common'
+};
+```
+
+In the last file, once again see that to properly resolve your config, you need to include the full package path.
+
+## Further Reading
+
+* [npm Developer Guide](https://docs.npmjs.com/misc/developers)
--- /dev/null
+---
+title: Ways to Extend ESLint
+eleventyNavigation:
+ key: ways to extend
+ parent: extend eslint
+ title: Ways to Extend ESLint
+ order: 1
+---
+
+ESLint is highly pluggable and configurable. There are a variety of ways that you can extend ESLint's functionality.
+
+This page explains the ways to extend ESLint, and how these extensions all fit together.
+
+## Plugins
+
+Plugins let you add your own ESLint custom rules and custom processors to a project. You can publish a plugin as an npm module.
+
+Plugins are useful because your project may require some ESLint configuration that isn't included in the core `eslint` package. For example, if you're using a frontend JavaScript library like React or framework like Vue, these tools have some features that require custom rules outside the scope of the ESLint core rules.
+
+Often a plugin is paired with a configuration for ESLint that applies a set of features from the plugin to a project. You can include configurations in a plugin as well.
+
+For example, [`eslint-plugin-react`](https://www.npmjs.com/package/eslint-plugin-react) is an ESLint plugin that includes rules specifically for React projects. The rules include things like enforcing consistent usage of React component lifecycle methods and requiring the use of key props when rendering dynamic lists.
+
+To learn more about creating the extensions you can include in a plugin, refer to the following documentation:
+
+* [Custom Rules](custom-rules)
+* [Custom Processors](custom-processors)
+* [Configs in Plugins](plugins#configs-in-plugins)
+
+To learn more about bundling these extensions into a plugin, refer to [Plugins](plugins).
+
+## Shareable Configs
+
+ESLint shareable configs are pre-defined configurations for ESLint that you can use in your projects. They bundle rules and other configuration together in an npm package. Anything that you can put in a configuration file can be put in a shareable config.
+
+You can either publish a shareable config independently or as part of a plugin.
+
+For example, a popular shareable config is [eslint-config-airbnb](https://www.npmjs.com/package/eslint-config-airbnb), which contains a variety of rules in addition to some [parser options](../use/configure/language-options#specifying-parser-options). This is a set of rules for ESLint that is designed to match the style guide used by the [Airbnb JavaScript style guide](https://github.com/airbnb/javascript). By using the `eslint-config-airbnb` shareable config, you can automatically enforce the Airbnb style guide in your project without having to manually configure each rule.
+
+To learn more about creating a shareable config, refer to [Share Configuration](shareable-configs).
+
+## Custom Formatters
+
+Custom formatters take ESLint linting results and output the results in a format that you define. Custom formatters let you display linting results in a format that best fits your needs, whether that's in a specific file format, a certain display style, or a format optimized for a particular tool. You only need to create a custom formatter if the [built-in formatters](../use/formatters/) don't serve your use case.
+
+For example, the custom formatter [eslint-formatter-gitlab](https://www.npmjs.com/package/eslint-formatter-gitlab) can be used to display ESLint results in GitLab code quality reports.
+
+To learn more about creating a custom formatter, refer to [Custom Formatters](custom-formatters).
+
+## Custom Parsers
+
+ESLint custom parsers are a way to extend ESLint to support the linting of new language features or custom syntax in your code. A parser is responsible for taking your code and transforming it into an abstract syntax tree (AST) that ESLint can then analyze and lint.
+
+ESLint ships with a built-in JavaScript parser (Espree), but custom parsers allow you to lint other languages or to extend the linting capabilities of the built-in parser.
+
+For example, the custom parser [@typescript-eslint/parser](https://typescript-eslint.io/architecture/parser/) extends ESLint to lint TypeScript code.
+
+Custom parsers **cannot** be included in a plugin, unlike the other extension types.
+
+To learn more about creating a custom parser, refer to [Custom Parsers](custom-parsers).
--- /dev/null
+---
+title: Node.js API Reference
+eleventyNavigation:
+ key: node.js api
+ parent: extend eslint
+ title: Node.js API Reference
+ order: 6
+---
+
+While ESLint is designed to be run on the command line, it's possible to use ESLint programmatically through the Node.js API. The purpose of the Node.js API is to allow plugin and tool authors to use the ESLint functionality directly, without going through the command line interface.
+
+**Note:** Use undocumented parts of the API at your own risk. Only those parts that are specifically mentioned in this document are approved for use and will remain stable and reliable. Anything left undocumented is unstable and may change or be removed at any point.
+
+## ESLint class
+
+The `ESLint` class is the primary class to use in Node.js applications.
+
+This class depends on the Node.js `fs` module and the file system, so you cannot use it in browsers. If you want to lint code on browsers, use the [Linter](#linter) class instead.
+
+Here's a simple example of using the `ESLint` class:
+
+```js
+const { ESLint } = require("eslint");
+
+(async function main() {
+ // 1. Create an instance.
+ const eslint = new ESLint();
+
+ // 2. Lint files.
+ const results = await eslint.lintFiles(["lib/**/*.js"]);
+
+ // 3. Format the results.
+ const formatter = await eslint.loadFormatter("stylish");
+ const resultText = formatter.format(results);
+
+ // 4. Output it.
+ console.log(resultText);
+})().catch((error) => {
+ process.exitCode = 1;
+ console.error(error);
+});
+```
+
+Here's an example that autofixes lint problems:
+
+```js
+const { ESLint } = require("eslint");
+
+(async function main() {
+ // 1. Create an instance with the `fix` option.
+ const eslint = new ESLint({ fix: true });
+
+ // 2. Lint files. This doesn't modify target files.
+ const results = await eslint.lintFiles(["lib/**/*.js"]);
+
+ // 3. Modify the files with the fixed code.
+ await ESLint.outputFixes(results);
+
+ // 4. Format the results.
+ const formatter = await eslint.loadFormatter("stylish");
+ const resultText = formatter.format(results);
+
+ // 5. Output it.
+ console.log(resultText);
+})().catch((error) => {
+ process.exitCode = 1;
+ console.error(error);
+});
+```
+
+And here is an example of using the `ESLint` class with `lintText` API:
+
+```js
+const { ESLint } = require("eslint");
+
+const testCode = `
+ const name = "eslint";
+ if(true) {
+ console.log("constant condition warning")
+ };
+`;
+
+(async function main() {
+ // 1. Create an instance
+ const eslint = new ESLint({
+ useEslintrc: false,
+ overrideConfig: {
+ extends: ["eslint:recommended"],
+ parserOptions: {
+ sourceType: "module",
+ ecmaVersion: "latest",
+ },
+ env: {
+ es2022: true,
+ node: true,
+ },
+ },
+ });
+
+ // 2. Lint text.
+ const results = await eslint.lintText(testCode);
+
+ // 3. Format the results.
+ const formatter = await eslint.loadFormatter("stylish");
+ const resultText = formatter.format(results);
+
+ // 4. Output it.
+ console.log(resultText);
+})().catch((error) => {
+ process.exitCode = 1;
+ console.error(error);
+});
+```
+
+### ◆ new ESLint(options)
+
+```js
+const eslint = new ESLint(options);
+```
+
+Create a new `ESLint` instance.
+
+#### Parameters
+
+The `ESLint` constructor takes an `options` object. If you omit the `options` object then it uses default values for all options. The `options` object has the following properties.
+
+##### File Enumeration
+
+* `options.cwd` (`string`)<br>
+ Default is `process.cwd()`. The working directory. This must be an absolute path.
+* `options.errorOnUnmatchedPattern` (`boolean`)<br>
+ Default is `true`. Unless set to `false`, the [`eslint.lintFiles()`][eslint-lintfiles] method will throw an error when no target files are found.
+* `options.extensions` (`string[] | null`)<br>
+ Default is `null`. If you pass directory paths to the [`eslint.lintFiles()`][eslint-lintfiles] method, ESLint checks the files in those directories that have the given extensions. For example, when passing the `src/` directory and `extensions` is `[".js", ".ts"]`, ESLint will lint `*.js` and `*.ts` files in `src/`. If `extensions` is `null`, ESLint checks `*.js` files and files that match `overrides[].files` patterns in your configuration.<br>**Note:** This option only applies when you pass directory paths to the [`eslint.lintFiles()`][eslint-lintfiles] method. If you pass glob patterns like `lib/**/*`, ESLint will lint all files matching the glob pattern regardless of extension.
+* `options.globInputPaths` (`boolean`)<br>
+ Default is `true`. If `false` is present, the [`eslint.lintFiles()`][eslint-lintfiles] method doesn't interpret glob patterns.
+* `options.ignore` (`boolean`)<br>
+ Default is `true`. If `false` is present, the [`eslint.lintFiles()`][eslint-lintfiles] method doesn't respect `.eslintignore` files or `ignorePatterns` in your configuration.
+* `options.ignorePath` (`string | null`)<br>
+ Default is `null`. The path to a file ESLint uses instead of `$CWD/.eslintignore`. If a path is present and the file doesn't exist, this constructor will throw an error.
+
+##### Linting
+
+* `options.allowInlineConfig` (`boolean`)<br>
+ Default is `true`. If `false` is present, ESLint suppresses directive comments in source code. If this option is `false`, it overrides the `noInlineConfig` setting in your configurations.
+* `options.baseConfig` (`ConfigData | null`)<br>
+ Default is `null`. [Configuration object], extended by all configurations used with this instance. You can use this option to define the default settings that will be used if your configuration files don't configure it.
+* `options.overrideConfig` (`ConfigData | null`)<br>
+ Default is `null`. [Configuration object], overrides all configurations used with this instance. You can use this option to define the settings that will be used even if your configuration files configure it.
+* `options.overrideConfigFile` (`string | null`)<br>
+ Default is `null`. The path to a configuration file, overrides all configurations used with this instance. The `options.overrideConfig` option is applied after this option is applied.
+* `options.plugins` (`Record<string, Plugin> | null`)<br>
+ Default is `null`. The plugin implementations that ESLint uses for the `plugins` setting of your configuration. This is a map-like object. Those keys are plugin IDs and each value is implementation.
+* `options.reportUnusedDisableDirectives` (`"error" | "warn" | "off" | null`)<br>
+ Default is `null`. The severity to report unused eslint-disable directives. If this option is a severity, it overrides the `reportUnusedDisableDirectives` setting in your configurations.
+* `options.resolvePluginsRelativeTo` (`string` | `null`)<br>
+ Default is `null`. The path to a directory where plugins should be resolved from. If `null` is present, ESLint loads plugins from the location of the configuration file that contains the plugin setting. If a path is present, ESLint loads all plugins from there.
+* `options.rulePaths` (`string[]`)<br>
+ Default is `[]`. An array of paths to directories to load custom rules from.
+* `options.useEslintrc` (`boolean`)<br>
+ Default is `true`. If `false` is present, ESLint doesn't load configuration files (`.eslintrc.*` files). Only the configuration of the constructor options is valid.
+
+##### Autofix
+
+* `options.fix` (`boolean | (message: LintMessage) => boolean`)<br>
+ Default is `false`. If `true` is present, the [`eslint.lintFiles()`][eslint-lintfiles] and [`eslint.lintText()`][eslint-linttext] methods work in autofix mode. If a predicate function is present, the methods pass each lint message to the function, then use only the lint messages for which the function returned `true`.
+* `options.fixTypes` (`("directive" | "problem" | "suggestion" | "layout")[] | null`)<br>
+ Default is `null`. The types of the rules that the [`eslint.lintFiles()`][eslint-lintfiles] and [`eslint.lintText()`][eslint-linttext] methods use for autofix.
+
+##### Cache-related
+
+* `options.cache` (`boolean`)<br>
+ Default is `false`. If `true` is present, the [`eslint.lintFiles()`][eslint-lintfiles] method caches lint results and uses it if each target file is not changed. Please mind that ESLint doesn't clear the cache when you upgrade ESLint plugins. In that case, you have to remove the cache file manually. The [`eslint.lintText()`][eslint-linttext] method doesn't use caches even if you pass the `options.filePath` to the method.
+* `options.cacheLocation` (`string`)<br>
+ Default is `.eslintcache`. The [`eslint.lintFiles()`][eslint-lintfiles] method writes caches into this file.
+* `options.cacheStrategy` (`string`)<br>
+ Default is `"metadata"`. Strategy for the cache to use for detecting changed files. Can be either `"metadata"` or `"content"`.
+
+### ◆ eslint.lintFiles(patterns)
+
+```js
+const results = await eslint.lintFiles(patterns);
+```
+
+This method lints the files that match the glob patterns and then returns the results.
+
+#### Parameters
+
+* `patterns` (`string | string[]`)<br>
+ The lint target files. This can contain any of file paths, directory paths, and glob patterns.
+
+#### Return Value
+
+* (`Promise<LintResult[]>`)<br>
+ The promise that will be fulfilled with an array of [LintResult] objects.
+
+### ◆ eslint.lintText(code, options)
+
+```js
+const results = await eslint.lintText(code, options);
+```
+
+This method lints the given source code text and then returns the results.
+
+By default, this method uses the configuration that applies to files in the current working directory (the `cwd` constructor option). If you want to use a different configuration, pass `options.filePath`, and ESLint will load the same configuration that [`eslint.lintFiles()`][eslint-lintfiles] would use for a file at `options.filePath`.
+
+If the `options.filePath` value is configured to be ignored, this method returns an empty array. If the `options.warnIgnored` option is set along with the `options.filePath` option, this method returns a [LintResult] object. In that case, the result may contain a warning that indicates the file was ignored.
+
+#### Parameters
+
+The second parameter `options` is omittable.
+
+* `code` (`string`)<br>
+ The source code text to check.
+* `options.filePath` (`string`)<br>
+ Optional. The path to the file of the source code text. If omitted, the `result.filePath` becomes the string `"<text>"`.
+* `options.warnIgnored` (`boolean`)<br>
+ Optional. If `true` is present and the `options.filePath` is a file ESLint should ignore, this method returns a lint result contains a warning message.
+
+#### Return Value
+
+* (`Promise<LintResult[]>`)<br>
+ The promise that will be fulfilled with an array of [LintResult] objects. This is an array (despite there being only one lint result) in order to keep the interfaces between this and the [`eslint.lintFiles()`][eslint-lintfiles] method similar.
+
+### ◆ eslint.getRulesMetaForResults(results)
+
+```js
+const results = await eslint.lintFiles(patterns);
+const rulesMeta = eslint.getRulesMetaForResults(results);
+```
+
+This method returns an object containing meta information for each rule that triggered a lint error in the given `results`.
+
+#### Parameters
+
+* `results` (`LintResult[]`)<br>
+ An array of [LintResult] objects returned from a call to `ESLint#lintFiles()` or `ESLint#lintText()`.
+
+#### Return Value
+
+* (`Object`)<br>
+ An object whose property names are the rule IDs from the `results` and whose property values are the rule's meta information (if available).
+
+### ◆ eslint.calculateConfigForFile(filePath)
+
+```js
+const config = await eslint.calculateConfigForFile(filePath);
+```
+
+This method calculates the configuration for a given file, which can be useful for debugging purposes.
+
+* It resolves and merges `extends` and `overrides` settings into the top level configuration.
+* It resolves the `parser` setting to absolute paths.
+* It normalizes the `plugins` setting to align short names. (e.g., `eslint-plugin-foo` → `foo`)
+* It adds the `processor` setting if a legacy file extension processor is matched.
+* It doesn't interpret the `env` setting to the `globals` and `parserOptions` settings, so the result object contains the `env` setting as is.
+
+#### Parameters
+
+* `filePath` (`string`)<br>
+ The path to the file whose configuration you would like to calculate. Directory paths are forbidden because ESLint cannot handle the `overrides` setting.
+
+#### Return Value
+
+* (`Promise<Object>`)<br>
+ The promise that will be fulfilled with a configuration object.
+
+### ◆ eslint.isPathIgnored(filePath)
+
+```js
+const isPathIgnored = await eslint.isPathIgnored(filePath);
+```
+
+This method checks if a given file is ignored by your configuration.
+
+#### Parameters
+
+* `filePath` (`string`)<br>
+ The path to the file you want to check.
+
+#### Return Value
+
+* (`Promise<boolean>`)<br>
+ The promise that will be fulfilled with whether the file is ignored or not. If the file is ignored, then it will return `true`.
+
+### ◆ eslint.loadFormatter(nameOrPath)
+
+```js
+const formatter = await eslint.loadFormatter(nameOrPath);
+```
+
+This method loads a formatter. Formatters convert lint results to a human- or machine-readable string.
+
+#### Parameters
+
+* `nameOrPath` (`string | undefined`)<br>
+ The path to the file you want to check. The following values are allowed:
+ * `undefined`. In this case, loads the `"stylish"` built-in formatter.
+ * A name of [built-in formatters][builtin-formatters].
+ * A name of [third-party formatters][third-party-formatters]. For examples:
+ * `"foo"` will load `eslint-formatter-foo`.
+ * `"@foo"` will load `@foo/eslint-formatter`.
+ * `"@foo/bar"` will load `@foo/eslint-formatter-bar`.
+ * A path to the file that defines a formatter. The path must contain one or more path separators (`/`) in order to distinguish if it's a path or not. For example, start with `./`.
+
+#### Return Value
+
+* (`Promise<LoadedFormatter>`)<br>
+ The promise that will be fulfilled with a [LoadedFormatter] object.
+
+### ◆ ESLint.version
+
+```js
+const version = ESLint.version;
+```
+
+The version string of ESLint. E.g. `"7.0.0"`.
+
+This is a static property.
+
+### ◆ ESLint.outputFixes(results)
+
+```js
+await ESLint.outputFixes(results);
+```
+
+This method writes code modified by ESLint's autofix feature into its respective file. If any of the modified files don't exist, this method does nothing.
+
+This is a static method.
+
+#### Parameters
+
+* `results` (`LintResult[]`)<br>
+ The [LintResult] objects to write.
+
+#### Return Value
+
+* (`Promise<void>`)<br>
+ The promise that will be fulfilled after all files are written.
+
+### ◆ ESLint.getErrorResults(results)
+
+```js
+const filteredResults = ESLint.getErrorResults(results);
+```
+
+This method copies the given results and removes warnings. The returned value contains only errors.
+
+This is a static method.
+
+#### Parameters
+
+* `results` (`LintResult[]`)<br>
+ The [LintResult] objects to filter.
+
+#### Return Value
+
+* (`LintResult[]`)<br>
+ The filtered [LintResult] objects.
+
+### ◆ LintResult type
+
+The `LintResult` value is the information of the linting result of each file. The [`eslint.lintFiles()`][eslint-lintfiles] and [`eslint.lintText()`][eslint-linttext] methods return it. It has the following properties:
+
+* `filePath` (`string`)<br>
+ The absolute path to the file of this result. This is the string `"<text>"` if the file path is unknown (when you didn't pass the `options.filePath` option to the [`eslint.lintText()`][eslint-linttext] method).
+* `messages` (`LintMessage[]`)<br>
+ The array of [LintMessage] objects.
+* `suppressedMessages` (`SuppressedLintMessage[]`)<br>
+ The array of [SuppressedLintMessage] objects.
+* `fixableErrorCount` (`number`)<br>
+ The number of errors that can be fixed automatically by the `fix` constructor option.
+* `fixableWarningCount` (`number`)<br>
+ The number of warnings that can be fixed automatically by the `fix` constructor option.
+* `errorCount` (`number`)<br>
+ The number of errors. This includes fixable errors and fatal errors.
+* `fatalErrorCount` (`number`)<br>
+ The number of fatal errors.
+* `warningCount` (`number`)<br>
+ The number of warnings. This includes fixable warnings.
+* `output` (`string | undefined`)<br>
+ The modified source code text. This property is undefined if any fixable messages didn't exist.
+* `source` (`string | undefined`)<br>
+ The original source code text. This property is undefined if any messages didn't exist or the `output` property exists.
+* `usedDeprecatedRules` (`{ ruleId: string; replacedBy: string[] }[]`)<br>
+ The information about the deprecated rules that were used to check this file.
+
+### ◆ LintMessage type
+
+The `LintMessage` value is the information of each linting error. The `messages` property of the [LintResult] type contains it. It has the following properties:
+
+* `ruleId` (`string` | `null`)<br>
+ The rule name that generates this lint message. If this message is generated by the ESLint core rather than rules, this is `null`.
+* `severity` (`1 | 2`)<br>
+ The severity of this message. `1` means warning and `2` means error.
+* `fatal` (`boolean | undefined`)<br>
+ `true` if this is a fatal error unrelated to a rule, like a parsing error.
+* `message` (`string`)<br>
+ The error message.
+* `line` (`number | undefined`)<br>
+ The 1-based line number of the begin point of this message.
+* `column` (`number | undefined`)<br>
+ The 1-based column number of the begin point of this message.
+* `endLine` (`number | undefined`)<br>
+ The 1-based line number of the end point of this message. This property is undefined if this message is not a range.
+* `endColumn` (`number | undefined`)<br>
+ The 1-based column number of the end point of this message. This property is undefined if this message is not a range.
+* `fix` (`EditInfo | undefined`)<br>
+ The [EditInfo] object of autofix. This property is undefined if this message is not fixable.
+* `suggestions` (`{ desc: string; fix: EditInfo }[] | undefined`)<br>
+ The list of suggestions. Each suggestion is the pair of a description and an [EditInfo] object to fix code. API users such as editor integrations can choose one of them to fix the problem of this message. This property is undefined if this message doesn't have any suggestions.
+
+### ◆ SuppressedLintMessage type
+
+The `SuppressedLintMessage` value is the information of each suppressed linting error. The `suppressedMessages` property of the [LintResult] type contains it. It has the following properties:
+
+* `ruleId` (`string` | `null`)<br>
+ Same as `ruleId` in [LintMessage] type.
+* `severity` (`1 | 2`)<br>
+ Same as `severity` in [LintMessage] type.
+* `fatal` (`boolean | undefined`)<br>
+ Same as `fatal` in [LintMessage] type.
+* `message` (`string`)<br>
+ Same as `message` in [LintMessage] type.
+* `line` (`number | undefined`)<br>
+ Same as `line` in [LintMessage] type.
+* `column` (`number | undefined`)<br>
+ Same as `column` in [LintMessage] type.
+* `endLine` (`number | undefined`)<br>
+ Same as `endLine` in [LintMessage] type.
+* `endColumn` (`number | undefined`)<br>
+ Same as `endColumn` in [LintMessage] type.
+* `fix` (`EditInfo | undefined`)<br>
+ Same as `fix` in [LintMessage] type.
+* `suggestions` (`{ desc: string; fix: EditInfo }[] | undefined`)<br>
+ Same as `suggestions` in [LintMessage] type.
+* `suppressions` (`{ kind: string; justification: string}[]`)<br>
+ The list of suppressions. Each suppression is the pair of a kind and a justification.
+
+### ◆ EditInfo type
+
+The `EditInfo` value is information to edit text. The `fix` and `suggestions` properties of [LintMessage] type contain it. It has following properties:
+
+* `range` (`[number, number]`)<br>
+ The pair of 0-based indices in source code text to remove.
+* `text` (`string`)<br>
+ The text to add.
+
+This edit information means replacing the range of the `range` property by the `text` property value. It's like `sourceCodeText.slice(0, edit.range[0]) + edit.text + sourceCodeText.slice(edit.range[1])`. Therefore, it's an add if the `range[0]` and `range[1]` property values are the same value, and it's removal if the `text` property value is empty string.
+
+### ◆ LoadedFormatter type
+
+The `LoadedFormatter` 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[], resultsMeta: ResultsMeta) => string | Promise<string>`)<br>
+ The method to convert the [LintResult] objects to text. `resultsMeta` is an object that will contain a `maxWarningsExceeded` object if `--max-warnings` was set and the number of warnings exceeded the limit. The `maxWarningsExceeded` object will contain two properties: `maxWarnings`, the value of the `--max-warnings` option, and `foundWarnings`, the number of lint warnings.
+
+---
+
+## SourceCode
+
+The `SourceCode` type represents the parsed source code that ESLint executes on. It's used internally in ESLint and is also available so that already-parsed code can be used. You can create a new instance of `SourceCode` by passing in the text string representing the code and an abstract syntax tree (AST) in [ESTree](https://github.com/estree/estree) format (including location information, range information, comments, and tokens):
+
+```js
+const SourceCode = require("eslint").SourceCode;
+
+const code = new SourceCode("var foo = bar;", ast);
+```
+
+The `SourceCode` constructor throws an error if the AST is missing any of the required information.
+
+The `SourceCode` constructor strips Unicode BOM.
+Please note the AST also should be parsed from stripped text.
+
+```js
+const SourceCode = require("eslint").SourceCode;
+
+const code = new SourceCode("\uFEFFvar foo = bar;", ast);
+
+assert(code.hasBOM === true);
+assert(code.text === "var foo = bar;");
+```
+
+### SourceCode#splitLines()
+
+This is a static function on `SourceCode` that is used to split the source code text into an array of lines.
+
+```js
+const SourceCode = require("eslint").SourceCode;
+
+const code = "var a = 1;\nvar b = 2;"
+
+// split code into an array
+const codeLines = SourceCode.splitLines(code);
+
+/*
+ Value of codeLines will be
+ [
+ "var a = 1;",
+ "var b = 2;"
+ ]
+ */
+```
+
+---
+
+## Linter
+
+The `Linter` object does the actual evaluation of the JavaScript code. It doesn't do any filesystem operations, it simply parses and reports on the code. In particular, the `Linter` object does not process configuration objects or files. Unless you are working in the browser, you probably want to use the [ESLint class](#eslint-class) instead.
+
+The `Linter` is a constructor, and you can create a new instance by passing in the options you want to use. The available options are:
+
+* `cwd` - Path to a directory that should be considered as the current working directory. It is accessible to rules from `context.cwd` or by calling `context.getCwd()` (see [The Context Object](../extend/custom-rules#the-context-object)). If `cwd` is `undefined`, it will be normalized to `process.cwd()` if the global `process` object is defined (for example, in the Node.js runtime) , or `undefined` otherwise.
+
+For example:
+
+```js
+const Linter = require("eslint").Linter;
+const linter1 = new Linter({ cwd: 'path/to/project' });
+const linter2 = new Linter();
+```
+
+In this example, rules run on `linter1` will get `path/to/project` from `context.cwd` or 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>).
+
+### Linter#verify
+
+The most important method on `Linter` is `verify()`, which initiates linting of the given text. This method accepts three arguments:
+
+* `code` - the source code to lint (a string or instance of `SourceCode`).
+* `config` - a configuration object that has been processed and normalized by `ESLint` using eslintrc files and/or other configuration arguments.
+ * **Note**: If you want to lint text and have your configuration be read and processed, use [`ESLint#lintFiles()`][eslint-lintfiles] or [`ESLint#lintText()`][eslint-linttext] instead.
+* `options` - (optional) Additional options for this run.
+ * `filename` - (optional) the filename to associate with the source code.
+ * `preprocess` - (optional) A function that [Processors in Plugins](../extend/plugins#processors-in-plugins) documentation describes as the `preprocess` method.
+ * `postprocess` - (optional) A function that [Processors in Plugins](../extend/plugins#processors-in-plugins) documentation describes as the `postprocess` method.
+ * `filterCodeBlock` - (optional) A function that decides which code blocks the linter should adopt. The function receives two arguments. The first argument is the virtual filename of a code block. The second argument is the text of the code block. If the function returned `true` then the linter adopts the code block. If the function was omitted, the linter adopts only `*.js` code blocks. If you provided a `filterCodeBlock` function, it overrides this default behavior, so the linter doesn't adopt `*.js` code blocks automatically.
+ * `disableFixes` - (optional) when set to `true`, the linter doesn't make either the `fix` or `suggestions` property of the lint result.
+ * `allowInlineConfig` - (optional) set to `false` to disable inline comments from changing ESLint rules.
+ * `reportUnusedDisableDirectives` - (optional) when set to `true`, adds reported errors for unused `eslint-disable` directives when no problems would be reported in the disabled area anyway.
+
+If the third argument is a string, it is interpreted as the `filename`.
+
+You can call `verify()` like this:
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+const messages = linter.verify("var foo;", {
+ rules: {
+ semi: 2
+ }
+}, { filename: "foo.js" });
+
+// or using SourceCode
+
+const Linter = require("eslint").Linter,
+ linter = new Linter(),
+ SourceCode = require("eslint").SourceCode;
+
+const code = new SourceCode("var foo = bar;", ast);
+
+const messages = linter.verify(code, {
+ rules: {
+ semi: 2
+ }
+}, { filename: "foo.js" });
+```
+
+The `verify()` method returns an array of objects containing information about the linting warnings and errors. Here's an example:
+
+```js
+{
+ fatal: false,
+ ruleId: "semi",
+ severity: 2,
+ line: 1,
+ column: 23,
+ message: "Expected a semicolon.",
+ fix: {
+ range: [1, 15],
+ text: ";"
+ }
+}
+```
+
+The information available for each linting message is:
+
+* `column` - the column on which the error occurred.
+* `fatal` - usually omitted, but will be set to true if there's a parsing error (not related to a rule).
+* `line` - the line on which the error occurred.
+* `message` - the message that should be output.
+* `nodeType` - the node or token type that was reported with the problem.
+* `ruleId` - the ID of the rule that triggered the messages (or null if `fatal` is true).
+* `severity` - either 1 or 2, depending on your configuration.
+* `endColumn` - the end column of the range on which the error occurred (this property is omitted if it's not range).
+* `endLine` - the end line of the range on which the error occurred (this property is omitted if it's not range).
+* `fix` - an object describing the fix for the problem (this property is omitted if no fix is available).
+* `suggestions` - an array of objects describing possible lint fixes for editors to programmatically enable (see details in the [Working with Rules docs](../extend/custom-rules#providing-suggestions)).
+
+You can get the suppressed messages from the previous run by `getSuppressedMessages()` method. If there is not a previous run, `getSuppressedMessage()` will return an empty list.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+const messages = linter.verify("var foo = bar; // eslint-disable-line -- Need to suppress", {
+ rules: {
+ semi: ["error", "never"]
+ }
+}, { filename: "foo.js" });
+const suppressedMessages = linter.getSuppressedMessages();
+
+console.log(suppressedMessages[0].suppressions); // [{ "kind": "directive", "justification": "Need to suppress" }]
+```
+
+Linting message objects have a deprecated `source` property. This property **will be removed** from linting messages in an upcoming breaking release. If you depend on this property, you should now use the `SourceCode` instance provided by the linter.
+
+You can also get an instance of the `SourceCode` object used inside of `linter` by using the `getSourceCode()` method:
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+const messages = linter.verify("var foo = bar;", {
+ rules: {
+ semi: 2
+ }
+}, { filename: "foo.js" });
+
+const code = linter.getSourceCode();
+
+console.log(code.text); // "var foo = bar;"
+```
+
+In this way, you can retrieve the text and AST used for the last run of `linter.verify()`.
+
+### Linter#verifyAndFix()
+
+This method is similar to verify except that it also runs autofixing logic, similar to the `--fix` flag on the command line. The result object will contain the autofixed code, along with any remaining linting messages for the code that were not autofixed.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+const messages = linter.verifyAndFix("var foo", {
+ rules: {
+ semi: 2
+ }
+});
+```
+
+Output object from this method:
+
+```js
+{
+ fixed: true,
+ output: "var foo;",
+ messages: []
+}
+```
+
+The information available is:
+
+* `fixed` - True, if the code was fixed.
+* `output` - Fixed code text (might be the same as input if no fixes were applied).
+* `messages` - Collection of all messages for the given code (It has the same information as explained above under `verify` block).
+
+### Linter#defineRule
+
+Each `Linter` instance holds a map of rule names to loaded rule objects. By default, all ESLint core rules are loaded. If you want to use `Linter` with custom rules, you should use the `defineRule` method to register your rules by ID.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+linter.defineRule("my-custom-rule", {
+ // (an ESLint rule)
+
+ create(context) {
+ // ...
+ }
+});
+
+const results = linter.verify("// some source text", { rules: { "my-custom-rule": "error" } });
+```
+
+### Linter#defineRules
+
+This is a convenience method similar to `Linter#defineRule`, except that it allows you to define many rules at once using an object.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+linter.defineRules({
+ "my-custom-rule": { /* an ESLint rule */ create() {} },
+ "another-custom-rule": { /* an ESLint rule */ create() {} }
+});
+
+const results = linter.verify("// some source text", {
+ rules: {
+ "my-custom-rule": "error",
+ "another-custom-rule": "warn"
+ }
+});
+```
+
+### Linter#getRules
+
+This method returns a map of all loaded rules.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+linter.getRules();
+
+/*
+Map {
+ 'accessor-pairs' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
+ 'array-bracket-newline' => { meta: { docs: [Object], schema: [Array] }, create: [Function: create] },
+ ...
+}
+*/
+```
+
+### Linter#defineParser
+
+Each instance of `Linter` holds a map of custom parsers. If you want to define a parser programmatically, you can add this function
+with the name of the parser as first argument and the [parser object](../extend/custom-parsers) as second argument. The default `"espree"` parser will already be loaded for every `Linter` instance.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+linter.defineParser("my-custom-parser", {
+ parse(code, options) {
+ // ...
+ }
+});
+
+const results = linter.verify("// some source text", { parser: "my-custom-parser" });
+```
+
+### Linter#version/Linter.version
+
+Each instance of `Linter` has a `version` property containing the semantic version number of ESLint that the `Linter` instance is from.
+
+```js
+const Linter = require("eslint").Linter;
+const linter = new Linter();
+
+linter.version; // => '4.5.0'
+```
+
+There is also a `Linter.version` property that you can read without instantiating `Linter`:
+
+```js
+const Linter = require("eslint").Linter;
+
+Linter.version; // => '4.5.0'
+```
+
+---
+
+## RuleTester
+
+`eslint.RuleTester` is a utility to write tests for ESLint rules. It is used internally for the bundled rules that come with ESLint, and it can also be used by plugins.
+
+Example usage:
+
+```js
+"use strict";
+
+const rule = require("../../../lib/rules/my-rule"),
+ RuleTester = require("eslint").RuleTester;
+
+const ruleTester = new RuleTester();
+
+ruleTester.run("my-rule", rule, {
+ valid: [
+ {
+ code: "var foo = true",
+ options: [{ allowFoo: true }]
+ }
+ ],
+
+ invalid: [
+ {
+ code: "var invalidVariable = true",
+ errors: [{ message: "Unexpected invalid variable." }]
+ },
+ {
+ code: "var invalidVariable = true",
+ errors: [{ message: /^Unexpected.+variable/ }]
+ }
+ ]
+});
+```
+
+The `RuleTester` constructor accepts an optional object argument, which can be used to specify defaults for your test cases. For example, if all of your test cases use ES2015, you can set it as a default:
+
+```js
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } });
+```
+
+The `RuleTester#run()` method is used to run the tests. It should be passed the following arguments:
+
+* The name of the rule (string)
+* The rule object itself (see ["working with rules"](../extend/custom-rules))
+* An object containing `valid` and `invalid` properties, each of which is an array containing test cases.
+
+A test case is an object with the following properties:
+
+* `name` (string, optional): The name to use for the test case, to make it easier to find
+* `code` (string, required): The source code that the rule should be run on
+* `options` (array, optional): The options passed to the rule. The rule severity should not be included in this list.
+* `filename` (string, optional): The filename for the given case (useful for rules that make assertions about filenames).
+* `only` (boolean, optional): Run this case exclusively for debugging in supported test frameworks.
+
+In addition to the properties above, invalid test cases can also have the following properties:
+
+* `errors` (number or array, required): Asserts some properties of the errors that the rule is expected to produce when run on this code. If this is a number, asserts the number of errors produced. Otherwise, this should be a list of objects, each containing information about a single reported error. The following properties can be used for an error (all are optional):
+ * `message` (string/regexp): The message for the error
+ * `messageId` (string): The Id for the error. See [testing errors with messageId](#testing-errors-with-messageid) for details
+ * `data` (object): Placeholder data which can be used in combination with `messageId`
+ * `type` (string): The type of the reported AST node
+ * `line` (number): The 1-based line number of the reported location
+ * `column` (number): The 1-based column number of the reported location
+ * `endLine` (number): The 1-based line number of the end of the reported location
+ * `endColumn` (number): The 1-based column number of the end of the reported location
+ * `suggestions` (array): An array of objects with suggestion details to check. See [Testing Suggestions](#testing-suggestions) for details
+
+ If a string is provided as an error instead of an object, the string is used to assert the `message` of the error.
+* `output` (string, required if the rule fixes code): Asserts the output that will be produced when using this rule for a single pass of autofixing (e.g. with the `--fix` command line flag). If this is `null`, asserts that none of the reported problems suggest autofixes.
+
+Any additional properties of a test case will be passed directly to the linter as config options. For example, a test case can have a `parserOptions` property to configure parser behavior:
+
+```js
+{
+ code: "let foo;",
+ parserOptions: { ecmaVersion: 2015 }
+}
+```
+
+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`
+
+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`.
+
+```js
+{
+ code: "let foo;",
+ errors: [{ messageId: "unexpected" }]
+}
+```
+
+For messages with placeholders, a test case can also use `data` property to additionally assert reported error's `message`.
+
+```js
+{
+ code: "let foo;",
+ errors: [{ messageId: "unexpected", data: { name: "foo" } }]
+}
+```
+
+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
+
+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):
+
+* `desc` (string): The suggestion `desc` value
+* `messageId` (string): The suggestion `messageId` value for suggestions that use `messageId`s
+* `data` (object): Placeholder data which can be used in combination with `messageId`
+* `output` (string): A code string representing the result of applying the suggestion fix to the input code
+
+Example:
+
+```js
+ruleTester.run("my-rule-for-no-foo", rule, {
+ valid: [],
+ invalid: [{
+ code: "var foo;",
+ errors: [{
+ suggestions: [{
+ desc: "Rename identifier 'foo' to 'bar'",
+ output: "var bar;"
+ }]
+ }]
+ }]
+})
+```
+
+`messageId` and `data` properties in suggestion test objects work the same way as in error test objects. See [testing errors with messageId](#testing-errors-with-messageid) for details.
+
+```js
+ruleTester.run("my-rule-for-no-foo", rule, {
+ valid: [],
+ invalid: [{
+ code: "var foo;",
+ errors: [{
+ suggestions: [{
+ messageId: "renameFoo",
+ data: { newName: "bar" },
+ output: "var bar;"
+ }]
+ }]
+ }]
+})
+```
+
+### Customizing RuleTester
+
+`RuleTester` depends on two functions to run tests: `describe` and `it`. These functions can come from various places:
+
+1. If `RuleTester.describe` and `RuleTester.it` have been set to function values, `RuleTester` will use `RuleTester.describe` and `RuleTester.it` to run tests. You can use this to customize the behavior of `RuleTester` to match a test framework that you're using.
+
+ If `RuleTester.itOnly` has been set to a function value, `RuleTester` will call `RuleTester.itOnly` instead of `RuleTester.it` to run cases with `only: true`. If `RuleTester.itOnly` is not set but `RuleTester.it` has an `only` function property, `RuleTester` will fall back to `RuleTester.it.only`.
+
+2. Otherwise, if `describe` and `it` are present as globals, `RuleTester` will use `global.describe` and `global.it` to run tests and `global.it.only` to run cases with `only: true`. This allows `RuleTester` to work when using frameworks like [Mocha](https://mochajs.org/) without any additional configuration.
+3. Otherwise, `RuleTester#run` will simply execute all of the tests in sequence, and will throw an error if one of them fails. This means you can simply execute a test file that calls `RuleTester.run` using `Node.js`, without needing a testing framework.
+
+`RuleTester#run` calls the `describe` function with two arguments: a string describing the rule, and a callback function. The callback calls the `it` function with a string describing the test case, and a test function. The test function will return successfully if the test passes, and throw an error if the test fails. The signature for `only` is the same as `it`. `RuleTester` calls either `it` or `only` for every case even when some cases have `only: true`, and the test framework is responsible for implementing test case exclusivity. (Note that this is the standard behavior for test suites when using frameworks like [Mocha](https://mochajs.org/); this information is only relevant if you plan to customize `RuleTester.describe`, `RuleTester.it`, or `RuleTester.itOnly`.)
+
+Example of customizing `RuleTester`:
+
+```js
+"use strict";
+
+const RuleTester = require("eslint").RuleTester,
+ test = require("my-test-runner"),
+ myRule = require("../../../lib/rules/my-rule");
+
+RuleTester.describe = function(text, method) {
+ RuleTester.it.title = text;
+ return method.call(this);
+};
+
+RuleTester.it = function(text, method) {
+ test(RuleTester.it.title + ": " + text, method);
+};
+
+// then use RuleTester as documented
+
+const ruleTester = new RuleTester();
+
+ruleTester.run("my-rule", myRule, {
+ valid: [
+ // valid test cases
+ ],
+ invalid: [
+ // invalid test cases
+ ]
+})
+```
+
+---
+
+[configuration object]: ../use/configure/
+[builtin-formatters]: ../use/formatters/
+[third-party-formatters]: https://www.npmjs.com/search?q=eslintformatter
+[eslint-lintfiles]: #-eslintlintfilespatterns
+[eslint-linttext]: #-eslintlinttextcode-options
+[eslint-loadformatter]: #-eslintloadformatternameorpath
+[lintresult]: #-lintresult-type
+[lintmessage]: #-lintmessage-type
+[suppressedlintmessage]: #-suppressedlintmessage-type
+[editinfo]: #-editinfo-type
+[loadedformatter]: #-loadedformatter-type
## Rule categories
-The rule categories—namely “recommended”, “fixable”, and “hasSuggestions”—are shown in the [rules page](/rules/). They are rendered using the `ruleCategories` macro (imported from `/components/rule-categories.macro.html`). There is also an individual macro for each category type.
+The rule categories—namely “recommended”, “fixable”, and “hasSuggestions”—are shown in the [rules page](../rules/). They are rendered using the `ruleCategories` macro (imported from `/components/rule-categories.macro.html`). There is also an individual macro for each category type.
```html
{ % from 'components/rule-categories.macro.html' import ruleCategories % }
--- /dev/null
+---
+title: Maintain ESLint
+eleventyNavigation:
+ key: maintain eslint
+ title: Maintain ESLint
+ order: 4
+
+---
+
+This guide is intended for those who work as part of the ESLint project team.
+
+## [How ESLint is Maintained](overview)
+
+Explains how ESLint is maintained, including information about team, governance, and funding.
+
+## [Manage Issues](manage-issues)
+
+Describes how to deal with issues when they're opened, how to interact with users who open issues, and how to close issues effectively.
+
+## [Review Pull Requests](review-pull-requests)
+
+Describes how to review incoming pull requests.
+
+## [Manage Releases](manage-releases)
+
+Describes how to do an ESLint project release.
+
+## [Working Groups](working-groups)
+
+Describes how working groups are created and how they function within the ESLint project.
--- /dev/null
+---
+title: Manage Issues
+eleventyNavigation:
+ key: manage issues
+ parent: maintain eslint
+ title: Manage Issues
+ order: 2
+
+---
+
+New issues are filed frequently, and how we respond to those issues directly affects the success of the project. Being part of the project team means helping to triage and address issues as they come in so the project can continue to run smoothly.
+
+## Things to Keep in Mind
+
+1. **Be nice.** Even if the people are being rude or aggressive on an issue, you must be the mature one in the conversation as a project team member. Do your best to work with everyone no matter their style. Remember, poor wording choice can also be a sign of someone who doesn't know English very well, so be sure to consider that when trying to determine the tone of someone's message. Being rude, even when someone is being rude to you, reflects poorly on the team and the project as a whole.
+1. **Be inquisitive.** Ask questions on the issue whenever something isn't clear. Don't assume you understand what's being reported if there are details missing. Whenever you are unsure, it's best to ask for more information.
+1. **Not all requests are equal.** It's unlikely we'll be able to accommodate every request, so don't be afraid to say that something doesn't fit into the scope of the project or isn't practical. It's better to give such feedback if that's the case.
+1. **Close when appropriate.** Don't be afraid to close issues that you don't think will be done, or when it's become clear from the conversation that there's no further work to do. Issues can always be reopened if they are closed incorrectly, so feel free to close issues when appropriate. Just be sure to leave a comment explaining why the issue is being closed (if not closed by a commit).
+
+## Types of Issues
+
+There are four primary issue categories:
+
+1. **Bug**: Something isn't working the way it's expected to work.
+1. **Enhancement**: A change to something that already exists. For instance, adding a new option to an existing rule or fixing a bug in a rule where fixing it will result in the rule reporting more problems (in this case, use both "Bug" and "Enhancement").
+1. **Feature**: Adding something that doesn't already exist. For example, adding a new rule, new formatter, or new command line flag.
+1. **Question**: An inquiry about how something works that won't result in a code change. We prefer if people use GitHub Discussions or Discord for questions, but sometimes they'll open an issue.
+
+The first goal when evaluating an issue is to determine which category the issue falls into.
+
+## Triaging Process
+
+All of ESLint's issues, across all GitHub repositories, are managed on our [Triage Project](https://github.com/orgs/eslint/projects/3). Please use the Triage project instead of the issues list when reviewing issues to determine what to work on. The Triage project has several columns:
+
+* **Needs Triage**: Issues that have not yet been reviewed by anyone
+* **Triaging**: Issues that someone has reviewed but has not been able to fully triage yet
+* **Ready for Dev Team**: Issues that have been triaged and have all the information necessary for the dev team to take a look
+* **Evaluating**: The dev team is evaluating these issues to determine whether to move forward or not
+* **Feedback Needed**: A team member is requesting more input from the rest of the team before proceeding
+* **Waiting for RFC**: The next step in the process is for an RFC to be written
+* **RFC Opened**: An RFC is opened to address these issues
+* **Blocked**: The issue can't move forward due to some dependency
+* **Ready to Implement**: These issues have all the details necessary to start implementation
+* **Implementing**: There is an open pull request for each of these issues
+* **Completed**: The issue has been closed (either via pull request merge or by the team manually closing the issue)
+
+We make every attempt to automate movement between as many columns as we can, but sometimes moving issues needs to be done manually.
+
+### When an Issue is Opened
+
+When an issue is opened, it is automatically added to the "Needs Triage" column in the Triage project. These issues need to be evaluated to determine next steps. Anyone on the support team or dev team can follow these steps to properly triage issues.
+
+**Note:** If an issue is in the "Triaging" column, that means someone is already triaging it, and you should let them finish. There's no need to comment on issues in the "Triaging" column unless someone asks for help.
+
+The steps for triaging an issue are:
+
+1. Move the issue from "Needs Triage" to "Triaging" in the Triage project.
+1. Check: Has all the information in the issue template been provided?
+ * **No:** If information is missing from the issue template, or you can't tell what is being requested, please ask the author to provide the missing information:
+ * Add the "needs info" label to the issue so we know that this issue is stalled due to lack of information.
+ * Don't move on to other steps until the necessary information has been provided.
+ * If the issue author hasn't provided the necessary information after 7 days, please close the issue. The bot will add a comment stating that the issue was closed because there was information missing.
+ * **Yes:**
+ * If the issue is actually a question (rather than something the dev team needs to change), please [convert it to a discussion](https://docs.github.com/en/free-pro-team@latest/discussions/managing-discussions-for-your-community/moderating-discussions#converting-an-issue-to-a-discussion). You can continue the conversation as a discussion.
+ * If the issue is reporting a bug, try to reproduce the issue following the instructions in the issue. If you can reproduce the bug, please add the "repro:yes" label. (The bot will automatically remove the "repro:needed" label.) If you can't reproduce the bug, ask the author for more information about their environment or to clarify reproduction steps.
+ * If the issue is reporting something that works as intended, please add the "works as intended" label and close the issue.
+ * Please add labels describing the part of ESLint affected:
+ * **3rd party plugin**: Related to third-party functionality (plugins, parsers, rules, etc.)
+ * **build**: Related to commands run during a build (testing, linting, release scripts, etc.)
+ * **cli**: Related to command line input or output, or to `CLIEngine`
+ * **core**: Related to internal APIs
+ * **documentation**: Related to content on eslint.org
+ * **infrastructure**: Related to resources needed for builds or deployment (VMs, CI tools, bots, etc.)
+ * **rule**: Related to core rules
+ * Please assign an initial priority based on the importance of the issue. If you're not sure, use your best judgment. We can always change the priority later.
+ * **P1**: Urgent and important, we need to address this immediately.
+ * **P2**: Important but not urgent. Should be handled by a TSC member or reviewer.
+ * **P3**: Nice to have but not important. Can be handled by any team member.
+ * **P4**: A good idea that we'd like to have but may take a while for the team to get to it.
+ * **P5**: A good idea that the core team can't commit to. Will likely need to be done by an outside contributor.
+ * Please assign an initial impact assessement (make your best guess):
+ * **Low**: Doesn't affect many users.
+ * **Medium**: Affects most users or has a noticeable effect on user experience.
+ * **High**: Affects a lot of users, is a breaking change, or otherwise will be very noticeable to users.
+ * If you can't properly triage the issue, move the issue back to the "Needs Triage" column in the Triage project so someone else can triage it.
+ * If you have triaged the issue, move the issue to the "Ready for Dev Team" column in the Triage project.
+
+## Evaluation Process
+
+When an issue has been moved to the "Ready for Dev Team" column, any dev team member can pick up the issue to start evaluating it.
+
+1. Move the issue into the "Evaluating" column.
+1. Next steps:
+ * **Bugs**: If you can verify the bug, add the "accepted" label and ask if they would like to submit a pull request.
+ * **New Rules**: If you are willing to champion the rule (meaning you believe it should be included in ESLint core and you will take ownership of the process for including it), add a comment saying you will champion the issue, assign the issue to yourself, and follow the [guidelines](#championing-issues) below.
+ * **Rule Changes**: If you are willing to champion the change and it would not be a breaking change (requiring a major version increment), add a comment saying that you will champion the issue, assign the issue to yourself, and follow the [guidelines](#championing-issues) below.
+ * **Breaking Changes**: If you suspect or can verify that a change would be breaking, label it as "Breaking".
+ * **Duplicates**: If you can verify the issue is a duplicate, add a comment mentioning the duplicate issue (such as, "Duplicate of #1234") and close the issue.
+1. Regardless of the above, always leave a comment. Don't just add labels; engage with the person who opened the issue by asking a question (request more information if necessary) or stating your opinion of the issue. If it's a verified bug, ask if the user would like to submit a pull request.
+1. If the issue can't be implemented because it needs an external dependency to be updated or needs to wait for another issue to be resolved, move the issue to the "Blocked" column.
+1. If the issue has been accepted and an RFC is required as the next step, move the issue to the "Waiting for RFC" column and comment on the issue that an RFC is needed.
+
+**Note:** "Good first issue" issues are intended to help new contributors feel welcome and empowered to make a contribution to ESLint. To ensure that new contributors are given a chance to work on these issues, issues labeled "good first issue" must be open for 30 days *from the day the issue was labeled* before a team member is permitted to work on them.
+
+## Accepting Issues
+
+Issues may be labeled as "accepted" when the issue is:
+
+* A bug that you've been able to reproduce and verify (i.e. you're sure it's a bug)
+* A new rule or rule change that you're championing and [consensus](#consensus) has been reached for its inclusion in the project
+
+The "accepted" label will be added to other issues by a TSC member if it's appropriate for the roadmap.
+
+When an issue is accepted and implementation can begin, it should be moved to the "Ready to Implement" column.
+
+## Championing Issues
+
+New rules and rule changes require a champion. As champion, it's your job to:
+
+* Gain [consensus](#consensus) from the ESLint team on inclusion
+* Guide the rule creation process until it's complete (so only champion a rule that you have time to implement or help another contributor implement)
+
+Once consensus has been reached on inclusion, add the "accepted" label. Optionally, add "help wanted" and "good first issue" labels, as necessary.
+
+## Consensus
+
+Consensus is reached on issues when there are at least three team members who believe the change is a good idea and no one who believes the change is a bad idea. In order to indicate your support for an issue, leave a +1 reaction (thumbs up) on the original issue description in addition to any comments you might have.
+
+## When to Send to TSC
+
+If consensus cannot be reached on an issue, or an issue's progress has been stalled and it's not clear if the issue should be closed, then you can refer the issue to the TSC for resolution. To do so, add the "tsc agenda" label to the issue and add a comment including the following information:
+
+1. A one-paragraph summary of the discussion to this point. This should begin with "TSC Summary:".
+2. The question you would like the TSC to answer. This should begin with "TSC Question:".
+
+The issue will be discussed at the next TSC meeting and the resolution will be posted back to the issue.
+
+## Evaluating Core Features and Enhancements (TSC members only)
+
+In addition to the above, changes to the core (including CLI changes) that would result in a minor or major version release must be approved by the TSC by standard TSC motion. Add the label "tsc agenda" to the issue and it will be discussed at the next TSC meeting. In general, requests should meet the following criteria to be considered:
+
+1. The feature or enhancement is in scope for the project and should be added to the roadmap.
+1. Someone is committed to including the change within the next year.
+1. There is reasonable certainty about who will do the work.
+
+When a suggestion is too ambitious or would take too much time to complete, it's better not to accept the proposal. Stick to small, incremental changes and lay out a roadmap of where you'd like the project to go eventually. Don't let the project get bogged down in big features that will take a long time to complete.
+
+**Breaking Changes:** Be on the lookout for changes that would be breaking. Issues that represent breaking changes should be labeled as "breaking".
+
+## When to Close an Issue
+
+All team members are allowed to close issues depending on how the issue has been resolved.
+
+Team members may close an issue **immediately** if:
+
+1. The issue is a duplicate of an existing issue.
+1. The issue is just a question and has been answered.
+
+Team members may close an issue where the consensus is to not accept the issue after a waiting period (to ensure that other team members have a chance to review the issue before it is closed):
+
+* Wait **2 days** if the issue was opened Monday through Friday.
+* Wait **3 days** if the issue was opened on Saturday or Sunday.
+
+In an effort to keep the issues backlog manageable, team members may also close an issue if the following conditions are met:
+
+* **Unaccepted**: Close after it has been open for 21 days, as these issues do not have enough support to move forward.
+* **Accepted**: Close after 90 days if no one from the team or the community is willing to step forward and own the work to complete to it.
+* **Help wanted:** Close after 90 days if it has not been completed.
--- /dev/null
+---
+title: Manage Releases
+eleventyNavigation:
+ key: manage releases
+ parent: maintain eslint
+ title: Manage Releases
+ order: 4
+
+---
+
+Releases are when a project formally publishes a new version so the community can use it. There are two types of releases:
+
+* Regular releases that follow [semantic versioning](https://semver.org/) and are considered production-ready.
+* Prereleases that are not considered production-ready and are intended to give the community a preview of upcoming changes.
+
+## Release Manager
+
+One member of the Technical Steering Committee (TSC) is assigned to manage each scheduled release. The release manager is determined at the TSC meeting the day before the release.
+
+The release manager is responsible for:
+
+1. The scheduled release on Friday
+1. Monitoring issues over the weekend
+1. Determining if a patch release is necessary on Monday
+1. Publishing the patch release (if necessary)
+
+The release manager should seek input from the whole team on the Monday following a release to double-check if a patch release is necessary.
+
+The release manager needs to have access to ESLint's two-factor authentication for npm in order to do a release.
+
+## Release Communication
+
+Each scheduled release should be associated with a release issue ([example](https://github.com/eslint/eslint/issues/8138)). The release issue is the source of information for the team about the status of a release. Be sure the release issue has the "release" label so that it's easy to find.
+
+## Process
+
+On the day of a scheduled release, the release manager should follow these steps:
+
+1. Review open pull requests to see if any should be merged. In general, you can merge pull requests that:
+ * Have been open for at least two days and approved (these are just waiting for merge).
+ * Important pull requests (as determined by the team). You should stop and have people review before merging if they haven't been already.
+ * Documentation changes.
+ * Small bugfixes written by a team member.
+1. Log into Jenkins and schedule a build for the "ESLint Release" job.
+1. Watch the console output of the build on Jenkins. At some point, the build will pause and a link will be produced with an input field for a six-digit 2FA code.
+1. Enter the current six-digit 2FA code from your authenticator app.
+1. Continue the build and wait for it to finish.
+1. Update the release blog post with a "Highlights" section, including new rules and anything else that's important.
+1. Make a release announcement in the public chatroom.
+1. Make a release announcement on Twitter.
+1. Make a release announcement on the release issue. Document any problems that occurred during the release, and remind the team not to merge anything other than documentation changes and bugfixes. Leave the release issue open.
+1. Add the `patch release pending` label to the release issue. (When this label is present, `eslint-github-bot` will create a pending status check on non-semver-patch pull requests, to ensure that they aren't accidentally merged while a patch release is pending.)
+
+All release-related communications occur in the `#team` channel on Discord.
+
+On the Monday following the scheduled release, the release manager needs to determine if a patch release is necessary. A patch release is considered necessary if any of the following occurred since the scheduled release:
+
+* A regression bug is causing people's lint builds to fail when it previously passed.
+* Any bug that is causing a lot of problems for users (frequently happens due to new functionality).
+
+The patch release decision should be made as early on Monday as possible. If a patch release is necessary, then follow the same steps as the scheduled release process.
+
+In rare cases, a second patch release might be necessary if the release is known to have a severe regression that hasn't been fixed by Monday. If this occurs, the release manager should announce the situation on the release issue, and leave the issue open until all patch releases are complete. However, it's usually better to fix bugs for the next release cycle rather than doing a second patch release.
+
+After the patch release has been published (or no patch release is necessary), close the release issue and inform the team that they can start merging in semver-minor changes again.
+
+## Emergency Releases
+
+An emergency release is unplanned and isn't the regularly scheduled release or the anticipated patch release.
+
+In general, we try not to do emergency releases. Even if there is a regression, it's best to wait until Monday to see if any other problems arise so a patch release can fix as many issues as possible.
+
+The only real exception is if ESLint is completely unusable by most of the current users. For instance, we once pushed a release that errored for everyone because it was missing some core files. In that case, an emergency release is appropriate.
--- /dev/null
+---
+title: How ESLint is Maintained
+eleventyNavigation:
+ key: how eslint is maintained
+ parent: maintain eslint
+ title: How ESLint is Maintained
+ order: 1
+
+---
+
+This page explains the different roles and structures involved in maintaining ESLint.
+
+## The ESLint Team
+
+The ESLint team works together to develop and maintain ESLint. To learn more about the different roles on the ESLint team, refer to [Governance](../contribute/governance). To see the current team members, refer to [Team](/team/).
+
+## Organization Structure
+
+ESLint is part of the [OpenJS Foundation](https://openjsf.org/), a nonprofit organization that supports open-source projects and communities in the JavaScript ecosystem.
+
+The OpenJS Foundation provides legal infrastructure for JavaScript projects like ESLint. It is the owner of the intellectual property related to ESLint, including copyrights and trademarks, and ensures the independence of the project. They are also a resource for ESLint if we need legal advice or representation.
+
+The OpenJS Foundation does not participate in the day-to-day functioning of ESLint.
+
+## Funding
+
+ESLint is funded through several sources, including:
+
+* [**Open Collective**](https://opencollective.com/eslint): A platform for financing open source projects.
+* [**GitHub Sponsors**](https://github.com/sponsors/eslint): A platform for funding open source projects associated with Github.
+* [**Tidelift**](https://tidelift.com/subscription/pkg/npm-eslint): A subscription service that lets enterprises manage and fund the open source projects that their organization uses.
+* [**Carbon Ads**](https://www.carbonads.net/open-source): Developer-centric advertising provider used on [eslint.org](https://eslint.org/).
+* [**Stackaid.us**](https://simulation.stackaid.us/github/eslint/eslint): Tool that developers can use to allocate funding to the open source projects they use.
+
+ESLint uses this funding for the following purposes:
+
+* Pay team members and contractors
+* Fund projects
+* Pay for services that keep ESLint running (web hosting, software subscriptions, etc.)
+* Provide financial support to our dependencies and ecosystem
+
+## Joining the Maintainer Team
+
+ESLint is an open-source project, and anyone can contribute to the project. If you're interested in becoming part of the maintainer team, stop by our [Discord](https://eslint.org/chat) and introduce yourself.
--- /dev/null
+---
+title: Review Pull Requests
+eleventyNavigation:
+ key: review pull requests
+ parent: maintain eslint
+ title: Review Pull Requests
+ order: 3
+
+---
+
+Pull requests are submitted frequently and represent our best opportunity to interact with the community. As such, it's important that pull requests are well-reviewed before being merged and that interactions on pull requests are positive.
+
+## Who Can Review Pull Requests?
+
+Anyone, both team members and the public, may leave comments on pull requests.
+
+## Reviewing a Pull Request
+
+When a pull request is opened, the bot will check the following:
+
+1. Has the submitter signed a CLA?
+1. Is the commit message summary in the correct format?
+1. Is the commit summary too long?
+
+The bot will add a comment specifying the problems that it finds. You do not need to look at the pull request any further until those problems have been addressed (there's no need to comment on the pull request to ask the submitter to do what the bot asked - that's why we have the bot!).
+
+Once the bot checks have been satisfied, you check the following:
+
+1. Double-check that the commit message tag ("Fix:", "New:", etc.) is correct based on the issue (or, if no issue is referenced, based on the stated problem).
+1. If the pull request makes a change to core, ensure that an issue exists and the pull request references the issue in the commit message.
+1. Does the code follow our conventions (including header comments, JSDoc comments, etc.)? If not, please leave that feedback and reference the [Code Conventions](../contribute/code-conventions) documentation.
+1. For code changes:
+ * Are there tests that verify the change? If not, please ask for them.
+ * Is documentation needed for the change? If yes, please ask the submitter to add the necessary documentation.
+1. Are there any automated testing errors? If yes, please ask the submitter to check on them.
+1. If you've reviewed the pull request and there are no outstanding issues, leave a comment "LGTM" to indicate your approval. If you would like someone else to verify the change, comment "LGTM but would like someone else to verify."
+
+**Note:** If you are a team member and you've left a comment on the pull request, please follow up to verify that your comments have been addressed.
+
+## Who Can Merge a Pull Request
+
+TSC members, Reviewers, Committers, and Website Team Members may merge pull requests, depending on the contents of the pull request.
+
+Website Team Members may merge a pull request in the `eslint.org` repository if it is:
+
+1. A documentation change
+1. A dependency upgrade
+1. A chore
+
+Committers may merge a pull request if it is a non-breaking change and is:
+
+1. A documentation change
+1. A bug fix (for either rules or core)
+1. A dependency upgrade
+1. Related to the build tool
+1. A chore
+
+In addition, committers may merge any non-breaking pull request if it has been approved by at least one TSC member.
+
+TSC members may merge all pull requests, including those that committers may merge.
+
+## When to Merge a Pull Request
+
+We use the "Merge" button to merge requests into the repository. Before merging a pull request, verify that:
+
+1. All comments have been addressed
+1. Any team members who made comments have verified that their concerns were addressed
+1. All automated tests are passing (never merge a pull request with failing tests)
+
+Be sure to say thank you to the submitter before merging, especially if they put a lot of work into the pull request.
+
+Team members may merge a pull request immediately if it:
+
+1. Makes a small documentation change
+1. Is a chore
+1. Fixes a block of other work on the repository (build-related, test-related, dependency-related, etc.)
+1. Is an important fix to get into a patch release
+
+Otherwise, team members should observe a waiting period before merging a pull request:
+
+* Wait **2 days** if the pull request was opened Monday through Friday.
+* Wait **3 days** if the pull request was opened on Saturday or Sunday.
+
+The waiting period ensures that other team members have a chance to review the pull request before it is merged.
+
+If the pull request was created from a branch on the `eslint/eslint` repository (as opposed to a fork), delete the branch after merging the pull request. (GitHub will display a "Delete branch" button after the pull request is merged.)
+
+**Note:** You should not merge your own pull request unless you're received feedback from at least one other team member.
+
+## When to Close a Pull Request
+
+There are several times when it's appropriate to close a pull request without merging:
+
+1. The pull request addresses an issue that is already fixed.
+1. The pull request hasn't been updated in 17 days.
+1. The pull request submitter isn't willing to follow project guidelines.
+
+In any of these cases, please be sure to leave a comment stating why the pull request is being closed.
+
+### Example Closing Comments
+
+If a pull request hasn't been updated in 17 days:
+
+> Closing because there hasn't been activity for 17 days. If you're still interested in submitting this code, please feel free to resubmit.
+
+If a pull request submitter isn't willing to follow project guidelines.
+
+> Unfortunately, we can't accept pull requests that don't follow our guidelines. I'm going to close this pull request now, but if you'd like to resubmit following our guidelines, we'll be happy to review.
--- /dev/null
+---
+title: Working Groups
+eleventyNavigation:
+ key: working groups
+ parent: maintain eslint
+ title: Working Groups
+ order: 5
+---
+
+The ESLint [Technical Steering Committee](../contribute/governance#technical-steering-committee-tsc) (TSC) may form working groups to focus on a specific area of the project.
+
+## Creating a Working Group
+
+Working groups are created by sending an email to the team mailing list. Each working group:
+
+1. Must have a GitHub team under the "ESLint Team" top-level GitHub team. (The GitHub team name should end with "WG" to distinguish it from other types of teams.)
+1. Must have at least one TSC member.
+1. May have any number of Committers and Reviewers.
+1. Must have at least two members.
+
+Active working groups are listed on the [team page](https://eslint.org/team).
+
+## How Working Groups Work
+
+Each working group is responsible for its own inner working. Working groups can decide how large or small they should be (so long as there is at least two members), when and who to add or remove from the working group, and how to accomplish their objectives.
+
+Working groups may be temporary or permanent.
+
+If working groups intend to make a significant change to the ESLint project, the proposal must still be approved by the TSC.
+++ /dev/null
----
-title: Governance
-layout: doc
-eleventyNavigation:
- key: governance
- parent: maintainer guide
- title: Governance
- order: 4
-
----
-
-ESLint is an open source project that depends on contributions from the community. Anyone may contribute to the project at any time by submitting code, participating in discussions, making suggestions, or any other contribution they see fit. This document describes how various types of contributors work within the ESLint project.
-
-## Roles and Responsibilities
-
-### Users
-
-Users are community members who have a need for the project. Anyone can be a User; there are no special requirements. Common User contributions include evangelizing the project (e.g., display a link on a website and raise awareness through word-of-mouth), informing developers of strengths and weaknesses from a new user perspective, or providing moral support (a "thank you" goes a long way).
-
-Users who continue to engage with the project and its community will often become more and more involved. Such Users may find themselves becoming Contributors, as described in the next section.
-
-### Contributors
-
-Contributors are community members who contribute in concrete ways to the project, most often in the form of code and/or documentation. Anyone can become a Contributor, and contributions can take many forms. There is no expectation of commitment to the project, no specific skill requirements, and no selection process.
-
-Contributors have read-only access to source code and so submit changes via pull requests. Contributor pull requests have their contribution reviewed and merged by a TSC member. TSC members and Committers work with Contributors to review their code and prepare it for merging.
-
-As Contributors gain experience and familiarity with the project, their profile within, and commitment to, the community will increase. At some stage, they may find themselves being nominated as either a Website Team Member or Committer by an existing Website Team Member or Committer.
-
-### Website Team Member
-
-Website Team Members are community members who have shown that they are committed to the continued maintenance of [eslint.org](https://eslint.org/) through ongoing engagement with the community. Website Team Members are given push access to the `eslint.org` GitHub repository and must abide by the project's [Contribution Guidelines](../developer-guide/contributing/).
-
- Website Team Members:
-
-* Are expected to work on public branches of the source repository and submit pull requests from that branch to the master branch.
-* Are expected to delete their public branches when they are no longer necessary.
-* Must submit pull requests for all changes.
-* Have their work reviewed by Reviewers and TSC members before acceptance into the repository.
-* May label and close website-related issues (see [Managing Issues](issues.html))
-* May merge some pull requests (see [Managing Pull Requests](pullrequests.html))
-
-To become a Website Team Member:
-
-* One must have shown a willingness and ability to participate in the maintenance of [eslint.org](https://eslint.org/) as a team player. Typically, a potential Website Team Member will need to show that they have an understanding of the structure of the website and how it fits into the larger ESLint project's objectives and strategy.
-* Website Team Members are expected to be respectful of every community member and to work collaboratively in the spirit of inclusion.
-* Have submitted a minimum of 10 website-related pull requests. What's a website-related pull request? One that is made to the `eslint.org` repository or the `docs` directory in the `eslint` repository and requires little effort to accept because it's well documented and tested.
-
-New Website Team Members can be nominated by any existing Website Team Member or Committer. Once they have been nominated, there will be a vote by the TSC members.
-
-It is important to recognize that membership on the website team is a privilege, not a right. That privilege must be earned and once earned it can be removed by the TSC members by a standard TSC motion. However, under normal circumstances Website Team Members remain for as long as they wish to continue engaging with the project.
-
-### Committers
-
-Committers are community members who have shown that they are committed to the continued development of the project through ongoing engagement with the community. Committers are given push access to the project's GitHub repos and must abide by the project's [Contribution Guidelines](../developer-guide/contributing/).
-
-Committers:
-
-* Are expected to work on public branches of the source repository and submit pull requests from that branch to the master branch.
-* Are expected to delete their public branches when they are no longer necessary.
-* Must submit pull requests for all changes.
-* Have their work reviewed by TSC members before acceptance into the repository.
-* May label and close issues (see [Managing Issues](issues.html))
-* May merge some pull requests (see [Managing Pull Requests](pullrequests.html))
-
-To become a Committer:
-
-* One must have shown a willingness and ability to participate in the project as a team player. Typically, a potential Committer will need to show that they have an understanding of and alignment with the project, its objectives, and its strategy.
-* Committers are expected to be respectful of every community member and to work collaboratively in the spirit of inclusion.
-* Have submitted a minimum of 10 qualifying pull requests. What's a qualifying pull request? One that carries significant technical weight and requires little effort to accept because it's well documented and tested.
-
-New Committers can be nominated by any existing Committer. Once they have been nominated, there will be a vote by the TSC members.
-
-It is important to recognize that committership is a privilege, not a right. That privilege must be earned and once earned it can be removed by the TSC members by a standard TSC motion. However, under normal circumstances committership exists for as long as the Committer wishes to continue engaging with the project.
-
-A Committer who shows an above-average level of contribution to the project, particularly with respect to its strategic direction and long-term health, may be nominated to become a reviewer, described below.
-
-#### Process for Adding Committers
-
-1. Send email congratulating the new committer and confirming that they would like to accept. This should also outline the responsibilities of a committer with a link to the maintainer guide.
-1. Add the GitHub user to the "ESLint Team" team
-1. Add committer email to the ESLint team mailing list
-1. Invite to Discord team channel
-1. Tweet congratulations to the new committer from the ESLint Twitter account
-
-### Reviewers
-
-Reviewers are community members who have contributed a significant amount of time to the project through triaging of issues, fixing bugs, implementing enhancements/features, and are trusted community leaders.
-
-Reviewers may perform all of the duties of Committers, and also:
-
-* May merge external pull requests for accepted issues upon reviewing and approving the changes.
-* May merge their own pull requests once they have collected the feedback they deem necessary. (No pull request should be merged without at least one Committer/Reviewer/TSC member comment stating they've looked at the code.)
-
-To become a Reviewer:
-
-* Work in a helpful and collaborative way with the community.
-* Have given good feedback on others' submissions and displayed an overall understanding of the code quality standards for the project.
-* Commit to being a part of the community for the long-term.
-* Have submitted a minimum of 50 qualifying pull requests.
-
-A Committer is invited to become a Reviewer by existing Reviewers and TSC members. A nomination will result in discussion and then a decision by the TSC.
-
-#### Process for Adding Reviewers
-
-1. Add the GitHub user to the "ESLint Reviewers" GitHub team
-1. Tweet congratulations to the new Reviewer from the ESLint Twitter account
-
-### Technical Steering Committee (TSC)
-
-The ESLint project is jointly governed by a Technical Steering Committee (TSC) which is responsible for high-level guidance of the project.
-
-The TSC has final authority over this project including:
-
-* Technical direction
-* Project governance and process (including this policy)
-* Contribution policy
-* GitHub repository hosting
-
-TSC seats are not time-limited. The size of the TSC can not be larger than five members. This size ensures adequate coverage of important areas of expertise balanced with the ability to make decisions efficiently.
-
-The TSC may add additional members to the TSC by a standard TSC motion.
-
-A TSC member may be removed from the TSC by voluntary resignation, by a standard TSC motion, or by missing four consecutive TSC meetings. In all cases, the TSC member will revert to Reviewer status unless they prefer Alumni status.
-
-Changes to TSC membership should be posted in the agenda, and may be suggested as any other agenda item (see "TSC Meetings" below).
-
-No more than 1/3 of the TSC members may be affiliated with the same employer. If removal or resignation of a TSC member, or a change of employment by a TSC member, creates a situation where more than 1/3 of the TSC membership shares an employer, then the situation must be immediately remedied by the resignation or removal of one or more TSC members affiliated with the over-represented employer(s).
-
-TSC members have additional responsibilities over and above those of a Reviewer. These responsibilities ensure the smooth running of the project. TSC members are expected to review code contributions, approve changes to this document, manage the copyrights within the project outputs, and attend regular TSC meetings.
-
-TSC members may perform all of the duties of Reviewers, and also:
-
-* May release new versions of all ESLint projects.
-* May participate in TSC meetings.
-* May propose budget items.
-* May propose new ESLint projects.
-
-There is no specific set of requirements or qualifications for TSC members beyond those that are expected of Reviewers.
-
-A Reviewer is invited to become a TSC member by existing TSC members. A nomination will result in discussion and then a decision by the TSC.
-
-#### Process for Adding TSC Members
-
-1. Add the GitHub user to the "ESLint TSC" GitHub team
-1. Set the GitHub user to be have the "Owner" role for the ESLint organization
-1. Send a welcome email with a link to the [maintainer guide](./) and instructions for npm 2FA.
-1. Invite to the Discord TSC channel
-1. Make the TSC member an admin on the ESLint team mailing list
-1. Add the TSC member to the recurring TSC meeting event on Google Calendar
-1. Add the TSC member as an admin to ESLint Twitter Account on Tweetdeck
-1. Add the TSC member to the ESLint TSC mailing list as an "Owner"
-1. Tweet congratulations to the new TSC member from the ESLint Twitter account
-
-#### TSC Meetings
-
-The TSC meets every other week in the TSC Meeting [Discord](https://eslint.org/chat) channel. The meeting is run by a designated moderator approved by the TSC.
-
-Items are added to the TSC agenda which are considered contentious or
-are modifications of governance, contribution policy, TSC membership,
-or release process.
-
-The intention of the agenda is not to approve or review all patches.
-That should happen continuously on GitHub and be handled by the larger
-group of Committers.
-
-Any community member, Committer, or Reviewer can ask that something be added to
-the next meeting's agenda by logging a GitHub Issue. Anyone can add the item to the agenda by adding
-the "tsc agenda" tag to the issue.
-
-Prior to each TSC meeting, the moderator will share the Agenda with
-members of the TSC. TSC members can add any items they like to the
-agenda at the beginning of each meeting. The moderator and the TSC
-cannot veto or remove items.
-
-No binding votes on TSC agenda items can take place without a quorum of
-TSC members present in the meeting. Quorum is achieved when more than
-half of the TSC members (minus non-attending members) are present.
-
-The TSC may invite persons or representatives from certain projects to
-participate in a non-voting capacity.
-
-The moderator is responsible for summarizing the discussion of each
-agenda item and sending it as a pull request after the meeting.
-
-## Consensus Seeking Process
-
-The TSC follows a
-[Consensus Seeking](https://en.wikipedia.org/wiki/Consensus-seeking_decision-making)
-decision making model.
-
-When an agenda item has appeared to reach a consensus, the moderator
-will ask "Does anyone object?" as a final call for dissent from the
-consensus.
-
-If an agenda item cannot reach a consensus, a TSC member can call for
-either a closing vote or a vote to table the issue to the next
-meeting. The call for a vote must be approved by a majority of the TSC
-or else the discussion will continue. Simple majority wins.
-
-----
-
-This work is a derivative of [YUI Contributor Model](https://github.com/yui/yui3/wiki/Contributor-Model) and the [Node.js Project Governance Model](https://github.com/nodejs/node/blob/master/GOVERNANCE.md).
-
-This work is licensed under a [Creative Commons Attribution-ShareAlike 2.0 UK: England & Wales License](https://creativecommons.org/licenses/by-sa/2.0/uk/).
+++ /dev/null
----
-title: Maintainer Guide
-layout: doc
-eleventyNavigation:
- key: maintainer guide
- title: Maintainer Guide
- order: 3
-
----
-
-This guide is intended for those who work as part of the ESLint project team.
-
-## [Managing Issues](issues)
-
-Describes how to deal with issues when they're opened, when interacting with users, and how to close them effectively.
-
-## [Reviewing Pull Requests](pullrequests)
-
-Describes how to review incoming pull requests.
-
-## [Managing Releases](releases)
-
-Describes how to do an ESLint project release.
-
-## [Governance](governance)
-
-Describes the governance policy for ESLint, including the rights and privileges of individuals inside the project.
-
-## [Working Groups](working-groups)
-
-Describes how working groups are created and how they function within the ESLint project.
+++ /dev/null
----
-title: Managing Issues
-layout: doc
-eleventyNavigation:
- key: managing issues
- parent: maintainer guide
- title: Managing Issues
- order: 1
-
----
-
-New issues are filed frequently, and how we respond to those issues directly affects the success of the project. Being part of the project team means helping to triage and address issues as they come in so the project can continue to run smoothly.
-
-## Things to Keep in Mind
-
-1. **Be nice.** Even if the people are being rude or aggressive on an issue, as a project team member you must be the mature one in the conversation. Do your best to work with everyone no matter their style. Remember, poor wording choice can also be a sign of someone who doesn't know English very well, so be sure to consider that when trying to determine the tone of someone's message. Being rude, even when someone is being rude to you, reflects poorly on the team and the project as a whole.
-1. **Be inquisitive.** Ask questions on the issue whenever something isn't clear. Don't assume you understand what's being reported if there are details missing. Whenever you are unsure, it's best to ask for more information.
-1. **Not all requests are equal.** It's unlikely we'll be able to accommodate every request, so don't be afraid to say that something doesn't fit into the scope of the project or isn't practical. It's better to give such feedback if that's the case.
-1. **Close when appropriate.** Don't be afraid to close issues that you don't think will be done, or when it's become clear from the conversation that there's no further work to do. Issues can always be reopened if they are closed incorrectly, so feel free to close issues when appropriate. Just be sure to leave a comment explaining why the issue is being closed (if not closed by a commit).
-
-## Types of Issues
-
-There are four primary issue categories:
-
-1. **Bug** - something isn't working the way it's expected to work.
-1. **Enhancement** - a change to something that already exists. For instance, adding a new option to an existing rule or a bug in a rule where fixing it will result in the rule reporting more problems (in this case, use both "Bug" and "Enhancement").
-1. **Feature** - adding something that doesn't already exist. For example, adding a new rule, new formatter, or new command line flag.
-1. **Question** - an inquiry about how something works that won't result in a code change. We'd prefer if people use the mailing list or chatroom for questions, but sometimes they'll open an issue.
-
-The first goal when evaluating an issue is to determine which category the issue falls into.
-
-## Triaging Process
-
-All of ESLint's issues, across all GitHub repositories, are managed on our [Triage Project](https://github.com/orgs/eslint/projects/2). Please use the Triage project instead of the issues list when reviewing issues to determine what to work on. The Triage project has several columns:
-
-* **Needs Triage** - issues that have not yet been reviewed by anyone
-* **Triaging** - issues that someone has reviewed but has not been able to fully triage yet
-* **Ready for Dev Team** - issues that have been triaged and have all of the information necessary for the dev team to take a look
-* **Evaluating** - the dev team is evaluating these issues to determine whether to move forward or not
-* **Feedback Needed** - a team member is requesting more input from the rest of the team before proceeding
-* **Waiting for RFC** - the next step in the process is for an RFC to be written
-* **RFC Opened** - an RFC is opened to address these issues
-* **Blocked** - the issue can't move forward due to some dependency
-* **Ready to Implement** - these issues have all of the details necessary to start implementation
-* **PR Opened** - there is an open pull request for each of these issues
-* **Completed** - the issue has been closed (either via pull request merge or by the team manually closing the issue)
-
-We make every attempt to automate movement between as many columns as we can, but sometimes moving issues needs to be done manually.
-
-### When an Issue is Opened
-
-When an issue is opened, it is automatically added to the "Needs Triage" column in the Triage project. These issues need to be evaluated to determine next steps. Anyone on the support team or dev team can follow these steps to properly triage issues.
-
-**Note:** If an issue is in the "Triaging" column, that means someone is already triaging it and you should let them finish. There's no need to comment on issues in the "Triaging" column unless someone asks for help.
-
-The steps for triaging an issue are:
-
-1. Move the issue from "Needs Triage" to "Triaging" in the Triage project
-1. Check: Has all of the information in the issue template been provided?
- * **No:** If information is missing from the issue template, or you can't tell what is being requested, please ask the author to provide the missing information:
- * Add the "needs info" label to the issue so we know that this issue is stalled due to lack of information.
- * Don't move on to other steps until the necessary information has been provided.
- * If the issue author hasn't provided the necessary information after 7 days, please close the issue. The bot will add a comment stating that the issue was closed because there was information missing.
- * **Yes:**
- * If the issue is actually a question (rather than something the dev team needs to change), please [convert it to a discussion](https://docs.github.com/en/free-pro-team@latest/discussions/managing-discussions-for-your-community/moderating-discussions#converting-an-issue-to-a-discussion). You can continue the conversation as a discussion.
- * If the issue is reporting a bug, try to reproduce the issue following the instructions in the issue. If you can reproduce the bug, please add the "repro:yes" label. (The bot will automatically remove the "repro:needed" label.) If you can't reproduce the bug, ask the author for more information about their environment or to clarify reproduction steps.
- * If the issue is reporting something that works as intended, please add the "works as intended" label and close the issue.
- * For all issues, please add labels describing the part of ESLint affected:
- * "3rd party plugin" - related to third-party functionality (plugins, parsers, rules, etc.)
- * "build" - related to commands run during a build (testing, linting, release scripts, etc.)
- * "cli" - related to command line input or output, or to `CLIEngine`
- * "core" - related to internal APIs
- * "documentation" - related to content on eslint.org
- * "infrastructure" - related to resources needed for builds or deployment (VMs, CI tools, bots, etc.)
- * "rule" - related to core rules
- * If you can't properly triage the issue, move the issue back to the "Needs Triage" column in the Triage project so someone else can triage it
- * If you have triaged the issue, move the issue to the "Ready for Dev Team" column in the Triage project
-
-## Evaluation Process
-
-When an issue has been moved to the "Ready for Dev Team" column, any dev team member can pick up the issue to start evaluating it.
-
-1. Move the issue into the "Evaluating" column.
-1. Next steps:
- * **Bugs:** if you can verify the bug, add the "accepted" label and ask if they would like to submit a pull request.
- * **New Rules:** if you are willing to champion the rule (meaning you believe it should be included in ESLint core and you will take ownership of the process for including it), add a comment saying you will champion the issue, assign the issue to yourself, and follow the [guidelines](#championing-issues) below.
- * **Rule Changes:** if you are willing to champion the change and it would not be a breaking change (requiring a major version increment), add a comment saying that you will champion the issue, assign the issue to yourself, and follow the [guidelines](#championing-issues) below.
- * **Breaking Changes:** if you suspect or can verify that a change would be breaking, label it as "Breaking".
- * **Duplicates:** if you can verify the issue is a duplicate, add a comment mentioning the duplicate issue (such as, "Duplicate of #1234") and close the issue.
-1. Regardless of the above, always leave a comment. Don't just add labels, engage with the person who opened the issue by asking a question (request more information if necessary) or stating your opinion of the issue. If it's a verified bug, ask if the user would like to submit a pull request.
-1. If the issue can't be implemented because it needs an external dependency to be updated or needs to wait for another issue to be resolved, move the issue to the "Blocked" column.
-1. If the issue has been accepted and an RFC is required as the next step, move the issue to the "Waiting for RFC" column and comment on the issue that an RFC is needed.
-
-**Note:** "Good first issue" issues are intended to help new contributors feel welcome and empowered to make a contribution to ESLint. To ensure that new contributors are given a chance to work on these issues, issues labeled "good first issue" must be open for 30 days *from the day the issue was labeled* before a team member is permitted to work on them.
-
-## Accepting Issues
-
-Issues may be labeled as "accepted" when the issue is:
-
-* A bug that you've been able to reproduce and verify (i.e. you're sure it's a bug)
-* A new rule or rule change that you're championing and [consensus](#consensus) has been reached for its inclusion in the project
-
-The "accepted" label will be added to other issues by a TSC member if it's appropriate for the roadmap.
-
-When an issue is accepted and implementation can begin, it should be moved to the "Ready to Implement" column.
-
-## Championing Issues
-
-New rules and rule changes require a champion. As champion, it's your job to:
-
-* Gain [consensus](#consensus) from the ESLint team on inclusion
-* Guide the rule creation process until it's complete (so only champion a rule that you have time to implement or help another contributor implement)
-
-Once consensus has been reached on inclusion, add the "accepted" and, optionally, "help wanted" and "good first issue" labels, as necessary.
-
-## Consensus
-
-Consensus is reached on issues when there are at least three team members who believe the change is a good idea and no one who believes the change is a bad idea. In order to indicate your support for an issue, leave a +1 reaction (thumbs up) on the original issue description in addition to any comments you might have.
-
-## When to Send to TSC
-
-If consensus cannot be reached on an issue, or an issue's progress has been stalled and it's not clear if the issue should be closed, then you can refer the issue to the TSC for resolution. To do so, add the "tsc agenda" label to the issue and add a comment including the following information:
-
-1. A one-paragraph summary of the discussion to this point.
-2. The question you would like the TSC to answer.
-
-The issue will be discussed at the next TSC meeting and the resolution will be posted back to the issue.
-
-## Evaluating Core Features and Enhancements (TSC members only)
-
-In addition to the above, changes to the core (including CLI changes) that would result in a minor or major version release must be approved by the TSC by standard TSC motion. Add the label "tsc agenda" to the issue and it will be discussed at the next TSC meeting. In general, requests should meet the following criteria to be considered:
-
-1. The feature or enhancement is in scope for the project and should be added to the roadmap
-1. Someone is committed to including the change within the next year
-1. There is reasonable certainty about who will do the work
-
-When a suggestion is too ambitious or would take too much time to complete, it's better not to accept the proposal. Stick to small, incremental changes and lay out a roadmap of where you'd like the project to go eventually. Don't let the project get bogged down in big features that will take a long time to complete.
-
-**Breaking Changes:** Be on the lookout for changes that would be breaking. Issues that represent breaking changes should be labeled as "breaking".
-
-## When to Close an Issue
-
-All team members are allowed to close issues depending on how the issue has been resolved.
-
-Team members may close an issue **immediately** if:
-
-1. The issue is a duplicate of an existing issue.
-1. The issue is just a question and has been answered.
-
-Team members may close an issue where the consensus is to not accept the issue after a waiting period (to ensure that other team members have a chance to review the issue before it is closed):
-
-* Wait **2 days** if the issue was opened Monday through Friday.
-* Wait **3 days** if the issue was opened on Saturday or Sunday.
-
-In an effort to keep the issues backlog manageable, team members may also close an issue if the following conditions are met:
-
-* **Unaccepted**: Close after it has been open for 21 days, as these issues do not have enough support to move forward.
-* **Accepted**: Close after 90 days if no one from the team or the community is willing to step forward and own the work to complete to it.
-* **Help wanted:** Close after 90 days if it has not been completed.
+++ /dev/null
----
-title: Reviewing Pull Requests
-layout: doc
-eleventyNavigation:
- key: reviewing pull requests
- parent: maintainer guide
- title: Reviewing Pull Requests
- order: 2
-
----
-
-Pull requests are submitted frequently and represent our best opportunity to interact with the community. As such, it's important that pull requests are well-reviewed before being merged and that interactions on pull requests are positive.
-
-## Who Can Review Pull Requests?
-
-Anyone, both team members and the public, may leave comments on pull requests.
-
-## Reviewing a Pull Request
-
-When a pull request is opened, the bot will check the following:
-
-1. Has the submitter signed a CLA?
-1. Is the commit message summary in the correct format?
-1. Is the commit summary too long?
-
-The bot will add a comment specifying the problems that it finds. You do not need to look at the pull request any further until those problems have been addressed (there's no need to comment on the pull request to ask the submitter to do what the bot asked - that's why we have the bot!).
-
-Once the bot checks have been satisfied, you check the following:
-
-1. Double-check that the commit message tag ("Fix:", "New:", etc.) is correct based on the issue (or, if no issue is referenced, based on the stated problem).
-1. If the pull request makes a change to core, ensure that an issue exists and the pull request references the issue in the commit message.
-1. Does the code follow our conventions (including header comments, JSDoc comments, etc.)? If not, please leave that feedback and reference the conventions document.
-1. For code changes:
- * Are there tests that verify the change? If not, please ask for them.
- * Is documentation needed for the change? If yes, please let the submitter know.
-1. Are there any automated testing errors? If yes, please ask the submitter to check on them.
-1. If you've reviewed the pull request and there are no outstanding issues, leave a comment "LGTM" to indicate your approval. If you would like someone else to verify the change, comment "LGTM but would like someone else to verify."
-
-**Note:** If you are a team member and you've left a comment on the pull request, please follow up to verify that your comments have been addressed.
-
-## Who Can Merge a Pull Request
-
-TSC members, Reviewers, Committers, and Website Team Members may merge pull requests, depending on the contents of the pull request.
-
-Website Team Members may merge a pull request in the `eslint.org` repository if it is:
-
-1. A documentation change
-1. A dependency upgrade
-1. A chore
-
-Committers may merge a pull request if it is a non-breaking change and is:
-
-1. A documentation change
-1. A bug fix (for either rules or core)
-1. A dependency upgrade
-1. Related to the build tool
-1. A chore
-
-In addition, committers may merge any non-breaking pull request if it has been approved by at least one TSC member.
-
-TSC members may merge all pull requests, including those that committers may merge.
-
-## When to Merge a Pull Request
-
-We use the "Merge" button to merge requests into the repository. Before merging a pull request, verify that:
-
-1. All comments have been addressed
-1. Any team members who made comments have verified that their concerns were addressed
-1. All automated tests are passing (never merge a pull request with failing tests)
-
-Be sure to say thank you to the submitter before merging, especially if they put a lot of work into the pull request.
-
-Team members may merge a pull request immediately if it:
-
-1. Makes a small documentation change
-1. Is a chore
-1. Fixes a block of other work on the repository (build-related, test-related, dependency-related, etc.)
-1. Is an important fix to get into a patch release
-
-Otherwise, team members should observe a waiting period before merging a pull request:
-
-* Wait **2 days** if the pull request was opened Monday through Friday.
-* Wait **3 days** if the pull request was opened on Saturday or Sunday.
-
-The waiting period ensures that other team members have a chance to review the pull request before it is merged.
-
-If the pull request was created from a branch on the `eslint/eslint` repository (as opposed to a fork), delete the branch after merging the pull request. (GitHub will display a "Delete branch" button after the pull request is merged.)
-
-**Note:** You should not merge your own pull request unless you're received feedback from at least one other team member.
-
-## When to Close a Pull Request
-
-There are several times when it's appropriate to close a pull request without merging:
-
-1. The pull request addresses an issue that is already fixed
-1. The pull request hasn't been updated in 30 days
-1. The pull request submitter isn't willing to follow project guidelines.
-
-In any of these cases, please be sure to leave a comment stating why the pull request is being closed.
-
-### Example Closing Comments
-
-If a pull request hasn't been updated in 30 days:
-
-> Closing because there hasn't been activity for 30 days. If you're still interested in submitting this code, please feel free to resubmit.
-
-If a pull request submitter isn't willing to follow project guidelines.
-
-> Unfortunately, we can't accept pull requests that don't follow our guidelines. I'm going to close this pull request now, but if you'd like to resubmit following our guidelines, we'll be happy to review.
+++ /dev/null
----
-title: Managing Releases
-layout: doc
-eleventyNavigation:
- key: managing releases
- parent: maintainer guide
- title: Managing Releases
- order: 3
-
----
-
-Releases are when a project formally publishes a new version so the community can use it. There are two types of releases:
-
-* Regular releases that follow [semantic versioning](https://semver.org/) and are considered production-ready.
-* Prereleases that are not considered production-ready and are intended to give the community a preview of upcoming changes.
-
-## Release Team
-
-A two-person release team is assigned to each scheduled release. This two-person team is responsible for:
-
-1. The scheduled release on Friday
-1. Monitoring issues over the weekend
-1. Determining if a patch release is necessary on Monday
-1. Publishing the patch release (if necessary)
-
-The two-person team should seek input from the whole team on the Monday following a release to double-check if a patch release is necessary.
-
-At least one member of the release team needs to have access to eslint's two-factor authentication for npm in order to do a release.
-
-## Release Communication
-
-Each scheduled release should be associated with a release issue ([example](https://github.com/eslint/eslint/issues/8138)). The release issue is the source of information for the team about the status of a release. Be sure the release issue has the "release" label so that it's easy to find.
-
-## Process
-
-On the day of a scheduled release, the release team should follow these steps:
-
-1. Review open pull requests to see if any should be merged. In general, you can merge pull requests that:
- * Have been open at least two days and have been reviewed (these are just waiting for merge).
- * Important pull requests (as determined by the team). You should stop and have people review before merging if they haven't been already.
- * Documentation changes.
- * Small bugfixes written by a team member.
-1. Log into Jenkins and schedule a build for the "ESLint Release" job.
-1. Watch the console output of the build on Jenkins. At some point, the build will pause and a link will be produced with an input field for a six-digit 2FA code.
-1. Enter the current six-digit 2FA code from your authenticator app.
-1. Continue the build and wait for it to finish.
-1. Update the release blog post with a "Highlights" section, including new rules and anything else that's important.
-1. Make a release announcement in the public chatroom.
-1. Make a release announcement on Twitter.
-1. Make a release announcement on the release issue. Document any problems that occurred during the release, and remind the team not to merge anything other than documentation changes and bugfixes. Leave the release issue open.
-1. Add the `patch release pending` label to the release issue. (When this label is present, `eslint-github-bot` will create a pending status check on non-semver-patch pull requests, to ensure that they aren't accidentally merged while a patch release is pending.)
-
-On the Monday following the scheduled release, the release team needs to determine if a patch release is necessary. A patch release is considered necessary if any of the following occurred since the scheduled release:
-
-* A regression bug is causing people's lint builds to fail when it previously passed.
-* Any bug that is causing a lot of problems for users (frequently happens due to new functionality).
-
-The patch release decision should be made as early on Monday as possible. If a patch release is necessary, then follow the same steps as the scheduled release process.
-
-In rare cases, a second patch release might be necessary if the release is known to have a severe regression that hasn't been fixed by Monday. If this occurs, the release team should announce the situation on the release issue, and leave the issue open until all patch releases are complete. However, it's usually better to fix bugs for the next release cycle rather than doing a second patch release.
-
-After the patch release has been published (or no patch release is necessary), close the release issue and inform the team that they can start merging in semver-minor changes again.
-
-## Emergency Releases
-
-In general, we try not to do emergency releases (an emergency release is unplanned and isn't the regularly scheduled release or the anticipated patch release). Even if there is a regression, it's best to wait the weekend to see if any other problems arise so a patch release can fix as many issues as possible.
-
-The only real exception is if ESLint is completely unusable by most of the current users. For instance, we once pushed a release that errored for everyone because it was missing some core files. In that case, an emergency release is appropriate.
+++ /dev/null
----
-title: Working Groups
-layout: doc
-
----
-
-The ESLint TSC may form working groups to focus on a specific area of the project.
-
-## Creating a Working Group
-
-Working groups are created by sending an email to the team mailing list. Each working group:
-
-1. Must have a GitHub team under the "ESLint Team" top-level GitHub team. (The GitHub team name should end with "WG" to distinguish it from other types of teams.)
-1. Must have at least one TSC member.
-1. May have any number of Committers and Reviewers.
-1. Must have at least two members.
-
-Active working groups are listed on the [team page](https://eslint.org/team).
-
-## How Working Groups Work
-
-Each working group is responsible for its own inner working. Working groups can decide how large or small they should be (so long as there is at least two members), when and who to add or remove from the working group, and how to accomplish their objectives.
-
-Working groups may be temporary or permanent.
-
-If working groups intend to make a significant change to the ESLint project, the proposal must still be approved by the TSC.
---
title: Documentation
-layout: doc
permalink: /index.html
---
Welcome to our documentation pages! What would you like to view?
-## [User Guide](user-guide/)
+## [Use ESLint in Your Project](use/)
Intended for end users of ESLint. Contains information about core rules, configuration, command line options, formatters, and integrations,
as well as guides for migrating from earlier versions of ESLint.
-## [Developer Guide](developer-guide/)
+## [Extend ESLint](extend/)
-Intended for contributors to ESLint and people who wish to extend ESLint. Contains information about contributing to ESLint; creating custom
-rules, configurations, plugins, and formatters; and information about our architecture and Node.js API.
+Intended for people who wish to extend ESLint. Contains information about creating custom rules, configurations, plugins, and formatters; and information about our Node.js API.
-## [Maintainer Guide](maintainer-guide/)
+## [Contribute to ESLint](contribute/)
+
+Intended for people who wish to contribute to the ESLint project. Contains information about ways you can contribute, the project structure, and setting up the development environment.
+
+## [Maintain ESLint](maintain/)
Intended for maintainers of ESLint.
---
-title: Rules
-layout: doc
+title: Rules Reference
permalink: /rules/index.html
eleventyNavigation:
key: rules
- parent: user guide
- title: Rules
- order: 4
+ parent: use eslint
+ title: Rules Reference
+ order: 5
---
{% from 'components/rule-categories.macro.html' import ruleCategories, recommended, fixable, hasSuggestions %}
---
title: accessor-pairs
-layout: doc
rule_type: suggestion
related_rules:
- no-dupe-keys
---
title: array-bracket-newline
-layout: doc
rule_type: layout
related_rules:
- array-bracket-spacing
---
title: array-bracket-spacing
-layout: doc
rule_type: layout
related_rules:
- space-in-parens
---
title: array-callback-return
-layout: doc
rule_type: problem
---
* [`Array.prototype.filter`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.filter)
* [`Array.prototype.find`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.find)
* [`Array.prototype.findIndex`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.findindex)
+* [`Array.prototype.findLast`](https://tc39.es/ecma262/#sec-array.prototype.findlast)
+* [`Array.prototype.findLastIndex`](https://tc39.es/ecma262/#sec-array.prototype.findlastindex)
* [`Array.prototype.flatMap`](https://www.ecma-international.org/ecma-262/10.0/#sec-array.prototype.flatmap)
* [`Array.prototype.forEach`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.foreach) (optional, based on `checkForEach` parameter)
* [`Array.prototype.map`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.map)
* [`Array.prototype.reduceRight`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.reduceright)
* [`Array.prototype.some`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.some)
* [`Array.prototype.sort`](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.sort)
+* [`Array.prototype.toSorted`](https://tc39.es/ecma262/#sec-array.prototype.tosorted)
* And above of typed arrays.
Examples of **incorrect** code for this rule:
---
title: array-element-newline
-layout: doc
rule_type: layout
related_rules:
- array-bracket-spacing
---
title: arrow-body-style
-layout: doc
rule_type: suggestion
---
---
title: arrow-parens
-layout: doc
rule_type: layout
further_reading:
- https://github.com/airbnb/javascript#arrows--one-arg-parens
if ((a) => b) {
console.log('truthy value returned');
} else {
- console.log('falsey value returned');
+ console.log('falsy value returned');
}
// outputs 'truthy value returned'
```
---
title: arrow-spacing
-layout: doc
rule_type: layout
---
---
title: block-scoped-var
-layout: doc
rule_type: suggestion
further_reading:
- https://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
---
title: block-spacing
-layout: doc
rule_type: layout
related_rules:
- space-before-blocks
---
title: brace-style
-layout: doc
rule_type: layout
related_rules:
- block-spacing
---
title: callback-return
-layout: doc
rule_type: suggestion
related_rules:
- handle-callback-err
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
The callback pattern is at the heart of most I/O and event-driven programming
in JavaScript.
---
title: camelcase
-layout: doc
rule_type: suggestion
---
var obj = {
my_pref: 1
};
+
+obj.foo_bar = "baz";
```
:::
---
title: capitalized-comments
-layout: doc
rule_type: suggestion
---
---
title: class-methods-use-this
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
"class-methods-use-this": [<enabled>, { "exceptMethods": [<...exceptions>] }]
```
-The `exceptMethods` option allows you to pass an array of method names for which you would like to ignore warnings. For example, you might have a spec from an external library that requires you to overwrite a method as a regular function (and not as a static method) and does not use `this` inside the function body. In this case, you can add that method to ignore in the warnings.
+The `"exceptMethods"` option allows you to pass an array of method names for which you would like to ignore warnings. For example, you might have a spec from an external library that requires you to overwrite a method as a regular function (and not as a static method) and does not use `this` inside the function body. In this case, you can add that method to ignore in the warnings.
-Examples of **incorrect** code for this rule when used without exceptMethods:
+Examples of **incorrect** code for this rule when used without `"exceptMethods"`:
::: incorrect
---
title: comma-dangle
-layout: doc
rule_type: layout
---
---
title: comma-spacing
-layout: doc
rule_type: layout
related_rules:
- array-bracket-spacing
---
title: comma-style
-layout: doc
rule_type: layout
related_rules:
- operator-linebreak
---
title: complexity
-layout: doc
rule_type: suggestion
related_rules:
- max-depth
---
title: computed-property-spacing
-layout: doc
rule_type: layout
related_rules:
- array-bracket-spacing
---
title: consistent-return
-layout: doc
rule_type: suggestion
---
---
title: consistent-this
-layout: doc
rule_type: suggestion
---
---
title: constructor-super
-layout: doc
rule_type: problem
---
---
title: curly
-layout: doc
rule_type: suggestion
---
---
title: default-case-last
-layout: doc
rule_type: suggestion
related_rules:
- default-case
---
title: default-case
-layout: doc
rule_type: suggestion
related_rules:
- no-fallthrough
---
title: default-param-last
-layout: doc
rule_type: suggestion
---
---
title: dot-location
-layout: doc
rule_type: layout
related_rules:
- newline-after-var
---
title: dot-notation
-layout: doc
rule_type: suggestion
---
---
title: eol-last
-layout: doc
rule_type: layout
---
---
title: eqeqeq
-layout: doc
rule_type: suggestion
---
### allow-null
-**Deprecated:** Instead of using this option use "always" and pass a "null" option property with value "ignore". This will tell ESLint to always enforce strict equality except when comparing with the `null` literal.
+**Deprecated:** Instead of using this option use `"always"` and pass a `"null"` option property with value `"ignore"`. This will tell ESLint to always enforce strict equality except when comparing with the `null` literal.
```js
["error", "always", {"null": "ignore"}]
---
title: for-direction
-layout: doc
rule_type: problem
---
---
title: func-call-spacing
-layout: doc
rule_type: layout
related_rules:
- no-spaced-func
---
title: func-name-matching
-layout: doc
rule_type: suggestion
---
## Options
-This rule takes an optional string of "always" or "never" (when omitted, it defaults to "always"), and an optional options object with two properties `considerPropertyDescriptor` and `includeCommonJSModuleExports`.
+This rule takes an optional string of `"always"` or `"never"` (when omitted, it defaults to `"always"`), and an optional options object with two properties `considerPropertyDescriptor` and `includeCommonJSModuleExports`.
### considerPropertyDescriptor
---
title: func-names
-layout: doc
rule_type: suggestion
further_reading:
- https://web.archive.org/web/20201112040809/http://markdaggett.com/blog/2013/02/15/functions-explained/
---
title: func-style
-layout: doc
rule_type: suggestion
further_reading:
- https://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
---
title: function-call-argument-newline
-layout: doc
rule_type: layout
related_rules:
- function-paren-newline
---
title: function-paren-newline
-layout: doc
rule_type: layout
---
---
title: generator-star-spacing
-layout: doc
rule_type: layout
further_reading:
- https://leanpub.com/understandinges6/read/#leanpub-auto-generators
## Options
-The rule takes one option, an object, which has two keys `before` and `after` having boolean values `true` or `false`.
+The rule takes one option, an object, which has two keys `"before"` and `"after"` having boolean values `true` or `false`.
-* `before` enforces spacing between the `*` and the `function` keyword.
+* `"before"` enforces spacing between the `*` and the `function` keyword.
If it is `true`, a space is required, otherwise spaces are disallowed.
In object literal shorthand methods, spacing before the `*` is not checked, as they lack a `function` keyword.
-* `after` enforces spacing between the `*` and the function name (or the opening parenthesis for anonymous generator functions).
+* `"after"` enforces spacing between the `*` and the function name (or the opening parenthesis for anonymous generator functions).
If it is `true`, a space is required, otherwise spaces are disallowed.
The default is `{"before": true, "after": false}`.
}]
```
-In the example configuration above, the top level "before" and "after" options define the default behavior of
-the rule, while the "anonymous" and "method" options override the default behavior.
-Overrides can be either an object with "before" and "after", or a shorthand string as above.
+In the example configuration above, the top level `"before"` and `"after"` options define the default behavior of
+the rule, while the `"anonymous"` and `"method"` options override the default behavior.
+Overrides can be either an object with `"before"` and `"after"`, or a shorthand string as above.
## Examples
---
title: generator-star
-layout: doc
further_reading:
- https://leanpub.com/understandinges6/read/#leanpub-auto-generators
---
---
title: getter-return
-layout: doc
rule_type: problem
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
---
title: global-require
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
In Node.js, module dependencies are included using the `require()` function, such as:
---
title: global-strict
-layout: doc
---
---
title: grouped-accessor-pairs
-layout: doc
rule_type: suggestion
related_rules:
- accessor-pairs
---
title: guard-for-in
-layout: doc
rule_type: suggestion
related_rules:
+- prefer-object-has-own
- no-prototype-builtins
further_reading:
- https://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/
}
```
+For codebases that do not support ES2022, `Object.prototype.hasOwnProperty.call(foo, key)` can be used as a check that the property is not inherited.
+
+For codebases that do support ES2022, `Object.hasOwn(foo, key)` can be used as a shorter alternative; see [prefer-object-has-own](prefer-object-has-own).
+
Note that simply checking `foo.hasOwnProperty(key)` is likely to cause an error in some cases; see [no-prototype-builtins](no-prototype-builtins).
## Rule Details
```js
/*eslint guard-for-in: "error"*/
+for (key in foo) {
+ if (Object.hasOwn(foo, key)) {
+ doSomething(key);
+ }
+}
+
for (key in foo) {
if (Object.prototype.hasOwnProperty.call(foo, key)) {
doSomething(key);
---
title: handle-callback-err
-layout: doc
rule_type: suggestion
further_reading:
- https://github.com/maxogden/art-of-node#callbacks
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
In Node.js, a common pattern for dealing with asynchronous behavior is called the callback pattern.
This pattern expects an `Error` object or `null` as the first argument of the callback.
---
title: id-blacklist
-layout: doc
rule_type: suggestion
---
---
title: id-denylist
-layout: doc
rule_type: suggestion
---
}
```
-**Note:** The first element of the array is for the rule severity (see [configuring rules](/docs/latest/user-guide/configuring/rules). The other elements in the array are the identifiers that you want to disallow.
+**Note:** The first element of the array is for the rule severity (see [Configure Rules](../use/configure/rules). The other elements in the array are the identifiers that you want to disallow.
Examples of **incorrect** code for this rule with sample `"data", "callback"` restricted identifiers:
---
title: id-length
-layout: doc
rule_type: suggestion
related_rules:
- max-len
This rule enforces a minimum and/or maximum identifier length convention.
+This rule counts [graphemes](https://unicode.org/reports/tr29/#Default_Grapheme_Cluster_Table) instead of using [`String length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length).
+
## Options
Examples of **incorrect** code for this rule with the default options:
---
title: id-match
-layout: doc
rule_type: suggestion
---
* `"properties": false` (default) does not check object properties
* `"properties": true` requires object literal properties and member expression assignment properties to match the specified regular expression
-* `"classFields": false` (default) does not class field names
+* `"classFields": false` (default) does not check class field names
* `"classFields": true` requires class field names to match the specified regular expression
* `"onlyDeclarations": false` (default) requires all variable names to match the specified regular expression
-* `"onlyDeclarations": true` requires only `var`, `function`, and `class` declarations to match the specified regular expression
+* `"onlyDeclarations": true` requires only `var`, `const`, `let`, `function`, and `class` declarations to match the specified regular expression
* `"ignoreDestructuring": false` (default) enforces `id-match` for destructured identifiers
* `"ignoreDestructuring": true` does not check destructured identifiers
---
title: implicit-arrow-linebreak
-layout: doc
rule_type: layout
related_rules:
- brace-style
---
title: indent-legacy
-layout: doc
rule_type: layout
---
This rule was **deprecated** in ESLint v4.0.0.
-ESLint 4.0.0 introduced a rewrite of the [`indent`](/docs/rules/indent) rule, which now reports more errors than it did in previous versions. To ease the process of migrating to 4.0.0, the `indent-legacy` rule was introduced as a snapshot of the `indent` rule from ESLint 3.x. If your build is failing after the upgrade to 4.0.0, you can disable `indent` and enable `indent-legacy` as a quick fix. Eventually, you should switch back to the `indent` rule to get bugfixes and improvements in future versions.
+ESLint 4.0.0 introduced a rewrite of the [`indent`](indent) rule, which now reports more errors than it did in previous versions. To ease the process of migrating to 4.0.0, the `indent-legacy` rule was introduced as a snapshot of the `indent` rule from ESLint 3.x. If your build is failing after the upgrade to 4.0.0, you can disable `indent` and enable `indent-legacy` as a quick fix. Eventually, you should switch back to the `indent` rule to get bugfixes and improvements in future versions.
---
---
title: indent
-layout: doc
rule_type: layout
---
This rule has an object option:
-* `"ignoredNodes"` can be used to disable indentation checking for any AST node. This accepts an array of [selectors](/docs/developer-guide/selectors). If an AST node is matched by any of the selectors, the indentation of tokens which are direct children of that node will be ignored. This can be used as an escape hatch to relax the rule if you disagree with the indentation that it enforces for a particular syntactic pattern.
+* `"ignoredNodes"` can be used to disable indentation checking for any AST node. This accepts an array of [selectors](../extend/selectors). If an AST node is matched by any of the selectors, the indentation of tokens which are direct children of that node will be ignored. This can be used as an escape hatch to relax the rule if you disagree with the indentation that it enforces for a particular syntactic pattern.
* `"SwitchCase"` (default: 0) enforces indentation level for `case` clauses in `switch` statements
* `"VariableDeclarator"` (default: 1) enforces indentation level for `var` declarators; can also take an object to define separate rules for `var`, `let` and `const` declarations. It can also be `"first"`, indicating all the declarators should be aligned with the first declarator.
* `"outerIIFEBody"` (default: 1) enforces indentation level for file-level IIFEs. This can also be set to `"off"` to disable checking for file-level IIFEs.
---
title: init-declarations
-layout: doc
rule_type: suggestion
---
---
title: jsx-quotes
-layout: doc
rule_type: layout
related_rules:
- quotes
---
title: key-spacing
-layout: doc
rule_type: layout
---
---
title: keyword-spacing
-layout: doc
rule_type: layout
---
---
title: line-comment-position
-layout: doc
rule_type: layout
---
---
title: linebreak-style
-layout: doc
rule_type: layout
---
---
title: lines-around-comment
-layout: doc
rule_type: layout
related_rules:
- space-before-blocks
* `"allowClassEnd": true` allows comments to appear at the end of classes
* `"applyDefaultIgnorePatterns"` enables or disables the default comment patterns to be ignored by the rule
* `"ignorePattern"` custom patterns to be ignored by the rule
+* `"afterHashbangComment": true` requires an empty line after hashbang comments
### beforeBlockComment
:::
+### afterHashbangComment
+
+Examples of **incorrect** code for this rule with the `{ "afterHashbangComment": true }` option:
+
+::: incorrect
+
+```js
+#!foo
+var day = "great"
+
+/*eslint lines-around-comment: ["error", { "afterHashbangComment": true }] */
+```
+
+:::
+
+Examples of **correct** code for this rule with the `{ "afterHashbangComment": true }` option:
+
+::: correct
+
+```js
+#!foo
+
+var day = "great"
+
+/*eslint lines-around-comment: ["error", { "afterHashbangComment": true }] */
+```
+
+:::
+
## 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.
---
title: lines-around-directive
-layout: doc
rule_type: layout
related_rules:
- lines-around-comment
---
title: lines-between-class-members
-layout: doc
rule_type: layout
related_rules:
- padded-blocks
--- /dev/null
+---
+title: logical-assignment-operators
+rule_type: suggestion
+---
+
+ES2021 introduces the assignment operator shorthand for the logical operators `||`, `&&` and `??`.
+Before, this was only allowed for mathematical operations such as `+` or `*` (see the rule [operator-assignment](./operator-assignment)).
+The shorthand can be used if the assignment target and the left expression of a logical expression are the same.
+For example `a = a || b` can be shortened to `a ||= b`.
+
+## Rule Details
+
+This rule requires or disallows logical assignment operator shorthand.
+
+### Options
+
+This rule has a string and an object option.
+String option:
+
+* `"always"` (default)
+* `"never"`
+
+Object option (only available if string option is set to `"always"`):
+
+* `"enforceForIfStatements": false`(default) Do *not* check for equivalent `if` statements
+* `"enforceForIfStatements": true` Check for equivalent `if` statements
+
+#### always
+
+Examples of **incorrect** code for this rule with the default `"always"` option:
+
+::: incorrect
+
+```js
+/*eslint logical-assignment-operators: ["error", "always"]*/
+
+a = a || b
+a = a && b
+a = a ?? b
+a || (a = b)
+a && (a = b)
+a ?? (a = b)
+```
+
+:::
+
+Examples of **correct** code for this rule with the default `"always"` option:
+
+::: correct
+
+```js
+/*eslint logical-assignment-operators: ["error", "always"]*/
+
+a = b
+a += b
+a ||= b
+a = b || c
+a || (b = c)
+
+if (a) a = b
+```
+
+:::
+
+#### never
+
+Examples of **incorrect** code for this rule with the `"never"` option:
+
+::: incorrect
+
+```js
+/*eslint logical-assignment-operators: ["error", "never"]*/
+
+a ||= b
+a &&= b
+a ??= b
+```
+
+:::
+
+Examples of **correct** code for this rule with the `"never"` option:
+
+::: correct
+
+```js
+/*eslint logical-assignment-operators: ["error", "never"]*/
+
+a = a || b
+a = a && b
+a = a ?? b
+```
+
+:::
+
+#### enforceForIfStatements
+
+This option checks for additional patterns with if statements which could be expressed with the logical assignment operator.
+
+::: incorrect
+
+Examples of **incorrect** code for this rule with the `["always", { enforceForIfStatements: true }]` option:
+
+```js
+/*eslint logical-assignment-operators: ["error", "always", { enforceForIfStatements: true }]*/
+
+if (a) a = b // <=> a &&= b
+if (!a) a = b // <=> a ||= b
+
+if (a == null) a = b // <=> a ??= b
+if (a === null || a === undefined) a = b // <=> a ??= b
+```
+
+:::
+
+Examples of **correct** code for this rule with the `["always", { enforceForIfStatements: true }]` option:
+
+::: correct
+
+```js
+/*eslint logical-assignment-operators: ["error", "always", { enforceForIfStatements: true }]*/
+
+if (a) b = c
+if (a === 0) a = b
+```
+
+:::
+
+## When Not To Use It
+
+Use of logical operator assignment shorthand is a stylistic choice. Leaving this rule turned off would allow developers to choose which style is more readable on a case-by-case basis.
---
title: max-classes-per-file
-layout: doc
rule_type: suggestion
---
---
title: max-depth
-layout: doc
rule_type: suggestion
related_rules:
- complexity
---
title: max-len
-layout: doc
rule_type: layout
related_rules:
- complexity
---
title: max-lines-per-function
-layout: doc
rule_type: suggestion
related_rules:
- complexity
---
title: max-lines
-layout: doc
rule_type: suggestion
related_rules:
- complexity
---
title: max-nested-callbacks
-layout: doc
rule_type: suggestion
related_rules:
- complexity
---
title: max-params
-layout: doc
rule_type: suggestion
related_rules:
- complexity
---
title: max-statements-per-line
-layout: doc
rule_type: layout
related_rules:
- max-depth
---
title: max-statements
-layout: doc
rule_type: suggestion
related_rules:
- complexity
---
title: multiline-comment-style
-layout: doc
rule_type: suggestion
---
This rule has a string option, which can have one of the following values:
* `"starred-block"` (default): Disallows consecutive line comments in favor of block comments. Additionally, requires block comments to have an aligned `*` character before each line.
-* `"bare-block"`: Disallows consecutive line comments in favor of block comments, and disallows block comments from having a `"*"` character before each line.
-* `"separate-lines"`: Disallows block comments in favor of consecutive line comments
+* `"bare-block"`: Disallows consecutive line comments in favor of block comments, and disallows block comments from having a `"*"` character before each line. This option ignores JSDoc comments.
+* `"separate-lines"`: Disallows block comments in favor of consecutive line comments. By default, this option ignores JSDoc comments. To also apply this rule to JSDoc comments, set the `checkJSDoc` option to `true`.
-The rule always ignores directive comments such as `/* eslint-disable */`. Additionally, unless the mode is `"starred-block"`, the rule ignores JSDoc comments.
+The rule always ignores directive comments such as `/* eslint-disable */`.
Examples of **incorrect** code for this rule with the default `"starred-block"` option:
:::
+Examples of **incorrect** code for this rule with the `"separate-lines"` option and `checkJSDoc` set to `true`:
+
+::: incorrect
+
+```js
+
+/* eslint multiline-comment-style: ["error", "separate-lines", { "checkJSDoc": true }] */
+
+/**
+ * I am a JSDoc comment
+ * and I'm not allowed
+ */
+foo();
+
+```
+
+:::
+
+Examples of **correct** code for this rule with the `"separate-lines"` option and `checkJSDoc` set to `true`:
+
+::: correct
+
+```js
+/* eslint multiline-comment-style: ["error", "separate-lines", { "checkJSDoc": true }] */
+
+// I am a JSDoc comment
+// and I'm not allowed
+foo();
+
+```
+
+:::
+
## When Not To Use It
If you don't want to enforce a particular style for multiline comments, you can disable the rule.
---
title: multiline-ternary
-layout: doc
rule_type: layout
related_rules:
- operator-linebreak
---
title: new-cap
-layout: doc
rule_type: suggestion
---
* `RegExp`
* `String`
* `Symbol`
+* `BigInt`
Examples of **correct** code for this rule:
---
title: new-parens
-layout: doc
rule_type: layout
---
---
title: newline-after-var
-layout: doc
rule_type: layout
---
---
title: newline-before-return
-layout: doc
rule_type: layout
related_rules:
- newline-after-var
---
title: newline-per-chained-call
-layout: doc
rule_type: layout
---
---
title: no-alert
-layout: doc
rule_type: suggestion
related_rules:
- no-console
---
title: no-array-constructor
-layout: doc
rule_type: suggestion
related_rules:
- no-new-object
---
title: no-arrow-condition
-layout: doc
related_rules:
- arrow-parens
---
title: no-async-promise-executor
-layout: doc
rule_type: problem
---
---
title: no-await-in-loop
-layout: doc
rule_type: problem
---
---
title: no-bitwise
-layout: doc
rule_type: suggestion
---
---
title: no-buffer-constructor
-layout: doc
rule_type: problem
further_reading:
- https://nodejs.org/api/buffer.html
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
In Node.js, the behavior of the `Buffer` constructor is different depending on the type of its argument. Passing an argument from user input to `Buffer()` without validating its type can lead to security vulnerabilities such as remote memory disclosure and denial of service. As a result, the `Buffer` constructor has been deprecated and should not be used. Use the producer methods `Buffer.from`, `Buffer.alloc`, and `Buffer.allocUnsafe` instead.
---
title: no-caller
-layout: doc
rule_type: suggestion
---
---
title: no-case-declarations
-layout: doc
rule_type: suggestion
related_rules:
- no-fallthrough
---
title: no-catch-shadow
-layout: doc
rule_type: suggestion
---
---
title: no-class-assign
-layout: doc
rule_type: problem
---
---
title: no-comma-dangle
-layout: doc
---
---
title: no-compare-neg-zero
-layout: doc
rule_type: problem
---
---
title: no-cond-assign
-layout: doc
rule_type: problem
related_rules:
- no-extra-parens
---
title: no-confusing-arrow
-layout: doc
rule_type: suggestion
related_rules:
- no-constant-condition
---
title: no-console
-layout: doc
rule_type: suggestion
related_rules:
- no-alert
---
title: no-const-assign
-layout: doc
rule_type: problem
---
---
title: no-constant-binary-expression
-layout: doc
rule_type: problem
related_rules:
- no-constant-condition
const objIsEmpty = someObj === {};
const arrIsEmpty = someArr === [];
+
+const shortCircuit1 = condition1 && false && condition2;
+
+const shortCircuit2 = condition1 || true || condition2;
+
+const shortCircuit3 = condition1 ?? "non-nullish" ?? condition2;
```
:::
---
title: no-constant-condition
-layout: doc
rule_type: problem
related_rules:
- no-constant-binary-expression
} while (x = -1);
var result = 0 ? a : b;
+
+if(input === "hello" || "bye"){
+ output(input);
+}
```
:::
} while (x);
var result = x !== 0 ? a : b;
+
+if(input === "hello" || input === "bye"){
+ output(input);
+}
```
:::
---
title: no-constructor-return
-layout: doc
rule_type: problem
---
---
title: no-continue
-layout: doc
rule_type: suggestion
---
---
title: no-control-regex
-layout: doc
rule_type: problem
related_rules:
- no-div-regex
---
title: no-debugger
-layout: doc
rule_type: problem
related_rules:
- no-alert
---
title: no-delete-var
-layout: doc
rule_type: suggestion
---
---
title: no-div-regex
-layout: doc
rule_type: suggestion
related_rules:
- no-control-regex
-Require regex literals to escape division operators.
+Characters `/=` at the beginning of a regular expression literal can be confused with a division assignment operator.
```js
function bar() { return /=foo/; }
## Rule Details
-This is used to disambiguate the division operator to not confuse users.
+This rule forbids equal signs (`=`) after the slash (`/`) at the beginning of a regular expression literal, because the characters `/=` can be confused with a division assignment operator.
Examples of **incorrect** code for this rule:
---
title: no-dupe-args
-layout: doc
rule_type: problem
---
---
title: no-dupe-class-members
-layout: doc
rule_type: problem
---
---
title: no-dupe-else-if
-layout: doc
rule_type: problem
related_rules:
- no-duplicate-case
---
title: no-dupe-keys
-layout: doc
rule_type: problem
---
---
title: no-duplicate-case
-layout: doc
rule_type: problem
---
---
title: no-duplicate-imports
-layout: doc
rule_type: problem
---
---
title: no-else-return
-layout: doc
rule_type: suggestion
---
---
title: no-empty-character-class
-layout: doc
rule_type: problem
---
---
title: no-empty-class
-layout: doc
---
---
title: no-empty-function
-layout: doc
rule_type: suggestion
related_rules:
- no-empty
---
title: no-empty-label
-layout: doc
related_rules:
- no-labels
---
title: no-empty-pattern
-layout: doc
rule_type: problem
---
--- /dev/null
+---
+title: no-empty-static-block
+layout: doc
+rule_type: suggestion
+related_rules:
+- no-empty
+- no-empty-function
+further_reading:
+- https://github.com/tc39/proposal-class-static-block
+---
+
+Empty static blocks, while not technically errors, usually occur due to refactoring that wasn't completed. They can cause confusion when reading code.
+
+## Rule Details
+
+This rule disallows empty static blocks. This rule ignores static blocks which contain a comment.
+
+Examples of **incorrect** code for this rule:
+
+::: incorrect
+
+```js
+/*eslint no-empty-static-block: "error"*/
+
+class Foo {
+ static {}
+}
+```
+
+:::
+
+Examples of **correct** code for this rule:
+
+:::correct
+
+```js
+/*eslint no-empty-static-block: "error"*/
+
+class Foo {
+ static {
+ bar();
+ }
+}
+
+class Foo {
+ static {
+ // comment
+ }
+}
+```
+
+:::
+
+## When Not To Use It
+
+This rule should not be used in environments prior to ES2022.
---
title: no-empty
-layout: doc
rule_type: suggestion
related_rules:
- no-empty-function
---
title: no-eq-null
-layout: doc
rule_type: suggestion
---
---
title: no-eval
-layout: doc
rule_type: suggestion
related_rules:
- no-implied-eval
---
title: no-ex-assign
-layout: doc
rule_type: problem
further_reading:
- https://bocoup.com/blog/the-catch-with-try-catch
---
title: no-extend-native
-layout: doc
rule_type: suggestion
related_rules:
- no-global-assign
---
title: no-extra-bind
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
---
title: no-extra-boolean-cast
-layout: doc
rule_type: suggestion
---
---
title: no-extra-label
-layout: doc
rule_type: suggestion
related_rules:
- no-labels
---
title: no-extra-parens
-layout: doc
rule_type: layout
related_rules:
- arrow-parens
* `"enforceForSequenceExpressions": false` allows extra parentheses around sequence expressions
* `"enforceForNewInMemberExpressions": false` allows extra parentheses around `new` expressions in member expressions
* `"enforceForFunctionPrototypeMethods": false` allows extra parentheses around immediate `.call` and `.apply` method calls on function expressions and around function expressions in the same context.
+* `"allowParensAfterCommentPattern": "any-string-pattern"` allows extra parentheses preceded by a comment that matches a regular expression.
### all
typeof (a);
+(Object.prototype.toString.call());
+
(function(){} ? a() : b());
class A {
(0).toString();
-(Object.prototype.toString.call());
-
({}.toString.call());
(function(){}) ? a() : b();
:::
+### allowParensAfterCommentPattern
+
+To make this rule allow extra parentheses preceded by specific comments, set this 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).
+
+Examples of **correct** code for this rule with the `"all"` and `{ "allowParensAfterCommentPattern": "@type" }` options:
+
+::: correct
+
+```js
+/* eslint no-extra-parens: ["error", "all", { "allowParensAfterCommentPattern": "@type" }] */
+
+const span = /**@type {HTMLSpanElement}*/(event.currentTarget);
+
+if (/** @type {Foo | Bar} */(options).baz) console.log('Lint free');
+
+foo(/** @type {Bar} */ (bar), options, {
+ name: "name",
+ path: "path",
+});
+
+if (foo) {
+ /** @type {Bar} */
+ (bar).prop = false;
+}
+```
+
+:::
+
### functions
Examples of **incorrect** code for this rule with the `"functions"` option:
---
title: no-extra-semi
-layout: doc
rule_type: suggestion
related_rules:
- semi
---
title: no-extra-strict
-layout: doc
further_reading:
- https://es5.github.io/#C
---
title: no-fallthrough
-layout: doc
rule_type: problem
related_rules:
- default-case
}
```
-That works fine when you don't want a fallthrough, but what if the fallthrough is intentional, there is no way to indicate that in the language. It's considered a best practice to always indicate when a fallthrough is intentional using a comment which matches the `/falls?\s?through/i` regular expression:
+That works fine when you don't want a fallthrough, but what if the fallthrough is intentional, there is no way to indicate that in the language. It's considered a best practice to always indicate when a fallthrough is intentional using a comment which matches the `/falls?\s?through/i` regular expression but isn't a directive:
```js
switch(foo) {
This rule has an object option:
-* Set the `commentPattern` option to a regular expression string to change the test for intentional fallthrough comment.
+* Set the `commentPattern` option to a regular expression string to change the test for intentional fallthrough comment. If the fallthrough comment matches a directive, that takes precedence over `commentPattern`.
* Set the `allowEmptyCase` option to `true` to allow empty cases regardless of the layout. By default, this rule does not require a fallthrough comment after an empty `case` only if the empty `case` and the next `case` are on the same line or on consecutive lines.
---
title: no-floating-decimal
-layout: doc
rule_type: suggestion
---
---
title: no-func-assign
-layout: doc
rule_type: problem
---
---
title: no-global-assign
-layout: doc
rule_type: suggestion
related_rules:
- no-extend-native
ESLint has the capability to configure global variables as read-only.
-* [Specifying Environments](../user-guide/configuring#specifying-environments)
-* [Specifying Globals](../user-guide/configuring#specifying-globals)
+* [Specifying Environments](../use/configure#specifying-environments)
+* [Specifying Globals](../use/configure#specifying-globals)
Examples of **incorrect** code for this rule:
---
title: no-implicit-coercion
-layout: doc
rule_type: suggestion
---
var n = Number(foo);
var n = parseFloat(foo);
var n = parseInt(foo, 10);
+
+var n = foo * 1/4; // `* 1` is allowed when followed by the `/` operator
```
:::
---
title: no-implicit-globals
-layout: doc
rule_type: suggestion
related_rules:
- no-undef
- no-global-assign
+- no-unused-vars
further_reading:
- https://benalman.com/news/2010/11/immediately-invoked-function-expression/
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Undeclared_var
(e.g. `window` in the browser environment), or a global variable defined as `readonly` in the configuration file
or in a `/*global */` comment.
-* [Specifying Environments](../user-guide/configuring#specifying-environments)
-* [Specifying Globals](../user-guide/configuring#specifying-globals)
+* [Specifying Environments](../use/configure#specifying-environments)
+* [Specifying Globals](../use/configure#specifying-globals)
Examples of **incorrect** code for this rule:
:::
+### exported
+
+You can use `/* exported variableName */` block comments in the same way as in [`no-unused-vars`](./no-unused-vars). See the [`no-unused-vars` exported section](./no-unused-vars#exported) for details.
+
+Examples of **correct** code for `/* exported variableName */` operation:
+
+::: correct
+
+```js
+/* exported global_var */
+
+var global_var = 42;
+```
+
+:::
+
## When Not To Use It
In the case of a browser script, if you want to be able to explicitly declare variables and functions in the global scope,
---
title: no-implied-eval
-layout: doc
rule_type: suggestion
related_rules:
- no-eval
---
title: no-import-assign
-layout: doc
rule_type: problem
---
---
title: no-inline-comments
-layout: doc
rule_type: suggestion
---
---
title: no-inner-declarations
-layout: doc
rule_type: problem
---
---
title: no-invalid-regexp
-layout: doc
rule_type: problem
further_reading:
- https://es5.github.io/#x7.8.5
---
title: no-invalid-this
-layout: doc
rule_type: suggestion
---
---
title: no-irregular-whitespace
-layout: doc
rule_type: problem
further_reading:
- https://es5.github.io/#x7.2
---
title: no-iterator
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
---
title: no-label-var
-layout: doc
rule_type: suggestion
related_rules:
- no-extra-label
---
title: no-labels
-layout: doc
rule_type: suggestion
related_rules:
- no-extra-label
---
title: no-lone-blocks
-layout: doc
rule_type: suggestion
---
---
title: no-lonely-if
-layout: doc
rule_type: suggestion
---
---
title: no-loop-func
-layout: doc
rule_type: suggestion
---
---
title: no-loss-of-precision
-layout: doc
rule_type: problem
---
---
title: no-magic-numbers
-layout: doc
rule_type: suggestion
---
:::
+### ignoreClassFieldInitialValues
+
+A boolean to specify if numbers used as initial values of class fields are considered okay. `false` by default.
+
+Examples of **correct** code for the `{ "ignoreClassFieldInitialValues": true }` option:
+
+::: correct
+
+```js
+/*eslint no-magic-numbers: ["error", { "ignoreClassFieldInitialValues": true }]*/
+
+class C {
+ foo = 2;
+ bar = -3;
+ #baz = 4;
+ static qux = 5;
+}
+```
+
+:::
+
+Examples of **incorrect** code for the `{ "ignoreClassFieldInitialValues": true }` option:
+
+::: incorrect
+
+```js
+/*eslint no-magic-numbers: ["error", { "ignoreClassFieldInitialValues": true }]*/
+
+class C {
+ foo = 2 + 3;
+}
+
+class D {
+ 2;
+}
+```
+
+:::
+
### enforceConst
A boolean to specify if we should check for the const keyword in variable declaration of numbers. `false` by default.
---
title: no-misleading-character-class
-layout: doc
rule_type: problem
---
---
title: no-mixed-operators
-layout: doc
rule_type: suggestion
related_rules:
- no-extra-parens
---
title: no-mixed-requires
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
In the Node.js community it is often customary to separate initializations with calls to `require` modules from other variable declarations, sometimes also grouping them by the type of module. This rule helps you enforce this convention.
---
title: no-mixed-spaces-and-tabs
-layout: doc
rule_type: layout
further_reading:
- https://www.emacswiki.org/emacs/SmartTabs
---
title: no-multi-assign
-layout: doc
rule_type: suggestion
related_rules:
- max-statements-per-line
---
title: no-multi-spaces
-layout: doc
rule_type: layout
related_rules:
- key-spacing
---
title: no-multi-str
-layout: doc
rule_type: suggestion
---
---
title: no-multiple-empty-lines
-layout: doc
rule_type: layout
---
var foo = 5;
+
var bar = 3;
```
var foo = 5;
+
var bar = 3;
```
var foo = 5;
+
var bar = 3;
+
```
:::
var foo = 5;
+
var bar = 3;
```
**Incorrect**:
+::: incorrect
+
```js
-1 /*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎
-2 ⏎
-3 var foo = 5;⏎
-4 ⏎
-5 ⏎
-6 var bar = 3;⏎
-7 ⏎
-8
+/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎
+⏎
+var foo = 5;⏎
+⏎
+⏎
+var bar = 3;⏎
+⏎
+
```
+:::
+
**Correct**:
+::: correct
+
```js
-1 /*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎
-2 ⏎
-3 var foo = 5;⏎
-4 ⏎
-5 ⏎
-6 var bar = 3;⏎
-7
+/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxEOF": 0 }]*/⏎
+⏎
+var foo = 5;⏎
+⏎
+⏎
+var bar = 3;⏎
+
```
+:::
+
### maxBOF
Examples of **incorrect** code for this rule with the `{ max: 2, maxBOF: 1 }` options:
```js
/*eslint no-multiple-empty-lines: ["error", { "max": 2, "maxBOF": 1 }]*/
+
var foo = 5;
+
var bar = 3;
```
var foo = 5;
+
var bar = 3;
```
---
title: no-native-reassign
-layout: doc
rule_type: suggestion
related_rules:
- no-extend-native
ESLint has the capability to configure global variables as read-only.
-* [Specifying Environments](../user-guide/configuring#specifying-environments)
-* [Specifying Globals](../user-guide/configuring#specifying-globals)
+* [Specifying Environments](../use/configure#specifying-environments)
+* [Specifying Globals](../use/configure#specifying-globals)
Examples of **incorrect** code for this rule:
---
title: no-negated-condition
-layout: doc
rule_type: suggestion
---
---
title: no-negated-in-lhs
-layout: doc
rule_type: problem
---
---
title: no-nested-ternary
-layout: doc
rule_type: suggestion
related_rules:
- no-ternary
---
title: no-new-func
-layout: doc
rule_type: suggestion
---
--- /dev/null
+---
+title: no-new-native-nonconstructor
+layout: doc
+rule_type: problem
+related_rules:
+- no-obj-calls
+further_reading:
+- https://tc39.es/ecma262/#sec-symbol-constructor
+- https://tc39.es/ecma262/#sec-bigint-constructor
+---
+
+
+
+It is a convention in JavaScript that global variables beginning with an uppercase letter typically represent classes that can be instantiated using the `new` operator, such as `new Array` and `new Map`. Confusingly, JavaScript also provides some global variables that begin with an uppercase letter that cannot be called using the `new` operator and will throw an error if you attempt to do so. These are typically functions that are related to data types and are easy to mistake for classes. Consider the following example:
+
+```js
+// throws a TypeError
+let foo = new Symbol("foo");
+
+// throws a TypeError
+let result = new BigInt(9007199254740991);
+```
+
+Both `new Symbol` and `new BigInt` throw a type error because they are functions and not classes. It is easy to make this mistake by assuming the uppercase letters indicate classes.
+
+## Rule Details
+
+This rule is aimed at preventing the accidental calling of native JavaScript global functions with the `new` operator. These functions are:
+
+* `Symbol`
+* `BigInt`
+
+## Examples
+
+Examples of **incorrect** code for this rule:
+
+::: incorrect
+
+```js
+/*eslint no-new-native-nonconstructor: "error"*/
+/*eslint-env es2022*/
+
+var foo = new Symbol('foo');
+var bar = new BigInt(9007199254740991);
+```
+
+:::
+
+Examples of **correct** code for this rule:
+
+::: correct
+
+```js
+/*eslint no-new-native-nonconstructor: "error"*/
+/*eslint-env es2022*/
+
+var foo = Symbol('foo');
+var bar = BigInt(9007199254740991);
+
+// Ignores shadowed Symbol.
+function baz(Symbol) {
+ const qux = new Symbol("baz");
+}
+function quux(BigInt) {
+ const corge = new BigInt(9007199254740991);
+}
+
+```
+
+:::
+
+## When Not To Use It
+
+This rule should not be used in ES3/5 environments.
---
title: no-new-object
-layout: doc
rule_type: suggestion
related_rules:
- no-array-constructor
---
title: no-new-require
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
The `require` function is used to include modules that exist in separate files, such as:
---
title: no-new-symbol
-layout: doc
rule_type: problem
further_reading:
- https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-objects
---
title: no-new-wrappers
-layout: doc
rule_type: suggestion
related_rules:
- no-array-constructor
---
title: no-new
-layout: doc
rule_type: suggestion
---
var thing = new Thing();
-Thing();
+Foo();
```
:::
---
title: no-nonoctal-decimal-escape
-layout: doc
rule_type: suggestion
related_rules:
- no-octal-escape
---
title: no-obj-calls
-layout: doc
rule_type: problem
further_reading:
- https://es5.github.io/#x15.8
> The Reflect object also does not have a `[[Call]]` internal method; it is not possible to invoke the Reflect object as a function.
-And the [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object) makes it clear that `Atomics` cannot be invoked:
+The [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-262/8.0/index.html#sec-atomics-object) makes it clear that `Atomics` cannot be invoked:
> The Atomics object does not have a `[[Call]]` internal method; it is not possible to invoke the Atomics object as a function.
+And the [ECMAScript Internationalization API Specification](https://tc39.es/ecma402/#intl-object) makes it clear that `Intl` cannot be invoked:
+
+> The Intl object does not have a `[[Call]]` internal method; it is not possible to invoke the Intl object as a function.
+
## Rule Details
-This rule disallows calling the `Math`, `JSON`, `Reflect` and `Atomics` objects as functions.
+This rule disallows calling the `Math`, `JSON`, `Reflect`, `Atomics` and `Intl` objects as functions.
This rule also disallows using these objects as constructors with the `new` operator.
```js
/*eslint no-obj-calls: "error"*/
-/*eslint-env es2017*/
+/*eslint-env es2017, browser */
var math = Math();
var atomics = Atomics();
var newAtomics = new Atomics();
+
+var intl = Intl();
+
+var newIntl = new Intl();
```
:::
```js
/*eslint no-obj-calls: "error"*/
-/*eslint-env es2017*/
+/*eslint-env es2017, browser*/
function area(r) {
return Math.PI * r * r;
var value = Reflect.get({ x: 1, y: 2 }, "x");
var first = Atomics.load(foo, 0);
+
+var segmenterFr = new Intl.Segmenter("fr", { granularity: "word" });
```
:::
---
title: no-octal-escape
-layout: doc
rule_type: suggestion
---
---
title: no-octal
-layout: doc
rule_type: suggestion
---
---
title: no-param-reassign
-layout: doc
rule_type: suggestion
further_reading:
- https://spin.atomicobject.com/2011/04/10/javascript-don-t-reassign-your-function-arguments/
---
title: no-path-concat
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
In Node.js, the `__dirname` and `__filename` global variables contain the directory path and the file path of the currently executing script file, respectively. Sometimes, developers try to use these variables to create paths to other files, such as:
---
title: no-plusplus
-layout: doc
rule_type: suggestion
---
---
title: no-process-env
-layout: doc
rule_type: suggestion
further_reading:
- https://stackoverflow.com/questions/5869216/how-to-store-node-js-deployment-settings-configuration-files
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
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.
---
title: no-process-exit
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
The `process.exit()` method in Node.js is used to immediately stop the Node.js process and exit. This is a dangerous operation because it can occur in any method at any point in time, potentially stopping a Node.js application completely when an error occurs. For example:
---
title: no-promise-executor-return
-layout: doc
rule_type: problem
related_rules:
- no-async-promise-executor
---
title: no-proto
-layout: doc
rule_type: suggestion
further_reading:
- https://johnresig.com/blog/objectgetprototypeof/
---
title: no-prototype-builtins
-layout: doc
rule_type: problem
---
---
title: no-redeclare
-layout: doc
rule_type: suggestion
related_rules:
- no-shadow
---
title: no-regex-spaces
-layout: doc
rule_type: suggestion
related_rules:
- no-div-regex
---
title: no-reserved-keys
-layout: doc
further_reading:
- https://kangax.github.io/compat-table/es5/#Reserved_words_as_property_names
---
title: no-restricted-exports
-layout: doc
rule_type: suggestion
---
This rule has an object option:
* `"restrictedNamedExports"` is an array of strings, where each string is a name to be restricted.
+* `"restrictDefaultExports"` is an object option with boolean properties to restrict certain default export declarations. The option works only if the `restrictedNamedExports` option does not contain the `"default"` value. The following properties are allowed:
+ * `direct`: restricts `export default` declarations.
+ * `named`: restricts `export { foo as default };` declarations.
+ * `defaultFrom`: restricts `export { default } from 'foo';` declarations.
+ * `namedFrom`: restricts `export { foo as default } from 'foo';` declarations.
+ * `namespaceFrom`: restricts `export * as default from 'foo';` declarations.
-Examples of **incorrect** code for this rule:
+### restrictedNamedExports
+
+Examples of **incorrect** code for the `"restrictedNamedExports"` option:
::: incorrect
:::
-Examples of **correct** code for this rule:
+Examples of **correct** code for the `"restrictedNamedExports"` option:
::: correct
:::
-### Default exports
+#### Default exports
-By design, this rule doesn't disallow `export default` declarations. If you configure `"default"` as a restricted name, that restriction will apply only to named export declarations.
+By design, the `"restrictedNamedExports"` option doesn't disallow `export default` declarations. If you configure `"default"` as a restricted name, that restriction will apply only to named export declarations.
-Examples of additional **incorrect** code for this rule:
+Examples of additional **incorrect** code for the `"restrictedNamedExports": ["default"]` option:
::: incorrect
:::
-Examples of additional **correct** code for this rule:
+Examples of additional **correct** code for the `"restrictedNamedExports": ["default"]` option:
::: correct
:::
+### restrictDefaultExports
+
+This option allows you to restrict certain `default` declarations. The option works only if the `restrictedNamedExports` option does not contain the `"default"` value. This option accepts the following properties:
+
+#### direct
+
+Examples of **incorrect** code for the `"restrictDefaultExports": { "direct": true }` option:
+
+::: incorrect
+
+```js
+/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "direct": true } }]*/
+
+export default foo;
+export default 42;
+export default function foo() {}
+```
+
+:::
+
+#### named
+
+Examples of **incorrect** code for the `"restrictDefaultExports": { "named": true }` option:
+
+::: incorrect
+
+```js
+/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "named": true } }]*/
+
+const foo = 123;
+
+export { foo as default };
+```
+
+:::
+
+#### defaultFrom
+
+Examples of **incorrect** code for the `"restrictDefaultExports": { "defaultFrom": true }` option:
+
+::: incorrect
+
+```js
+/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "defaultFrom": true } }]*/
+
+export { default } from 'foo';
+export { default as default } from 'foo';
+```
+
+:::
+
+#### namedFrom
+
+Examples of **incorrect** code for the `"restrictDefaultExports": { "namedFrom": true }` option:
+
+::: incorrect
+
+```js
+/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "namedFrom": true } }]*/
+
+export { foo as default } from 'foo';
+```
+
+:::
+
+#### namespaceFrom
+
+Examples of **incorrect** code for the `"restrictDefaultExports": { "namespaceFrom": true }` option:
+
+::: incorrect
+
+```js
+/*eslint no-restricted-exports: ["error", { "restrictDefaultExports": { "namespaceFrom": true } }]*/
+
+export * as default from 'foo';
+```
+
+:::
+
## Known Limitations
This rule doesn't inspect the content of source modules in re-export declarations. In particular, if you are re-exporting everything from another module's export, that export may include a restricted name. This rule cannot detect such cases.
---
title: no-restricted-globals
-layout: doc
rule_type: suggestion
related_rules:
- no-restricted-properties
---
title: no-restricted-imports
-layout: doc
rule_type: suggestion
---
---
title: no-restricted-modules
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
A module in Node.js is a simple or complex functionality organized in a JavaScript file which can be reused throughout the Node.js
application. The keyword `require` is used in Node.js/CommonJS to import modules into an application. This way you can have dynamic loading where the loaded module name isn't predefined /static, or where you conditionally load a module only if it's "truly required".
---
title: no-restricted-properties
-layout: doc
rule_type: suggestion
related_rules:
- no-restricted-globals
---
title: no-restricted-syntax
-layout: doc
rule_type: suggestion
related_rules:
- no-alert
Rather than creating separate rules for every language feature you want to turn off, this rule allows you to configure the syntax elements you want to restrict use of. These elements are represented by their [ESTree](https://github.com/estree/estree) node types. For example, a function declaration is represented by `FunctionDeclaration` and the `with` statement is represented by `WithStatement`. You may find the full list of AST node names you can use [on GitHub](https://github.com/eslint/eslint-visitor-keys/blob/main/lib/visitor-keys.js) and use [AST Explorer](https://astexplorer.net/) with the espree parser to see what type of nodes your code consists of.
-You can also specify [AST selectors](../developer-guide/selectors) to restrict, allowing much more precise control over syntax patterns.
+You can also specify [AST selectors](../extend/selectors) to restrict, allowing much more precise control over syntax patterns.
## Rule Details
---
title: no-return-assign
-layout: doc
rule_type: suggestion
---
---
title: no-return-await
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
---
title: no-script-url
-layout: doc
rule_type: suggestion
further_reading:
- https://stackoverflow.com/questions/13497971/what-is-the-matter-with-script-targeted-urls
---
title: no-self-assign
-layout: doc
rule_type: problem
---
---
title: no-self-compare
-layout: doc
rule_type: problem
---
---
title: no-sequences
-layout: doc
rule_type: suggestion
---
---
title: no-setter-return
-layout: doc
rule_type: problem
related_rules:
- getter-return
---
title: no-shadow-restricted-names
-layout: doc
rule_type: suggestion
related_rules:
- no-shadow
---
title: no-shadow
-layout: doc
rule_type: suggestion
related_rules:
- no-shadow-restricted-names
---
title: no-space-before-semi
-layout: doc
related_rules:
- semi
---
title: no-spaced-func
-layout: doc
rule_type: layout
---
---
title: no-sparse-arrays
-layout: doc
rule_type: problem
further_reading:
- https://www.nczonline.net/blog/2007/09/09/inconsistent-array-literals/
---
title: no-sync
-layout: doc
rule_type: suggestion
---
-This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-node`](https://github.com/mysticatea/eslint-plugin-node).
+This rule was **deprecated** in ESLint v7.0.0. Please use the corresponding rule in [`eslint-plugin-n`](https://github.com/eslint-community/eslint-plugin-n).
In Node.js, most I/O is done through asynchronous methods. However, there are often synchronous versions of the asynchronous methods. For example, `fs.exists()` and `fs.existsSync()`. In some contexts, using synchronous operations is okay (if, as with ESLint, you are writing a command line utility). However, in other contexts the use of synchronous operations is considered a bad practice that should be avoided. For example, if you are running a high-travel web server on Node.js, you should consider carefully if you want to allow any synchronous operations that could lock up the server.
---
title: no-tabs
-layout: doc
rule_type: layout
---
---
title: no-template-curly-in-string
-layout: doc
rule_type: problem
---
---
title: no-ternary
-layout: doc
rule_type: suggestion
related_rules:
- no-nested-ternary
---
title: no-this-before-super
-layout: doc
rule_type: problem
---
---
title: no-throw-literal
-layout: doc
rule_type: suggestion
---
---
title: no-trailing-spaces
-layout: doc
rule_type: layout
---
---
title: no-undef-init
-layout: doc
rule_type: suggestion
related_rules:
- no-undefined
---
title: no-undef
-layout: doc
rule_type: problem
related_rules:
- no-global-assign
## Rule Details
-Any reference to an undeclared variable causes a warning, unless the variable is explicitly mentioned in a `/*global ...*/` comment, or specified in the [`globals` key in the configuration file](../user-guide/configuring/language-options#using-configuration-files-1). A common use case for these is if you intentionally use globals that are defined elsewhere (e.g. in a script sourced from HTML).
+Any reference to an undeclared variable causes a warning, unless the variable is explicitly mentioned in a `/*global ...*/` comment, or specified in the [`globals` key in the configuration file](../use/configure/language-options#using-configuration-files-1). A common use case for these is if you intentionally use globals that are defined elsewhere (e.g. in a script sourced from HTML).
Examples of **incorrect** code for this rule:
## Environments
-For convenience, ESLint provides shortcuts that pre-define global variables exposed by popular libraries and runtime environments. This rule supports these environments, as listed in [Specifying Environments](../user-guide/configuring/language-options#specifying-environments). A few examples are given below.
+For convenience, ESLint provides shortcuts that pre-define global variables exposed by popular libraries and runtime environments. This rule supports these environments, as listed in [Specifying Environments](../use/configure/language-options#specifying-environments). A few examples are given below.
### browser
---
title: no-undefined
-layout: doc
rule_type: suggestion
related_rules:
- no-undef-init
function foo(undefined) {
// ...
}
+
+bar(undefined, "lorem");
```
:::
}
global.undefined = "foo";
+
+bar(void 0, "lorem");
```
:::
---
title: no-underscore-dangle
-layout: doc
rule_type: suggestion
---
* `"allowAfterThisConstructor": false` (default) disallows dangling underscores in members of the `this.constructor` object
* `"enforceInMethodNames": false` (default) allows dangling underscores in method names
* `"enforceInClassFields": false` (default) allows dangling underscores in es2022 class fields names
+* `"allowInArrayDestructuring": true` (default) allows dangling underscores in variable names assigned by array destructuring
+* `"allowInObjectDestructuring": true` (default) allows dangling underscores in variable names assigned by object destructuring
* `"allowFunctionParams": true` (default) allows dangling underscores in function parameter names
### allow
:::
+### allowInArrayDestructuring
+
+Examples of **incorrect** code for this rule with the `{ "allowInArrayDestructuring": false }` option:
+
+::: incorrect
+
+```js
+/*eslint no-underscore-dangle: ["error", { "allowInArrayDestructuring": false }]*/
+
+const [_foo, _bar] = list;
+const [foo_, ..._bar] = list;
+const [foo, [bar, _baz]] = list;
+```
+
+:::
+
+### allowInObjectDestructuring
+
+Examples of **incorrect** code for this rule with the `{ "allowInObjectDestructuring": false }` option:
+
+::: incorrect
+
+```js
+/*eslint no-underscore-dangle: ["error", { "allowInObjectDestructuring": false }]*/
+
+const { foo, bar: _bar } = collection;
+const { foo, bar, _baz } = collection;
+```
+
+:::
+
+Examples of **correct** code for this rule with the `{ "allowInObjectDestructuring": false }` option:
+
+::: correct
+
+```js
+/*eslint no-underscore-dangle: ["error", { "allowInObjectDestructuring": false }]*/
+
+const { foo, bar, _baz: { a, b } } = collection;
+const { foo, bar, _baz: baz } = collection;
+```
+
+:::
+
### allowFunctionParams
Examples of **incorrect** code for this rule with the `{ "allowFunctionParams": false }` option:
---
title: no-unexpected-multiline
-layout: doc
rule_type: problem
related_rules:
- func-call-spacing
---
title: no-unmodified-loop-condition
-layout: doc
rule_type: problem
---
---
title: no-unneeded-ternary
-layout: doc
rule_type: suggestion
related_rules:
- no-ternary
---
title: no-unreachable-loop
-layout: doc
rule_type: problem
related_rules:
- no-unreachable
---
title: no-unreachable
-layout: doc
rule_type: problem
---
---
title: no-unsafe-finally
-layout: doc
rule_type: problem
---
---
title: no-unsafe-negation
-layout: doc
rule_type: problem
---
---
title: no-unsafe-optional-chaining
-layout: doc
rule_type: problem
---
---
title: no-unused-expressions
-layout: doc
rule_type: suggestion
---
---
title: no-unused-labels
-layout: doc
rule_type: suggestion
related_rules:
- no-extra-label
---
title: no-unused-private-class-members
-layout: doc
rule_type: problem
---
---
title: no-unused-vars
-layout: doc
rule_type: problem
---
:::
-### ignoreRestSiblings
-
-The `ignoreRestSiblings` option is a boolean (default: `false`). Using a [Rest Property](https://github.com/tc39/proposal-object-rest-spread) it is possible to "omit" properties from an object, but by default the sibling properties are marked as "unused". With this option enabled the rest property's siblings are ignored.
-
-Examples of **correct** code for the `{ "ignoreRestSiblings": true }` option:
-
-::: correct
-
-```js
-/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
-// 'foo' and 'bar' were ignored because they have a rest property sibling.
-var { foo, ...coords } = data;
-
-var bar;
-({ bar, ...coords } = data);
-```
-
-:::
-
### argsIgnorePattern
The `argsIgnorePattern` option specifies exceptions not to check for usage: arguments whose names match a regexp pattern. For example, variables whose names begin with an underscore.
:::
-### destructuredArrayIgnorePattern
-
-The `destructuredArrayIgnorePattern` option specifies exceptions not to check for usage: elements of array destructuring patterns whose names match a regexp pattern. For example, variables whose names begin with an underscore.
-
-Examples of **correct** code for the `{ "destructuredArrayIgnorePattern": "^_" }` option:
-
-::: correct
-
-```js
-/*eslint no-unused-vars: ["error", { "destructuredArrayIgnorePattern": "^_" }]*/
-
-const [a, _b, c] = ["a", "b", "c"];
-console.log(a+c);
-
-const { x: [_a, foo] } = bar;
-console.log(foo);
-
-function baz([_c, x]) {
- x;
-}
-baz();
-
-function test({p: [_q, r]}) {
- r;
-}
-test();
-
-let _m, n;
-foo.forEach(item => {
- [_m, n] = item;
- console.log(n);
-});
-
-let _o, p;
-_o = 1;
-[_o, p] = foo;
-p;
-```
-
-:::
-
### caughtErrors
The `caughtErrors` option is used for `catch` block arguments validation.
:::
+### destructuredArrayIgnorePattern
+
+The `destructuredArrayIgnorePattern` option specifies exceptions not to check for usage: elements of array destructuring patterns whose names match a regexp pattern. For example, variables whose names begin with an underscore.
+
+Examples of **correct** code for the `{ "destructuredArrayIgnorePattern": "^_" }` option:
+
+::: correct
+
+```js
+/*eslint no-unused-vars: ["error", { "destructuredArrayIgnorePattern": "^_" }]*/
+
+const [a, _b, c] = ["a", "b", "c"];
+console.log(a+c);
+
+const { x: [_a, foo] } = bar;
+console.log(foo);
+
+function baz([_c, x]) {
+ x;
+}
+baz();
+
+function test({p: [_q, r]}) {
+ r;
+}
+test();
+
+let _m, n;
+foo.forEach(item => {
+ [_m, n] = item;
+ console.log(n);
+});
+
+let _o, p;
+_o = 1;
+[_o, p] = foo;
+p;
+```
+
+:::
+
+### ignoreRestSiblings
+
+The `ignoreRestSiblings` option is a boolean (default: `false`). Using a [Rest Property](https://github.com/tc39/proposal-object-rest-spread) it is possible to "omit" properties from an object, but by default the sibling properties are marked as "unused". With this option enabled the rest property's siblings are ignored.
+
+Examples of **correct** code for the `{ "ignoreRestSiblings": true }` option:
+
+::: correct
+
+```js
+/*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/
+// 'foo' and 'bar' were ignored because they have a rest property sibling.
+var { foo, ...coords } = data;
+
+var bar;
+({ bar, ...coords } = data);
+```
+
+:::
+
## 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.
---
title: no-use-before-define
-layout: doc
rule_type: problem
---
---
title: no-useless-backreference
-layout: doc
rule_type: problem
related_rules:
- no-control-regex
---
title: no-useless-call
-layout: doc
rule_type: suggestion
related_rules:
- prefer-spread
---
title: no-useless-catch
-layout: doc
rule_type: suggestion
---
---
title: no-useless-computed-key
-layout: doc
rule_type: suggestion
---
---
title: no-useless-concat
-layout: doc
rule_type: suggestion
---
---
title: no-useless-constructor
-layout: doc
rule_type: suggestion
---
---
title: no-useless-escape
-layout: doc
rule_type: suggestion
---
---
title: no-useless-rename
-layout: doc
rule_type: suggestion
related_rules:
- object-shorthand
---
title: no-useless-return
-layout: doc
rule_type: suggestion
---
---
title: no-var
-layout: doc
rule_type: suggestion
---
---
title: no-void
-layout: doc
rule_type: suggestion
related_rules:
- no-undef-init
---
title: no-warning-comments
-layout: doc
rule_type: suggestion
---
---
title: no-whitespace-before-property
-layout: doc
rule_type: layout
---
---
title: no-with
-layout: doc
rule_type: suggestion
further_reading:
- https://web.archive.org/web/20200717110117/https://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/
---
title: no-wrap-func
-layout: doc
---
---
title: nonblock-statement-body-position
-layout: doc
rule_type: layout
further_reading:
- https://jscs-dev.github.io/rule/requireNewlineBeforeSingleStatementsInIf
This rule aims to enforce a consistent location for single-line statements.
-Note that this rule does not enforce the usage of single-line statements in general. If you would like to disallow single-line statements, use the [`curly`](/docs/rules/curly) rule instead.
+Note that this rule does not enforce the usage of single-line statements in general. If you would like to disallow single-line statements, use the [`curly`](curly) rule instead.
### Options
## When Not To Use It
-If you're not concerned about consistent locations of single-line statements, you should not turn on this rule. You can also disable this rule if you're using the `"all"` option for the [`curly`](/docs/rules/curly) rule, because this will disallow single-line statements entirely.
+If you're not concerned about consistent locations of single-line statements, you should not turn on this rule. You can also disable this rule if you're using the `"all"` option for the [`curly`](curly) rule, because this will disallow single-line statements entirely.
---
title: object-curly-newline
-layout: doc
rule_type: layout
related_rules:
- comma-spacing
---
title: object-curly-spacing
-layout: doc
rule_type: layout
related_rules:
- array-bracket-spacing
---
title: object-property-newline
-layout: doc
rule_type: layout
related_rules:
- brace-style
---
title: object-shorthand
-layout: doc
rule_type: suggestion
related_rules:
- no-useless-rename
---
title: one-var-declaration-per-line
-layout: doc
rule_type: suggestion
related_rules:
- one-var
---
title: one-var
-layout: doc
rule_type: suggestion
---
---
title: operator-assignment
-layout: doc
rule_type: suggestion
---
---
title: operator-linebreak
-layout: doc
rule_type: layout
related_rules:
- comma-style
---
title: padded-blocks
-layout: doc
rule_type: layout
related_rules:
- lines-between-class-members
---
title: padding-line-between-statements
-layout: doc
rule_type: layout
---
---
title: prefer-arrow-callback
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
---
title: prefer-const
-layout: doc
rule_type: suggestion
related_rules:
- no-var
// `end` is never reassigned, but we cannot separate the declarations without modifying the scope.
for (let i = 0, end = 10; i < end; ++i) {
- console.log(a);
+ console.log(i);
}
// `predicate` is only assigned once but cannot be separately declared as `const`
---
title: prefer-destructuring
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
---
title: prefer-exponentiation-operator
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation
---
title: prefer-named-capture-group
-layout: doc
rule_type: suggestion
related_rules:
- no-invalid-regexp
---
title: prefer-numeric-literals
-layout: doc
rule_type: suggestion
---
---
title: prefer-object-has-own
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
---
title: prefer-object-spread
-layout: doc
rule_type: suggestion
---
---
title: prefer-promise-reject-errors
-layout: doc
rule_type: suggestion
related_rules:
- no-throw-literal
---
title: prefer-reflect
-layout: doc
rule_type: suggestion
related_rules:
- no-useless-call
This rule was **deprecated** in ESLint v3.9.0 and will not be replaced. The original intent of this rule now seems misguided as we have come to understand that `Reflect` methods are not actually intended to replace the `Object` counterparts the rule suggests, but rather exist as low-level primitives to be used with proxies in order to replicate the default behavior of various previously existing functionality.
+**Please note**: This rule contains an incorrect behavior - it will suggest you to use `Reflect.getOwnPropertyNames` rather than `Object.getOwnPropertyNames`, but the former one doesn't exist in the [specification](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflection). We suggest using the `exceptions` option with `"getOwnPropertyNames"` to avoid this false suggestion.
+
The ES6 Reflect API comes with a handful of methods which somewhat deprecate methods on old constructors:
* [`Reflect.apply`](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-reflect.apply) effectively deprecates [`Function.prototype.apply`](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-function.prototype.apply) and [`Function.prototype.call`](https://www.ecma-international.org/ecma-262/6.0/index.html#sec-function.prototype.call)
:::
-### Reflect.getOwnPropertyNames
-
-Deprecates `Object.getOwnPropertyNames()`
-
-Examples of **incorrect** code for this rule when used without exceptions:
-
-::: incorrect
-
-```js
-/*eslint prefer-reflect: "error"*/
-
-Object.getOwnPropertyNames({})
-```
-
-:::
-
-Examples of **correct** code for this rule when used without exceptions:
-
-::: correct
-
-```js
-/*eslint prefer-reflect: "error"*/
-
-Reflect.getOwnPropertyNames({})
-```
-
-:::
-
-Examples of **correct** code for this rule with the `{ "exceptions": ["getOwnPropertyNames"] }` option:
-
-::: correct
-
-```js
-/*eslint prefer-reflect: ["error", { "exceptions": ["getOwnPropertyNames"] }]*/
-
-Object.getOwnPropertyNames({})
-Reflect.getOwnPropertyNames({})
-```
-
-:::
-
### Reflect.preventExtensions
Deprecates `Object.preventExtensions()`
---
title: prefer-regex-literals
-layout: doc
rule_type: suggestion
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
---
title: prefer-rest-params
-layout: doc
rule_type: suggestion
related_rules:
- prefer-spread
---
title: prefer-spread
-layout: doc
rule_type: suggestion
related_rules:
- no-useless-call
---
title: prefer-template
-layout: doc
rule_type: suggestion
related_rules:
- no-useless-concat
---
title: quote-props
-layout: doc
rule_type: suggestion
further_reading:
- https://kangax.github.io/compat-table/es5/#Reserved_words_as_property_names
---
title: quotes
-layout: doc
rule_type: layout
---
---
title: radix
-layout: doc
rule_type: suggestion
further_reading:
- https://davidwalsh.name/parseint-radix
---
title: require-atomic-updates
-layout: doc
rule_type: problem
---
---
title: require-await
-layout: doc
rule_type: suggestion
related_rules:
- require-yield
---
title: require-jsdoc
-layout: doc
rule_type: suggestion
related_rules:
- valid-jsdoc
---
title: require-unicode-regexp
-layout: doc
rule_type: suggestion
---
---
title: require-yield
-layout: doc
rule_type: suggestion
related_rules:
- require-await
---
title: rest-spread-spacing
-layout: doc
rule_type: layout
further_reading:
- https://github.com/tc39/proposal-object-rest-spread
}
```
-Please read the user guide's section on [configuring parser options](/docs/user-guide/configuring#specifying-parser-options) to learn more.
+Please read the user guide's section on [configuring parser options](../use/configure#specifying-parser-options) to learn more.
## Options
---
title: semi-spacing
-layout: doc
rule_type: layout
related_rules:
- semi
---
title: semi-style
-layout: doc
rule_type: layout
related_rules:
- no-extra-semi
---
title: semi
-layout: doc
rule_type: layout
related_rules:
- no-extra-semi
String option:
* `"always"` (default) requires semicolons at the end of statements
-* `"never"` disallows semicolons as the end of statements (except to disambiguate statements beginning with `[`, `(`, `/`, `+`, or `-`)
+* `"never"` disallows semicolons at the end of statements (except to disambiguate statements beginning with `[`, `(`, `/`, `+`, or `-`)
Object option (when `"always"`):
-* `"omitLastInOneLineBlock": true` ignores the last semicolon in a block in which its braces (and therefore the content of the block) are in the same line
+* `"omitLastInOneLineBlock": true` disallows the last semicolon in a block in which its braces (and therefore the content of the block) are in the same line
+* `"omitLastInOneLineClassBody": true` disallows the last semicolon in a class body in which its braces (and therefore the content of the class body) are in the same line
Object option (when `"never"`):
* `"beforeStatementContinuationChars": "any"` (default) ignores semicolons (or lacking semicolon) at the end of statements if the next line starts with `[`, `(`, `/`, `+`, or `-`.
* `"beforeStatementContinuationChars": "always"` requires semicolons at the end of statements if the next line starts with `[`, `(`, `/`, `+`, or `-`.
-* `"beforeStatementContinuationChars": "never"` disallows semicolons as the end of statements if it doesn't make ASI hazard even if the next line starts with `[`, `(`, `/`, `+`, or `-`.
+* `"beforeStatementContinuationChars": "never"` disallows semicolons at the end of statements if it doesn't make ASI hazard even if the next line starts with `[`, `(`, `/`, `+`, or `-`.
**Note:** `beforeStatementContinuationChars` does not apply to class fields because class fields are not statements.
:::
+#### omitLastInOneLineBlock
+
+Examples of additional **correct** code for this rule with the `"always", { "omitLastInOneLineBlock": true }` options:
+
+::: correct
+
+```js
+/*eslint semi: ["error", "always", { "omitLastInOneLineBlock": true}] */
+
+if (foo) { bar() }
+
+if (foo) { bar(); baz() }
+
+function f() { bar(); baz() }
+
+class C {
+ foo() { bar(); baz() }
+
+ static { bar(); baz() }
+}
+```
+
+:::
+
+#### omitLastInOneLineClassBody
+
+Examples of additional **correct** code for this rule with the `"always", { "omitLastInOneLineClassBody": true }` options:
+
+::: correct
+
+```js
+/*eslint semi: ["error", "always", { "omitLastInOneLineClassBody": true}] */
+
+export class SomeClass{
+ logType(){
+ console.log(this.type);
+ console.log(this.anotherType);
+ }
+}
+
+export class Variant1 extends SomeClass{type=1}
+export class Variant2 extends SomeClass{type=2; anotherType=3}
+```
+
+:::
+
### never
Examples of **incorrect** code for this rule with the `"never"` option:
:::
-#### omitLastInOneLineBlock
-
-Examples of additional **correct** code for this rule with the `"always", { "omitLastInOneLineBlock": true }` options:
-
-::: correct
-
-```js
-/*eslint semi: ["error", "always", { "omitLastInOneLineBlock": true}] */
-
-if (foo) { bar() }
-
-if (foo) { bar(); baz() }
-
-function f() { bar(); baz() }
-
-class C {
- foo() { bar(); baz() }
-
- static { bar(); baz() }
-}
-```
-
-:::
-
#### beforeStatementContinuationChars
Examples of additional **incorrect** code for this rule with the `"never", { "beforeStatementContinuationChars": "always" }` options:
---
title: sort-imports
-layout: doc
rule_type: suggestion
related_rules:
- sort-keys
---
title: sort-keys
-layout: doc
rule_type: suggestion
related_rules:
- sort-imports
---
title: sort-vars
-layout: doc
rule_type: suggestion
related_rules:
- sort-keys
---
title: space-after-function-name
-layout: doc
---
---
title: space-after-keywords
-layout: doc
---
(removed) This rule was **removed** in ESLint v2.0 and replaced by the [keyword-spacing](keyword-spacing) rule.
-(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#--fix) automatically fixed problems reported by this rule.
+(fixable) The `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixed problems reported by this rule.
Some style guides will require or disallow spaces following the certain keywords.
---
title: space-before-blocks
-layout: doc
rule_type: layout
related_rules:
- keyword-spacing
---
title: space-before-function-paren
-layout: doc
rule_type: layout
related_rules:
-- space-after-keywords
-- space-return-throw-case
+- keyword-spacing
---
---
title: space-before-function-parentheses
-layout: doc
related_rules:
- space-after-keywords
---
title: space-before-keywords
-layout: doc
related_rules:
- space-after-keywords
(removed) This rule was **removed** in ESLint v2.0 and **replaced** by the [keyword-spacing](keyword-spacing) rule.
-(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#--fix) automatically fixed problems reported by this rule.
+(fixable) The `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixed problems reported by this rule.
Keywords are syntax elements of JavaScript, such as `function` and `if`. These identifiers have special meaning to the language and so often appear in a different color in code editors. As an important part of the language, style guides often refer to the spacing that should be used around keywords. For example, you might have a style guide that says keywords should be always be preceded by spaces, which would mean `if-else` statements must look like this:
---
title: space-in-brackets
-layout: doc
related_rules:
- array-bracket-spacing
---
title: space-in-parens
-layout: doc
rule_type: layout
related_rules:
- array-bracket-spacing
---
title: space-infix-ops
-layout: doc
rule_type: layout
---
---
title: space-return-throw-case
-layout: doc
---
(removed) This rule was **removed** in ESLint v2.0 and **replaced** by the [keyword-spacing](keyword-spacing) rule.
-(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#--fix) automatically fixed problems reported by this rule.
+(fixable) The `--fix` option on the [command line](../use/command-line-interface#--fix) automatically fixed problems reported by this rule.
Require spaces following `return`, `throw`, and `case`.
---
title: space-unary-ops
-layout: doc
rule_type: layout
---
---
title: space-unary-word-ops
-layout: doc
---
---
title: spaced-comment
-layout: doc
rule_type: suggestion
related_rules:
- spaced-line-comment
---
title: spaced-line-comment
-layout: doc
related_rules:
- spaced-comment
---
title: strict
-layout: doc
rule_type: suggestion
---
This rule requires or disallows strict mode directives.
-This rule disallows strict mode directives, no matter which option is specified, if ESLint configuration specifies either of the following as [parser options](/docs/user-guide/configuring/language-options#specifying-parser-options):
+This rule disallows strict mode directives, no matter which option is specified, if ESLint configuration specifies either of the following as [parser options](../use/configure/language-options#specifying-parser-options):
* `"sourceType": "module"` that is, files are **ECMAScript** modules
* `"impliedStrict": true` property in the `ecmaFeatures` object
The `"safe"` option corresponds to the `"global"` option if ESLint considers a file to be a **Node.js** or **CommonJS** module because the configuration specifies either of the following:
-* `node` or `commonjs` [environments](/docs/user-guide/configuring/language-options#specifying-environments)
-* `"globalReturn": true` property in the `ecmaFeatures` object of [parser options](/docs/user-guide/configuring/language-options#specifying-parser-options)
+* `node` or `commonjs` [environments](../use/configure/language-options#specifying-environments)
+* `"globalReturn": true` property in the `ecmaFeatures` object of [parser options](../use/configure/language-options#specifying-parser-options)
Otherwise the `"safe"` option corresponds to the `"function"` option. Note that if `"globalReturn": false` is explicitly specified in the configuration, the `"safe"` option will correspond to the `"function"` option regardless of the specified environment.
## When Not To Use It
-In a codebase that has both strict and non-strict code, either turn this rule off, or [selectively disable it](/docs/user-guide/configuring/rules#disabling-rules) where necessary. For example, functions referencing `arguments.callee` are invalid in strict mode. A [full list of strict mode differences](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode#Differences_from_non-strict_to_strict) is available on MDN.
+In a codebase that has both strict and non-strict code, either turn this rule off, or [selectively disable it](../use/configure/rules#disabling-rules) where necessary. For example, functions referencing `arguments.callee` are invalid in strict mode. A [full list of strict mode differences](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode#Differences_from_non-strict_to_strict) is available on MDN.
---
title: switch-colon-spacing
-layout: doc
rule_type: layout
---
---
title: symbol-description
-layout: doc
rule_type: suggestion
further_reading:
- https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-description
---
title: template-curly-spacing
-layout: doc
rule_type: layout
---
---
title: template-tag-spacing
-layout: doc
rule_type: layout
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals
---
title: unicode-bom
-layout: doc
rule_type: layout
---
---
title: use-isnan
-layout: doc
rule_type: problem
---
---
title: valid-jsdoc
-layout: doc
rule_type: suggestion
related_rules:
- require-jsdoc
---
title: valid-typeof
-layout: doc
rule_type: problem
further_reading:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
---
title: vars-on-top
-layout: doc
rule_type: suggestion
further_reading:
- https://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
---
title: wrap-iife
-layout: doc
rule_type: layout
---
---
title: wrap-regex
-layout: doc
rule_type: layout
---
---
title: yield-star-spacing
-layout: doc
rule_type: layout
further_reading:
- https://leanpub.com/understandinges6/read/#leanpub-auto-generators
---
title: yoda
-layout: doc
rule_type: suggestion
further_reading:
- https://en.wikipedia.org/wiki/Yoda_conditions
---json
{
"permalink": "feed.xml",
+ "layout": false,
"eleventyExcludeFromCollections": true,
"metadata": {
"title": "ESLint Blog",
---
permalink: /sitemap.xml
+layout: false
eleventyExcludeFromCollections: true
---
<?xml version="1.0" encoding="utf-8"?>
--- /dev/null
+---
+title: Command Line Interface Reference
+eleventyNavigation:
+ key: command line interface
+ parent: use eslint
+ title: Command Line Interface Reference
+ order: 4
+
+---
+
+The ESLint Command Line Interface (CLI) lets you execute linting from the terminal. The CLI has a variety of options that you can pass to configure ESLint.
+
+## Run the CLI
+
+ESLint requires Node.js for installation. Follow the instructions in the [Getting Started Guide](getting-started) to install ESLint.
+
+Most users use [`npx`](https://docs.npmjs.com/cli/v8/commands/npx) to run ESLint on the command line like this:
+
+```shell
+npx eslint [options] [file|dir|glob]*
+```
+
+Such as:
+
+```shell
+# Run on two files
+npx eslint file1.js file2.js
+
+# Run on multiple files
+npx eslint lib/**
+```
+
+Please note that when passing a glob as a parameter, it is expanded by your shell. The results of the expansion can vary depending on your shell, and its configuration. If you want to use node `glob` syntax, you have to quote your parameter (using double quotes if you need it to run in Windows), as follows:
+
+```shell
+npx eslint "lib/**"
+```
+
+**Note:** You can also use alternative package managers such as [Yarn](https://yarnpkg.com/) or [pnpm](https://pnpm.io/) to run ESLint. Please refer to your package manager's documentation for the correct syntax.
+
+## Pass Multiple Values to an Option
+
+Options that accept multiple values can be specified by repeating the option or with a comma-delimited list (other than [`--ignore-pattern`](#--ignore-pattern), which does not allow the second style).
+
+Examples of options that accept multiple values:
+
+```shell
+npx eslint --ext .jsx --ext .js lib/
+# OR
+npx eslint --ext .jsx,.js lib/
+```
+
+## Options
+
+You can view all the CLI options by running `npx eslint -h`.
+
+```txt
+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
+ --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
+
+Specify rules and plugins:
+ --plugin [String] Specify plugins
+ --rule Object Specify rules
+ --rulesdir [path::String] Load additional rules from this directory. Deprecated: Use rules from plugins
+
+Fix 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)
+
+Ignore 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)
+
+Use stdin:
+ --stdin Lint code provided on <STDIN> - default: false
+ --stdin-filename String Specify filename to process STDIN as
+
+Handle warnings:
+ --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
+
+Inline configuration comments:
+ --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 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
+ --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
+```
+
+### Basic Configuration
+
+#### `--no-eslintrc`
+
+Disables use of configuration from `.eslintrc.*` and `package.json` files.
+
+* **Argument Type**: No argument.
+
+##### `--no-eslintrc` example
+
+```shell
+npx eslint --no-eslintrc file.js
+```
+
+#### `-c`, `--config`
+
+This option allows you to specify an additional configuration file for ESLint (see [Configure ESLint](configure/) for more).
+
+* **Argument Type**: String. Path to file.
+* **Multiple Arguments**: No
+
+##### `-c`, `--config` example
+
+```shell
+npx eslint -c ~/my-eslint.json file.js
+```
+
+This example uses the configuration file at `~/my-eslint.json`.
+
+If `.eslintrc.*` and/or `package.json` files are also used for configuration (i.e., `--no-eslintrc` was not specified), the configurations are merged. Options from this configuration file have precedence over the options from `.eslintrc.*` and `package.json` files.
+
+#### `--env`
+
+This option enables specific environments.
+
+* **Argument Type**: String. One of the available environments.
+* **Multiple Arguments**: Yes
+
+Details about the global variables defined by each environment are available in the [Specifying Environments](configure/language-options#specifying-environments) documentation. This option only enables environments. It does not disable environments set in other configuration files. To specify multiple environments, separate them using commas, or use the option multiple times.
+
+##### `--env` example
+
+```shell
+npx eslint --env browser,node file.js
+npx eslint --env browser --env node file.js
+```
+
+#### `--ext`
+
+This option allows you to specify which file extensions ESLint uses when searching for target files in the directories you specify.
+
+* **Argument Type**: String. File extension.
+* **Multiple Arguments**: Yes
+* **Default Value**: `.js` and the files that match the `overrides` entries of your configuration.
+
+`--ext` is only used when the patterns to lint are directories. If you use glob patterns or file names, then `--ext` is ignored. For example, `npx eslint "lib/*" --ext .js` matches all files within the `lib/` directory, regardless of extension.
+
+##### `--ext` example
+
+```shell
+# Use only .ts extension
+npx eslint . --ext .ts
+
+# Use both .js and .ts
+npx eslint . --ext .js --ext .ts
+
+# Also use both .js and .ts
+npx eslint . --ext .js,.ts
+```
+
+#### `--global`
+
+This option defines global variables so that they are not flagged as undefined by the [`no-undef`](../rules/no-undef) rule.
+
+* **Argument Type**: String. Name of the global variable. Any specified global variables are assumed to be read-only by default, but appending `:true` to a variable's name ensures that `no-undef` also allows writes.
+* **Multiple Arguments**: Yes
+
+##### `--global` example
+
+```shell
+npx eslint --global require,exports:true file.js
+npx eslint --global require --global exports:true
+```
+
+#### `--parser`
+
+This option allows you to specify a parser to be used by ESLint.
+
+* **Argument Type**: String. Parser to be used by ESLint.
+* **Multiple Arguments**: No
+* **Default Value**: `espree`
+
+##### `--parser` example
+
+```shell
+# Use TypeScript ESLint parser
+npx eslint --parser @typescript-eslint/parser file.ts
+```
+
+#### `--parser-options`
+
+This option allows you to specify parser options to be used by ESLint. The available parser options are determined by the parser being used.
+
+* **Argument Type**: Key/value pair separated by colon (`:`).
+* **Multiple Arguments**: Yes
+
+##### `--parser-options` example
+
+```shell
+echo '3 ** 4' | npx eslint --stdin --parser-options ecmaVersion:6 # fails with a parsing error
+echo '3 ** 4' | npx eslint --stdin --parser-options ecmaVersion:7 # succeeds, yay!
+```
+
+#### `--resolve-plugins-relative-to`
+
+Changes the directory where plugins are resolved from.
+
+* **Argument Type**: String. Path to directory.
+* **Multiple Arguments**: No
+* **Default Value**: By default, plugins are resolved from the directory in which your configuration file is found.
+
+This option should be used when plugins were installed by someone other than the end user. It should be set to the project directory of the project that has a dependency on the necessary plugins.
+
+For example:
+
+* When using a config file that is located outside of the current project (with the `--config` flag), if the config uses plugins which are installed locally to itself, `--resolve-plugins-relative-to` should be set to the directory containing the config file.
+* If an integration has dependencies on ESLint and a set of plugins, and the tool invokes ESLint on behalf of the user with a preset configuration, the tool should set `--resolve-plugins-relative-to` to the top-level directory of the tool.
+
+##### `--resolve-plugins-relative-to` example
+
+```shell
+npx eslint --config ~/personal-eslintrc.js \
+--resolve-plugins-relative-to /usr/local/lib/
+```
+
+### Specify Rules and Plugins
+
+#### `--plugin`
+
+This option specifies a plugin to load.
+
+* **Argument Type**: String. Plugin name. You can optionally omit the prefix `eslint-plugin-` from the plugin name.
+* **Multiple Arguments**: Yes
+
+Before using the plugin, you have to install it using npm.
+
+##### `--plugin` example
+
+```shell
+npx eslint --plugin jquery file.js
+npx eslint --plugin eslint-plugin-mocha file.js
+```
+
+#### `--rule`
+
+This option specifies the rules to be used.
+
+* **Argument Type**: Rules and their configuration specified with [levn](https://github.com/gkz/levn#levn--) format.
+* **Multiple Arguments**: Yes
+
+These rules are merged with any rules specified with configuration files. If the rule is defined in a plugin, you have to prefix the rule ID with the plugin name and a `/`.
+
+To ignore rules in `.eslintrc` configuration files and only run rules specified in the command line, use the `--rules` flag in combination with the [`--no-eslintrc`](#--no-eslintrc) flag.
+
+##### `--rule` example
+
+```shell
+# Apply single rule
+npx eslint --rule 'quotes: [error, double]'
+# Apply multiple rules
+npx eslint --rule 'guard-for-in: error' --rule 'brace-style: [error, 1tbs]'
+# Apply rule from jquery plugin
+npx eslint --rule 'jquery/dollar-sign: error'
+# Only apply rule from the command line
+npx eslint --rule 'quotes: [error, double]' --no-eslintrc
+```
+
+#### `--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.
+
+* **Argument Type**: String. Path to directory. The rules in your custom rules directory must follow the same format as bundled rules to work properly.
+* **Multiple Arguments**: Yes.
+
+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.
+
+##### `--rulesdir` example
+
+```shell
+npx eslint --rulesdir my-rules/ file.js
+npx eslint --rulesdir my-rules/ --rulesdir my-other-rules/ file.js
+```
+
+### Fix Problems
+
+#### `--fix`
+
+This option instructs ESLint to try to fix as many issues as possible. The fixes are made to the actual files themselves and only the remaining unfixed issues are output.
+
+* **Argument Type**: No argument.
+
+Not all problems are fixable using this option, and the option does not work in these situations:
+
+1. This option throws an error when code is piped to ESLint.
+1. This option has no effect on code that uses a processor, unless the processor opts into allowing autofixes.
+
+If you want to fix code from `stdin` or otherwise want to get the fixes without actually writing them to the file, use the [`--fix-dry-run`](#--fix-dry-run) option.
+
+##### `--fix` example
+
+```shell
+npx eslint --fix file.js
+```
+
+#### `--fix-dry-run`
+
+This option has the same effect as `--fix` with the difference that the fixes are not saved to the file system. Because the default formatter does not output the fixed code, you'll have to use another formatter (e.g. `--format json`) to get the fixes.
+
+* **Argument Type**: No argument.
+
+This makes it possible to fix code from `stdin` when used with the `--stdin` flag.
+
+This flag can be useful for integrations (e.g. editor plugins) which need to autofix text from the command line without saving it to the filesystem.
+
+##### `--fix-dry-run` example
+
+```shell
+getSomeText | npx eslint --stdin --fix-dry-run --format json
+```
+
+#### `--fix-type`
+
+This option allows you to specify the type of fixes to apply when using either `--fix` or `--fix-dry-run`.
+
+* **Argument Type**: String. One of the following fix types:
+ 1. `problem` - fix potential errors in the code
+ 1. `suggestion` - apply fixes to the code that improve it
+ 1. `layout` - apply fixes that do not change the program structure (AST)
+ 1. `directive` - apply fixes to inline directives such as `// eslint-disable`
+* **Multiple Arguments**: Yes
+
+This option is helpful if you are using another program to format your code, but you would still like ESLint to apply other types of fixes.
+
+##### `--fix-type` example
+
+```shell
+npx eslint --fix --fix-type suggestion .
+npx eslint --fix --fix-type suggestion --fix-type problem .
+npx eslint --fix --fix-type suggestion,layout .
+```
+
+### Ignore Files
+
+#### `--ignore-path`
+
+This option allows you to specify the file to use as your `.eslintignore`.
+
+* **Argument Type**: String. Path to file.
+* **Multiple Arguments**: No
+* **Default Value**: By default, ESLint looks for `.eslintignore` in the current working directory.
+
+**Note:** `--ignore-path` is not supported when using [flat configuration](./configure/configuration-files-new) (`eslint.config.js`).
+
+##### `--ignore-path` example
+
+```shell
+npx eslint --ignore-path tmp/.eslintignore file.js
+npx eslint --ignore-path .gitignore file.js
+```
+
+#### `--no-ignore`
+
+Disables excluding of files from `.eslintignore` files, `--ignore-path` flags, `--ignore-pattern` flags, and the `ignorePatterns` property in config files.
+
+* **Argument Type**: No argument.
+
+##### `--no-ignore` example
+
+```shell
+npx eslint --no-ignore file.js
+```
+
+#### `--ignore-pattern`
+
+This option allows you to specify patterns of files to ignore (in addition to those in `.eslintignore`).
+
+* **Argument Type**: String. The supported syntax is the same as for [`.eslintignore` files](configure/ignore#the-eslintignore-file), which use the same patterns as the [`.gitignore` specification](https://git-scm.com/docs/gitignore). You should quote your patterns in order to avoid shell interpretation of glob patterns.
+* **Multiple Arguments**: Yes
+
+##### `--ignore-pattern` example
+
+```shell
+npx eslint --ignore-pattern "/lib/" --ignore-pattern "/src/vendor/*" .
+```
+
+### Use stdin
+
+#### `--stdin`
+
+This option tells ESLint to read and lint source code from STDIN instead of from files. You can use this to pipe code to ESLint.
+
+* **Argument Type**: No argument.
+
+##### `--stdin` example
+
+```shell
+cat myfile.js | npx eslint --stdin
+```
+
+#### `--stdin-filename`
+
+This option allows you to specify a filename to process STDIN as.
+
+* **Argument Type**: String. Path to file.
+* **Multiple Arguments**: No
+
+This is useful when processing files from STDIN and you have rules which depend on the filename.
+
+##### `--stdin-filename` example
+
+```shell
+cat myfile.js | npx eslint --stdin --stdin-filename myfile.js
+```
+
+### Handle Warnings
+
+#### `--quiet`
+
+This option allows you to disable reporting on warnings. If you enable this option, only errors are reported by ESLint.
+
+* **Argument Type**: No argument.
+
+##### `--quiet` example
+
+```shell
+npx eslint --quiet file.js
+```
+
+#### `--max-warnings`
+
+This option allows you to specify a warning threshold, which can be used to force ESLint to exit with an error status if there are too many warning-level rule violations in your project.
+
+* **Argument Type**: Integer. The maximum number of warnings to allow. To prevent this behavior, do not use this option or specify `-1` as the argument.
+* **Multiple Arguments**: No
+
+Normally, if ESLint runs and finds no errors (only warnings), it exits with a success exit status. However, if `--max-warnings` is specified and the total warning count is greater than the specified threshold, ESLint exits with an error status.
+
+##### `--max-warnings` example
+
+```shell
+npx eslint --max-warnings 10 file.js
+```
+
+### Output
+
+#### `-o`, `--output-file`
+
+Write the output of linting results to a specified file.
+
+* **Argument Type**: String. Path to file.
+* **Multiple Arguments**: No
+
+##### `-o`, `--output-file` example
+
+```shell
+npx eslint -o ./test/test.html
+```
+
+#### `-f`, `--format`
+
+This option specifies the output format for the console.
+
+* **Argument Type**: String. One of the [built-in formatters](formatters/) or a custom formatter.
+* **Multiple Arguments**: No
+* **Default Value**: [`stylish`](formatters/#stylish)
+
+If you are using a custom formatter defined in a local file, you can specify the path to the custom formatter file.
+
+An npm-installed formatter is resolved with or without `eslint-formatter-` prefix.
+
+When specified, the given format is output to the console. If you'd like to save that output into a file, you can do so on the command line like so:
+
+```shell
+# Saves the output into the `results.txt` file.
+npx eslint -f compact file.js > results.txt
+```
+
+##### `-f`, `--format` example
+
+Use the built-in `compact` formatter:
+
+```shell
+npx eslint --format compact file.js
+```
+
+Use a local custom formatter:
+
+```shell
+npx eslint -f ./customformat.js file.js
+```
+
+Use an npm-installed formatter:
+
+```shell
+npm install eslint-formatter-pretty
+
+# Then run one of the following commands
+npx eslint -f pretty file.js
+# or alternatively
+npx eslint -f eslint-formatter-pretty file.js
+```
+
+#### `--color` and `--no-color`
+
+These options force the enabling/disabling of colorized output.
+
+* **Argument Type**: No argument.
+
+You can use these options to override the default behavior, which is to enable colorized output unless no TTY is detected, such as when piping `eslint` through `cat` or `less`.
+
+##### `--color` and `--no-color` example
+
+```shell
+npx eslint --color file.js | cat
+npx eslint --no-color file.js
+```
+
+### Inline Configuration Comments
+
+#### `--no-inline-config`
+
+This option prevents inline comments like `/*eslint-disable*/` or
+`/*global foo*/` from having any effect.
+
+* **Argument Type**: No argument.
+
+This allows you to set an ESLint config without files modifying it. All inline config comments are ignored, such as:
+
+* `/*eslint-disable*/`
+* `/*eslint-enable*/`
+* `/*global*/`
+* `/*eslint*/`
+* `/*eslint-env*/`
+* `// eslint-disable-line`
+* `// eslint-disable-next-line`
+
+##### `--no-inline-config` example
+
+```shell
+npx eslint --no-inline-config file.js
+```
+
+#### `--report-unused-disable-directives`
+
+This option causes ESLint to report directive comments like `// eslint-disable-line` when no errors would have been reported on that line anyway.
+
+* **Argument Type**: No argument.
+
+This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` comments which are no longer applicable.
+
+::: warning
+When using this option, it is possible that new errors start being reported whenever ESLint or custom rules are upgraded.
+
+For example, suppose a rule has a bug that causes it to report a false positive, and an `eslint-disable` comment is added to suppress the incorrect report. If the bug is then fixed in a patch release of ESLint, the `eslint-disable` comment becomes unused since ESLint is no longer generating an incorrect report. This results in a new reported error for the unused directive if the `report-unused-disable-directives` option is used.
+:::
+
+##### `--report-unused-disable-directives` example
+
+```shell
+npx eslint --report-unused-disable-directives file.js
+```
+
+### Caching
+
+#### `--cache`
+
+Store the info about processed files in order to only operate on the changed ones. Enabling this option can dramatically improve ESLint's run time performance by ensuring that only changed files are linted.
+The cache is stored in `.eslintcache` by default.
+
+* **Argument Type**: No argument.
+
+If you run ESLint with `--cache` and then run ESLint without `--cache`, the `.eslintcache` file will be deleted. This is necessary because the results of the lint might change and make `.eslintcache` invalid. If you want to control when the cache file is deleted, then use `--cache-location` to specify an alternate location for the cache file.
+
+Autofixed files are not placed in the cache. Subsequent linting that does not trigger an autofix will place it in the cache.
+
+##### `--cache` example
+
+```shell
+npx eslint --cache file.js
+```
+
+#### `--cache-file`
+
+**Deprecated**: Use `--cache-location` instead.
+
+Path to the cache file. If none specified `.eslintcache` is used. The file is created in the directory where the `eslint` command is executed.
+
+#### `--cache-location`
+
+Specify the path to the cache location. Can be a file or a directory.
+
+* **Argument Type**: String. Path to file or directory. If a directory is specified, a cache file is created inside the specified folder. The name of the file is based on the hash of the current working directory, e.g.: `.cache_hashOfCWD`.
+* **Multiple Arguments**: No
+* **Default Value**: If no location is specified, `.eslintcache` is used. The file is created in the directory where the `eslint` command is executed.
+
+If the directory for the cache does not exist make sure you add a trailing `/` on \*nix systems or `\` on Windows. Otherwise, the path is assumed to be a file.
+
+##### `--cache-location` example
+
+```shell
+npx eslint "src/**/*.js" --cache --cache-location "/Users/user/.eslintcache/"
+```
+
+#### `--cache-strategy`
+
+Strategy for the cache to use for detecting changed files.
+
+* **Argument Type**: String. One of the following values:
+ 1. `metadata`
+ 1. `content`
+* **Multiple Arguments**: No
+* **Default Value**: `metadata`
+
+The `content` strategy can be useful in cases where the modification time of your files changes even if their contents have not. For example, this can happen during git operations like `git clone` because git does not track file modification time.
+
+##### `--cache-strategy` example
+
+```shell
+npx eslint "src/**/*.js" --cache --cache-strategy content
+```
+
+### Miscellaneous
+
+#### `--init`
+
+This option runs `npm init @eslint/config` to start the config initialization wizard. It's designed to help new users quickly create an `.eslintrc` file by answering a few questions. When you use this flag, the CLI does not perform linting.
+
+* **Argument Type**: No argument.
+
+The resulting configuration file is created in the current directory.
+
+##### `--init` example
+
+```shell
+npx eslint --init
+```
+
+#### `--env-info`
+
+This option outputs information about the execution environment, including the version of Node.js, npm, and local and global installations of ESLint.
+
+* **Argument Type**: No argument.
+
+The ESLint team may ask for this information to help solve bugs. When you use this flag, the CLI does not perform linting.
+
+##### `--env-info` example
+
+```shell
+npx eslint --env-info
+```
+
+#### `--no-error-on-unmatched-pattern`
+
+This option prevents errors when a quoted glob pattern or `--ext` is unmatched. This does not prevent errors when your shell can't match a glob.
+
+* **Argument Type**: No argument.
+
+##### `--no-error-on-unmatched-pattern` example
+
+```shell
+npx eslint --no-error-on-unmatched-pattern --ext .ts "lib/*"
+```
+
+#### `--exit-on-fatal-error`
+
+This option causes ESLint to exit with exit code 2 if one or more fatal parsing errors occur. Without this option, ESLint reports fatal parsing errors as rule violations.
+
+* **Argument Type**: No argument.
+
+##### `--exit-on-fatal-error` example
+
+```shell
+npx eslint --exit-on-fatal-error file.js
+```
+
+#### `--debug`
+
+This option outputs debugging information to the console. Add this flag to an ESLint command line invocation in order to get extra debugging information while the command runs.
+
+* **Argument Type**: No argument.
+
+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.
+
+##### `--debug` example
+
+```shell
+npx eslint --debug test.js
+```
+
+#### `-h`, `--help`
+
+This option outputs the help menu, displaying all of the available options. All other options are ignored when this is present. When you use this flag, the CLI does not perform linting.
+
+* **Argument Type**: No argument.
+
+##### `-h`, `--help` example
+
+```shell
+npx eslint --help
+```
+
+#### `-v`, `--version`
+
+This option outputs the current ESLint version onto the console. All other options are ignored when this is present. When you use this flag, the CLI does not perform linting.
+
+* **Argument Type**: No argument.
+
+##### `-v`, `--version` example
+
+```shell
+npx eslint --version
+```
+
+#### `--print-config`
+
+This option outputs the configuration to be used for the file passed. When present, no linting is performed and only config-related options are valid. When you use this flag, the CLI does not perform linting.
+
+* **Argument Type**: String. Path to file.
+* **Multiple Arguments**: No
+
+##### `--print-config` example
+
+```shell
+npx eslint --print-config file.js
+```
+
+## Exit Codes
+
+When linting files, ESLint exits with one of the following exit codes:
+
+* `0`: Linting was successful and there are no linting errors. If the [`--max-warnings`](#--max-warnings) flag is set to `n`, the number of linting warnings is at most `n`.
+* `1`: Linting was successful and there is at least one linting error, or there are more linting warnings than allowed by the `--max-warnings` option.
+* `2`: Linting was unsuccessful due to a configuration problem or an internal error.
--- /dev/null
+---
+title: Configuration Files (New)
+eleventyNavigation:
+ key: configuration files
+ parent: configure
+ title: Configuration Files (New)
+ order: 1
+
+---
+
+::: warning
+This config system is feature complete but not enabled by default. To opt-in, place an `eslint.config.js` file in the root of your project or set the `ESLINT_USE_FLAT_CONFIG` environment variable to `true`. To opt-out, even in the presence of an `eslint.config.js` file, set the environment variable to `false`. If you are using the API, you can use the configuration system described on this page by using the `FlatESLint` class, the `FlatRuleTester` class, or by setting `configType: "flat"` in the `Linter` class.
+:::
+
+You can put your ESLint project configuration in a configuration file. You can include built-in rules, how you want them enforced, plugins with custom rules, shareable configurations, which files you want rules to apply to, and more.
+
+## Configuration File
+
+The ESLint configuration file is named `eslint.config.js`. It should be placed in the root directory of your project and export an array of [configuration objects](#configuration-objects). Here's an example:
+
+```js
+export default [
+ {
+ rules: {
+ semi: "error",
+ "prefer-const": "error"
+ }
+ }
+]
+```
+
+In this example, the configuration array contains just one configuration object. The configuration object enables two rules: `semi` and `prefer-const`. These rules are applied to all of the files ESLint processes using this config file.
+
+## Configuration Objects
+
+Each configuration object contains all of the information ESLint needs to execute on a set of files. Each configuration object is made up of these properties:
+
+* `files` - An array of glob patterns indicating the files that the configuration object should apply to. If not specified, the configuration object applies to all files matched by any other configuration object.
+* `ignores` - An array of glob patterns indicating the files that the configuration object should not apply to. If not specified, the configuration object applies to all files matched by `files`.
+* `languageOptions` - An object containing settings related to how JavaScript is configured for linting.
+ * `ecmaVersion` - The version of ECMAScript to support. May be any year (i.e., `2022`) or version (i.e., `5`). Set to `"latest"` for the most recent supported version. (default: `"latest"`)
+ * `sourceType` - The type of JavaScript source code. Possible values are `"script"` for traditional script files, `"module"` for ECMAScript modules (ESM), and `"commonjs"` for CommonJS files. (default: `"module"` for `.js` and `.mjs` files; `"commonjs"` for `.cjs` files)
+ * `globals` - An object specifying additional objects that should be added to the global scope during linting.
+ * `parser` - An object containing a `parse()` method or a `parseForESLint()` method. (default: [`espree`](https://github.com/eslint/espree))
+ * `parserOptions` - An object specifying additional options that are passed directly to the `parse()` or `parseForESLint()` method on the parser. The available options are parser-dependent.
+* `linterOptions` - An object containing settings related to the linting process.
+ * `noInlineConfig` - A Boolean value indicating if inline configuration is allowed.
+ * `reportUnusedDisableDirectives` - A Boolean value indicating if unused disable directives should be tracked and reported.
+* `processor` - Either an object containing `preprocess()` and `postprocess()` methods or a string indicating the name of a processor inside of a plugin (i.e., `"pluginName/processorName"`).
+* `plugins` - An object containing a name-value mapping of plugin names to plugin objects. When `files` is specified, these plugins are only available to the matching files.
+* `rules` - An object containing the configured rules. When `files` or `ignores` are specified, these rule configurations are only available to the matching files.
+* `settings` - An object containing name-value pairs of information that should be available to all rules.
+
+### Specifying `files` and `ignores`
+
+::: tip
+Patterns specified in `files` and `ignores` use [`minimatch`](https://www.npmjs.com/package/minimatch) syntax and are evaluated relative to the location of the `eslint.config.js` file.
+:::
+
+You can use a combination of `files` and `ignores` to determine which files should apply the configuration object and which should not. By default, ESLint matches `**/*.js`, `**/*.cjs`, and `**/*.mjs`. Because config objects that don't specify `files` or `ignores` apply to all files that have been matched by any other configuration object, those config objects apply to any JavaScript files passed to ESLint by default. For example:
+
+```js
+export default [
+ {
+ rules: {
+ semi: "error"
+ }
+ }
+];
+```
+
+With this configuration, the `semi` rule is enabled for all files that match the default files in ESLint. So if you pass `example.js` to ESLint, the `semi` rule is applied. If you pass a non-JavaScript file, like `example.txt`, the `semi` rule is not applied because there are no other configuration objects that match that filename. (ESLint outputs an error message letting you know that the file was ignored due to missing configuration.)
+
+#### Excluding files with `ignores`
+
+You can limit which files a configuration object applies to by specifying a combination of `files` and `ignores` patterns. For example, you may want certain rules to apply only to files in your `src` directory:
+
+```js
+export default [
+ {
+ files: ["src/**/*.js"],
+ rules: {
+ semi: "error"
+ }
+ }
+];
+```
+
+Here, only the JavaScript files in the `src` directory have the `semi` rule applied. If you run ESLint on files in another directory, this configuration object is skipped. By adding `ignores`, you can also remove some of the files in `src` from this configuration object:
+
+```js
+export default [
+ {
+ files: ["src/**/*.js"],
+ ignores: ["**/*.config.js"],
+ rules: {
+ semi: "error"
+ }
+ }
+];
+```
+
+This configuration object matches all JavaScript files in the `src` directory except those that end with `.config.js`. You can also use negation patterns in `ignores` to exclude files from the ignore patterns, such as:
+
+```js
+export default [
+ {
+ files: ["src/**/*.js"],
+ ignores: ["**/*.config.js", "!**/eslint.config.js"],
+ rules: {
+ semi: "error"
+ }
+ }
+];
+```
+
+Here, the configuration object excludes files ending with `.config.js` except for `eslint.config.js`. That file still has `semi` applied.
+
+If `ignores` is used without `files` and any other setting, then the configuration object applies to all files except the ones specified in `ignores`, for example:
+
+```js
+export default [
+ {
+ ignores: ["**/*.config.js"],
+ rules: {
+ semi: "error"
+ }
+ }
+];
+```
+
+This configuration object applies to all files except those ending with `.config.js`. Effectively, this is like having `files` set to `**/*`. In general, it's a good idea to always include `files` if you are specifying `ignores`.
+
+#### Globally ignoring files with `ignores`
+
+If `ignores` is used without any other keys in the configuration object, then the patterns act as global ignores. Here's an example:
+
+```js
+export default [
+ {
+ ignores: [".config/*"]
+ }
+];
+```
+
+This configuration specifies that all of the files in the `.config` directory should be ignored. This pattern is added after the default patterns, which are `["**/node_modules/", ".git/"]`.
+
+You can also unignore files and directories that are ignored by the default patterns. For example, this config unignores `node_modules/mylibrary`:
+
+```js
+export default [
+ {
+ ignores: [
+ "!node_modules/", // unignore `node_modules/` directory
+ "node_modules/*", // ignore its content
+ "!node_modules/mylibrary/" // unignore `node_modules/mylibrary` directory
+ ]
+ }
+];
+```
+
+#### Cascading configuration objects
+
+When more than one configuration object matches a given filename, the configuration objects are merged with later objects overriding previous objects when there is a conflict. For example:
+
+```js
+export default [
+ {
+ files: ["**/*.js"],
+ languageOptions: {
+ globals: {
+ MY_CUSTOM_GLOBAL: "readonly"
+ }
+ }
+ },
+ {
+ files: ["tests/**/*.js"],
+ languageOptions: {
+ globals: {
+ it: "readonly",
+ describe: "readonly"
+ }
+ }
+ }
+];
+```
+
+Using this configuration, all JavaScript files define a custom global object defined called `MY_CUSTOM_GLOBAL` while those JavaScript files in the `tests` directory have `it` and `describe` defined as global objects in addition to `MY_CUSTOM_GLOBAL`. For any JavaScript file in the tests directory, both configuration objects are applied, so `languageOptions.globals` are merged to create a final result.
+
+### Configuring linter options
+
+Options specific to the linting process can be configured using the `linterOptions` object. These effect how linting proceeds and does not affect how the source code of the file is interpreted.
+
+#### Disabling inline configuration
+
+Inline configuration is implemented using an `/*eslint*/` comment, such as `/*eslint semi: error*/`. You can disallow inline configuration by setting `noInlineConfig` to `true`. When enabled, all inline configuration is ignored. Here's an example:
+
+```js
+export default [
+ {
+ files: ["**/*.js"],
+ linterOptions: {
+ noInlineConfig: true
+ }
+ }
+];
+```
+
+#### Reporting unused disable directives
+
+Disable directives such as `/*eslint-disable*/` and `/*eslint-disable-next-line*/` are used to disable ESLint rules around certain portions of code. As code changes, it's possible for these directives to no longer be needed because the code has changed in such a way that the rule is no longer triggered. You can enable reporting of these unused disable directives by setting the `reportUnusedDisableDirectives` option to `true`, as in this example:
+
+```js
+export default [
+ {
+ files: ["**/*.js"],
+ linterOptions: {
+ reportUnusedDisableDirectives: true
+ }
+ }
+];
+```
+
+By default, unused disable directives are reported as warnings. You can change this setting using the `--report-unused-disable-directives` command line option.
+
+### Configuring language options
+
+Options specific to how ESLint evaluates your JavaScript code can be configured using the `languageOptions` object.
+
+#### Configuring the JavaScript version
+
+To configure the version of JavaScript (ECMAScript) that ESLint uses to evaluate your JavaScript, use the `ecmaVersion` property. This property determines which global variables and syntax are valid in your code and can be set to the version number (such as `6`), the year number (such as `2022`), or `"latest"` (for the most recent version that ESLint supports). By default, `ecmaVersion` is set to `"latest"` and it's recommended to keep this default unless you need to ensure that your JavaScript code is evaluated as an older version. For example, some older runtimes might only allow ECMAScript 5, in which case you can configure ESLint like this:
+
+```js
+export default [
+ {
+ files: ["**/*.js"],
+ languageOptions: {
+ ecmaVersion: 5
+ }
+ }
+];
+```
+
+#### Configuring the JavaScript source type
+
+ESLint can evaluate your code in one of three ways:
+
+1. ECMAScript module (ESM) - Your code has a module scope and is run in strict mode.
+1. CommonJS - Your code has a top-level function scope and runs in non-strict mode.
+1. Script - Your code has a shared global scope and runs in non-strict mode.
+
+You can specify which of these modes your code is intended to run in by specifying the `sourceType` property. This property can be set to `"module"`, `"commonjs"`, or `"script"`. By default, `sourceType` is set to `"module"` for `.js` and `.mjs` files and is set to `"commonjs"` for `.cjs` files. Here's an example:
+
+```js
+export default [
+ {
+ files: ["**/*.js"],
+ languageOptions: {
+ sourceType: "script"
+ }
+ }
+];
+```
+
+#### Configuring a custom parser and its options
+
+In many cases, you can use the default parser that ESLint ships with for parsing your JavaScript code. You can optionally override the default parser by using the `parser` property. The `parser` property must be an object containing either a `parse()` method or a `parseForESLint()` method. For example, you can use the [`@babel/eslint-parser`](https://www.npmjs.com/package/@babel/eslint-parser) package to allow ESLint to parse experimental syntax:
+
+```js
+import babelParser from "@babel/eslint-parser";
+
+export default [
+ {
+ files: ["**/*.js", "**/*.mjs"],
+ languageOptions: {
+ parser: babelParser
+ }
+ }
+];
+```
+
+This configuration ensures that the Babel parser, rather than the default Espree parser, is used to parse all files ending with `.js` and `.mjs`.
+
+You can also pass options directly to the custom parser by using the `parserOptions` property. This property is an object whose name-value pairs are specific to the parser that you are using. For the Babel parser, you might pass in options like this:
+
+```js
+import babelParser from "@babel/eslint-parser";
+
+export default [
+ {
+ files: ["**/*.js", "**/*.mjs"],
+ languageOptions: {
+ parser: babelParser,
+ parserOptions: {
+ requireConfigFile: false,
+ babelOptions: {
+ babelrc: false,
+ configFile: false,
+ // your babel options
+ presets: ["@babel/preset-env"],
+ }
+ }
+ }
+ }
+];
+```
+
+#### Configuring global variables
+
+To configure global variables inside of a configuration object, set the `globals` configuration property to an object containing keys named for each of the global variables you want to use. For each global variable key, set the corresponding value equal to `"writable"` to allow the variable to be overwritten or `"readonly"` to disallow overwriting. For example:
+
+```js
+export default [
+ {
+ files: ["**/*.js"],
+ languageOptions: {
+ globals: {
+ var1: "writable",
+ var2: "readonly"
+ }
+ }
+ }
+];
+```
+
+These examples allow `var1` to be overwritten in your code, but disallow it for `var2`.
+
+Globals can be disabled with the string `"off"`. For example, in an environment where most ES2015 globals are available but `Promise` is unavailable, you might use this config:
+
+```js
+export default [
+ {
+ languageOptions: {
+ globals: {
+ Promise: "off"
+ }
+ }
+ }
+];
+```
+
+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.
+
+##### Predefined global variables
+
+Apart from the ECMAScript standard built-in globals, which are automatically enabled based on the configured `languageOptions.ecmaVersion`, ESLint doesn't provide predefined sets of global variables. You can use the [`globals`](https://www.npmjs.com/package/globals) package to additionally enable all globals for a specific environment. For example, here is how you can add `console`, amongst other browser globals, into your configuration.
+
+```js
+import globals from "globals";
+
+export default [
+ {
+ languageOptions: {
+ globals: {
+ ...globals.browser
+ }
+ }
+ }
+];
+```
+
+### Using plugins in your configuration
+
+Plugins are used to share rules, processors, configurations, parsers, and more across ESLint projects.
+
+#### Using plugin rules
+
+You can use specific rules included in a plugin. To do this, specify the plugin
+in a configuration object using the `plugins` key. The value for the `plugin` key
+is an object where the name of the plugin is the property name and the value is the plugin object itself. Here's an example:
+
+```js
+import jsdoc from "eslint-plugin-jsdoc";
+
+export default [
+ {
+ files: ["**/*.js"],
+ plugins: {
+ jsdoc: jsdoc
+ },
+ rules: {
+ "jsdoc/require-description": "error",
+ "jsdoc/check-values": "error"
+ }
+ }
+];
+```
+
+In this configuration, the JSDoc plugin is defined to have the name `jsdoc`. The prefix `jsdoc/` in each rule name indicates that the rule is coming from the plugin with that name rather than from ESLint itself.
+
+Because the name of the plugin and the plugin object are both `jsdoc`, you can also shorten the configuration to this:
+
+```js
+import jsdoc from "eslint-plugin-jsdoc";
+
+export default [
+ {
+ files: ["**/*.js"],
+ plugins: {
+ jsdoc
+ },
+ rules: {
+ "jsdoc/require-description": "error",
+ "jsdoc/check-values": "error"
+ }
+ }
+];
+```
+
+While this is the most common convention, you don't need to use the same name that the plugin prescribes. You can specify any prefix that you'd like, such as:
+
+```js
+import jsdoc from "eslint-plugin-jsdoc";
+
+export default [
+ {
+ files: ["**/*.js"],
+ plugins: {
+ jsd: jsdoc
+ },
+ rules: {
+ "jsd/require-description": "error",
+ "jsd/check-values": "error"
+ }
+ }
+];
+```
+
+This configuration object uses `jsd` as the prefix plugin instead of `jsdoc`.
+
+#### Using configurations included in plugins
+
+You can use a configuration included in a plugin by adding that configuration
+directly to the `eslint.config.js` configurations array.
+Often, you do this for a plugin's recommended configuration. Here's an example:
+
+```js
+import jsdoc from "eslint-plugin-jsdoc";
+
+export default [
+ // configuration included in plugin
+ jsdoc.configs.recommended,
+ // other configuration objects...
+ {
+ files: ["**/*.js"],
+ plugins: {
+ jsdoc: jsdoc
+ },
+ rules: {
+ "jsdoc/require-description": "warn",
+ }
+ }
+];
+```
+
+### Using processors
+
+Processors allow ESLint to transform text into pieces of code that ESLint can lint. You can specify the processor to use for a given file type by defining a `processor` property that contains either the processor name in the format `"pluginName/processorName"` to reference a processor in a plugin or an object containing both a `preprocess()` and a `postprocess()` method. For example, to extract JavaScript code blocks from a Markdown file, you might add this to your configuration:
+
+```js
+import markdown from "eslint-plugin-markdown";
+
+export default [
+ {
+ files: ["**/*.md"],
+ plugins: {
+ markdown
+ },
+ processor: "markdown/markdown",
+ settings: {
+ sharedData: "Hello"
+ }
+ }
+];
+```
+
+This configuration object specifies that there is a processor called `"markdown"` contained in the plugin named `"markdown"`. The configuration applies the processor to all files ending with `.md`.
+
+Processors may make named code blocks that function as filenames in configuration objects, such as `0.js` and `1.js`. ESLint handles such a named code block as a child of the original file. You can specify additional configuration objects for named code blocks. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files.
+
+```js
+import markdown from "eslint-plugin-markdown";
+
+export default [
+ {
+ files: ["**/*.md"],
+ plugins: {
+ markdown
+ },
+ processor: "markdown/markdown",
+ settings: {
+ sharedData: "Hello"
+ }
+ },
+
+ // applies only to code blocks
+ {
+ files: ["**/*.md/*.js"],
+ rules: {
+ strict: "off"
+ }
+ }
+];
+```
+
+### Configuring rules
+
+You can configure any number of rules in a configuration object by add a `rules` property containing an object with your rule configurations. The names in this object are the names of the rules and the values are the configurations for each of those rules. Here's an example:
+
+```js
+export default [
+ {
+ rules: {
+ semi: "error"
+ }
+ }
+];
+```
+
+This configuration object specifies that the [`semi`](../../rules/semi) rule should be enabled with a severity of `"error"`. You can also provide options to a rule by specifying an array where the first item is the severity and each item after that is an option for the rule. For example, you can switch the `semi` rule to disallow semicolons by passing `"never"` as an option:
+
+```js
+export default [
+ {
+ rules: {
+ semi: ["error", "never"]
+ }
+ }
+];
+```
+
+Each rule specifies its own options and can be any valid JSON data type. Please check the documentation for the rule you want to configure for more information about its available options.
+
+#### Rule severities
+
+There are three possible severities you can specify for a rule
+
+* `"error"` (or `2`) - the reported problem should be treated as an error. When using the ESLint CLI, errors cause the CLI to exit with a nonzero code.
+* `"warn"` (or `1`) - the reported problem should be treated as a warning. When using the ESLint CLI, warnings are reported but do not change the exit code. If only warnings are reported, the exit code is 0.
+* `"off"` (or `0`) - the rule should be turned off completely.
+
+#### Rule configuration cascade
+
+When more than one configuration object specifies the same rule, the rule configuration is merged with the later object taking precedence over any previous objects. For example:
+
+```js
+export default [
+ {
+ rules: {
+ semi: ["error", "never"]
+ }
+ },
+ {
+ rules: {
+ semi: ["warn", "always"]
+ }
+ }
+];
+```
+
+Using this configuration, the final rule configuration for `semi` is `["warn", "always"]` because it appears last in the array. The array indicates that the configuration is for the severity and any options. You can change just the severity by defining only a string or number, as in this example:
+
+```js
+export default [
+ {
+ rules: {
+ semi: ["error", "never"]
+ }
+ },
+ {
+ rules: {
+ semi: "warn"
+ }
+ }
+];
+```
+
+Here, the second configuration object only overrides the severity, so the final configuration for `semi` is `["warn", "never"]`.
+
+### Configuring shared settings
+
+ESLint supports adding shared settings into configuration files. When you add a `settings` object to a configuration object, it is supplied to every rule. By convention, plugins namespace the settings they are interested in to avoid collisions with others. Plugins can use `settings` to specify the information that should be shared across all of their rules. This may be useful if you are adding custom rules and want them to have access to the same information. Here's an example:
+
+```js
+export default [
+ {
+ settings: {
+ sharedData: "Hello"
+ }
+ }
+];
+```
+
+### Using predefined configurations
+
+ESLint has two predefined configurations for JavaScript:
+
+* `js.configs.recommended` - enables the rules that ESLint recommends everyone use to avoid potential errors
+* `js.configs.all` - enables all of the rules shipped with ESLint
+
+To include these predefined configurations, install the `@eslint/js` package and then make any modifications to other properties in subsequent configuration objects:
+
+```js
+import js from "@eslint/js";
+
+export default [
+ js.configs.recommended,
+ {
+ rules: {
+ semi: ["warn", "always"]
+ }
+ }
+];
+```
+
+Here, the `js.configs.recommended` predefined configuration is applied first and then another configuration object adds the desired configuration for `semi`.
+
+You can apply these predefined configs to just a subset of files by specifying a config object with a `files` key, like this:
+
+```js
+import js from "@eslint/js";
+
+export default [
+ {
+ files: ["**/src/safe/*.js"],
+ ...js.configs.recommended
+ }
+];
+```
+
+## Configuration File Resolution
+
+When ESLint is run on the command line, it first checks the current working directory for `eslint.config.js`. If the file is not found, it looks to the next parent directory for the file. This search continues until either the file is found or the root directory is reached.
+
+You can prevent this search for `eslint.config.js` by setting the `ESLINT_USE_FLAT_CONFIG` environment variable to `true` and using the `-c` or `--config` option on the command line to specify an alternate configuration file, such as:
+
+```shell
+ESLINT_USE_FLAT_CONFIG=true npx eslint -c some-other-file.js **/*.js
+```
+
+In this case, ESLint does not search for `eslint.config.js` and instead uses `some-other-file.js`.
--- /dev/null
+---
+title: Configuration Files
+eleventyNavigation:
+ key: configuration files
+ parent: configure
+ title: Configuration Files
+ order: 2
+
+---
+
+::: warning
+We are transitioning to a new config system in ESLint v9.0.0. The config system shared on this page is currently the default but will be deprecated in v9.0.0. You can opt-in to the new config system by following the instructions in the [documentation](configuration-files-new).
+:::
+
+You can put your ESLint project configuration in a configuration file. You can include built-in rules, how you want them enforced, plugins with custom rules, shareable configurations, which files you want rules to apply to, and more.
+
+## Configuration File Formats
+
+ESLint supports configuration files in several formats:
+
+* **JavaScript** - use `.eslintrc.js` and export an object containing your configuration.
+* **JavaScript (ESM)** - use `.eslintrc.cjs` when running ESLint in JavaScript packages that specify `"type":"module"` in their `package.json`. Note that ESLint does not support ESM configuration at this time.
+* **YAML** - use `.eslintrc.yaml` or `.eslintrc.yml` to define the configuration structure.
+* **JSON** - use `.eslintrc.json` to define the configuration structure. ESLint's JSON files also allow JavaScript-style comments.
+* **package.json** - create an `eslintConfig` property in your `package.json` file and define your configuration there.
+
+If there are multiple configuration files in the same directory, ESLint only uses one. The priority order is as follows:
+
+1. `.eslintrc.js`
+1. `.eslintrc.cjs`
+1. `.eslintrc.yaml`
+1. `.eslintrc.yml`
+1. `.eslintrc.json`
+1. `package.json`
+
+## Using Configuration Files
+
+There are two ways to use configuration files.
+
+The first way to use configuration files is via `.eslintrc.*` and `package.json` files. ESLint automatically looks for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem (`/`), the home directory of the current user (`~/`), or when `root: true` is specified. See [Cascading and Hierarchy](#cascading-and-hierarchy) below for more details on this. Configuration files can be useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file.
+
+The second way to use configuration files is to save the file wherever you would like and pass its location to the CLI using the `--config` option, such as:
+
+```shell
+eslint -c myconfig.json myfiletotest.js
+```
+
+If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use [`--no-eslintrc`](../command-line-interface#--no-eslintrc) along with the [`--config`](../../use/command-line-interface#-c---config) flag.
+
+Here's an example JSON configuration file that uses the `typescript-eslint` parser to support TypeScript syntax:
+
+```json
+{
+ "root": true,
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": { "project": ["./tsconfig.json"] },
+ "plugins": [
+ "@typescript-eslint"
+ ],
+ "rules": {
+ "@typescript-eslint/strict-boolean-expressions": [
+ 2,
+ {
+ "allowString" : false,
+ "allowNumber" : false
+ }
+ ]
+ },
+ "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
+}
+```
+
+### Comments in configuration files
+
+Both the JSON and YAML configuration file formats support comments (`package.json` files should not include them). You can use JavaScript-style comments for JSON files and YAML-style comments for YAML files. ESLint safely ignores comments in configuration files. This allows your configuration files to be more human-friendly.
+
+For JavaScript-style comments:
+
+```js
+{
+ "env": {
+ "browser": true
+ },
+ "rules": {
+ // Override our default settings just for this directory
+ "eqeqeq": "warn",
+ "strict": "off"
+ }
+}
+```
+
+For YAML-style comments:
+
+```yaml
+env:
+ browser: true
+rules:
+ # Override default settings
+ eqeqeq: warn
+ strict: off
+```
+
+## Adding Shared Settings
+
+ESLint supports adding shared settings into configuration files. Plugins use `settings` to specify the information that should be shared across all of its rules. You can add a `settings` object to the ESLint configuration file and it is supplied to every executed rule. This may be useful if you are adding custom rules and want them to have access to the same information and be easily configurable.
+
+In JSON:
+
+```json
+{
+ "settings": {
+ "sharedData": "Hello"
+ }
+}
+```
+
+And in YAML:
+
+```yaml
+---
+ settings:
+ sharedData: "Hello"
+```
+
+## Cascading and Hierarchy
+
+When using `.eslintrc.*` and `package.json` files for configuration, you can take advantage of configuration cascading. Suppose your project has the following structure:
+
+```text
+your-project
+├── .eslintrc.json
+├── lib
+│ └── source.js
+└─┬ tests
+ ├── .eslintrc.json
+ └── test.js
+```
+
+The configuration cascade works based on the location of the file being linted. If there is an `.eslintrc` file in the same directory as the file being linted, then that configuration takes precedence. ESLint then searches up the directory structure, merging any `.eslintrc` files it finds along the way until reaching either an `.eslintrc` file with `root: true` or the root directory.
+
+In the same way, if there is a `package.json` file in the root directory with an `eslintConfig` field, the configuration it describes is applied to all subdirectories beneath it. However, the configuration described by the `.eslintrc` file in the `tests/` directory overrides conflicting specifications.
+
+```text
+your-project
+├── package.json
+├── lib
+│ └── source.js
+└─┬ tests
+ ├── .eslintrc.json
+ └── test.js
+```
+
+If there is an `.eslintrc` and a `package.json` file found in the same directory, `.eslintrc` takes priority and the `package.json` file is not used.
+
+By default, ESLint looks for configuration files in all parent folders up to the root directory. This can be useful if you want all of your projects to follow a certain convention, but can sometimes lead to unexpected results. To limit ESLint to a specific project, place `"root": true` inside the `.eslintrc.*` file or `eslintConfig` field of the `package.json` file or in the `.eslintrc.*` file at your project's root level. ESLint stops looking in parent folders once it finds a configuration with `"root": true`.
+
+```js
+{
+ "root": true
+}
+```
+
+And in YAML:
+
+```yaml
+---
+ root: true
+```
+
+For example, consider `projectA` which has `"root": true` set in the `.eslintrc` file in the `lib/` directory. In this case, while linting `main.js`, the configurations within `lib/` are used, but the `.eslintrc` file in `projectA/` is not.
+
+```text
+home
+└── user
+ └── projectA
+ ├── .eslintrc.json <- Not used
+ └── lib
+ ├── .eslintrc.json <- { "root": true }
+ └── main.js
+```
+
+The complete configuration hierarchy, from highest to lowest precedence, is as follows:
+
+1. Inline configuration
+ 1. `/*eslint-disable*/` and `/*eslint-enable*/`
+ 1. `/*global*/`
+ 1. `/*eslint*/`
+ 1. `/*eslint-env*/`
+1. Command line options (or CLIEngine equivalents):
+ 1. `--global`
+ 1. `--rule`
+ 1. `--env`
+ 1. `-c`, `--config`
+1. Project-level configuration:
+ 1. `.eslintrc.*` or `package.json` file in the same directory as the linted file
+ 1. Continue searching for `.eslintrc.*` and `package.json` files in ancestor directories up to and including the root directory or until a config with `"root": true` is found.
+
+Please note that the [home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir) (`~/`) is also considered a root directory in this context and searching for configuration files stops there as well. And with the [removal of support for Personal Configuration Files](configuration-files#personal-configuration-files-deprecated) from the 8.0.0 release forward, configuration files present in that directory are ignored.
+
+## Extending Configuration Files
+
+A configuration file, once extended, can inherit all the traits of another configuration file (including rules, plugins, and language options) and modify all the options. As a result, there are three configurations, as defined below:
+
+* Base config: the configuration that is extended.
+* Derived config: the configuration that extends the base configuration.
+* Resulting actual config: the result of merging the derived configuration into the base configuration.
+
+The `extends` property value is either:
+
+* a string that specifies a configuration (either a path to a config file, the name of a shareable config, `eslint:recommended`, or `eslint:all`)
+* an array of strings where each additional configuration extends the preceding configurations
+
+ESLint extends configurations recursively, so a base configuration can also have an `extends` property. Relative paths and shareable config names in an `extends` property are resolved from the location of the config file where they appear.
+
+The `eslint-config-` prefix can be omitted from the configuration name. For example, `airbnb` resolves as `eslint-config-airbnb`.
+
+The `rules` property can do any of the following to extend (or override) the set of rules:
+
+* enable additional rules
+* change an inherited rule's severity without changing its options:
+ * Base config: `"eqeqeq": ["error", "allow-null"]`
+ * Derived config: `"eqeqeq": "warn"`
+ * Resulting actual config: `"eqeqeq": ["warn", "allow-null"]`
+* override options for rules from base configurations:
+ * Base config: `"quotes": ["error", "single", "avoid-escape"]`
+ * Derived config: `"quotes": ["error", "single"]`
+ * Resulting actual config: `"quotes": ["error", "single"]`
+* override options for rules given as object from base configurations:
+ * Base config: `"max-lines": ["error", { "max": 200, "skipBlankLines": true, "skipComments": true }]`
+ * Derived config: `"max-lines": ["error", { "max": 100 }]`
+ * Resulting actual config: `"max-lines": ["error", { "max": 100 }]` where `skipBlankLines` and `skipComments` default to `false`
+
+### Using a shareable configuration package
+
+A [sharable configuration](../../extend/shareable-configs) is an npm package that exports a configuration object. Make sure that you have installed the package in your project root directory, so that ESLint can require it.
+
+The `extends` property value can omit the `eslint-config-` prefix of the package name.
+
+The `npm init @eslint/config` command can create a configuration so you can extend a popular style guide (for example, `eslint-config-standard`).
+
+Example of a configuration file in YAML format:
+
+```yaml
+extends: standard
+rules:
+ comma-dangle:
+ - error
+ - always
+ no-empty: warn
+```
+
+### Using `eslint:recommended`
+
+Using `"eslint:recommended"` in the `extends` property enables a subset of core rules that report common problems (these rules are identified with a checkmark (recommended) on the [rules page](../../rules/)).
+
+Here's an example of extending `eslint:recommended` and overriding some of the set configuration options:
+
+Example of a configuration file in JavaScript format:
+
+```js
+module.exports = {
+ "extends": "eslint:recommended",
+ "rules": {
+ // enable additional rules
+ "indent": ["error", 4],
+ "linebreak-style": ["error", "unix"],
+ "quotes": ["error", "double"],
+ "semi": ["error", "always"],
+
+ // override configuration set by extending "eslint:recommended"
+ "no-empty": "warn",
+ "no-cond-assign": ["error", "always"],
+
+ // disable rules from base configurations
+ "for-direction": "off",
+ }
+}
+```
+
+### Using a configuration from a plugin
+
+A [plugin](../../extend/plugins) is an npm package that can add various extensions to ESLint. A plugin can perform numerous functions, including but not limited to adding new rules and exporting [shareable configurations](../../extend/plugins#configs-in-plugins). Make sure the package has been installed in a directory where ESLint can require it.
+
+The `plugins` [property value](./plugins#configure-plugins) can omit the `eslint-plugin-` prefix of the package name.
+
+The `extends` property value can consist of:
+
+* `plugin:`
+* the package name (from which you can omit the prefix, for example, `react` is short for `eslint-plugin-react`)
+* `/`
+* the configuration name (for example, `recommended`)
+
+Example of a configuration file in JSON format:
+
+```json
+{
+ "plugins": [
+ "react"
+ ],
+ "extends": [
+ "eslint:recommended",
+ "plugin:react/recommended"
+ ],
+ "rules": {
+ "react/no-set-state": "off"
+ }
+}
+```
+
+### Using a configuration file
+
+The `extends` property value can be an absolute or relative path to a base [configuration file](#using-configuration-files). ESLint resolves a relative path to a base configuration file relative to the configuration file that uses it.
+
+Example of a configuration file in JSON format:
+
+```json
+{
+ "extends": [
+ "./node_modules/coding-standard/eslintDefaults.js",
+ "./node_modules/coding-standard/.eslintrc-es6",
+ "./node_modules/coding-standard/.eslintrc-jsx"
+ ],
+ "rules": {
+ "eqeqeq": "warn"
+ }
+}
+```
+
+### Using `"eslint:all"`
+
+The `extends` property value can be `"eslint:all"` to enable all core rules in the currently installed version of ESLint. The set of core rules can change at any minor or major version of ESLint.
+
+**Important:** This configuration is **not recommended for production use** because it changes with every minor and major version of ESLint. Use it at your own risk.
+
+You might enable all core rules as a shortcut to explore rules and options while you decide on the configuration for a project, especially if you rarely override options or disable rules. The default options for rules are not endorsements by ESLint (for example, the default option for the [`quotes`](../../rules/quotes) rule does not mean double quotes are better than single quotes).
+
+If your configuration extends `eslint:all`, after you upgrade to a newer major or minor version of ESLint, review the reported problems before you use the `--fix` option on the [command line](../command-line-interface#--fix), so you know if a new fixable rule will make changes to the code.
+
+Example of a configuration file in JavaScript format:
+
+```js
+module.exports = {
+ "extends": "eslint:all",
+ "rules": {
+ // override default options
+ "comma-dangle": ["error", "always"],
+ "indent": ["error", 2],
+ "no-cond-assign": ["error", "always"],
+
+ // disable now, but enable in the future
+ "one-var": "off", // ["error", "never"]
+
+ // disable
+ "init-declarations": "off",
+ "no-console": "off",
+ "no-inline-comments": "off",
+ }
+}
+```
+
+## Configuration Based on Glob Patterns
+
+**v4.1.0+.** Sometimes a more fine-controlled configuration is necessary, like if the configuration for files within the same directory has to be different. In this case, you can provide configurations under the `overrides` key that only apply to files that match specific glob patterns, using the same format you would pass on the command line (e.g., `app/**/*.test.js`).
+
+Glob patterns in overrides use [minimatch syntax](https://github.com/isaacs/minimatch).
+
+### How do overrides work?
+
+It is possible to override settings based on file glob patterns in your configuration by using the `overrides` key. An example of using the `overrides` key is as follows:
+
+In your `.eslintrc.json`:
+
+```json
+{
+ "rules": {
+ "quotes": ["error", "double"]
+ },
+
+ "overrides": [
+ {
+ "files": ["bin/*.js", "lib/*.js"],
+ "excludedFiles": "*.test.js",
+ "rules": {
+ "quotes": ["error", "single"]
+ }
+ }
+ ]
+}
+```
+
+Here is how overrides work in a configuration file:
+
+* The patterns are applied against the file path relative to the directory of the config file. For example, if your config file has the path `/Users/john/workspace/any-project/.eslintrc.js` and the file you want to lint has the path `/Users/john/workspace/any-project/lib/util.js`, then the pattern provided in `.eslintrc.js` is executed against the relative path `lib/util.js`.
+* Glob pattern overrides have higher precedence than the regular configuration in the same config file. Multiple overrides within the same config are applied in order. That is, the last override block in a config file always has the highest precedence.
+* A glob specific configuration works almost the same as any other ESLint config. Override blocks can contain any configuration options that are valid in a regular config, with the exception of `root` and `ignorePatterns`.
+ * A glob specific configuration can have an `extends` setting, but the `root` property in the extended configs is ignored. The `ignorePatterns` property in the extended configs is used only for the files the glob specific configuration matched.
+ * Nested `overrides` settings are applied only if the glob patterns of both the parent config and the child config are matched. This is the same when the extended configs have an `overrides` setting.
+* Multiple glob patterns can be provided within a single override block. A file must match at least one of the supplied patterns for the configuration to apply.
+* Override blocks can also specify patterns to exclude from matches. If a file matches any of the excluded patterns, the configuration won't apply.
+
+### Relative glob patterns
+
+```txt
+project-root
+├── app
+│ ├── lib
+│ │ ├── foo.js
+│ │ ├── fooSpec.js
+│ ├── components
+│ │ ├── bar.js
+│ │ ├── barSpec.js
+│ ├── .eslintrc.json
+├── server
+│ ├── server.js
+│ ├── serverSpec.js
+├── .eslintrc.json
+```
+
+The config in `app/.eslintrc.json` defines the glob pattern `**/*Spec.js`. This pattern is relative to the base directory of `app/.eslintrc.json`. So, this pattern would match `app/lib/fooSpec.js` and `app/components/barSpec.js` but **NOT** `server/serverSpec.js`. If you defined the same pattern in the `.eslintrc.json` file within in the `project-root` folder, it would match all three of the `*Spec` files.
+
+If a config is provided via the `--config` CLI option, the glob patterns in the config are relative to the current working directory rather than the base directory of the given config. For example, if `--config configs/.eslintrc.json` is present, the glob patterns in the config are relative to `.` rather than `./configs`.
+
+### Specifying target files to lint
+
+If you specified directories with CLI (e.g., `eslint lib`), ESLint searches target files in the directory to lint. The target files are `*.js` or the files that match any of `overrides` entries (but exclude entries that are any of `files` end with `*`).
+
+If you specified the [`--ext`](../command-line-interface#--ext) command line option along with directories, the target files are only the files that have specified file extensions regardless of `overrides` entries.
+
+## Personal Configuration Files (deprecated)
+
+⚠️ **This feature has been deprecated**. This feature was removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](../command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32).
+
+`~/` refers to [the home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir). The personal configuration file being referred to here is `~/.eslintrc.*` file, which is currently handled differently than other configuration files.
+
+### How does ESLint find personal configuration files?
+
+If `eslint` could not find any configuration file in the project, `eslint` loads `~/.eslintrc.*` file.
+
+If `eslint` could find configuration files in the project, `eslint` ignores `~/.eslintrc.*` file even if it's in an ancestor directory of the project directory.
+
+### How do personal configuration files behave?
+
+`~/.eslintrc.*` files behave similarly to regular configuration files, with some exceptions:
+
+`~/.eslintrc.*` files load shareable configs and custom parsers from `~/node_modules/` – similarly to `require()` – in the user's home directory. Please note that it doesn't load global-installed packages.
+
+`~/.eslintrc.*` files load plugins from `$CWD/node_modules` by default in order to identify plugins uniquely. If you want to use plugins with `~/.eslintrc.*` files, plugins must be installed locally per project. Alternatively, you can use the [`--resolve-plugins-relative-to` CLI option](../command-line-interface#--resolve-plugins-relative-to) to change the location from which ESLint loads plugins.
--- /dev/null
+---
+title: Ignore Files
+eleventyNavigation:
+ key: ignore files
+ parent: configure
+ title: Ignore Files
+ order: 7
+
+---
+
+You can configure ESLint to ignore certain files and directories while linting by specifying one or more glob patterns.
+You can ignore files in the following ways:
+
+* Add `ignorePatterns` to a configuration file.
+* Create a dedicated file that contains the ignore patterns (`.eslintignore` by default).
+
+## `ignorePatterns` in Config Files
+
+You can tell ESLint to ignore specific files and directories using `ignorePatterns` in your config files. `ignorePatterns` patterns follow the same rules as `.eslintignore`. Please see the [`.eslintignore` file documentation](#the-eslintignore-file) to learn more.
+
+```json
+{
+ "ignorePatterns": ["temp.js", "**/vendor/*.js"],
+ "rules": {
+ //...
+ }
+}
+```
+
+* Glob patterns in `ignorePatterns` are relative to the directory that the config file is placed in.
+* You cannot write `ignorePatterns` property under `overrides` property.
+* Patterns defined in `.eslintignore` take precedence over the `ignorePatterns` property of config files.
+
+If a glob pattern starts with `/`, the pattern is relative to the base directory of the config file. For example, `/foo.js` in `lib/.eslintrc.json` matches to `lib/foo.js` but not `lib/subdir/foo.js`.
+
+If a config is provided via the `--config` CLI option, the ignore patterns that start with `/` in the config are relative to the current working directory rather than the base directory of the given config. For example, if `--config configs/.eslintrc.json` is present, the ignore patterns in the config are relative to `.` rather than `./configs`.
+
+## The `.eslintignore` File
+
+You can tell ESLint to ignore specific files and directories by creating an `.eslintignore` file in your project's root directory. The `.eslintignore` file is a plain text file where each line is a glob pattern indicating which paths should be omitted from linting. For example, the following omits all JavaScript files:
+
+```text
+**/*.js
+```
+
+When ESLint is run, it looks in the current working directory to find an `.eslintignore` file before determining which files to lint. If this file is found, then those preferences are applied when traversing directories. Only one `.eslintignore` file can be used at a time, so `.eslintignore` files other than the one in the current working directory are not used.
+
+Globs are matched using [node-ignore](https://github.com/kaelzhang/node-ignore), so a number of features are available:
+
+* Lines beginning with `#` are treated as comments and do not affect the ignore patterns.
+* Paths are relative to the current working directory. This is also true of paths passed in via the `--ignore-pattern` [command](../command-line-interface#--ignore-pattern).
+* Lines preceded by `!` are negated patterns that re-include a pattern that was ignored by an earlier pattern.
+* Ignore patterns behave according to the `.gitignore` [specification](https://git-scm.com/docs/gitignore).
+
+Of particular note is that like `.gitignore` files, all paths used as patterns for both `.eslintignore` and `--ignore-pattern` must use forward slashes as their path separators.
+
+```text
+# Valid
+/root/src/*.js
+
+# Invalid
+\root\src\*.js
+```
+
+Please see [`.gitignore`](https://git-scm.com/docs/gitignore)'s specification for further examples of valid syntax.
+
+In addition to any patterns in the `.eslintignore` file, ESLint always follows a couple of implicit ignore rules even if the `--no-ignore` flag is passed. The implicit rules are as follows:
+
+* `node_modules/` is ignored.
+* dot-files (except for `.eslintrc.*`) as well as dot-folders and their contents are ignored.
+
+There are also some exceptions to these rules:
+
+* If the path to lint is a glob pattern or directory path and contains a dot-folder, all dot-files and dot-folders are linted. This includes dot-files and dot-folders that are buried deeper in the directory structure.
+
+ For example, `eslint .config/` would lint all dot-folders and dot-files in the `.config` directory, including immediate children as well as children that are deeper in the directory structure.
+
+* If the path to lint is a specific file path and the `--no-ignore` flag has been passed, ESLint would lint the file regardless of the implicit ignore rules.
+
+ For example, `eslint .config/my-config-file.js --no-ignore` would cause `my-config-file.js` to be linted. It should be noted that the same command without the `--no-ignore` line would not lint the `my-config-file.js` file.
+
+* Allowlist and denylist rules specified via `--ignore-pattern` or `.eslintignore` are prioritized above implicit ignore rules.
+
+ For example, in this scenario, `.build/test.js` is the desired file to allowlist. Because all dot-folders and their children are ignored by default, `.build` must first be allowlisted so that eslint becomes aware of its children. Then, `.build/test.js` must be explicitly allowlisted, while the rest of the content is denylisted. This is done with the following `.eslintignore` file:
+
+ ```text
+ # Allowlist 'test.js' in the '.build' folder
+ # But do not allow anything else in the '.build' folder to be linted
+ !.build
+ .build/*
+ !.build/test.js
+ ```
+
+ The following `--ignore-pattern` is also equivalent:
+
+ ```shell
+ eslint --ignore-pattern '!.build' --ignore-pattern '.build/*' --ignore-pattern '!.build/test.js' parent-folder/
+ ```
+
+## Using an Alternate File
+
+If you'd prefer to use a different file than the `.eslintignore` in the current working directory, you can specify it on the command line using the `--ignore-path` option. For example, you can use `.jshintignore` file because it has the same format:
+
+```shell
+eslint --ignore-path .jshintignore file.js
+```
+
+You can also use your `.gitignore` file:
+
+```shell
+eslint --ignore-path .gitignore file.js
+```
+
+Any file that follows the standard ignore file format can be used. Keep in mind that specifying `--ignore-path` means that the existing `.eslintignore` file is not used. Note that globbing rules in `.eslintignore` follow those of `.gitignore`.
+
+## Using eslintIgnore in package.json
+
+If an `.eslintignore` file is not found and an alternate file is not specified, ESLint looks in `package.json` for the `eslintIgnore` key to check for files to ignore.
+
+```json
+{
+ "name": "mypackage",
+ "version": "0.0.1",
+ "eslintConfig": {
+ "env": {
+ "browser": true,
+ "node": true
+ }
+ },
+ "eslintIgnore": ["hello.js", "world.js"]
+}
+```
+
+## Ignored File Warnings
+
+When you pass directories to ESLint, files and directories are silently ignored. If you pass a specific file to ESLint, then ESLint creates a warning that the file was skipped. For example, suppose you have an `.eslintignore` file that looks like this:
+
+```text
+foo.js
+```
+
+And then you run:
+
+```shell
+eslint foo.js
+```
+
+You'll see this warning:
+
+```text
+foo.js
+ 0:0 warning File ignored because of a matching ignore pattern. Use "--no-ignore" to override.
+
+✖ 1 problem (0 errors, 1 warning)
+```
+
+This message occurs because ESLint is unsure if you wanted to actually lint the file or not. As the message indicates, you can use `--no-ignore` to omit using the ignore rules.
+
+Consider another scenario where you want to run ESLint on a specific dot-file or dot-folder, but have forgotten to specifically allow those files in your `.eslintignore` file. You would run something like this:
+
+```shell
+eslint .config/foo.js
+```
+
+You would see this warning:
+
+```text
+.config/foo.js
+ 0:0 warning File ignored by default. Use a negated ignore pattern (like "--ignore-pattern '!<relative/path/to/filename>'") to override
+
+✖ 1 problem (0 errors, 1 warning)
+```
+
+This message occurs because, normally, this file would be ignored by ESLint's implicit ignore rules (as mentioned above). A negated ignore rule in your `.eslintignore` file would override the implicit rule and reinclude this file for linting. Additionally, in this case, `--no-ignore` could be used to lint the file as well.
--- /dev/null
+---
+title: Configure ESLint
+eleventyNavigation:
+ key: configure
+ parent: use eslint
+ title: Configure ESLint
+ order: 3
+
+---
+
+ESLint is designed to be flexible and configurable for your use case. You can turn off every rule and run only with basic syntax validation or mix and match the bundled rules and your custom rules to fit the needs of your project. There are two primary ways to configure ESLint:
+
+1. **Configuration Comments** - use JavaScript comments to embed configuration information directly into a file.
+2. **Configuration Files** - use a JavaScript, JSON, or YAML file to specify configuration information for an entire directory and all of its subdirectories. This can be in the form of a [`.eslintrc.*`](./configuration-files#configuration-file-formats) file or an `eslintConfig` field in a [`package.json`](https://docs.npmjs.com/files/package.json) file, both of which ESLint will look for and read automatically, or you can specify a configuration file on the [command line](../command-line-interface).
+
+Here are some of the options that you can configure in ESLint:
+
+* [**Environments**](./language-options#specifying-environments) - which environments your script is designed to run in. Each environment brings with it a certain set of predefined global variables.
+* [**Globals**](./language-options#specifying-globals) - the additional global variables your script accesses during execution.
+* [**Rules**](rules) - which rules are enabled and at what error level.
+* [**Plugins**](plugins) - which third-party plugins define additional rules, environments, configs, etc. for ESLint to use.
+
+All of these options give you fine-grained control over how ESLint treats your code.
+
+## Table of Contents
+
+[**Configuration Files**](configuration-files)
+
+* [Configuration File Formats](./configuration-files#configuration-file-formats)
+* [Using Configuration Files](./configuration-files#using-configuration-files)
+* [Adding Shared Settings](./configuration-files#adding-shared-settings)
+* [Cascading and Hierarchy](./configuration-files#cascading-and-hierarchy)
+* [Extending Configuration Files](./configuration-files#extending-configuration-files)
+* [Configuration Based on Glob Patterns](./configuration-files#configuration-based-on-glob-patterns)
+* [Personal Configuration Files](./configuration-files#personal-configuration-files-deprecated)
+
+[**Configure Language Options**](language-options)
+
+* [Specifying Environments](./language-options#specifying-environments)
+* [Specifying Globals](./language-options#specifying-globals)
+* [Specifying Parser Options](./language-options#specifying-parser-options)
+
+[**Configure Rules**](rules)
+
+* [Configuring Rules](./rules)
+* [Disabling Rules](./rules#disabling-rules)
+
+[**Configure Plugins**](plugins)
+
+* [Configure Plugins](./plugins#configure-plugins)
+* [Specify a Processor](./plugins#specify-a-processor)
+
+[**Configure a Parser**](./parser)
+
+* [Configure a Custom Parser](./parser#configure-a-custom-parser)
+
+[**Ignore Files**](ignore)
+
+* [`ignorePatterns` in Config Files](./ignore#ignorepatterns-in-config-files)
+* [The `.eslintignore` File](./ignore#the-eslintignore-file)
+* [Using an Alternate File](./ignore#using-an-alternate-file)
+* [Using eslintIgnore in package.json](./ignore#using-eslintignore-in-packagejson)
+* [Ignored File Warnings](./ignore#ignored-file-warnings)
--- /dev/null
+---
+title: Configure Language Options
+eleventyNavigation:
+ key: configure language options
+ parent: configure
+ title: Configure Language Options
+ order: 3
+
+---
+
+The JavaScript ecosystem has a variety of runtimes, versions, extensions, and frameworks. Each of these can have different supported syntax and global variables. ESLint lets you configure language options specific to the JavaScript used in your project, like custom global variables. You can also use plugins to extend ESLint to support your project's language options.
+
+## Specifying Environments
+
+An environment provides predefined global variables. The available environments are:
+
+* `browser` - browser global variables.
+* `node` - Node.js global variables and Node.js scoping.
+* `commonjs` - CommonJS global variables and CommonJS scoping (use this for browser-only code that uses Browserify/WebPack).
+* `shared-node-browser` - Globals common to both Node.js and Browser.
+* `es6` - enable all ECMAScript 6 features except for modules (this automatically sets the `ecmaVersion` parser option to 6).
+* `es2016` - adds all ECMAScript 2016 globals and automatically sets the `ecmaVersion` parser option to 7.
+* `es2017` - adds all ECMAScript 2017 globals and automatically sets the `ecmaVersion` parser option to 8.
+* `es2018` - adds all ECMAScript 2018 globals and automatically sets the `ecmaVersion` parser option to 9.
+* `es2019` - adds all ECMAScript 2019 globals and automatically sets the `ecmaVersion` parser option to 10.
+* `es2020` - adds all ECMAScript 2020 globals and automatically sets the `ecmaVersion` parser option to 11.
+* `es2021` - adds all ECMAScript 2021 globals and automatically sets the `ecmaVersion` parser option to 12.
+* `es2022` - adds all ECMAScript 2022 globals and automatically sets the `ecmaVersion` parser option to 13.
+* `worker` - web workers global variables.
+* `amd` - defines `require()` and `define()` as global variables as per the [amd](https://github.com/amdjs/amdjs-api/blob/master/AMD.md) spec.
+* `mocha` - adds all of the Mocha testing global variables.
+* `jasmine` - adds all of the Jasmine testing global variables for version 1.3 and 2.0.
+* `jest` - Jest global variables.
+* `phantomjs` - PhantomJS global variables.
+* `protractor` - Protractor global variables.
+* `qunit` - QUnit global variables.
+* `jquery` - jQuery global variables.
+* `prototypejs` - Prototype.js global variables.
+* `shelljs` - ShellJS global variables.
+* `meteor` - Meteor global variables.
+* `mongo` - MongoDB global variables.
+* `applescript` - AppleScript global variables.
+* `nashorn` - Java 8 Nashorn global variables.
+* `serviceworker` - Service Worker global variables.
+* `atomtest` - Atom test helper globals.
+* `embertest` - Ember test helper globals.
+* `webextensions` - WebExtensions globals.
+* `greasemonkey` - GreaseMonkey globals.
+
+These environments are not mutually exclusive, so you can define more than one at a time.
+
+Environments can be specified inside of a file, in configuration files or using the `--env` [command line](../command-line-interface) flag.
+
+### Using configuration comments
+
+To specify environments with a comment inside of a JavaScript file, use the following format:
+
+```js
+/* eslint-env node, mocha */
+```
+
+This enables Node.js and Mocha environments.
+
+### Using configuration files
+
+To specify environments in a configuration file, use the `env` key. Specify which environments you want to enable by setting each to `true`. For example, the following enables the browser and Node.js environments:
+
+```json
+{
+ "env": {
+ "browser": true,
+ "node": true
+ }
+}
+```
+
+Or in a `package.json` file
+
+```json
+{
+ "name": "mypackage",
+ "version": "0.0.1",
+ "eslintConfig": {
+ "env": {
+ "browser": true,
+ "node": true
+ }
+ }
+}
+```
+
+And in YAML:
+
+```yaml
+---
+ env:
+ browser: true
+ node: true
+```
+
+### Using a plugin
+
+If you want to use an environment from a plugin, be sure to specify the plugin name in the `plugins` array and then use the unprefixed plugin name, followed by a slash, followed by the environment name. For example:
+
+```json
+{
+ "plugins": ["example"],
+ "env": {
+ "example/custom": true
+ }
+}
+```
+
+Or in a `package.json` file
+
+```json
+{
+ "name": "mypackage",
+ "version": "0.0.1",
+ "eslintConfig": {
+ "plugins": ["example"],
+ "env": {
+ "example/custom": true
+ }
+ }
+}
+```
+
+## Specifying Globals
+
+Some of ESLint's core rules rely on knowledge of the global variables available to your code at runtime. Since these can vary greatly between different environments as well as be modified at runtime, ESLint makes no assumptions about what global variables exist in your execution environment. If you would like to use rules that require knowledge of what global variables are available, you can define global variables in your configuration file or by using configuration comments in your source code.
+
+### Using configuration comments
+
+To specify globals using a comment inside of your JavaScript file, use the following format:
+
+```js
+/* global var1, var2 */
+```
+
+This defines two global variables, `var1` and `var2`. If you want to optionally specify that these global variables can be written to (rather than only being read), then you can set each with a `"writable"` flag:
+
+```js
+/* global var1:writable, var2:writable */
+```
+
+### Using configuration files
+
+To configure global variables inside of a configuration file, set the `globals` configuration property to an object containing keys named for each of the global variables you want to use. For each global variable key, set the corresponding value equal to `"writable"` to allow the variable to be overwritten or `"readonly"` to disallow overwriting. For example:
+
+```json
+{
+ "globals": {
+ "var1": "writable",
+ "var2": "readonly"
+ }
+}
+```
+
+And in YAML:
+
+```yaml
+---
+ globals:
+ var1: writable
+ var2: readonly
+```
+
+These examples allow `var1` to be overwritten in your code, but disallow it for `var2`.
+
+Globals can be disabled by setting their value to `"off"`. For example, in an environment where most ES2015 globals are available but `Promise` is unavailable, you might use this config:
+
+```json
+{
+ "env": {
+ "es6": true
+ },
+ "globals": {
+ "Promise": "off"
+ }
+}
+```
+
+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 these 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 and JSX using parser options.
+
+Please note that supporting JSX syntax is not the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) if you are using React.
+
+By the same token, supporting ES6 syntax is not the same as supporting new ES6 globals (e.g., new types such as `Set`). For ES6 syntax, use `{ "parserOptions": { "ecmaVersion": 6 } }`; for new ES6 global variables, use `{ "env": { "es6": true } }`. Setting `{ "env": { "es6": true } }` enables ES6 syntax automatically, but `{ "parserOptions": { "ecmaVersion": 6 } }` does not enable ES6 globals automatically.
+
+Parser options are set in your `.eslintrc.*` file with the `parserOptions` property. The available options are:
+
+* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, 10, 11, 12, 13, or 14 to specify the version of ECMAScript syntax you want to use. You can also set it 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), 2022 (same as 13), or 2023 (same as 14) 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)
+ * `jsx` - enable [JSX](https://facebook.github.io/jsx/)
+
+Here's an example `.eslintrc.json` file:
+
+```json
+{
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "sourceType": "module",
+ "ecmaFeatures": {
+ "jsx": true
+ }
+ },
+ "rules": {
+ "semi": "error"
+ }
+}
+```
+
+Setting parser options helps ESLint determine what is a parsing error. All language options are `false` by default.
--- /dev/null
+---
+title: Configure a Parser
+eleventyNavigation:
+ key: configure parser
+ parent: configure
+ title: Configure a Parser
+ order: 6
+---
+
+You can use custom parsers to convert JavaScript code into an abstract syntax tree for ESLint to evaluate. You might want to add a custom parser if your code isn't compatible with ESLint's default parser, Espree.
+
+## Configure a Custom Parser
+
+By default, ESLint uses [Espree](https://github.com/eslint/espree) as its parser. You can optionally specify that a different parser should be used in your configuration file if the parser meets the following requirements:
+
+1. It must be a Node module loadable from the config file where the parser is used. Usually, this means you should install the parser package separately using npm.
+1. It must conform to the [parser interface](../../extend/custom-parsers).
+
+Note that even with these compatibilities, there are no guarantees that an external parser works correctly with ESLint. ESLint does not fix bugs related to incompatibilities with other parsers.
+
+To indicate the npm module to use as your parser, specify it using the `parser` option in your `.eslintrc` file. For example, the following specifies to use Esprima instead of Espree:
+
+```json
+{
+ "parser": "esprima",
+ "rules": {
+ "semi": "error"
+ }
+}
+```
+
+The following parsers are compatible with ESLint:
+
+* [Esprima](https://www.npmjs.com/package/esprima)
+* [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) - A wrapper around the [Babel](https://babeljs.io) parser that makes it compatible with ESLint.
+* [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint.
+
+Note that when using a custom parser, the `parserOptions` configuration property is still required for ESLint to work properly with features not in ECMAScript 5 by default. Parsers are all passed `parserOptions` and may or may not use them to determine which features to enable.
--- /dev/null
+---
+title: Configure Plugins
+eleventyNavigation:
+ key: configure plugins
+ parent: configure
+ title: Configure Plugins
+ order: 5
+
+---
+
+You can extend ESLint with plugins in a variety of different ways. Plugins can include:
+
+* Custom rules to validate if your code meets a certain expectation, and what to do if it does not meet that expectation.
+* Custom configurations.
+* Custom environments.
+* Custom processors to extract JavaScript code from other kinds of files or preprocess code before linting.
+
+## Configure Plugins
+
+ESLint supports the use of third-party plugins. Before using a plugin, you have to install it using npm.
+
+To configure plugins inside of a configuration file, use the `plugins` key, which contains a list of plugin names. The `eslint-plugin-` prefix can be omitted from the plugin name.
+
+```json
+{
+ "plugins": [
+ "plugin1",
+ "eslint-plugin-plugin2"
+ ]
+}
+```
+
+And in YAML:
+
+```yaml
+---
+ plugins:
+ - plugin1
+ - eslint-plugin-plugin2
+```
+
+**Notes:**
+
+1. Plugins are resolved relative to the config file. In other words, ESLint loads the plugin as a user would obtain by running `require('eslint-plugin-pluginname')` in the config file.
+2. Plugins in the base configuration (loaded by `extends` setting) are relative to the derived config file. For example, if `./.eslintrc` has `extends: ["foo"]` and the `eslint-config-foo` has `plugins: ["bar"]`, ESLint finds the `eslint-plugin-bar` from `./node_modules/` (rather than `./node_modules/eslint-config-foo/node_modules/`) or ancestor directories. Thus every plugin in the config file and base configurations is resolved uniquely.
+
+### Naming convention
+
+#### Include a plugin
+
+The `eslint-plugin-` prefix can be omitted for both non-scoped and scoped packages.
+
+A non-scoped package:
+
+```js
+{
+ // ...
+ "plugins": [
+ "jquery", // means eslint-plugin-jquery
+ ]
+ // ...
+}
+```
+
+A scoped package:
+
+```js
+{
+ // ...
+ "plugins": [
+ "@jquery/jquery", // means @jquery/eslint-plugin-jquery
+ "@foobar" // means @foobar/eslint-plugin
+ ]
+ // ...
+}
+```
+
+#### Use a plugin
+
+Rules, environments, and configurations defined in plugins must be referenced with the following convention:
+
+* `eslint-plugin-foo` → `foo/a-rule`
+* `@foo/eslint-plugin` → `@foo/a-config`
+* `@foo/eslint-plugin-bar` → `@foo/bar/a-environment`
+
+For example:
+
+```js
+{
+ // ...
+ "plugins": [
+ "jquery", // eslint-plugin-jquery
+ "@foo/foo", // @foo/eslint-plugin-foo
+ "@bar" // @bar/eslint-plugin
+ ],
+ "extends": [
+ "plugin:@foo/foo/recommended",
+ "plugin:@bar/recommended"
+ ],
+ "rules": {
+ "jquery/a-rule": "error",
+ "@foo/foo/some-rule": "error",
+ "@bar/another-rule": "error"
+ },
+ "env": {
+ "jquery/jquery": true,
+ "@foo/foo/env-foo": true,
+ "@bar/env-bar": true,
+ }
+ // ...
+}
+```
+
+### Specify a Processor
+
+Plugins may provide processors. Processors can extract JavaScript code from other kinds of files, then let ESLint lint the JavaScript code. Alternatively, processors can convert JavaScript code during preprocessing.
+
+To specify processors in a configuration file, use the `processor` key with the concatenated string of a plugin name and a processor name by a slash. For example, the following enables the processor `a-processor` that the plugin `a-plugin` provided:
+
+```json
+{
+ "plugins": ["a-plugin"],
+ "processor": "a-plugin/a-processor"
+}
+```
+
+To specify processors for specific kinds of files, use the combination of the `overrides` key and the `processor` key. For example, the following uses the processor `a-plugin/markdown` for `*.md` files.
+
+```json
+{
+ "plugins": ["a-plugin"],
+ "overrides": [
+ {
+ "files": ["*.md"],
+ "processor": "a-plugin/markdown"
+ }
+ ]
+}
+```
+
+Processors may make named code blocks such as `0.js` and `1.js`. ESLint handles such a named code block as a child file of the original file. You can specify additional configurations for named code blocks in the `overrides` section of the config. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files.
+
+```json
+{
+ "plugins": ["a-plugin"],
+ "overrides": [
+ {
+ "files": ["*.md"],
+ "processor": "a-plugin/markdown"
+ },
+ {
+ "files": ["**/*.md/*.js"],
+ "rules": {
+ "strict": "off"
+ }
+ }
+ ]
+}
+```
+
+ESLint checks the file path of named code blocks then ignores those if any `overrides` entry didn't match the file path. Be sure to add an `overrides` entry if you want to lint named code blocks other than `*.js`.
--- /dev/null
+---
+title: Configure Rules
+eleventyNavigation:
+ key: configure rules
+ parent: configure
+ title: Configure Rules
+ order: 4
+
+---
+
+Rules are the core building block of ESLint. A rule validates if your code meets a certain expectation, and what to do if it does not meet that expectation. Rules can also contain additional configuration options specific to that rule.
+
+ESLint comes with a large number of [built-in rules](../../rules/) and you can add more rules through plugins. You can modify which rules your project uses with either configuration comments or configuration files.
+
+## Rule Severities
+
+To change a rule's severity, set the rule ID equal to one of these values:
+
+* `"off"` or `0` - turn the rule off
+* `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
+* `"error"` or `2` - turn the rule on as an error (exit code is 1 when triggered)
+
+Rules are typically set to `"error"` to enforce compliance with the rule during continuous integration testing, pre-commit checks, and pull request merging because doing so causes ESLint to exit with a non-zero exit code.
+
+If you don't want to enforce compliance with a rule but would still like ESLint to report the rule's violations, set the severity to `"warn"`. This is typically used when introducing a new rule that will eventually be set to `"error"`, when a rule is flagging something other than a potential buildtime or runtime error (such as an unused variable), or when a rule cannot determine with certainty that a problem has been found (when a rule might have false positives and need manual review).
+
+### Using configuration comments
+
+To configure rules inside of a file using configuration comments, use a comment in the following format:
+
+```js
+/* eslint eqeqeq: "off", curly: "error" */
+```
+
+In this example, [`eqeqeq`](../../rules/eqeqeq) is turned off and [`curly`](../../rules/curly) is turned on as an error. You can also use the numeric equivalent for the rule severity:
+
+```js
+/* eslint eqeqeq: 0, curly: 2 */
+```
+
+This example is the same as the last example, only it uses the numeric codes instead of the string values. The `eqeqeq` rule is off and the `curly` rule is set to be an error.
+
+If a rule has additional options, you can specify them using array literal syntax, such as:
+
+```js
+/* eslint quotes: ["error", "double"], curly: 2 */
+```
+
+This comment specifies the "double" option for the [`quotes`](../../rules/quotes) rule. The first item in the array is always the rule severity (number or string).
+
+#### Configuration Comment Descriptions
+
+Configuration comments can include descriptions to explain why the comment is necessary. The description must occur after the configuration and is separated from the configuration by two or more consecutive `-` characters. For example:
+
+```js
+/* eslint eqeqeq: "off", curly: "error" -- Here's a description about why this configuration is necessary. */
+```
+
+```js
+/* eslint eqeqeq: "off", curly: "error"
+ --------
+ Here's a description about why this configuration is necessary. */
+```
+
+```js
+/* eslint eqeqeq: "off", curly: "error"
+ * --------
+ * This will not work due to the line above starting with a '*' character.
+ */
+```
+
+### Using configuration files
+
+To configure rules inside of a configuration file, use the `rules` key along with an error level and any options you want to use. For example:
+
+```json
+{
+ "rules": {
+ "eqeqeq": "off",
+ "curly": "error",
+ "quotes": ["error", "double"]
+ }
+}
+```
+
+And in YAML:
+
+```yaml
+---
+rules:
+ eqeqeq: off
+ curly: error
+ quotes:
+ - error
+ - double
+```
+
+## Rules from Plugins
+
+To configure a rule that is defined within a plugin, prefix the rule ID with the plugin name and `/`.
+
+In a configuration file, for example:
+
+```json
+{
+ "plugins": [
+ "plugin1"
+ ],
+ "rules": {
+ "eqeqeq": "off",
+ "curly": "error",
+ "quotes": ["error", "double"],
+ "plugin1/rule1": "error"
+ }
+}
+```
+
+And in YAML:
+
+```yaml
+---
+plugins:
+ - plugin1
+rules:
+ eqeqeq: 0
+ curly: error
+ quotes:
+ - error
+ - "double"
+ plugin1/rule1: error
+```
+
+In these configuration files, the rule `plugin1/rule1` comes from the plugin named `plugin1`, which is contained in an npm package named `eslint-plugin-plugin1`.
+
+You can also use this format with configuration comments, such as:
+
+```js
+/* eslint "plugin1/rule1": "error" */
+```
+
+**Note:** When specifying rules from plugins, make sure to omit `eslint-plugin-`. ESLint uses only the unprefixed name internally to locate rules.
+
+## Disabling Rules
+
+### Using configuration comments
+
+To disable rule warnings in a part of a file, use block comments in the following format:
+
+```js
+/* eslint-disable */
+
+alert('foo');
+
+/* eslint-enable */
+```
+
+You can also disable or enable warnings for specific rules:
+
+```js
+/* eslint-disable no-alert, no-console */
+
+alert('foo');
+console.log('bar');
+
+/* eslint-enable no-alert, no-console */
+```
+
+**Note:** `/* eslint-enable */` without any specific rules listed causes all disabled rules to be re-enabled.
+
+To disable rule warnings in an entire file, put a `/* eslint-disable */` block comment at the top of the file:
+
+```js
+/* eslint-disable */
+
+alert('foo');
+```
+
+You can also disable or enable specific rules for an entire file:
+
+```js
+/* eslint-disable no-alert */
+
+alert('foo');
+```
+
+To ensure that a rule is never applied (regardless of any future enable/disable lines):
+
+```js
+/* eslint no-alert: "off" */
+
+alert('foo');
+```
+
+To disable all rules on a specific line, use a line or block comment in one of the following formats:
+
+```js
+alert('foo'); // eslint-disable-line
+
+// eslint-disable-next-line
+alert('foo');
+
+/* eslint-disable-next-line */
+alert('foo');
+
+alert('foo'); /* eslint-disable-line */
+```
+
+To disable a specific rule on a specific line:
+
+```js
+alert('foo'); // eslint-disable-line no-alert
+
+// eslint-disable-next-line no-alert
+alert('foo');
+
+alert('foo'); /* eslint-disable-line no-alert */
+
+/* eslint-disable-next-line no-alert */
+alert('foo');
+```
+
+To disable multiple rules on a specific line:
+
+```js
+alert('foo'); // eslint-disable-line no-alert, quotes, semi
+
+// eslint-disable-next-line no-alert, quotes, semi
+alert('foo');
+
+alert('foo'); /* eslint-disable-line no-alert, quotes, semi */
+
+/* eslint-disable-next-line no-alert, quotes, semi */
+alert('foo');
+
+/* eslint-disable-next-line
+ no-alert,
+ quotes,
+ semi
+*/
+alert('foo');
+```
+
+All of the above methods also work for plugin rules. For example, to disable `eslint-plugin-example`'s `rule-name` rule, combine the plugin's name (`example`) and the rule's name (`rule-name`) into `example/rule-name`:
+
+```js
+foo(); // eslint-disable-line example/rule-name
+foo(); /* eslint-disable-line example/rule-name */
+```
+
+**Note:** Comments that disable warnings for a portion of a file tell ESLint not to report rule violations for the disabled code. ESLint still parses the entire file, however, so disabled code still needs to be syntactically valid JavaScript.
+
+#### Comment descriptions
+
+Configuration comments can include descriptions to explain why disabling or re-enabling the rule is necessary. The description must come after the configuration and needs to be separated from the configuration by two or more consecutive `-` characters. For example:
+
+```js
+// eslint-disable-next-line no-console -- Here's a description about why this configuration is necessary.
+console.log('hello');
+
+/* eslint-disable-next-line no-console --
+ * Here's a very long description about why this configuration is necessary
+ * along with some additional information
+**/
+console.log('hello');
+```
+
+### Using configuration files
+
+To disable rules inside of a configuration file for a group of files, use the `overrides` key along with a `files` key. For example:
+
+```json
+{
+ "rules": {...},
+ "overrides": [
+ {
+ "files": ["*-test.js","*.spec.js"],
+ "rules": {
+ "no-unused-expressions": "off"
+ }
+ }
+ ]
+}
+```
+
+### Disabling Inline Comments
+
+To disable all inline config comments, use the `noInlineConfig` setting in your configuration file. For example:
+
+```json
+{
+ "rules": {...},
+ "noInlineConfig": true
+}
+```
+
+You can also use the [--no-inline-config](../command-line-interface#--no-inline-config) CLI option to disable rule comments, in addition to other in-line configuration.
+
+#### Report unused `eslint-disable` comments
+
+To report unused `eslint-disable` comments, use the `reportUnusedDisableDirectives` setting. For example:
+
+```json
+{
+ "rules": {...},
+ "reportUnusedDisableDirectives": true
+}
+```
+
+This setting is similar to [--report-unused-disable-directives](../command-line-interface#--report-unused-disable-directives) CLI option, but doesn't fail linting (reports as `"warn"` severity).
--- /dev/null
+---
+title: Core Concepts
+eleventyNavigation:
+ key: core concepts
+ title: Core Concepts
+ parent: use eslint
+ order: 2
+---
+
+This page contains a high-level overview of some of the core concepts of ESLint.
+
+## What is ESLint?
+
+ESLint is a configurable JavaScript linter. It helps you find and fix problems in your JavaScript code. Problems can be anything from potential runtime bugs, to not following best practices, to styling issues.
+
+## Rules
+
+Rules are the core building block of ESLint. A rule validates if your code meets a certain expectation, and what to do if it does not meet that expectation. Rules can also contain additional configuration options specific to that rule.
+
+For example, the [`semi`](../rules/semi) rule lets you specify whether or not JavaScript statements should end with a semicolon (`;`). You can set the rule to either always require semicolons or require that a statement never ends with a semicolon.
+
+ESLint contains hundreds of built-in rules that you can use. You can also create custom rules or use rules that others have created with [plugins](#plugins).
+
+For more information, refer to [Rules](../rules/).
+
+## Configuration Files
+
+An ESLint configuration file is a place where you put the configuration for ESLint in your project. You can include built-in rules, how you want them enforced, plugins with custom rules, shareable configurations, which files you want rules to apply to, and more.
+
+For more information, refer to [Configuration Files](./configure/configuration-files).
+
+## Shareable Configurations
+
+Shareable configurations are ESLint configurations that are shared via npm.
+
+Often shareable configurations are used to enforce style guides using ESLint's built-in rules. For example the sharable configuration [eslint-config-airbnb-base](https://www.npmjs.com/package/eslint-config-airbnb-base) implements the popular Airbnb JavaScript style guide.
+
+For more information, refer to [Using a shareable configuration package](./configure/configuration-files#using-a-shareable-configuration-package).
+
+## Plugins
+
+An ESLint plugin is an npm module that can contain a set of ESLint rules, configurations, processors, and environments. Often plugins include custom rules. Plugins can be used to enforce a style guide and support JavaScript extensions (like TypeScript), libraries (like React), and frameworks (Angular).
+
+A popular use case for plugins is to enforce best practices for a framework. For example, [@angular-eslint/eslint-plugin](https://www.npmjs.com/package/@angular-eslint/eslint-plugin) contains best practices for using the Angular framework.
+
+For more information, refer to [Configure Plugins](./configure/plugins).
+
+## Parsers
+
+An ESLint parser converts code into an abstract syntax tree that ESLint can evaluate. By default, ESLint uses the built-in [Espree](https://github.com/eslint/espree) parser, which is compatible with standard JavaScript runtimes and versions.
+
+Custom parsers let ESLint parse non-standard JavaScript syntax. Often custom parsers are included as part of shareable configurations or plugins, so you don't have to use them directly.
+
+For example, [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) is a custom parser included in the [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint) project that lets ESLint parse TypeScript code.
+
+## Custom Processors
+
+An ESLint processor extracts JavaScript code from other kinds of files, then lets ESLint lint the JavaScript code. Alternatively, you can use a processor to manipulate JavaScript code before parsing it with ESLint.
+
+For example, [eslint-plugin-markdown](https://github.com/eslint/eslint-plugin-markdown) contains a custom processor that lets you lint JavaScript code inside of Markdown code blocks.
+
+## Formatters
+
+An ESLint formatter controls the appearance of the linting results in the CLI.
+
+For more information, refer to [Formatters](./formatters/).
+
+## Integrations
+
+One of the things that makes ESLint such a useful tool is the ecosystem of integrations that surrounds it. For example, many code editors have ESLint extensions that show you the ESLint results of your code in the file as you work so that you don't need to use the ESLint CLI to see linting results.
+
+For more information, refer to [Integrations](./integrations).
+
+## CLI & Node.js API
+
+The ESLint CLI is a command line interface that lets you execute linting from the terminal. The CLI has a variety of options that you can pass to its commands.
+
+The ESLint Node.js API lets you use ESLint programmatically from Node.js code. The API is useful when developing plugins, integrations, and other tools related to ESLint.
+
+Unless you are extending ESLint in some way, you should use the CLI.
+
+For more information, refer to [Command Line Interface](./command-line-interface) and [Node.js API](../integrate/nodejs-api).
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>ESLint Report</title>
+ <link rel="icon" type="image/png" sizes="any" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAHaAAAB2gGFomX7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAABD1JREFUWMPFl11sk2UUx3/nbYtjxS1MF7MLMTECMgSTtSSyrQkLhAj7UBPnDSEGoxegGzMwojhXVpmTAA5iYpSoMQa8GBhFOrMFk03buei6yRAlcmOM0SEmU9d90b19jxcM1o5+sGnsc/e+z/l6ztf/HFFVMnns6QieeOCHBePGsHM+wrOtvLG2C4WRVDSSygNV7sCjlspxwDnPB44aols/DXk+mbMBmx/6OseITF1CuOtfevkPh2Uu+/jbdX8lujSScRlT5r7/QDlAfsRmfzmpnkQ/H3H13gf6bBrBn1uqK8WylgEnU8eZmk1repbfchJG1TyKyIKEwuBHFd3lD3naY3O1siiwXsVoBV2VgM1ht/QQUJk2ByqKghsQziYQ8ifKgexIXmuyzC4r67Y7R+xPAfuB/Nn3Cpva+0s7khpQVtZtd4bt51BWxtBYAiciprG7c7D4SixzU9PYalDL6110Ifb/w8W9eY7JqFeFHbO8fPGyLHwwFHJNJTSgwtVTB9oaw9BlQ+tO93vOxypoaQnfEYlI43SeCHDC4TDq9+51/h5fxr33q0ZfV9g04wat9Q943rjJgCp3952W2i8Bi6eDvdsfKj0cK/DYMRyXL4/sUJUmIHd2zYMezsvLaamp4WpcWN3BXSiHpuMwbGbZlnZ8tXY4rgosy+G7oRwQ0cAsd28YGgqfU5UjCZQDLALxDg+Hv/P5Rqvj4hwrS8izXzWb4spwc1GgENFnkpWRzxeuB+ssUHgLdb9UVdt8vpGdKQpze7n7y1U3DBChNRUuqOo9c+0+qpKKxyZqtAIYla7gY4JszAAQri93BSsMRZoyBcUC+w3Q3AyOA4sNhAOZ0q7Iq0b2vUNvK5zPgP+/H8+Zetdoa6uOikhdGurxebwvJY8Iz3V1rTMNAH+opEuQj5KTT/qA1yC+wyUjBm12OidaUtCcPNNX2h0Hx2JG69VulANZAJZJwfU7rzd/FHixuXniTdM0m4GtSQT7bTartqEh9yfImUEzkwKZmTwmo5a5JwkYBfcDL01/RkR5y8iWhtPBknB8ZxwtU9UjwOrrKCeizzc25nTGg1F/turEHoU9wMLpDvWKf8DTmNCAKnd/tqUTF4ElMXJ+A5rWDJS+41WsGWzALhJ+ErBWrLj9g+pqojHxlXJX8HGUg0BsR/x1yhxf3jm4cSzpQFLp6tmi6PEE7g1ZhtZ91ufpSZUAFa6gC+UoQslNaSmypT1U8mHKiUgEKS8KfgF4EpYunFI16tsHin+OG0LcgQK7yj7g6cSzpva2D3hKVNG0Y3mVO1BkqfSlmJrHBQ4uvM12gJHc6ETW8HZVfMRmXvyxxNC1Z/o839zyXlDuCr4nsC11J+MXueaVJWn6yPv+/pJtc9oLTNN4AeTvNGByd3rlhE2x9s5pLwDoHCy+grDzWmOZ95lUtLYj5Bma126Y8eX0/zj/ADxGyViSg4BXAAAAAElFTkSuQmCC">
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PScwIDAgMjk0LjgyNSAyNTguOTgyJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPg0KPHBhdGggZmlsbD0nIzgwODBGMicgZD0nTTk3LjAyMSw5OS4wMTZsNDguNDMyLTI3Ljk2MmMxLjIxMi0wLjcsMi43MDYtMC43LDMuOTE4LDBsNDguNDMzLDI3Ljk2MiBjMS4yMTEsMC43LDEuOTU5LDEuOTkzLDEuOTU5LDMuMzkzdjU1LjkyNGMwLDEuMzk5LTAuNzQ4LDIuNjkzLTEuOTU5LDMuMzk0bC00OC40MzMsMjcuOTYyYy0xLjIxMiwwLjctMi43MDYsMC43LTMuOTE4LDAgbC00OC40MzItMjcuOTYyYy0xLjIxMi0wLjctMS45NTktMS45OTQtMS45NTktMy4zOTR2LTU1LjkyNEM5NS4wNjMsMTAxLjAwOSw5NS44MSw5OS43MTYsOTcuMDIxLDk5LjAxNicvPg0KPHBhdGggZmlsbD0nIzRCMzJDMycgZD0nTTI3My4zMzYsMTI0LjQ4OEwyMTUuNDY5LDIzLjgxNmMtMi4xMDItMy42NC01Ljk4NS02LjMyNS0xMC4xODgtNi4zMjVIODkuNTQ1IGMtNC4yMDQsMC04LjA4OCwyLjY4NS0xMC4xOSw2LjMyNWwtNTcuODY3LDEwMC40NWMtMi4xMDIsMy42NDEtMi4xMDIsOC4yMzYsMCwxMS44NzdsNTcuODY3LDk5Ljg0NyBjMi4xMDIsMy42NCw1Ljk4Niw1LjUwMSwxMC4xOSw1LjUwMWgxMTUuNzM1YzQuMjAzLDAsOC4wODctMS44MDUsMTAuMTg4LTUuNDQ2bDU3Ljg2Ny0xMDAuMDEgQzI3NS40MzksMTMyLjM5NiwyNzUuNDM5LDEyOC4xMjgsMjczLjMzNiwxMjQuNDg4IE0yMjUuNDE5LDE3Mi44OThjMCwxLjQ4LTAuODkxLDIuODQ5LTIuMTc0LDMuNTlsLTczLjcxLDQyLjUyNyBjLTEuMjgyLDAuNzQtMi44ODgsMC43NC00LjE3LDBsLTczLjc2Ny00Mi41MjdjLTEuMjgyLTAuNzQxLTIuMTc5LTIuMTA5LTIuMTc5LTMuNTlWODcuODQzYzAtMS40ODEsMC44ODQtMi44NDksMi4xNjctMy41OSBsNzMuNzA3LTQyLjUyN2MxLjI4Mi0wLjc0MSwyLjg4Ni0wLjc0MSw0LjE2OCwwbDczLjc3Miw0Mi41MjdjMS4yODMsMC43NDEsMi4xODYsMi4xMDksMi4xODYsMy41OVYxNzIuODk4eicvPg0KPC9zdmc+">
+ <style>
+ body {
+ font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
+ font-size: 16px;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+ color: #333;
+ }
+
+ #overview {
+ padding: 20px 30px;
+ }
+
+ td,
+ th {
+ padding: 5px 10px;
+ }
+
+ h1 {
+ margin: 0;
+ }
+
+ table {
+ margin: 30px;
+ width: calc(100% - 60px);
+ max-width: 1000px;
+ border-radius: 5px;
+ border: 1px solid #ddd;
+ border-spacing: 0;
+ }
+
+ th {
+ font-weight: 400;
+ font-size: medium;
+ text-align: left;
+ cursor: pointer;
+ }
+
+ td.clr-1,
+ td.clr-2,
+ th span {
+ font-weight: 700;
+ }
+
+ th span {
+ float: right;
+ margin-left: 20px;
+ }
+
+ th span::after {
+ content: "";
+ clear: both;
+ display: block;
+ }
+
+ tr:last-child td {
+ border-bottom: none;
+ }
+
+ tr td:first-child,
+ tr td:last-child {
+ color: #9da0a4;
+ }
+
+ #overview.bg-0,
+ tr.bg-0 th {
+ color: #468847;
+ background: #dff0d8;
+ border-bottom: 1px solid #d6e9c6;
+ }
+
+ #overview.bg-1,
+ tr.bg-1 th {
+ color: #f0ad4e;
+ background: #fcf8e3;
+ border-bottom: 1px solid #fbeed5;
+ }
+
+ #overview.bg-2,
+ tr.bg-2 th {
+ color: #b94a48;
+ background: #f2dede;
+ border-bottom: 1px solid #eed3d7;
+ }
+
+ td {
+ border-bottom: 1px solid #ddd;
+ }
+
+ td.clr-1 {
+ color: #f0ad4e;
+ }
+
+ td.clr-2 {
+ color: #b94a48;
+ }
+
+ td a {
+ color: #3a33d1;
+ text-decoration: none;
+ }
+
+ td a:hover {
+ color: #272296;
+ text-decoration: underline;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="overview" class="bg-2">
+ <h1>ESLint Report</h1>
+ <div>
+ <span>9 problems (5 errors, 4 warnings)</span> - Generated on Fri May 19 2023 16:52:13 GMT-0400 (Eastern Daylight Time)
+ </div>
+ </div>
+ <table>
+ <tbody>
+ <tr class="bg-2" data-group="f-0">
+ <th colspan="4">
+ [+] /var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js
+ <span>9 problems (5 errors, 4 warnings)</span>
+ </th>
+</tr>
+<tr style="display: none;" class="f-0">
+ <td>1:10</td>
+ <td class="clr-2">Error</td>
+ <td>'addOne' is defined but never used.</td>
+ <td>
+ <a href="" target="_blank" rel="noopener noreferrer">no-unused-vars</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>2:9</td>
+ <td class="clr-2">Error</td>
+ <td>Use the isNaN function to compare with NaN.</td>
+ <td>
+ <a href="" target="_blank" rel="noopener noreferrer">use-isnan</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>3:16</td>
+ <td class="clr-2">Error</td>
+ <td>Unexpected space before unary operator '++'.</td>
+ <td>
+ <a href="https://eslint.org/docs/latest/rules/space-unary-ops" target="_blank" rel="noopener noreferrer">space-unary-ops</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>3:20</td>
+ <td class="clr-1">Warning</td>
+ <td>Missing semicolon.</td>
+ <td>
+ <a href="https://eslint.org/docs/latest/rules/semi" target="_blank" rel="noopener noreferrer">semi</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>4:12</td>
+ <td class="clr-1">Warning</td>
+ <td>Unnecessary 'else' after 'return'.</td>
+ <td>
+ <a href="https://eslint.org/docs/latest/rules/no-else-return" target="_blank" rel="noopener noreferrer">no-else-return</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>5:1</td>
+ <td class="clr-1">Warning</td>
+ <td>Expected indentation of 8 spaces but found 6.</td>
+ <td>
+ <a href="https://eslint.org/docs/latest/rules/indent" target="_blank" rel="noopener noreferrer">indent</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>5:7</td>
+ <td class="clr-2">Error</td>
+ <td>Function 'addOne' expected a return value.</td>
+ <td>
+ <a href="https://eslint.org/docs/latest/rules/consistent-return" target="_blank" rel="noopener noreferrer">consistent-return</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>5:13</td>
+ <td class="clr-1">Warning</td>
+ <td>Missing semicolon.</td>
+ <td>
+ <a href="https://eslint.org/docs/latest/rules/semi" target="_blank" rel="noopener noreferrer">semi</a>
+ </td>
+</tr>
+
+<tr style="display: none;" class="f-0">
+ <td>7:2</td>
+ <td class="clr-2">Error</td>
+ <td>Unnecessary semicolon.</td>
+ <td>
+ <a href="" target="_blank" rel="noopener noreferrer">no-extra-semi</a>
+ </td>
+</tr>
+
+ </tbody>
+ </table>
+ <script type="text/javascript">
+ var groups = document.querySelectorAll("tr[data-group]");
+ for (i = 0; i < groups.length; i++) {
+ groups[i].addEventListener("click", function() {
+ var inGroup = document.getElementsByClassName(this.getAttribute("data-group"));
+ this.innerHTML = (this.innerHTML.indexOf("+") > -1) ? this.innerHTML.replace("+", "-") : this.innerHTML.replace("-", "+");
+ for (var j = 0; j < inGroup.length; j++) {
+ inGroup[j].style.display = (inGroup[j].style.display !== "none") ? "none" : "table-row";
+ }
+ });
+ }
+ </script>
+ </body>
+</html>
--- /dev/null
+{
+ "layout": false
+}
\ No newline at end of file
--- /dev/null
+---
+title: Formatters Reference
+eleventyNavigation:
+ key: formatters
+ parent: use eslint
+ title: Formatters Reference
+ order: 6
+edit_link: https://github.com/eslint/eslint/edit/main/templates/formatter-examples.md.ejs
+---
+
+ESLint comes with several built-in formatters to control the appearance of the linting results, and supports third-party formatters as well.
+
+You can specify a formatter using the `--format` or `-f` flag in the CLI. For example, `--format json` uses the `json` formatter.
+
+The built-in formatter options are:
+
+* [checkstyle](#checkstyle)
+* [compact](#compact)
+* [html](#html)
+* [jslint-xml](#jslint-xml)
+* [json-with-metadata](#json-with-metadata)
+* [json](#json)
+* [junit](#junit)
+* [stylish](#stylish)
+* [tap](#tap)
+* [unix](#unix)
+* [visualstudio](#visualstudio)
+
+## Example Source
+
+Examples of each formatter were created from linting `fullOfProblems.js` using the `.eslintrc.json` configuration shown below.
+
+`fullOfProblems.js`:
+
+```js
+function addOne(i) {
+ if (i != NaN) {
+ return i ++
+ } else {
+ return
+ }
+};
+```
+
+`.eslintrc.json`:
+
+```json
+{
+ "extends": "eslint:recommended",
+ "rules": {
+ "consistent-return": 2,
+ "indent" : [1, 4],
+ "no-else-return" : 1,
+ "semi" : [1, "always"],
+ "space-unary-ops" : 2
+ }
+}
+```
+
+Tests the formatters with the CLI:
+
+```shell
+npx eslint --format <Add formatter here> fullOfProblems.js
+```
+
+## Built-In Formatter Options
+
+### checkstyle
+
+Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format.
+
+Example output:
+
+```text
+<?xml version="1.0" encoding="utf-8"?><checkstyle version="4.3"><file name="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js"><error line="1" column="10" severity="error" message="'addOne' is defined but never used. (no-unused-vars)" source="eslint.rules.no-unused-vars" /><error line="2" column="9" severity="error" message="Use the isNaN function to compare with NaN. (use-isnan)" source="eslint.rules.use-isnan" /><error line="3" column="16" severity="error" message="Unexpected space before unary operator '++'. (space-unary-ops)" source="eslint.rules.space-unary-ops" /><error line="3" column="20" severity="warning" message="Missing semicolon. (semi)" source="eslint.rules.semi" /><error line="4" column="12" severity="warning" message="Unnecessary 'else' after 'return'. (no-else-return)" source="eslint.rules.no-else-return" /><error line="5" column="1" severity="warning" message="Expected indentation of 8 spaces but found 6. (indent)" source="eslint.rules.indent" /><error line="5" column="7" severity="error" message="Function 'addOne' expected a return value. (consistent-return)" source="eslint.rules.consistent-return" /><error line="5" column="13" severity="warning" message="Missing semicolon. (semi)" source="eslint.rules.semi" /><error line="7" column="2" severity="error" message="Unnecessary semicolon. (no-extra-semi)" source="eslint.rules.no-extra-semi" /></file></checkstyle>
+```
+
+### compact
+
+Human-readable output format. Mimics the default output of JSHint.
+
+Example output:
+
+```text
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 2, col 9, Error - Use the isNaN function to compare with NaN. (use-isnan)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 4, col 12, Warning - Unnecessary 'else' after 'return'. (no-else-return)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 1, Warning - Expected indentation of 8 spaces but found 6. (indent)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 7, Error - Function 'addOne' expected a return value. (consistent-return)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 13, Warning - Missing semicolon. (semi)
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 7, col 2, Error - Unnecessary semicolon. (no-extra-semi)
+
+9 problems
+```
+
+### html
+
+Outputs results to HTML. The `html` formatter is useful for visual presentation in the browser.
+
+Example output:
+
+<iframe src="html-formatter-example.html" width="100%" height="460px"></iframe>
+
+### jslint-xml
+
+Outputs results to format compatible with the [JSLint Jenkins plugin](https://plugins.jenkins.io/jslint/).
+
+Example output:
+
+```text
+<?xml version="1.0" encoding="utf-8"?><jslint><file name="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js"><issue line="1" char="10" evidence="" reason="'addOne' is defined but never used. (no-unused-vars)" /><issue line="2" char="9" evidence="" reason="Use the isNaN function to compare with NaN. (use-isnan)" /><issue line="3" char="16" evidence="" reason="Unexpected space before unary operator '++'. (space-unary-ops)" /><issue line="3" char="20" evidence="" reason="Missing semicolon. (semi)" /><issue line="4" char="12" evidence="" reason="Unnecessary 'else' after 'return'. (no-else-return)" /><issue line="5" char="1" evidence="" reason="Expected indentation of 8 spaces but found 6. (indent)" /><issue line="5" char="7" evidence="" reason="Function 'addOne' expected a return value. (consistent-return)" /><issue line="5" char="13" evidence="" reason="Missing semicolon. (semi)" /><issue line="7" char="2" evidence="" reason="Unnecessary semicolon. (no-extra-semi)" /></file></jslint>
+```
+
+### json-with-metadata
+
+Outputs JSON-serialized results. The `json-with-metadata` provides the same linting results as the [`json`](#json) formatter with additional metadata about the rules applied. The linting results are included in the `results` property and the rules metadata is included in the `metadata` property.
+
+Alternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint.
+
+Example output:
+
+```text
+{"results":[{"filePath":"/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js","messages":[{"ruleId":"no-unused-vars","severity":2,"message":"'addOne' is defined but never used.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":16},{"ruleId":"use-isnan","severity":2,"message":"Use the isNaN function to compare with NaN.","line":2,"column":9,"nodeType":"BinaryExpression","messageId":"comparisonWithNaN","endLine":2,"endColumn":17},{"ruleId":"space-unary-ops","severity":2,"message":"Unexpected space before unary operator '++'.","line":3,"column":16,"nodeType":"UpdateExpression","messageId":"unexpectedBefore","endLine":3,"endColumn":20,"fix":{"range":[57,58],"text":""}},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":3,"column":20,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":4,"endColumn":1,"fix":{"range":[60,60],"text":";"}},{"ruleId":"no-else-return","severity":1,"message":"Unnecessary 'else' after 'return'.","line":4,"column":12,"nodeType":"BlockStatement","messageId":"unexpected","endLine":6,"endColumn":6,"fix":{"range":[0,94],"text":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } \n return\n \n}"}},{"ruleId":"indent","severity":1,"message":"Expected indentation of 8 spaces but found 6.","line":5,"column":1,"nodeType":"Keyword","messageId":"wrongIndentation","endLine":5,"endColumn":7,"fix":{"range":[74,80],"text":" "}},{"ruleId":"consistent-return","severity":2,"message":"Function 'addOne' expected a return value.","line":5,"column":7,"nodeType":"ReturnStatement","messageId":"missingReturnValue","endLine":5,"endColumn":13},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":5,"column":13,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":6,"endColumn":1,"fix":{"range":[86,86],"text":";"}},{"ruleId":"no-extra-semi","severity":2,"message":"Unnecessary semicolon.","line":7,"column":2,"nodeType":"EmptyStatement","messageId":"unexpected","endLine":7,"endColumn":3,"fix":{"range":[93,95],"text":"}"}}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":2,"fixableWarningCount":4,"source":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } else {\n return\n }\n};"}],"metadata":{"rulesMeta":{"no-else-return":{"type":"suggestion","docs":{"description":"Disallow `else` blocks after `return` statements in `if` statements","recommended":false,"url":"https://eslint.org/docs/latest/rules/no-else-return"},"schema":[{"type":"object","properties":{"allowElseIf":{"type":"boolean","default":true}},"additionalProperties":false}],"fixable":"code","messages":{"unexpected":"Unnecessary 'else' after 'return'."}},"indent":{"type":"layout","docs":{"description":"Enforce consistent indentation","recommended":false,"url":"https://eslint.org/docs/latest/rules/indent"},"fixable":"whitespace","schema":[{"oneOf":[{"enum":["tab"]},{"type":"integer","minimum":0}]},{"type":"object","properties":{"SwitchCase":{"type":"integer","minimum":0,"default":0},"VariableDeclarator":{"oneOf":[{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},{"type":"object","properties":{"var":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"let":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"const":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]}},"additionalProperties":false}]},"outerIIFEBody":{"oneOf":[{"type":"integer","minimum":0},{"enum":["off"]}]},"MemberExpression":{"oneOf":[{"type":"integer","minimum":0},{"enum":["off"]}]},"FunctionDeclaration":{"type":"object","properties":{"parameters":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"body":{"type":"integer","minimum":0}},"additionalProperties":false},"FunctionExpression":{"type":"object","properties":{"parameters":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"body":{"type":"integer","minimum":0}},"additionalProperties":false},"StaticBlock":{"type":"object","properties":{"body":{"type":"integer","minimum":0}},"additionalProperties":false},"CallExpression":{"type":"object","properties":{"arguments":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]}},"additionalProperties":false},"ArrayExpression":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"ObjectExpression":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"ImportDeclaration":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"flatTernaryExpressions":{"type":"boolean","default":false},"offsetTernaryExpressions":{"type":"boolean","default":false},"ignoredNodes":{"type":"array","items":{"type":"string","not":{"pattern":":exit$"}}},"ignoreComments":{"type":"boolean","default":false}},"additionalProperties":false}],"messages":{"wrongIndentation":"Expected indentation of {{expected}} but found {{actual}}."}},"space-unary-ops":{"type":"layout","docs":{"description":"Enforce consistent spacing before or after unary operators","recommended":false,"url":"https://eslint.org/docs/latest/rules/space-unary-ops"},"fixable":"whitespace","schema":[{"type":"object","properties":{"words":{"type":"boolean","default":true},"nonwords":{"type":"boolean","default":false},"overrides":{"type":"object","additionalProperties":{"type":"boolean"}}},"additionalProperties":false}],"messages":{"unexpectedBefore":"Unexpected space before unary operator '{{operator}}'.","unexpectedAfter":"Unexpected space after unary operator '{{operator}}'.","unexpectedAfterWord":"Unexpected space after unary word operator '{{word}}'.","wordOperator":"Unary word operator '{{word}}' must be followed by whitespace.","operator":"Unary operator '{{operator}}' must be followed by whitespace.","beforeUnaryExpressions":"Space is required before unary expressions '{{token}}'."}},"semi":{"type":"layout","docs":{"description":"Require or disallow semicolons instead of ASI","recommended":false,"url":"https://eslint.org/docs/latest/rules/semi"},"fixable":"code","schema":{"anyOf":[{"type":"array","items":[{"enum":["never"]},{"type":"object","properties":{"beforeStatementContinuationChars":{"enum":["always","any","never"]}},"additionalProperties":false}],"minItems":0,"maxItems":2},{"type":"array","items":[{"enum":["always"]},{"type":"object","properties":{"omitLastInOneLineBlock":{"type":"boolean"},"omitLastInOneLineClassBody":{"type":"boolean"}},"additionalProperties":false}],"minItems":0,"maxItems":2}]},"messages":{"missingSemi":"Missing semicolon.","extraSemi":"Extra semicolon."}},"consistent-return":{"type":"suggestion","docs":{"description":"Require `return` statements to either always or never specify values","recommended":false,"url":"https://eslint.org/docs/latest/rules/consistent-return"},"schema":[{"type":"object","properties":{"treatUndefinedAsUnspecified":{"type":"boolean","default":false}},"additionalProperties":false}],"messages":{"missingReturn":"Expected to return a value at the end of {{name}}.","missingReturnValue":"{{name}} expected a return value.","unexpectedReturnValue":"{{name}} expected no return value."}}}}}
+```
+
+### json
+
+Outputs JSON-serialized results. The `json` formatter is useful when you want to programmatically work with the CLI's linting results.
+
+Alternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint.
+
+Example output:
+
+```text
+[{"filePath":"/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js","messages":[{"ruleId":"no-unused-vars","severity":2,"message":"'addOne' is defined but never used.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":16},{"ruleId":"use-isnan","severity":2,"message":"Use the isNaN function to compare with NaN.","line":2,"column":9,"nodeType":"BinaryExpression","messageId":"comparisonWithNaN","endLine":2,"endColumn":17},{"ruleId":"space-unary-ops","severity":2,"message":"Unexpected space before unary operator '++'.","line":3,"column":16,"nodeType":"UpdateExpression","messageId":"unexpectedBefore","endLine":3,"endColumn":20,"fix":{"range":[57,58],"text":""}},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":3,"column":20,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":4,"endColumn":1,"fix":{"range":[60,60],"text":";"}},{"ruleId":"no-else-return","severity":1,"message":"Unnecessary 'else' after 'return'.","line":4,"column":12,"nodeType":"BlockStatement","messageId":"unexpected","endLine":6,"endColumn":6,"fix":{"range":[0,94],"text":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } \n return\n \n}"}},{"ruleId":"indent","severity":1,"message":"Expected indentation of 8 spaces but found 6.","line":5,"column":1,"nodeType":"Keyword","messageId":"wrongIndentation","endLine":5,"endColumn":7,"fix":{"range":[74,80],"text":" "}},{"ruleId":"consistent-return","severity":2,"message":"Function 'addOne' expected a return value.","line":5,"column":7,"nodeType":"ReturnStatement","messageId":"missingReturnValue","endLine":5,"endColumn":13},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":5,"column":13,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":6,"endColumn":1,"fix":{"range":[86,86],"text":";"}},{"ruleId":"no-extra-semi","severity":2,"message":"Unnecessary semicolon.","line":7,"column":2,"nodeType":"EmptyStatement","messageId":"unexpected","endLine":7,"endColumn":3,"fix":{"range":[93,95],"text":"}"}}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":2,"fixableWarningCount":4,"source":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } else {\n return\n }\n};"}]
+```
+
+### junit
+
+Outputs results to format compatible with the [JUnit Jenkins plugin](https://plugins.jenkins.io/junit/).
+
+Example output:
+
+```text
+<?xml version="1.0" encoding="utf-8"?>
+<testsuites>
+<testsuite package="org.eslint" time="0" tests="9" errors="9" name="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js">
+<testcase time="0" name="org.eslint.no-unused-vars" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="'addOne' is defined but never used."><![CDATA[line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)]]></failure></testcase>
+<testcase time="0" name="org.eslint.use-isnan" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Use the isNaN function to compare with NaN."><![CDATA[line 2, col 9, Error - Use the isNaN function to compare with NaN. (use-isnan)]]></failure></testcase>
+<testcase time="0" name="org.eslint.space-unary-ops" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Unexpected space before unary operator '++'."><![CDATA[line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops)]]></failure></testcase>
+<testcase time="0" name="org.eslint.semi" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Missing semicolon."><![CDATA[line 3, col 20, Warning - Missing semicolon. (semi)]]></failure></testcase>
+<testcase time="0" name="org.eslint.no-else-return" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Unnecessary 'else' after 'return'."><![CDATA[line 4, col 12, Warning - Unnecessary 'else' after 'return'. (no-else-return)]]></failure></testcase>
+<testcase time="0" name="org.eslint.indent" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Expected indentation of 8 spaces but found 6."><![CDATA[line 5, col 1, Warning - Expected indentation of 8 spaces but found 6. (indent)]]></failure></testcase>
+<testcase time="0" name="org.eslint.consistent-return" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Function 'addOne' expected a return value."><![CDATA[line 5, col 7, Error - Function 'addOne' expected a return value. (consistent-return)]]></failure></testcase>
+<testcase time="0" name="org.eslint.semi" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Missing semicolon."><![CDATA[line 5, col 13, Warning - Missing semicolon. (semi)]]></failure></testcase>
+<testcase time="0" name="org.eslint.no-extra-semi" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Unnecessary semicolon."><![CDATA[line 7, col 2, Error - Unnecessary semicolon. (no-extra-semi)]]></failure></testcase>
+</testsuite>
+</testsuites>
+
+```
+
+### stylish
+
+Human-readable output format. This is the default formatter.
+
+Example output:
+
+```text
+
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js
+ 1:10 error 'addOne' is defined but never used no-unused-vars
+ 2:9 error Use the isNaN function to compare with NaN use-isnan
+ 3:16 error Unexpected space before unary operator '++' space-unary-ops
+ 3:20 warning Missing semicolon semi
+ 4:12 warning Unnecessary 'else' after 'return' no-else-return
+ 5:1 warning Expected indentation of 8 spaces but found 6 indent
+ 5:7 error Function 'addOne' expected a return value consistent-return
+ 5:13 warning Missing semicolon semi
+ 7:2 error Unnecessary semicolon no-extra-semi
+
+✖ 9 problems (5 errors, 4 warnings)
+ 2 errors and 4 warnings potentially fixable with the `--fix` option.
+
+```
+
+### tap
+
+Outputs results to the [Test Anything Protocol (TAP)](https://testanything.org/) specification format.
+
+Example output:
+
+```text
+TAP version 13
+1..1
+not ok 1 - /var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js
+ ---
+ message: '''addOne'' is defined but never used.'
+ severity: error
+ data:
+ line: 1
+ column: 10
+ ruleId: no-unused-vars
+ messages:
+ - message: Use the isNaN function to compare with NaN.
+ severity: error
+ data:
+ line: 2
+ column: 9
+ ruleId: use-isnan
+ - message: Unexpected space before unary operator '++'.
+ severity: error
+ data:
+ line: 3
+ column: 16
+ ruleId: space-unary-ops
+ - message: Missing semicolon.
+ severity: warning
+ data:
+ line: 3
+ column: 20
+ ruleId: semi
+ - message: Unnecessary 'else' after 'return'.
+ severity: warning
+ data:
+ line: 4
+ column: 12
+ ruleId: no-else-return
+ - message: Expected indentation of 8 spaces but found 6.
+ severity: warning
+ data:
+ line: 5
+ column: 1
+ ruleId: indent
+ - message: Function 'addOne' expected a return value.
+ severity: error
+ data:
+ line: 5
+ column: 7
+ ruleId: consistent-return
+ - message: Missing semicolon.
+ severity: warning
+ data:
+ line: 5
+ column: 13
+ ruleId: semi
+ - message: Unnecessary semicolon.
+ severity: error
+ data:
+ line: 7
+ column: 2
+ ruleId: no-extra-semi
+ ...
+
+```
+
+### unix
+
+Outputs results to a format similar to many commands in UNIX-like systems. Parsable with tools such as [grep](https://www.gnu.org/software/grep/manual/grep.html), [sed](https://www.gnu.org/software/sed/manual/sed.html), and [awk](https://www.gnu.org/software/gawk/manual/gawk.html).
+
+Example output:
+
+```text
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:1:10: 'addOne' is defined but never used. [Error/no-unused-vars]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:2:9: Use the isNaN function to compare with NaN. [Error/use-isnan]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:3:16: Unexpected space before unary operator '++'. [Error/space-unary-ops]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:3:20: Missing semicolon. [Warning/semi]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:4:12: Unnecessary 'else' after 'return'. [Warning/no-else-return]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:1: Expected indentation of 8 spaces but found 6. [Warning/indent]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:7: Function 'addOne' expected a return value. [Error/consistent-return]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:13: Missing semicolon. [Warning/semi]
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:7:2: Unnecessary semicolon. [Error/no-extra-semi]
+
+9 problems
+```
+
+### visualstudio
+
+Outputs results to format compatible with the integrated terminal of the [Visual Studio](https://visualstudio.microsoft.com/) IDE. When using Visual Studio, you can click on the linting results in the integrated terminal to go to the issue in the source code.
+
+Example output:
+
+```text
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(1,10): error no-unused-vars : 'addOne' is defined but never used.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(2,9): error use-isnan : Use the isNaN function to compare with NaN.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(3,16): error space-unary-ops : Unexpected space before unary operator '++'.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(3,20): warning semi : Missing semicolon.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(4,12): warning no-else-return : Unnecessary 'else' after 'return'.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,1): warning indent : Expected indentation of 8 spaces but found 6.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,7): error consistent-return : Function 'addOne' expected a return value.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,13): warning semi : Missing semicolon.
+/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(7,2): error no-extra-semi : Unnecessary semicolon.
+
+9 problems
+```
--- /dev/null
+---
+title: Getting Started with ESLint
+eleventyNavigation:
+ key: getting started
+ parent: use eslint
+ title: Getting Started
+ order: 1
+
+---
+
+ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs.
+
+ESLint is completely pluggable. Every single rule is a plugin and you can add more at runtime. You can also add community plugins, configurations, and parsers to extend the functionality of ESLint.
+
+## Prerequisites
+
+To use ESLint, you must have [Node.js](https://nodejs.org/en/) (`^12.22.0`, `^14.17.0`, or `>=16.0.0`) installed and built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
+
+## Quick start
+
+You can install and configure ESLint using this command:
+
+```shell
+npm init @eslint/config
+```
+
+If you want to use a specific shareable config that is hosted on npm, you can use the `--config` option and specify the package name:
+
+```shell
+# use `eslint-config-semistandard` shared config
+
+# npm 7+
+npm init @eslint/config -- --config semistandard
+
+# or (`eslint-config` prefix is optional)
+npm init @eslint/config -- --config eslint-config-semistandard
+
+# ⚠️ npm 6.x no extra double-dash:
+npm init @eslint/config --config semistandard
+
+```
+
+The `--config` flag also supports passing in arrays:
+
+```shell
+npm init @eslint/config -- --config semistandard,standard
+# or
+npm init @eslint/config -- --config semistandard --config standard
+```
+
+**Note:** `npm init @eslint/config` assumes you have a `package.json` file already. If you don't, make sure to run `npm init` or `yarn init` beforehand.
+
+After that, you can run ESLint on any file or directory like this:
+
+```shell
+npx eslint yourfile.js
+
+# or
+
+yarn run eslint yourfile.js
+```
+
+## Configuration
+
+**Note:** If you are coming from a version before 1.0.0 please see the [migration guide](migrating-to-1.0.0).
+
+After running `npm init @eslint/config`, you'll have an `.eslintrc.{js,yml,json}` file in your directory. In it, you'll see some rules configured like this:
+
+```json
+{
+ "rules": {
+ "semi": ["error", "always"],
+ "quotes": ["error", "double"]
+ }
+}
+```
+
+The names `"semi"` and `"quotes"` are the names of [rules](../rules) in ESLint. The first value is the error level of the rule and can be one of these values:
+
+* `"off"` or `0` - turn the rule off
+* `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
+* `"error"` or `2` - turn the rule on as an error (exit code will be 1)
+
+The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the [configuration docs](configure/)).
+
+Your `.eslintrc.{js,yml,json}` configuration file will also include the line:
+
+```json
+{
+ "extends": "eslint:recommended"
+}
+```
+
+Because of this line, all of the rules marked "(recommended)" on the [rules page](../rules) will be turned on. Alternatively, you can use configurations that others have created by searching for "eslint-config" on [npmjs.com](https://www.npmjs.com/search?q=eslint-config). ESLint will not lint your code unless you extend from a shared configuration or explicitly turn rules on in your configuration.
+
+## Global Install
+
+It is also possible to install ESLint globally, rather than locally, using `npm install eslint --global`. However, this is not recommended, and any plugins or shareable configs that you use must still be installed locally if you install ESLint globally.
+
+## Manual Set Up
+
+You can also manually set up ESLint in your project.
+
+Before you begin, you must already have a `package.json` file. If you don't, make sure to run `npm init` or `yarn init` to create the file beforehand.
+
+1. Install the ESLint package in your project:
+
+ ```shell
+ npm install --save-dev eslint
+ ```
+
+1. Add an `.eslintrc` file in one of the [supported configuration file formats](./configure/configuration-files#configuration-file-formats).
+
+ ```shell
+ # Create JavaScript configuration file
+ touch .eslintrc.js
+ ```
+
+1. Add configuration to the `.eslintrc` file. Refer to the [Configure ESLint documentation](configure/) to learn how to add rules, environments, custom configurations, plugins, and more.
+
+ ```js
+ // .eslintrc.js example
+ module.exports = {
+ "env": {
+ "browser": true,
+ "es2021": true
+ },
+ "extends": "eslint:recommended",
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "sourceType": "module"
+ },
+ }
+ ```
+
+1. Lint code using the ESLint CLI:
+
+ ```shell
+ npx eslint project-dir/ file1.js
+ ```
+
+ For more information on the available CLI options, refer to [Command Line Interface](./command-line-interface).
+
+---
+
+## Next Steps
+
+* Learn about [advanced configuration](configure/) of ESLint.
+* Get familiar with the [command line options](command-line-interface).
+* Explore [ESLint integrations](integrations) into other tools like editors, build systems, and more.
+* Can't find just the right rule? Make your own [custom rule](../extend/custom-rules).
+* Make ESLint even better by [contributing](../contribute/).
--- /dev/null
+---
+title: Use ESLint in Your Project
+eleventyNavigation:
+ key: use eslint
+ title: Use ESLint in Your Project
+ order: 1
+---
+
+This guide is intended for those who wish to use ESLint as an end-user. If you're looking for how to extend ESLint or work with the ESLint source code, please see the [Extend ESLint documentation](../extend/).
+
+## [Getting Started](getting-started)
+
+Want to skip ahead and just start using ESLint? This section gives a high-level overview of installation, setup, and configuration options.
+
+## [Core Concepts](core-concepts)
+
+Understand the main components of ESLint and how to use them in your project.
+
+## [Configure ESLint](configure/)
+
+Once you've got ESLint running, you'll probably want to adjust the configuration to better suit your project. This section explains all the different ways you can configure ESLint.
+
+## [Command Line Interface Reference](command-line-interface)
+
+There are a lot of command line flags for ESLint and this section explains what they do.
+
+## [Rules Reference](../rules/)
+
+ESLint has a lot of rules that you can configure to fine-tune it to your project. This section is an exhaustive list of every rule and link to each rule's documentation.
+
+## [Formatters Reference](formatters)
+
+Control the appearance of the linting results with formatters. View all built-in formatters on this page.
+
+## [Integrations](integrations)
+
+Wondering if ESLint will work with your favorite editor or build system? This page has a list of integrations (submitted by their authors).
+
+## [Rule Deprecation](rule-deprecation)
+
+The ESLint team is committed to making upgrading as easy and painless as possible. This section outlines the guidelines the team has set in place for the deprecation of rules in future releases.
+
+## Migrating
+
+If you were using a prior version of ESLint, you can get help with the transition by reading:
+
+* [migrating-to-1.0.0](migrating-to-1.0.0)
+* [migrating-to-2.0.0](migrating-to-2.0.0)
+* [migrating-to-3.0.0](migrating-to-3.0.0)
+* [migrating-to-4.0.0](migrating-to-4.0.0)
+* [migrating-to-5.0.0](migrating-to-5.0.0)
+* [migrating-to-6.0.0](migrating-to-6.0.0)
+* [migrating-to-7.0.0](migrating-to-7.0.0)
+* [migrate-to-8.0.0](migrate-to-8.0.0)
--- /dev/null
+---
+title: Integrations
+eleventyNavigation:
+ key: integrations
+ parent: use eslint
+ title: Integrations
+ order: 7
+
+---
+
+This page contains community projects that have integrated ESLint. The projects on this page are not maintained by the ESLint team.
+
+If you would like to recommend an integration to be added to this page, [submit a pull request](../contribute/pull-requests).
+
+## Editors
+
+* Sublime Text 3:
+ * [SublimeLinter-eslint](https://github.com/SublimeLinter/SublimeLinter-eslint)
+ * [Build Next](https://github.com/albertosantini/sublimetext-buildnext)
+* Vim:
+ * [ALE](https://github.com/dense-analysis/ale)
+ * [Syntastic](https://github.com/vim-syntastic/syntastic/tree/master/syntax_checkers/javascript)
+* Emacs: [Flycheck](http://www.flycheck.org/) supports ESLint with the [javascript-eslint](http://www.flycheck.org/en/latest/languages.html#javascript) checker.
+* Eclipse Orion: ESLint is the [default linter](https://dev.eclipse.org/mhonarc/lists/orion-dev/msg02718.html)
+* Eclipse IDE: [Tern ESLint linter](https://github.com/angelozerr/tern.java/wiki/Tern-Linter-ESLint)
+* TextMate 2:
+ * [eslint.tmbundle](https://github.com/ryanfitzer/eslint.tmbundle)
+ * [javascript-eslint.tmbundle](https://github.com/natesilva/javascript-eslint.tmbundle)
+* IntelliJ IDEA, WebStorm, PhpStorm, PyCharm, RubyMine, and other JetBrains IDEs: [How to use ESLint](https://www.jetbrains.com/help/webstorm/eslint.html)
+* Visual Studio: [Linting JavaScript in VS](https://learn.microsoft.com/en-us/visualstudio/javascript/linting-javascript?view=vs-2022)
+* 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)
+
+## Build tools
+
+* Grunt: [grunt-eslint](https://www.npmjs.com/package/grunt-eslint)
+* Webpack: [eslint-webpack-plugin](https://www.npmjs.com/package/eslint-webpack-plugin)
+* Rollup: [@rollup/plugin-eslint](https://www.npmjs.com/package/@rollup/plugin-eslint)
+
+## Command Line Tools
+
+* [ESLint Watch](https://www.npmjs.com/package/eslint-watch)
+* [Code Climate CLI](https://github.com/codeclimate/codeclimate)
+* [ESLint Nibble](https://github.com/IanVS/eslint-nibble)
+
+## Source Control
+
+* [Git Precommit Hook](https://coderwall.com/p/zq8jlq/eslint-pre-commit-hook)
+* [Git pre-commit hook that only lints staged changes](https://gist.github.com/dahjelle/8ddedf0aebd488208a9a7c829f19b9e8)
+* [overcommit Git hook manager](https://github.com/brigade/overcommit)
+* [Mega-Linter](https://megalinter.io/latest/): Linters aggregator for CI, [embedding eslint](https://megalinter.io/latest/descriptors/javascript_eslint/)
+
+## Other Integration Lists
+
+You can find a curated list of other popular integrations for ESLint in the [awesome-eslint](https://github.com/dustinspecker/awesome-eslint) GitHub repository.
--- /dev/null
+---
+title: Migrate to v8.0.0
+eleventyNavigation:
+ key: migrate to v8
+ parent: use eslint
+ title: Migrate to v8.x
+ order: 7
+
+---
+
+ESLint v8.0.0 is a major release of ESLint. We have made a few breaking changes in this release. This guide is intended to walk you through the 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.
+
+## Table of Contents
+
+### Breaking changes for users
+
+* [Node.js 10, 13, and 15 are no longer supported](#drop-old-node)
+* [Removed `codeframe` and `table` formatters](#removed-formatters)
+* [`comma-dangle` rule schema is stricter](#comma-dangle)
+* [Unused disable directives are now fixable](#directives)
+* [`eslint:recommended` has been updated](#eslint-recommended)
+
+### Breaking changes for plugin developers
+
+* [Node.js 10, 13, and 15 are no longer supported](#drop-old-node)
+* [Rules require `meta.hasSuggestions` to provide suggestions](#suggestions)
+* [Rules require `meta.fixable` to provide fixes](#fixes)
+* [`SourceCode#getComments()` fails in `RuleTester`](#get-comments)
+* [Changes to shorthand property AST format](#ast-format)
+
+### Breaking changes for integration developers
+
+* [Node.js 10, 13, and 15 are no longer supported](#drop-old-node)
+* [The `CLIEngine` class has been removed](#remove-cliengine)
+* [The `linter` object has been removed](#remove-linter)
+* [The `/lib` entrypoint has been removed](#remove-lib)
+
+---
+
+## <a name="drop-old-node"></a> Node.js 10, 13, and 15 are no longer supported
+
+Node.js 10, 13, 15 all reached end of life either in 2020 or early 2021. ESLint is officially dropping support for these versions of Node.js starting with ESLint v8.0.0. ESLint now supports the following versions of Node.js:
+
+* Node.js 12.22 and above
+* Node.js 14 and above
+* Node.js 16 and above
+
+**To address:** Make sure you upgrade to at least Node.js `12.22.0` when using ESLint v8.0.0. One important thing to double check is the Node.js version supported by your editor when using ESLint via editor integrations. If you are unable to upgrade, we recommend continuing to use ESLint 7 until you are able to upgrade Node.js.
+
+**Related issue(s):** [#14023](https://github.com/eslint/eslint/issues/14023)
+
+## <a name="removed-formatters"></a> Removed `codeframe` and `table` formatters
+
+ESLint v8.0.0 has removed the `codeframe` and `table` formatters from the core. These formatters required dependencies that weren't used anywhere else in ESLint, and removing them allows us to reduce the size of ESLint, allowing for faster installation.
+
+**To address:** If you are using the `codeframe` or `table` formatters, you'll need to install the standalone [`eslint-formatter-codeframe`](https://github.com/eslint-community/eslint-formatter-codeframe) or [`eslint-formatter-table`](https://github.com/eslint-community/eslint-formatter-table) packages, respectively, to be able to use them in ESLint v8.0.0.
+
+**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:
+
+```json
+{
+ "rules": {
+ "comma-dangle": ["error", "never", { "arrays": "always" }]
+ }
+}
+```
+
+With this configuration, the rule would ignore the third element in the array because only the second element is read. In ESLint v8.0.0, this configuration will cause ESLint to throw an error.
+
+**To address:** Change your rule configuration so that there are only two elements in the array, and the second element is either a string or an object, such as:
+
+```json
+{
+ "comma-dangle": ["error", "never"],
+}
+```
+
+or
+
+```json
+{
+ "comma-dangle": ["error", {
+ "arrays": "never",
+ "objects": "never",
+ "imports": "never",
+ "exports": "never",
+ "functions": "never"
+ }]
+}
+```
+
+**Related issue(s):** [#13739](https://github.com/eslint/eslint/issues/13739)
+
+## <a name="directives"></a> Unused disable directives are now fixable
+
+In ESLint v7.0.0, using both `--report-unused-disable-directives` and `--fix` on the command line would fix only rules but leave unused disable directives in place. In ESLint v8.0.0, this combination of command-line options will result in the unused disable directives being removed.
+
+**To address:** If you are using `--report-unused-disable-directives` and `--fix` together on the command line, and you don't want unused disable directives to be removed, add `--fix-type problem,suggestion,layout` as a command line option.
+
+**Related issue(s):** [#11815](https://github.com/eslint/eslint/issues/11815)
+
+## <a name="eslint-recommended"></a> `eslint:recommended` has been updated
+
+Four new rules have been enabled in the `eslint:recommended` preset.
+
+* [`no-loss-of-precision`](../rules/no-loss-of-precision)
+* [`no-nonoctal-decimal-escape`](../rules/no-nonoctal-decimal-escape)
+* [`no-unsafe-optional-chaining`](../rules/no-unsafe-optional-chaining)
+* [`no-useless-backreference`](../rules/no-useless-backreference)
+
+**To address:** Fix errors or disable these rules.
+
+**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](../extend/custom-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.
+
+**To address:** If your rule provides suggestions, add `meta.hasSuggestions` to the object, such as:
+
+```js
+module.exports = {
+ meta: {
+ hasSuggestions: true
+ },
+ create(context) {
+ // your rule
+ }
+};
+```
+
+The [eslint-plugin/require-meta-has-suggestions](https://github.com/eslint-community/eslint-plugin-eslint-plugin/blob/main/docs/rules/require-meta-has-suggestions.md) rule can automatically fix and enforce that your rules are properly specifying `meta.hasSuggestions`.
+
+**Related issue(s):** [#14312](https://github.com/eslint/eslint/issues/14312)
+
+## <a name="fixes"></a> Rules require `meta.fixable` to provide fixes
+
+In ESLint v7.0.0, rules that were written as a function (rather than object) were able to provide fixes. In ESLint v8.0.0, only rules written as an object are allowed to provide fixes and must have a `meta.fixable` property set to either `"code"` or `"whitespace"`.
+
+**To address:** If your rule makes fixes and is written as a function, such as:
+
+```js
+module.exports = function(context) {
+ // your rule
+};
+```
+
+Then rewrite your rule in this format:
+
+```js
+module.exports = {
+ meta: {
+ fixable: "code" // or "whitespace"
+ },
+ create(context) {
+ // your rule
+ }
+};
+```
+
+The [eslint-plugin/require-meta-fixable](https://github.com/eslint-community/eslint-plugin-eslint-plugin/blob/main/docs/rules/require-meta-fixable.md) rule can automatically fix and enforce that your rules are properly specifying `meta.fixable`.
+
+The [eslint-plugin/prefer-object-rule](https://github.com/eslint-community/eslint-plugin-eslint-plugin/blob/main/docs/rules/prefer-object-rule.md) rule can automatically fix and enforce that your rules are written with the object format instead of the deprecated function format.
+
+See the [rule documentation](../extend/custom-rules) for more information on writing rules.
+
+**Related issue(s):** [#13349](https://github.com/eslint/eslint/issues/13349)
+
+## <a name="get-comments"></a> `SourceCode#getComments()` fails in `RuleTester`
+
+Back in ESLint v4.0.0, we deprecated `SourceCode#getComments()`, but we neglected to remove it. Rather than removing it completely in v8.0.0, we are taking the intermediate step of updating `RuleTester` to fail when `SourceCode#getComments()` is used inside of a rule. As such, all existing rules will continue to work, but when the developer runs tests for the rule there will be a failure.
+
+The `SourceCode#getComments()` method will be removed in v9.0.0.
+
+**To address:** If your rule uses `SourceCode#getComments()`, please use [`SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, or `SourceCode#getCommentsInside()`](../extend/custom-rules#accessing-comments).
+
+**Related issue(s):** [#14744](https://github.com/eslint/eslint/issues/14744)
+
+## <a name="ast-format"></a> Changes to shorthand property AST format
+
+ESLint v8.0.0 includes an upgrade to Espree v8.0.0 to support new syntax. This Espree upgrade, in turn, contains an upgrade to Acorn v8.0.0, which changed how shorthand properties were represented in the AST. Here's an example:
+
+```js
+const version = 8;
+const x = {
+ version
+};
+```
+
+This code creates a property node that looks like this:
+
+```json
+{
+ "type": "Property",
+ "method": false,
+ "shorthand": true,
+ "computed": false,
+ "key": {
+ "type": "Identifier",
+ "name": "version"
+ },
+ "kind": "init",
+ "value": {
+ "type": "Identifier",
+ "name": "version"
+ }
+}
+```
+
+Note that both the `key` and the `value` properties contain the same information. Prior to Acorn v8.0.0 (and therefore prior to ESLint v8.0.0), these two nodes were represented by the same object, so you could use `===` to determine if they represented the same node, such as:
+
+```js
+// true in ESLint v7.x, false in ESLint v8.0.0
+if (propertyNode.key === propertyNode.value) {
+ // do something
+}
+```
+
+In ESLint v8.0.0 (via Acorn v8.0.0), the key and value are now separate objects and therefore no longer equivalent.
+
+**To address:** If your rule makes a comparison between the key and value of a shorthand object literal property to determine if they are the same node, you'll need to change your code in one of two ways:
+
+1. Use `propertyNode.shorthand` to determine if the property is a shorthand property node.
+1. Use the `range` property of each node to determine if the key and value occupy the same location.
+
+**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](../integrate/nodejs-api#eslint-class).
+
+**To address:** Update your code to use the new `ESLint` class if you are currently using `CLIEngine`. The following table maps the existing `CLIEngine` methods to their `ESLint` counterparts:
+
+| `CLIEngine` | `ESLint` |
+| :------------------------------------------- | :--------------------------------- |
+| `executeOnFiles(patterns)` | `lintFiles(patterns)` |
+| `executeOnText(text, filePath, warnIgnored)` | `lintText(text, options)` |
+| `getFormatter(name)` | `loadFormatter(name)` |
+| `getConfigForFile(filePath)` | `calculateConfigForFile(filePath)` |
+| `isPathIgnored(filePath)` | `isPathIgnored(filePath)` |
+| `static outputFixes(results)` | `static outputFixes(results)` |
+| `static getErrorResults(results)` | `static getErrorResults(results)` |
+| `static getFormatter(name)` | (removed ※1) |
+| `addPlugin(pluginId, definition)` | the `plugins` constructor option |
+| `getRules()` | (removed ※2) |
+| `resolveFileGlobPatterns()` | (removed ※3) |
+
+* ※1 The `engine.getFormatter()` method currently returns the object of loaded packages as-is, which made it difficult to add new features to formatters for backward compatibility reasons. The new `eslint.loadFormatter()` method returns an adapter object that wraps the object of loaded packages, to ease the process of adding new features. Additionally, the adapter object has access to the `ESLint` instance to calculate default data (using loaded plugin rules to make `rulesMeta`, for example). As a result, the `ESLint` class only implements an instance version of the `loadFormatter()` method.
+* ※2 The `CLIEngine#getRules()` method had side effects and so was removed. If you were using `CLIEngine#getRules()` to retrieve meta information about rules based on linting results, use `ESLint#getRulesMetaForResults()` instead. If you were using `CLIEngine#getRules()` to retrieve all built-in rules, import `builtinRules` from `eslint/use-at-your-own-risk` for an unsupported API that allows access to internal rules.
+* ※3 Since ESLint v6.0.0, ESLint uses different logic from the `resolveFileGlobPatterns()` method to iterate files, making this method obsolete.
+
+**Related issue(s):** [RFC80](https://github.com/eslint/rfcs/tree/main/designs/2021-package-exports), [#14716](https://github.com/eslint/eslint/pull/14716), [#13654](https://github.com/eslint/eslint/issues/13654)
+
+## <a name="remove-linter"></a> The `linter` object has been removed
+
+The deprecated `linter` object has been removed from the ESLint package in v8.0.0.
+
+**To address:** If you are using the `linter` object, such as:
+
+```js
+const { linter } = require("eslint");
+```
+
+Change your code to this:
+
+```js
+const { Linter } = require("eslint");
+const linter = new Linter();
+```
+
+**Related issue(s):** [RFC80](https://github.com/eslint/rfcs/tree/main/designs/2021-package-exports), [#14716](https://github.com/eslint/eslint/pull/14716), [#13654](https://github.com/eslint/eslint/issues/13654)
+
+## <a name="remove-lib"></a> The `/lib` entrypoint has been removed
+
+Beginning in v8.0.0, ESLint is strictly defining its public API. Previously, you could reach into individual files such as `require("eslint/lib/rules/semi")` and this is no longer allowed. There are a limited number of existing APIs that are now available through the `/use-at-your-own-risk` entrypoint for backwards compatibility, but these APIs are not formally supported and may break or disappear at any point in time.
+
+**To address:** If you are accessing rules directly through the `/lib` entrypoint, such as:
+
+```js
+const rule = require("eslint/lib/rules/semi");
+```
+
+Change your code to this:
+
+```js
+const { builtinRules } = require("eslint/use-at-your-own-risk");
+const rule = builtinRules.get("semi");
+```
+
+If you are accessing `FileEnumerator` directly through the `/lib` entrypoint, such as:
+
+```js
+const { FileEnumerator } = require("eslint/lib/cli-engine/file-enumerator");
+```
+
+Change your code to this:
+
+```js
+const { FileEnumerator } = require("eslint/use-at-your-own-risk");
+```
+
+**Related issue(s):** [RFC80](https://github.com/eslint/rfcs/tree/main/designs/2021-package-exports), [#14716](https://github.com/eslint/eslint/pull/14716), [#13654](https://github.com/eslint/eslint/issues/13654)
--- /dev/null
+---
+title: Migrating from JSCS
+
+---
+
+In April 2016, we [announced](https://eslint.org/blog/2016/04/welcoming-jscs-to-eslint) that the JSCS project was shutting down and the JSCS team would be joining the ESLint team. This guide is intended to help those who are using JSCS to migrate their settings and projects to use ESLint. We've tried to automate as much of the conversion as possible, but there are some manual changes that are needed.
+
+## Terminology
+
+Before beginning the process of migrating to ESLint, it's helpful to understand some of the terminology that ESLint uses and how it relates to terminology that JSCS uses.
+
+* **Configuration File** - In JSCS, the configuration file is `.jscsrc`, `.jscsrc.json`, `.jscsrc.yaml`, or `.jscsrs.js`. In ESLint, the configuration file can be `.eslintrc.json`, `.eslintrc.yml`, `.eslintrc.yaml`, or `.eslintrc.js` (there is also a deprecated `.eslintrc` file format).
+* **Presets** - In JSCS, there were numerous predefined configurations shipped directly within JSCS. ESLint ships with just one predefined configuration (`eslint:recommended`) that has no style rules enabled. However, ESLint does support [shareable configs](../extend/shareable-configs). Shareable configs are configurations that are published on their own to npm and there are shareable configs available for almost all of the JSCS presets (see [the "Converting Presets" section](#converting-presets) below). Additionally, the `preset` option in a configuration file is the equivalent of the ESLint `extends` option.
+
+## Convert Configuration Files Using Polyjuice
+
+[Polyjuice](https://github.com/brenolf/polyjuice) is a utility for converting JSCS (and JSHint) configuration files into ESLint configuration files automatically. It understands the equivalent rules from each utility and will automatically output an ESLint configuration file that is a good approximation of your existing JSCS file.
+
+To install Polyjuice:
+
+```shell
+npm install -g polyjuice
+```
+
+Polyjuice works with JSON configuration files, so if you're using a JavaScript or YAML JSCS configuration file, you should first convert it into a JSON configuration file.
+
+To convert your configuration file, pass in the location of your `.jscs.json` file using the `--jscs` flag:
+
+```shell
+polyjuice --jscs .jscsrc.json > .eslintrc.json
+```
+
+This creates an `.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:
+
+```shell
+polyjuice --jscs .jscsrc.json ./foo/.jscsrc.json > .eslintrc.json
+```
+
+**Note:** Polyjuice does a good job of creating a reasonable ESLint configuration from your JSCS configuration, but it may not be 100%. You may still see different warnings than you saw with JSCS, and so you may need to further modify your configuration after using Polyjuice. This is especially true if you're using inline comments to enable/disable certain rules in JSCS (you'll need to manually convert those to use ESLint-style comments instead, [see "Disabling Rules Inline"](#disabling-rules-inline) later in this page).
+
+### Creating a New Configuration From Scratch
+
+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:
+
+```shell
+npm init @eslint/config
+```
+
+You'll be guided through a series of questions that will help you setup a basic configuration file to get you started.
+
+## Converting Presets
+
+There are shareable configs available for most JSCS presets. The equivalent shareable configs for each JSCS preset are listed in the following table:
+
+| **JSCS Preset** | **ESLint Shareable Config** |
+|-----------------|-----------------------------|
+| `airbnb` | [`eslint-config-airbnb-base`](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base) |
+| `crockford` | (not available) |
+| `google` | [`eslint-config-google`](https://github.com/google/eslint-config-google) |
+| `grunt` | [`eslint-config-grunt`](https://github.com/markelog/eslint-config-grunt) |
+| `idiomatic` | [`eslint-config-idiomatic`](https://github.com/jamespamplin/eslint-config-idiomatic) |
+| `jquery` | [`eslint-config-jquery`](https://github.com/jquery/eslint-config-jquery) |
+| `mdcs` | [`eslint-config-mdcs`](https://github.com/zz85/mrdoobapproves) |
+| `node-style-guide` | [`eslint-config-node-style-guide`](https://github.com/pdehaan/eslint-config-node-style-guide) |
+| `wikimedia` | [`eslint-config-wikimedia`](https://github.com/wikimedia/eslint-config-wikimedia) |
+| `wordpress` | [`eslint-config-wordpress`](https://github.com/WordPress-Coding-Standards/eslint-config-wordpress) |
+
+As an example, suppose that you are using the `airbnb` preset, so your `.jscsrc` file looks like this:
+
+```json
+{
+ "preset": "airbnb"
+}
+```
+
+In order to get the same functionality in ESLint, you would first need to install the `eslint-config-airbnb` shareable config package:
+
+```shell
+npm install eslint-config-airbnb-base --save-dev
+```
+
+And then you would modify your configuration file like this:
+
+```json
+{
+ "extends": "airbnb-base"
+}
+```
+
+ESLint sees `"airbnb-base"` and will look for `eslint-config-airbnb-base` (to save you some typing).
+
+## Disabling Rules Inline
+
+Both JSCS and ESLint use comments inside of files to disable rules around certain parts of your code. The following table lists out the JSCS inline configuration comments and their ESLint equivalents.
+
+| **Description** | **JSCS Comment** | **ESLint Comment** |
+|-----------------|------------------|--------------------|
+| Disable all rules | `// jscs:disable` or `/* jscs:disable */` | `/* eslint-disable */` |
+| Enable all rules | `// jscs:enable` or `/* jscs:enable */` | `/* eslint-enable */` |
+| Disable one rule | `// jscs:disable ruleName` or `/* jscs:disable ruleName */` | `/* eslint-disable rule-name */` |
+| Enable one rule | `// jscs:enable ruleName` or `/* jscs:enable ruleName */` | `/* eslint-enable rule-name */` |
+| Disable multiple rules | `// jscs:disable ruleName1, ruleName2` or `/* jscs:disable ruleName1, ruleName2 */` | `/* eslint-disable rule-name1, rule-name2 */` |
+| Enable multiple rules | `// jscs:enable ruleName1, ruleName2` or `/* jscs:enable ruleName1, ruleName2 */` | `/* eslint-enable rule-name1, rule-name2 */` |
+| Disable one rule on single line | `// jscs:ignore ruleName` | `// eslint-disable-line rule-name` |
+
+## Command Line Options
+
+Both JSCS and ESLint have command line arguments corresponding to many of their configuration options. The following are the ESLint equivalents of JSCS command line options.
+
+### `--fix`
+
+JSCS uses the `--fix` option to apply automatic fixes to code:
+
+```shell
+jscs --fix file.js
+```
+
+ESLint has the same option:
+
+```shell
+eslint --fix file.js
+```
+
+### `--auto-configure`
+
+The JSCS `--auto-configure` option created a configuration based on what it found in a given file:
+
+```shell
+jscs --auto-configure file.js
+```
+
+In ESLint, there's a similar option when you use `--init`. Just select "Inspect your JavaScript file(s)":
+
+```shell
+eslint --init
+? How would you like to configure ESLint? (Use arrow keys)
+> Answer questions about your style
+ Use a popular style guide
+ Inspect your JavaScript file(s)
+```
+
+## `--config`, `-c`
+
+JSCS allows you to specify a configuration file to use on the command line using either `--config` or `-c`, such as:
+
+```shell
+jscs --config myconfig.json file.js
+jscs -c myconfig.json file.js
+```
+
+Both flags are also supported by ESLint:
+
+```shell
+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:
+
+```shell
+cat file.js | jscs
+```
+
+In ESLint, you can also pipe in code, but you need to use the `--stdin` flag:
+
+```shell
+cat file.js | eslint --stdin
+```
--- /dev/null
+---
+title: Migrating to v1.0.0
+
+---
+
+ESLint v1.0.0 is the first major version release. As a result, there are some significant changes between how ESLint worked during its life in 0.x and how it will work going forward. These changes are the direct result of feedback from the ESLint community of users and were not made without due consideration for the upgrade path. We believe that these changes make ESLint even better, and while some work is necessary to upgrade, we hope the pain of this upgrade is small enough that you will see the benefit of upgrading.
+
+## All Rules Off by Default
+
+The most important difference in v1.0.0 is that all rules are off by default. We made this change after numerous requests to allow turning off the default rules from within configuration files. While that wasn't technically feasible, it was feasible to have all rules off by default and then re-enable rules in configuration files using `extends`. As such, we've made the `--reset` behavior the default and removed this command line option.
+
+When using `--init`, your configuration file will automatically include the following line:
+
+```json
+{
+ "extends": "eslint:recommended"
+}
+```
+
+This setting mimics some of the default behavior from 0.x, but not all. If you don't want to use any of the recommended rules, you can delete this line.
+
+**To address:** If you are currently using `--reset`, then you should stop passing `--reset` on the command line; no other changes are necessary. If you are not using `--reset`, then you should review your configuration to determine which rules should be on by default. You can partially restore some of the default behavior by adding the following to your configuration file:
+
+The `"eslint:recommended"` configuration contains many of the same default rule settings from 0.x, but not all. These rules are no longer on by default, so you should review your settings to ensure they are still as you expect:
+
+* [no-alert](../rules/no-alert)
+* [no-array-constructor](../rules/no-array-constructor)
+* [no-caller](../rules/no-caller)
+* [no-catch-shadow](../rules/no-catch-shadow)
+* [no-empty-label](../rules/no-empty-label)
+* [no-eval](../rules/no-eval)
+* [no-extend-native](../rules/no-extend-native)
+* [no-extra-bind](../rules/no-extra-bind)
+* [no-extra-strict](../rules/no-extra-strict)
+* [no-implied-eval](../rules/no-implied-eval)
+* [no-iterator](../rules/no-iterator)
+* [no-label-var](../rules/no-label-var)
+* [no-labels](../rules/no-labels)
+* [no-lone-blocks](../rules/no-lone-blocks)
+* [no-loop-func](../rules/no-loop-func)
+* [no-multi-spaces](../rules/no-multi-spaces)
+* [no-multi-str](../rules/no-multi-str)
+* [no-native-reassign](../rules/no-native-reassign)
+* [no-new](../rules/no-new)
+* [no-new-func](../rules/no-new-func)
+* [no-new-object](../rules/no-new-object)
+* [no-new-wrappers](../rules/no-new-wrappers)
+* [no-octal-escape](../rules/no-octal-escape)
+* [no-process-exit](../rules/no-process-exit)
+* [no-proto](../rules/no-proto)
+* [no-return-assign](../rules/no-return-assign)
+* [no-script-url](../rules/no-script-url)
+* [no-sequences](../rules/no-sequences)
+* [no-shadow](../rules/no-shadow)
+* [no-shadow-restricted-names](../rules/no-shadow-restricted-names)
+* [no-spaced-func](../rules/no-spaced-func)
+* [no-trailing-spaces](../rules/no-trailing-spaces)
+* [no-undef-init](../rules/no-undef-init)
+* [no-underscore-dangle](../rules/no-underscore-dangle)
+* [no-unused-expressions](../rules/no-unused-expressions)
+* [no-use-before-define](../rules/no-use-before-define)
+* [no-with](../rules/no-with)
+* [no-wrap-func](../rules/no-wrap-func)
+* [camelcase](../rules/camelcase)
+* [comma-spacing](../rules/comma-spacing)
+* [consistent-return](../rules/consistent-return)
+* [curly](../rules/curly)
+* [dot-notation](../rules/dot-notation)
+* [eol-last](../rules/eol-last)
+* [eqeqeq](../rules/eqeqeq)
+* [key-spacing](../rules/key-spacing)
+* [new-cap](../rules/new-cap)
+* [new-parens](../rules/new-parens)
+* [quotes](../rules/quotes)
+* [semi](../rules/semi)
+* [semi-spacing](../rules/semi-spacing)
+* [space-infix-ops](../rules/space-infix-ops)
+* [space-return-throw-case](../rules/space-return-throw-case)
+* [space-unary-ops](../rules/space-unary-ops)
+* [strict](../rules/strict)
+* [yoda](../rules/yoda)
+
+See also: the [full diff](https://github.com/eslint/eslint/commit/e3e9dbd9876daf4bdeb4e15f8a76a9d5e6e03e39#diff-b01a5cfd9361ca9280a460fd6bb8edbbL1) where the defaults were changed.
+
+Here's a configuration file with the closest equivalent of the old defaults:
+
+```json
+{
+ "extends": "eslint:recommended",
+ "rules": {
+ "no-alert": 2,
+ "no-array-constructor": 2,
+ "no-caller": 2,
+ "no-catch-shadow": 2,
+ "no-empty-label": 2,
+ "no-eval": 2,
+ "no-extend-native": 2,
+ "no-extra-bind": 2,
+ "no-implied-eval": 2,
+ "no-iterator": 2,
+ "no-label-var": 2,
+ "no-labels": 2,
+ "no-lone-blocks": 2,
+ "no-loop-func": 2,
+ "no-multi-spaces": 2,
+ "no-multi-str": 2,
+ "no-native-reassign": 2,
+ "no-new": 2,
+ "no-new-func": 2,
+ "no-new-object": 2,
+ "no-new-wrappers": 2,
+ "no-octal-escape": 2,
+ "no-process-exit": 2,
+ "no-proto": 2,
+ "no-return-assign": 2,
+ "no-script-url": 2,
+ "no-sequences": 2,
+ "no-shadow": 2,
+ "no-shadow-restricted-names": 2,
+ "no-spaced-func": 2,
+ "no-trailing-spaces": 2,
+ "no-undef-init": 2,
+ "no-underscore-dangle": 2,
+ "no-unused-expressions": 2,
+ "no-use-before-define": 2,
+ "no-with": 2,
+ "camelcase": 2,
+ "comma-spacing": 2,
+ "consistent-return": 2,
+ "curly": [2, "all"],
+ "dot-notation": [2, { "allowKeywords": true }],
+ "eol-last": 2,
+ "no-extra-parens": [2, "functions"],
+ "eqeqeq": 2,
+ "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
+ "new-cap": 2,
+ "new-parens": 2,
+ "quotes": [2, "double"],
+ "semi": 2,
+ "semi-spacing": [2, {"before": false, "after": true}],
+ "space-infix-ops": 2,
+ "space-return-throw-case": 2,
+ "space-unary-ops": [2, { "words": true, "nonwords": false }],
+ "strict": [2, "function"],
+ "yoda": [2, "never"]
+ }
+}
+```
+
+## Removed Rules
+
+Over the past several releases, we have been deprecating rules and introducing new rules to take their place. The following is a list of the removed rules and their replacements:
+
+* [generator-star](../rules/generator-star) is replaced by [generator-star-spacing](../rules/generator-star-spacing)
+* [global-strict](../rules/global-strict) is replaced by [strict](../rules/strict)
+* [no-comma-dangle](../rules/no-comma-dangle) is replaced by [comma-dangle](../rules/comma-dangle)
+* [no-empty-class](../rules/no-empty-class) is replaced by [no-empty-character-class](../rules/no-empty-character-class)
+* [no-extra-strict](../rules/no-extra-strict) is replaced by [strict](../rules/strict)
+* [no-reserved-keys](../rules/no-reserved-keys) is replaced by [quote-props](../rules/quote-props)
+* [no-space-before-semi](../rules/no-space-before-semi) is replaced by [semi-spacing](../rules/semi-spacing)
+* [no-wrap-func](../rules/no-wrap-func) is replaced by [no-extra-parens](../rules/no-extra-parens)
+* [space-after-function-name](../rules/space-after-function-name) is replaced by [space-before-function-paren](../rules/space-before-function-paren)
+* [space-before-function-parentheses](../rules/space-before-function-parentheses) is replaced by [space-before-function-paren](../rules/space-before-function-paren)
+* [space-in-brackets](../rules/space-in-brackets) is replaced by[object-curly-spacing](../rules/object-curly-spacing) and [array-bracket-spacing](../rules/array-bracket-spacing)
+* [space-unary-word-ops](../rules/space-unary-word-ops) is replaced by [space-unary-ops](../rules/space-unary-ops)
+* [spaced-line-comment](../rules/spaced-line-comment) is replaced by [spaced-comment](../rules/spaced-comment)
+
+**To address:** You'll need to update your rule configurations to use the new rules. ESLint v1.0.0 will also warn you when you're using a rule that has been removed and will suggest the replacement rules. Hopefully, this will result in few surprises during the upgrade process.
+
+## Column Numbers are 1-based
+
+From the beginning, ESLint has reported errors using 0-based columns because that's what Esprima, and later Espree, reported. However, most tools and editors use 1-based columns, which made for some tricky integrations with ESLint. In v1.0.0, we've switched over to reporting errors using 1-based columns to fall into line with the tools developers use everyday.
+
+**To address:** If you've created an editor integration, or a tool that had to correct the column number, you'll need to update to just pass through the column number from ESLint. Otherwise, no change is necessary.
+
+## No Longer Exporting cli
+
+In 0.x, the `cli` object was exported for use by external tools. It was later deprecated in favor of `CLIEngine`. In v1.0.0, we are no longer exporting `cli` as it should not be used by external tools. This will break existing tools that make use of it.
+
+**To address:** If you are using the exported `cli` object, switch to using `CLIEngine` instead.
+
+## Deprecating eslint-tester
+
+The `eslint-tester` module, which has long been the primary tester for ESLint rules, has now been moved into the `eslint` module. This was the result of a difficult relationship between these two modules that created circular dependencies and was causing a lot of problems in rule tests. Moving the tester into the `eslint` module fixed a lot of those issues.
+
+The replacement for `eslint-tester` is called `RuleTester`. It's a simplified version of `ESLintTester` that's designed to work with any testing framework. This object is exposed by the package.
+
+**To address:** Convert all of your rule tests to use `RuleTester`. If you have this as a test using `ESLintTester`:
+
+```js
+var eslint = require("../../../lib/eslint"),
+ ESLintTester = require("eslint-tester");
+
+var eslintTester = new ESLintTester(eslint);
+eslintTester.addRuleTest("lib/rules/your-rule", {
+ valid: [],
+ invalid: []
+});
+```
+
+Then you can change to:
+
+```js
+var rule = require("../../../lib/rules/your-rule"),
+ RuleTester = require("eslint").RuleTester;
+
+var ruleTester = new RuleTester();
+ruleTester.run("your-rule", rule, {
+ valid: [],
+ invalid: []
+});
+```
--- /dev/null
+---
+title: Migrating to v2.0.0
+
+---
+
+ESLint v2.0.0 is the second major version release. As a result, there are some significant changes between how ESLint worked during its life in 0.x and 1.x and how it will work going forward. These changes are the direct result of feedback from the ESLint community of users and were not made without due consideration for the upgrade path. We believe that these changes make ESLint even better, and while some work is necessary to upgrade, we hope the pain of this upgrade is small enough that you will see the benefit of upgrading.
+
+**Important:** If you are upgrading from 0.x, please refer to [Migrating to 1.0.0](./migrating-to-1.0.0) as your starting point.
+
+## Rule Schema Changes
+
+Due to a quirk in the way rule schemas worked, it was possible that you'd need to account for the rule severity (0, 1, or 2) in a rule schema if the options were sufficiently complex. That would result in a schema such as:
+
+```js
+module.exports = {
+ "type": "array",
+ "items": [
+ {
+ "enum": [0, 1, 2]
+ },
+ {
+ "enum": ["always", "never"]
+ }
+ ],
+ "minItems": 1,
+ "maxItems": 2
+};
+```
+
+This was confusing to rule developers as it seemed that rules shouldn't be in charge of validating their own severity. In 2.0.0, rules no longer need to check their own severity.
+
+**To address:** If you are exporting a rule schema that checks severity, you need to make several changes:
+
+1. Remove the severity from the schema
+1. Adjust `minItems` from 1 to 0
+1. Adjust `maxItems` by subtracting 1
+
+Here's what the schema from above looks like when properly converted:
+
+```js
+module.exports = {
+ "type": "array",
+ "items": [
+ {
+ "enum": ["always", "never"]
+ }
+ ],
+ "minItems": 0,
+ "maxItems": 1
+};
+```
+
+## Removed Rules
+
+The following rules have been deprecated with new rules created to take their place. The following is a list of the removed rules and their replacements:
+
+* [no-arrow-condition](../rules/no-arrow-condition) is replaced by a combination of [no-confusing-arrow](../rules/no-confusing-arrow) and [no-constant-condition](../rules/no-constant-condition). Turn on both of these rules to get the same functionality as `no-arrow-condition`.
+* [no-empty-label](../rules/no-empty-label) is replaced by [no-labels](../rules/no-labels) with `{"allowLoop": true, "allowSwitch": true}` option.
+* [space-after-keywords](../rules/space-after-keywords) is replaced by [keyword-spacing](../rules/keyword-spacing).
+* [space-before-keywords](../rules/space-before-keywords) is replaced by [keyword-spacing](../rules/keyword-spacing).
+* [space-return-throw-case](../rules/space-return-throw-case) is replaced by [keyword-spacing](../rules/keyword-spacing).
+
+**To address:** You'll need to update your rule configurations to use the new rules. ESLint v2.0.0 will also warn you when you're using a rule that has been removed and will suggest the replacement rules. Hopefully, this will result in few surprises during the upgrade process.
+
+## Configuration Cascading Changes
+
+Prior to 2.0.0, if a directory contained both an `.eslintrc` file and a `package.json` file with ESLint configuration information, the settings from the two files would be merged together. In 2.0.0, only the settings from the `.eslintrc.*` file are used and the ones in `package.json` are ignored when both are present. Otherwise, `package.json` can still be used with ESLint configuration, but only if no other `.eslintrc.*` files are present.
+
+**To address:** If you have both an `.eslintrc.*` and `package.json` with ESLint configuration information in the same directory, combine your configurations into just one of those files.
+
+## Built-In Global Variables
+
+Prior to 2.0.0, new global variables that were standardized as part of ES6 such as `Promise`, `Map`, `Set`, and `Symbol` were included in the built-in global environment. This could lead to potential issues when, for example, `no-undef` permitted use of the `Promise` constructor even in ES5 code where promises are unavailable. In 2.0.0, the built-in environment only includes the standard ES5 global variables, and the new ES6 global variables have been moved to the `es6` environment.
+
+**To address:** If you are writing ES6 code, enable the `es6` environment if you have not already done so:
+
+```js
+// In your .eslintrc
+{
+ env: {
+ es6: true
+ }
+}
+
+// Or in a configuration comment
+/*eslint-env es6*/
+```
+
+## Language Options
+
+Prior to 2.0.0, the way to enable language options was by using `ecmaFeatures` in your configuration. In 2.0.0:
+
+* The `ecmaFeatures` property is now under a top-level `parserOptions` property.
+* All ECMAScript 6 `ecmaFeatures` flags have been removed in favor of a `ecmaVersion` property under `parserOptions` that can be set to 3, 5 (default), or 6.
+* The `ecmaFeatures.modules` flag has been replaced by a `sourceType` property under `parserOptions` which can be set to `"script"` (default) or `"module"` for ES6 modules.
+
+**To address:** If you are using any ECMAScript 6 feature flags in `ecmaFeatures`, you'll need to use `ecmaVersion: 6` instead. The ECMAScript 6 feature flags are:
+
+* `arrowFunctions` - enable [arrow functions](https://leanpub.com/understandinges6/read#leanpub-auto-arrow-functions)
+* `binaryLiterals` - enable [binary literals](https://leanpub.com/understandinges6/read#leanpub-auto-octal-and-binary-literals)
+* `blockBindings` - enable `let` and `const` (aka [block bindings](https://leanpub.com/understandinges6/read#leanpub-auto-block-bindings))
+* `classes` - enable classes
+* `defaultParams` - enable [default function parameters](https://leanpub.com/understandinges6/read/#leanpub-auto-default-parameters)
+* `destructuring` - enable [destructuring](https://leanpub.com/understandinges6/read#leanpub-auto-destructuring-assignment)
+* `forOf` - enable [`for-of` loops](https://leanpub.com/understandinges6/read#leanpub-auto-iterables-and-for-of)
+* `generators` - enable [generators](https://leanpub.com/understandinges6/read#leanpub-auto-generators)
+* `modules` - enable modules and global strict mode
+* `objectLiteralComputedProperties` - enable [computed object literal property names](https://leanpub.com/understandinges6/read#leanpub-auto-computed-property-names)
+* `objectLiteralDuplicateProperties` - enable [duplicate object literal properties](https://leanpub.com/understandinges6/read#leanpub-auto-duplicate-object-literal-properties) in strict mode
+* `objectLiteralShorthandMethods` - enable [object literal shorthand methods](https://leanpub.com/understandinges6/read#leanpub-auto-method-initializer-shorthand)
+* `objectLiteralShorthandProperties` - enable [object literal shorthand properties](https://leanpub.com/understandinges6/read#leanpub-auto-property-initializer-shorthand)
+* `octalLiterals` - enable [octal literals](https://leanpub.com/understandinges6/read#leanpub-auto-octal-and-binary-literals)
+* `regexUFlag` - enable the [regular expression `u` flag](https://leanpub.com/understandinges6/read#leanpub-auto-the-regular-expression-u-flag)
+* `regexYFlag` - enable the [regular expression `y` flag](https://leanpub.com/understandinges6/read#leanpub-auto-the-regular-expression-y-flag)
+* `restParams` - enable the [rest parameters](https://leanpub.com/understandinges6/read#leanpub-auto-rest-parameters)
+* `spread` - enable the [spread operator](https://leanpub.com/understandinges6/read#leanpub-auto-the-spread-operator) for arrays
+* `superInFunctions` - enable `super` references inside of functions
+* `templateStrings` - enable [template strings](https://leanpub.com/understandinges6/read/#leanpub-auto-template-strings)
+* `unicodeCodePointEscapes` - enable [code point escapes](https://leanpub.com/understandinges6/read/#leanpub-auto-escaping-non-bmp-characters)
+
+If you're using any of these flags, such as:
+
+```js
+{
+ ecmaFeatures: {
+ arrowFunctions: true
+ }
+}
+```
+
+Then you should enable ES6 using `ecmaVersion`:
+
+```js
+{
+ parserOptions: {
+ ecmaVersion: 6
+ }
+}
+```
+
+If you're using any non-ES6 flags in `ecmaFeatures`, you need to move those inside of `parserOptions`. For instance:
+
+```js
+{
+ ecmaFeatures: {
+ jsx: true
+ }
+}
+```
+
+Then you should move `ecmaFeatures` under `parserOptions`:
+
+```js
+{
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true
+ }
+ }
+}
+```
+
+If you were using `ecmaFeatures.modules` to enable ES6 module support like this:
+
+```js
+{
+ ecmaFeatures: {
+ modules: true
+ }
+}
+```
+
+```js
+{
+ parserOptions: {
+ sourceType: "module"
+ }
+}
+```
+
+Additionally, if you are using `context.ecmaFeatures` inside of your rules, then you'll need to update your code in the following ways:
+
+1. If you're using an ES6 feature flag such as `context.ecmaFeatures.blockBindings`, rewrite to check for `context.parserOptions.ecmaVersion > 5`.
+1. If you're using `context.ecmaFeatures.modules`, rewrite to check that the `sourceType` property of the Program node is `"module"`.
+1. If you're using a non-ES6 feature flag such as `context.ecmaFeatures.jsx`, rewrite to check for `context.parserOptions.ecmaFeatures.jsx`.
+
+If you have a plugin with rules and you are using RuleTester, then you also need to update the options you pass for rules that use `ecmaFeatures`. For example:
+
+```js
+var ruleTester = new RuleTester();
+ruleTester.run("no-var", rule, {
+ valid: [
+ {
+ code: "let x;",
+ parserOptions: { ecmaVersion: 6 }
+ }
+ ]
+});
+```
+
+If you're not using `ecmaFeatures` in your configuration or your custom/plugin rules and tests, then no change is needed.
+
+## New Rules in `"eslint:recommended"`
+
+```json
+{
+ "extends": "eslint:recommended"
+}
+```
+
+In 2.0.0, the following 11 rules were added to `"eslint:recommended"`.
+
+* [constructor-super](../rules/constructor-super)
+* [no-case-declarations](../rules/no-case-declarations)
+* [no-class-assign](../rules/no-class-assign)
+* [no-const-assign](../rules/no-const-assign)
+* [no-dupe-class-members](../rules/no-dupe-class-members)
+* [no-empty-pattern](../rules/no-empty-pattern)
+* [no-new-symbol](../rules/no-new-symbol)
+* [no-self-assign](../rules/no-self-assign)
+* [no-this-before-super](../rules/no-this-before-super)
+* [no-unexpected-multiline](../rules/no-unexpected-multiline)
+* [no-unused-labels](../rules/no-unused-labels)
+
+**To address:** If you don't want to be notified by those rules, you can simply disable those rules.
+
+```json
+{
+ "extends": "eslint:recommended",
+ "rules": {
+ "no-case-declarations": 0,
+ "no-class-assign": 0,
+ "no-const-assign": 0,
+ "no-dupe-class-members": 0,
+ "no-empty-pattern": 0,
+ "no-new-symbol": 0,
+ "no-self-assign": 0,
+ "no-this-before-super": 0,
+ "no-unexpected-multiline": 0,
+ "no-unused-labels": 0,
+ "constructor-super": 0
+ }
+}
+```
+
+## Scope Analysis Changes
+
+We found some bugs in our scope analysis that needed to be addressed. Specifically, we were not properly accounting for global variables in all the ways they are defined.
+
+Originally, `Variable` objects and `Reference` objects refer each other:
+
+* `Variable#references` property is an array of `Reference` objects which are referencing the variable.
+* `Reference#resolved` property is a `Variable` object which are referenced.
+
+But until 1.x, the following variables and references had the wrong value (empty) in those properties:
+
+* `var` declarations in the global.
+* `function` declarations in the global.
+* Variables defined in config files.
+* Variables defined in `/* global */` comments.
+
+Now, those variables and references have correct values in these properties.
+
+`Scope#through` property has references where `Reference#resolved` is `null`. So as a result of this change, the value of `Scope#through` property was changed also.
+
+**To address:** If you are using `Scope#through` to find references of a built-in global variable, you need to make several changes.
+
+For example, this is how you might locate the `window` global variable in 1.x:
+
+```js
+var globalScope = context.getScope();
+globalScope.through.forEach(function(reference) {
+ if (reference.identifier.name === "window") {
+ checkForWindow(reference);
+ }
+});
+```
+
+This was a roundabout way to find the variable because it was added after the fact by ESLint. The `window` variable was in `Scope#through` because the definition couldn't be found.
+
+In 2.0.0, `window` is no longer located in `Scope#through` because we have added back the correct declaration. That means you can reference the `window` object (or any other global object) directly. So the previous example would change to this:
+
+```js
+var globalScope = context.getScope();
+var variable = globalScope.set.get("window");
+if (variable) {
+ variable.references.forEach(checkForWindow);
+}
+```
+
+Further Reading: <https://estools.github.io/escope/>
+
+## Default Changes When Using `eslint:recommended`
+
+This will affect you if you are extending from `eslint:recommended`, and are enabling [`no-multiple-empty-lines`] or [`func-style`] with only a severity, such as:
+
+```json
+{
+ "extends": "eslint:recommended",
+ "rules": {
+ "no-multiple-empty-lines": 2,
+ "func-style": 2
+ }
+}
+```
+
+The rule `no-multiple-empty-lines` has no default exceptions, but in ESLint `1.x`, a default from `eslint:recommended` was applied such that a maximum of two empty lines would be permitted.
+
+The rule `func-style` has a default configuration of `"expression"`, but in ESLint `1.x`, `eslint:recommended` defaulted it to `"declaration"`.
+
+ESLint 2.0.0 removes these conflicting defaults, and so you may begin seeing linting errors related to these rules.
+
+**To address:** If you would like to maintain the previous behavior, update your configuration for `no-multiple-empty-lines` by adding `{"max": 2}`, and change `func-style` to `"declaration"`. For example:
+
+```json
+{
+ "extends": "eslint:recommended",
+ "rules": {
+ "no-multiple-empty-lines": [2, {"max": 2}],
+ "func-style": [2, "declaration"]
+ }
+}
+```
+
+[`no-multiple-empty-lines`]: ../rules/no-multiple-empty-lines
+[`func-style`]: ../rules/func-style
+
+## SourceCode constructor (Node API) changes
+
+`SourceCode` constructor got to handle Unicode BOM.
+If the first argument `text` has BOM, `SourceCode` constructor sets `true` to `this.hasBOM` and strips BOM from the text.
+
+```js
+var SourceCode = require("eslint").SourceCode;
+
+var code = new SourceCode("\uFEFFvar foo = bar;", ast);
+
+assert(code.hasBOM === true);
+assert(code.text === "var foo = bar;");
+```
+
+So the second argument `ast` also should be parsed from stripped text.
+
+**To address:** If you are using `SourceCode` constructor in your code, please parse the source code after it stripped BOM:
+
+```js
+var ast = yourParser.parse(text.replace(/^\uFEFF/, ""), options);
+var sourceCode = new SourceCode(text, ast);
+```
+
+## Rule Changes
+
+* [`strict`](../rules/strict) - defaults to `"safe"` (previous default was `"function"`)
+
+## Plugins No Longer Have Default Configurations
+
+Prior to v2.0.0, plugins could specify a `rulesConfig` for the plugin. The `rulesConfig` would automatically be applied whenever someone uses the plugin, which is the opposite of what ESLint does in every other situation (where nothing is on by default). To bring plugins behavior in line, we have removed support for `rulesConfig` in plugins.
+
+**To address:** If you are using a plugin in your configuration file, you will need to manually enable the plugin rules in the configuration file.
--- /dev/null
+---
+title: Migrating to v3.0.0
+
+---
+
+ESLint v3.0.0 is the third major version release. We have made several breaking changes in this release, however, we believe the changes to be small enough that they should not require significant changes for ESLint users. This guide is intended to walk you through the changes.
+
+## Dropping Support for Node.js < 4
+
+With ESLint v3.0.0, we are dropping support for Node.js versions prior to 4. Node.js 0.10 and 0.12 are in [maintenance mode](https://github.com/nodejs/Release) and Node.js 4 is the current LTS version. If you are using an older version of Node.js, we recommend upgrading to at least Node.js 4 as soon as possible. If you are unable to upgrade to Node.js 4 or higher, then we recommend continuing to use ESLint v2.x until you are ready to upgrade Node.js.
+
+**Important:** We will not be updating the ESLint v2.x versions going forward. All bug fixes and enhancements will land in ESLint v3.x.
+
+## Requiring Configuration to Run
+
+ESLint v3.0.0 now requires that you use a configuration to run. A configuration can be any of the following:
+
+1. An `.eslintrc.js`, `.eslintrc.json`, `.eslintrc.yml`, `.eslintrc.yaml`, or `.eslintrc` file either in your project or home directory.
+2. Configuration options passed on the command line using `--rule` (or to CLIEngine using `rules`).
+3. A configuration file passed on the command line using `-c` (or to CLIEngine using `configFile`).
+4. A base configuration is provided to CLIEngine using the `baseConfig` option.
+
+If ESLint can't find a configuration, then it will throw an error and ask you to provide one.
+
+This change was made to help new ESLint users who are frequently confused that ESLint does nothing by default besides reporting parser errors. We anticipate this change will have minimal impact on most established users because you're more likely to have configuration files already.
+
+**To Address:** You should be sure to use a configuration whenever you run ESLint. However, you can still run ESLint without a configuration by passing the `--no-eslintrc` option on the command line or setting the `useEslintrc` option to `false` for `CLIEngine`.
+
+To create a new configuration, use `eslint --init`.
+
+## Changes to `"eslint:recommended"`
+
+```json
+{
+ "extends": "eslint:recommended"
+}
+```
+
+In 3.0.0, the following rules were added to `"eslint:recommended"`:
+
+* [`no-unsafe-finally`](../rules/no-unsafe-finally) helps catch `finally` clauses that may not behave as you think.
+* [`no-native-reassign`](../rules/no-native-reassign) was previously part of `no-undef`, but was split out because it didn't make sense as part of another rule. The `no-native-reassign` rule warns whenever you try to overwrite a read-only global variable.
+* [`require-yield`](../rules/require-yield) helps to identify generator functions that do not have the `yield` keyword.
+
+The following rules were removed from `"eslint:recommended"`:
+
+* [`comma-dangle`](../rules/comma-dangle) used to be recommended because Internet Explorer 8 and earlier threw a syntax error when it found a dangling comma on object literal properties. However, [Internet Explorer 8 was end-of-lifed](https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support) in January 2016 and all other active browsers allow dangling commas. As such, we consider dangling commas to now be a stylistic issue instead of a possible error.
+
+The following rules were modified:
+
+* [`complexity`](../rules/complexity) used to have a hardcoded default of 11 in `eslint:recommended` that would be used if you turned the rule on without specifying a maximum. The default is now 20. The rule actually always had a default of 20, but `eslint:recommended` was overriding it by mistake.
+
+**To address:** If you want to mimic how `eslint:recommended` worked in v2.x, you can use the following:
+
+```json
+{
+ "extends": "eslint:recommended",
+ "rules": {
+ "no-unsafe-finally": "off",
+ "no-native-reassign": "off",
+ "complexity": ["off", 11],
+ "comma-dangle": "error",
+ "require-yield": "error"
+ }
+}
+```
+
+## Changes to `CLIEngine#executeOnText()`
+
+The `CLIEngine#executeOnText()` method has changed to work more like `CLIEngine#executeOnFiles()`. In v2.x, `CLIEngine#executeOnText()` warned about ignored files by default and didn't have a way to opt-out of those warnings whereas `CLIEngine#executeOnFiles()` did not warn about ignored files by default and allowed you to opt-in to warning about them. The `CLIEngine#executeOnText()` method now also does not warn about ignored files by default and allows you to opt-in with a new, third argument (a boolean, `true` to warn about ignored files and `false` to not warn).
+
+**To address:** If you are currently using `CLIEngine#executeOnText()` in your project like this:
+
+```js
+var result = engine.executeOnText(text, filename);
+```
+
+You can get the equivalent behavior using this:
+
+```js
+var result = engine.executeOnText(text, filename, true);
+```
+
+If you do not want ignored file warnings output to the console, you can omit the third argument or pass `false`.
--- /dev/null
+---
+title: Migrating to v4.0.0
+
+---
+
+ESLint v4.0.0 is the fourth major version release. We have made several breaking changes in this release; however, we expect that most of the changes will only affect a very small percentage of users. This guide is intended to walk you through the 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
+
+1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
+1. [The `indent` rule is more strict](#indent-rewrite)
+1. [Unrecognized properties in config files now cause a fatal error](#config-validation)
+1. [.eslintignore patterns are now resolved from the location of the file](#eslintignore-patterns)
+1. [The `padded-blocks` rule is more strict by default](#padded-blocks-defaults)
+1. [The `space-before-function-paren` rule is more strict by default](#space-before-function-paren-defaults)
+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
+
+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
+
+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)
+1. [Some exposed APIs are now ES2015 classes](#exposed-es2015-classes)
+
+---
+
+## <a name="eslint-recommended-changes"></a> `eslint:recommended` changes
+
+Two new rules have been added to the [`eslint:recommended`](configure#using-eslintrecommended) config:
+
+* [`no-compare-neg-zero`](../rules/no-compare-neg-zero) disallows comparisons to `-0`
+* [`no-useless-escape`](../rules/no-useless-escape) disallows uselessly-escaped characters in strings and regular expressions
+
+**To address:** To mimic the `eslint:recommended` behavior from 3.x, you can disable these rules in a config file:
+
+```json
+{
+ "extends": "eslint:recommended",
+
+ "rules": {
+ "no-compare-neg-zero": "off",
+ "no-useless-escape": "off"
+ }
+}
+```
+
+## <a name="indent-rewrite"></a> The `indent` rule is more strict
+
+Previously, the [`indent`](../rules/indent) rule was fairly lenient about checking indentation; there were many code patterns where indentation was not validated by the rule. This caused confusion for users, because they were accidentally writing code with incorrect indentation, and they expected ESLint to catch the issues.
+
+In 4.0.0, the `indent` rule has been rewritten. The new version of the rule will report some indentation errors that the old version of the rule did not catch. Additionally, the indentation of `MemberExpression` nodes, function parameters, and function arguments will now be checked by default (it was previously ignored by default for backwards compatibility).
+
+To make the upgrade process easier, we've introduced the [`indent-legacy`](../rules/indent-legacy) rule as a snapshot of the `indent` rule from 3.x. If you run into issues from the `indent` rule when you upgrade, you should be able to use the `indent-legacy` rule to replicate the 3.x behavior. However, the `indent-legacy` rule is deprecated and will not receive bugfixes or improvements in the future, so you should eventually switch back to the `indent` rule.
+
+**To address:** We recommend upgrading without changing your `indent` configuration, and fixing any new indentation errors that appear in your codebase. However, if you want to mimic how the `indent` rule worked in 3.x, you can update your configuration:
+
+```js
+{
+ rules: {
+ indent: "off",
+ "indent-legacy": "error" // replace this with your previous `indent` configuration
+ }
+}
+```
+
+## <a name="config-validation"></a> Unrecognized properties in config files now cause a fatal error
+
+When creating a config, users sometimes make typos or misunderstand how the config is supposed to be structured. Previously, ESLint did not validate the properties of a config file, so a typo in a config could be very tedious to debug. Starting in 4.0.0, ESLint will raise an error if a property in a config file is unrecognized or has the wrong type.
+
+**To address:** If you see a config validation error after upgrading, verify that your config doesn't contain any typos. If you are using an unrecognized property, you should be able to remove it from your config to restore the previous behavior.
+
+## <a name="eslintignore-patterns"></a> .eslintignore patterns are now resolved from the location of the file
+
+Due to a bug, glob patterns in an `.eslintignore` file were previously resolved from the current working directory of the process, rather than the location of the `.eslintignore` file. Starting in 4.0, patterns in an `.eslintignore` file will be resolved from the `.eslintignore` file's location.
+
+**To address:** If you use an `.eslintignore` file and you frequently run ESLint from somewhere other than the project root, it's possible that the patterns will be matched differently. You should update the patterns in the `.eslintignore` file to ensure they are relative to the file, not to the working directory.
+
+## <a name="padded-blocks-defaults"></a> The `padded-blocks` rule is more strict by default
+
+By default, the [`padded-blocks`](../rules/padded-blocks) rule will now enforce padding in class bodies and switch statements. Previously, the rule would ignore these cases unless the user opted into enforcing them.
+
+**To address:** If this change results in more linting errors in your codebase, you should fix them or reconfigure the rule.
+
+## <a name="space-before-function-paren-defaults"></a> The `space-before-function-paren` rule is more strict by default
+
+By default, the [`space-before-function-paren`](../rules/space-before-function-paren) rule will now enforce spacing for async arrow functions. Previously, the rule would ignore these cases unless the user opted into enforcing them.
+
+**To address:** To mimic the default config from 3.x, you can use:
+
+```json
+{
+ "rules": {
+ "space-before-function-paren": ["error", {
+ "anonymous": "always",
+ "named": "always",
+ "asyncArrow": "ignore"
+ }]
+ }
+}
+```
+
+## <a name="no-multi-spaces-eol-comments"></a> The `no-multi-spaces` rule is more strict by default
+
+By default, the [`no-multi-spaces`](../rules/no-multi-spaces) rule will now disallow multiple spaces before comments at the end of a line. Previously, the rule did not check this case.
+
+**To address:** To mimic the default config from 3.x, you can use:
+
+```json
+{
+ "rules": {
+ "no-multi-spaces": ["error", {"ignoreEOLComments": true}]
+ }
+}
+```
+
+## <a name="scoped-plugin-resolution"></a> References to scoped plugins in config files are now required to include the scope
+
+In 3.x, there was a bug where references to scoped NPM packages as plugins in config files could omit the scope. For example, in 3.x the following config was legal:
+
+```json
+{
+ "plugins": [
+ "@my-organization/foo"
+ ],
+ "rules": {
+ "foo/some-rule": "error"
+ }
+}
+```
+
+In other words, it was possible to reference a rule from a scoped plugin (such as `foo/some-rule`) without explicitly stating the `@my-organization` scope. This was a bug because it could lead to ambiguous rule references if there was also an unscoped plugin called `eslint-plugin-foo` loaded at the same time.
+
+To avoid this ambiguity, in 4.0 references to scoped plugins must include the scope. The config from above should be fixed to:
+
+```json
+{
+ "plugins": [
+ "@my-organization/foo"
+ ],
+ "rules": {
+ "@my-organization/foo/some-rule": "error"
+ }
+}
+```
+
+**To address:** If you reference a scoped NPM package as a plugin in a config file, be sure to include the scope wherever you reference it.
+
+---
+
+## <a name="rule-tester-validation"></a> `RuleTester` now validates properties of test cases
+
+Starting in 4.0, the `RuleTester` utility will validate properties of test case objects, and an error will be thrown if an unknown property is encountered. This change was added because we found that it was relatively common for developers to make typos in rule tests, often invalidating the assertions that the test cases were trying to make.
+
+**To address:** If your tests for custom rules have extra properties, you should remove those properties.
+
+## <a name="comment-attachment"></a> AST Nodes no longer have comment properties
+
+Prior to 4.0, ESLint required parsers to implement comment attachment, a process where AST nodes would gain additional properties corresponding to their leading and trailing comments in the source file. This made it difficult for users to develop custom parsers, because they would have to replicate the confusing comment attachment semantics required by ESLint.
+
+In 4.0, we have moved away from the concept of comment attachment and have moved all comment handling logic into ESLint itself. This should make it easier to develop custom parsers, but it also means that AST nodes will no longer have `leadingComments` and `trailingComments` properties. Conceptually, rule authors can now think of comments in the context of tokens rather than AST nodes.
+
+**To address:** If you have a custom rule that depends on the `leadingComments` or `trailingComments` properties of an AST node, you can now use `sourceCode.getCommentsBefore()` and `sourceCode.getCommentsAfter()` instead, respectively.
+
+Additionally, the `sourceCode` object now also has `sourceCode.getCommentsInside()` (which returns all the comments inside a node), `sourceCode.getAllComments()` (which returns all the comments in the file), and allows comments to be accessed through various other token iterator methods (such as `getTokenBefore()` and `getTokenAfter()`) with the `{ includeComments: true }` option.
+
+For rule authors concerned about supporting ESLint v3.0 in addition to v4.0, the now deprecated `sourceCode.getComments()` is still available and will work for both versions.
+
+Finally, please note that the following `SourceCode` methods have been deprecated and will be removed in a future version of ESLint:
+
+* `getComments()` - replaced by `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()`
+* `getTokenOrCommentBefore()` - replaced by `getTokenBefore()` with the `{ includeComments: true }` option
+* `getTokenOrCommentAfter()` - replaced by `getTokenAfter()` with the `{ includeComments: true }` option
+
+## <a name="event-comments"></a> `LineComment` and `BlockComment` events will no longer be emitted during AST traversal
+
+Starting in 4.0, `LineComment` and `BlockComments` events will not be emitted during AST traversal. There are two reasons for this:
+
+* This behavior was relying on comment attachment happening at the parser level, which does not happen anymore, to ensure that all comments would be accounted for
+* Thinking of comments in the context of tokens is more predictable and easier to reason about than thinking about comment tokens in the context of AST nodes
+
+**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");
+```
+
+## <a name="shebangs"></a> Shebangs are now returned from comment APIs
+
+Prior to 4.0, shebang comments in a source file would not appear in the output of `sourceCode.getAllComments()` or `sourceCode.getComments()`, but they would appear in the output of `sourceCode.getTokenOrCommentBefore` as line comments. This inconsistency led to some confusion for rule developers.
+
+In 4.0, shebang comments are treated as comment tokens of type `Shebang` and will be returned by any `SourceCode` method that returns comments. The goal of this change is to make working with shebang comments more consistent with how other tokens are handled.
+
+**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");
+```
+
+---
+
+## <a name="global-property"></a> The `global` property in the `linter.verify()` API is no longer supported
+
+Previously, the `linter.verify()` API accepted a `global` config option, which was a synonym for the documented `globals` property. The `global` option was never documented or officially supported, and did not work in config files. It has been removed in 4.0.
+
+**To address:** If you were using the `global` property, please use the `globals` property instead, which does the same thing.
+
+## <a name="report-locations"></a> More report messages now have full location ranges
+
+Starting in 3.1.0, rules have been able to specify the *end* location of a reported problem, in addition to the start location, by explicitly specifying an end location in the `report` call. This is useful for tools like editor integrations, which can use the range to precisely display where a reported problem occurs. Starting in 4.0, if a *node* is reported rather than a location, the end location of the range will automatically be inferred from the end location of the node. As a result, many more reported problems will have end locations.
+
+This is not expected to cause breakage. However, it will likely result in larger report locations than before. For example, if a rule reports the root node of the AST, the reported problem's range will be the entire program. In some integrations, this could result in a poor user experience (e.g. if the entire program is highlighted to indicate an error).
+
+**To address:** If you have an integration that deals with the ranges of reported problems, make sure you handle large report ranges in a user-friendly way.
+
+## <a name="exposed-es2015-classes"></a> Some exposed APIs are now ES2015 classes
+
+The `CLIEngine`, `SourceCode`, and `RuleTester` modules from ESLint's Node.js API are now ES2015 classes. This will not break any documented behavior, but it does have some observable effects (for example, the methods on `CLIEngine.prototype` are now non-enumerable).
+
+**To address:** If you rely on enumerating the methods of ESLint's Node.js APIs, use a function that can also access non-enumerable properties such as `Object.getOwnPropertyNames`.
--- /dev/null
+---
+title: Migrating to v5.0.0
+
+---
+
+ESLint v5.0.0 is the fifth major version release. We have made a few breaking changes in this release, but we expect that most users will be able to upgrade without any modifications to their build. This guide is intended to walk you through the 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
+
+1. [Node.js 4 is no longer supported](#drop-node-4)
+1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
+1. [The `experimentalObjectRestSpread` option has been deprecated](#experimental-object-rest-spread)
+1. [Linting nonexistent files from the command line is now a fatal error](#nonexistent-files)
+1. [The default options for some rules have changed](#rule-default-changes)
+1. [Deprecated globals have been removed from the `node`, `browser`, and `jest` environments](#deprecated-globals)
+1. [Empty files are now linted](#empty-files)
+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
+
+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)
+1. [When using the default parser, rest operators now have type `RestElement`](#rest-operators)
+1. [When using the default parser, text nodes in JSX elements now have type `JSXText`](#jsx-text-nodes)
+1. [The `context.getScope()` method now returns more proper scopes](#context-get-scope)
+1. [The `_linter` property on rule context objects has been removed](#no-context-linter)
+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
+
+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)
+1. [The `eslint.linter` property is now non-enumerable](#non-enumerable-linter)
+
+---
+
+## <a name="drop-node-4"></a> Node.js 4 is no longer supported
+
+As of April 30th, 2018, Node.js 4 will be at EOL and will no longer be receiving security updates. As a result, we have decided to drop support for it in ESLint v5. We now support the following versions of Node.js:
+
+* Node.js 6 (6.14.0 and above)
+* Node.js 8 (8.10.0 and above)
+* Anything above Node.js 9.10.0
+
+**To address:** Make sure you upgrade to at least Node.js 6 when using ESLint v5. If you are unable to upgrade, we recommend continuing to use ESLint v4.x until you are able to upgrade Node.js.
+
+## <a name="eslint-recommended-changes"/> `eslint:recommended` changes
+
+Two new rules have been added to the [`eslint:recommended`](configure/configuration-files#using-eslintrecommended) config:
+
+* [`for-direction`](../rules/for-direction) enforces that a `for` loop update clause moves the counter in the right direction.
+* [`getter-return`](../rules/getter-return) enforces that a `return` statement is present in property getters.
+
+**To address:** To mimic the `eslint:recommended` behavior from 4.x, you can disable these rules in a config file:
+
+```json
+{
+ "extends": "eslint:recommended",
+
+ "rules": {
+ "for-direction": "off",
+ "getter-return": "off"
+ }
+}
+```
+
+## <a name="experimental-object-rest-spread"></a> The `experimentalObjectRestSpread` option has been deprecated
+
+Previously, when using the default parser it was possible to use the `experimentalObjectRestSpread` option to enable support for [rest/spread properties](https://developers.google.com/web/updates/2017/06/object-rest-spread), as follows:
+
+```json
+{
+ "parserOptions": {
+ "ecmaFeatures": {
+ "experimentalObjectRestSpread": true
+ }
+ }
+}
+```
+
+Object rest/spread is now an official part of the JavaScript language, so our support for it is no longer experimental. In both ESLint v4 and ESLint v5, object rest/spread can now be enabled with the `"ecmaVersion": 2018` option:
+
+```json
+{
+ "parserOptions": {
+ "ecmaVersion": 2018
+ }
+}
+```
+
+Note that this also enables parsing for other features from ES2018, such as [async iteration](https://github.com/tc39/proposal-async-iteration). When using ESLint v5 with the default parser, it is no longer possible to toggle syntax support for object rest/spread independently of other features.
+
+For compatibility, ESLint v5 will treat `ecmaFeatures: { experimentalObjectRestSpread: true }` as an alias for `ecmaVersion: 2018` when the former is found in a config file. As a result, if you use object rest/spread, your code should still parse successfully with ESLint v5. However, note that this alias will be removed in ESLint v6.
+
+**To address:** If you use the `experimentalObjectRestSpread` option, you should be able to upgrade to ESLint v5 without any changes, but you will encounter a deprecation warning. To avoid the warning, use `ecmaVersion: 2018` in your config file rather than `ecmaFeatures: { experimentalObjectRestSpread: true }`. If you would like to disallow the use of other ES2018 features, consider using rules such as [`no-restricted-syntax`](../rules/no-restricted-syntax).
+
+## <a name="nonexistent-files"></a> Linting nonexistent files from the command line is now a fatal error
+
+Previous versions of ESLint silently ignored any nonexistent files and globs provided on the command line:
+
+```bash
+eslint nonexistent-file.js 'nonexistent-folder/**/*.js' # exits without any errors in ESLint v4
+```
+
+Many users found this behavior confusing, because if they made a typo in a filename, ESLint would appear to lint that file successfully while actually not linting anything.
+
+ESLint v5 will report a fatal error when either of the following conditions is met:
+
+* A file provided on the command line does not exist
+* A glob or folder provided on the command line does not match any lintable files
+
+Note that this also affects the [`CLIEngine.executeOnFiles()`](../integrate/nodejs-api#cliengineexecuteonfiles) API.
+
+**To address:** If you encounter an error about missing files after upgrading to ESLint v5, you may want to double-check that there are no typos in the paths you provide to ESLint. To make the error go away, you can simply remove the given files or globs from the list of arguments provided to ESLint on the command line.
+
+If you use a boilerplate generator that relies on this behavior (e.g. to generate a script that runs `eslint tests/` in a new project before any test files are actually present), you can work around this issue by adding a dummy file that matches the given pattern (e.g. an empty `tests/index.js` file).
+
+## <a name="rule-default-changes"></a> The default options for some rules have changed
+
+* The default options for the [`object-curly-newline`](../rules/object-curly-newline) rule have changed from `{ multiline: true }` to `{ consistent: true }`.
+* The default options object for the [`no-self-assign`](../rules/no-self-assign) rule has changed from `{ props: false }` to `{ props: true }`.
+
+**To address:** To restore the rule behavior from ESLint v4, you can update your config file to include the previous options:
+
+```json
+{
+ "rules": {
+ "object-curly-newline": ["error", { "multiline": true }],
+ "no-self-assign": ["error", { "props": false }]
+ }
+}
+```
+
+## <a name="deprecated-globals"></a> Deprecated globals have been removed from the `node`, `browser`, and `jest` environments
+
+Some global variables have been deprecated or removed for code running in Node.js, browsers, and Jest. (For example, browsers used to expose an `SVGAltGlyphElement` global variable to JavaScript code, but this global has been removed from web standards and is no longer present in browsers.) As a result, we have removed these globals from the corresponding `eslint` environments, so use of these globals will trigger an error when using rules such as [`no-undef`](../rules/no-undef).
+
+**To address:** If you use deprecated globals in the `node`, `browser`, or `jest` environments, you can add a `globals` section to your configuration to re-enable any globals you need. For example:
+
+```json
+{
+ "env": {
+ "browser": true
+ },
+ "globals": {
+ "SVGAltGlyphElement": false
+ }
+}
+```
+
+## <a name="empty-files"></a> Empty files are now linted
+
+ESLint v4 had a special behavior when linting files that only contain whitespace: it would skip running the parser and rules, and it would always return zero errors. This led to some confusion for users and rule authors, particularly when writing tests for rules. (When writing a stylistic rule, rule authors would occasionally write a test where the source code only contained whitespace, to ensure that the rule behaved correctly when no applicable code was found. However, a test like this would actually not run the rule at all, so an aspect of the rule would end up untested.)
+
+ESLint v5 treats whitespace-only files the same way as all other files: it parses them and runs enabled rules on them as appropriate. This could lead to additional linting problems if you use a custom rule that reports errors on empty files.
+
+**To address:** If you have an empty file in your project and you don't want it to be linted, consider adding it to an [`.eslintignore` file](configure/ignore).
+
+If you have a custom rule, you should make sure it handles empty files appropriately. (In most cases, no changes should be necessary.)
+
+## <a name="scoped-plugins"></a> Plugins in scoped packages are now resolvable in configs
+
+When ESLint v5 encounters a plugin name in a config starting with `@`, the plugin will be resolved as a [scoped npm package](https://docs.npmjs.com/misc/scope). For example, if a config contains `"plugins": ["@foo"]`, ESLint v5 will attempt to load a package called `@foo/eslint-plugin`. (On the other hand, ESLint v4 would attempt to load a package called `eslint-plugin-@foo`.) This is a breaking change because users might have been relying on ESLint finding a package at `node_modules/eslint-plugin-@foo`. However, we think it is unlikely that many users were relying on this behavior, because packages published to npm cannot contain an `@` character in the middle.
+
+**To address:** If you rely on ESLint loading a package like `eslint-config-@foo`, consider renaming the package to something else.
+
+## <a name="multiline-directives"></a> Multi-line `eslint-disable-line` directives are now reported as problems
+
+`eslint-disable-line` and `eslint-disable-next-line` directive comments are only allowed to span a single line. For example, the following directive comment is invalid:
+
+```js
+alert('foo'); /* eslint-disable-line
+ no-alert */ alert('bar');
+
+// (which line is the rule disabled on?)
+```
+
+Previously, ESLint would ignore these malformed directive comments. ESLint v5 will report an error when it sees a problem like this, so that the issue can be more easily corrected.
+
+**To address:** If you see new reported errors as a result of this change, ensure that your `eslint-disable-line` directives only span a single line. Note that "block comments" (delimited by `/* */`) are still allowed to be used for directives, provided that the block comments do not contain linebreaks.
+
+---
+
+## <a name="parent-before-rules"></a> The `parent` property of AST nodes is now set before rules start running
+
+Previously, ESLint would set the `parent` property on each AST node immediately before running rule listeners for that node. This caused some confusion for rule authors, because the `parent` property would not initially be present on any nodes, and it was sometimes necessary to complicate the structure of a rule to ensure that the `parent` property of a given node would be available when needed.
+
+In ESLint v5, the `parent` property is set on all AST nodes before any rules have access to the AST. This makes it easier to write some rules, because the `parent` property is always available rather than being mutated behind the scenes. However, as a side-effect of having `parent` properties, the AST object has a circular structure the first time a rule sees it (previously, it only had a circular structure after the first rule listeners were called). As a result, a custom rule that enumerates all properties of a node in order to traverse the AST might now loop forever or run out of memory if it does not check for cycles properly.
+
+**To address:** If you have written a custom rule that enumerates all properties of an AST node, consider excluding the `parent` property or implementing cycle detection to ensure that you obtain the correct result.
+
+## <a name="spread-operators"></a> When using the default parser, spread operators now have type `SpreadElement`
+
+Previously, when parsing JS code like `const foo = {...data}` with the `experimentalObjectRestSpread` option enabled, the default parser would generate an `ExperimentalSpreadProperty` node type for the `...data` spread element.
+
+In ESLint v5, the default parser will now always give the `...data` AST node the `SpreadElement` type, even if the (now deprecated) [`experimentalObjectRestSpread`](#experimental-object-rest-spread) option is enabled. This makes the AST compliant with the current ESTree spec.
+
+**To address:** If you have written a custom rule that relies on spread operators having the `ExperimentalSpreadProperty` type, you should update it to also work with spread operators that have the `SpreadElement` type.
+
+## <a name="rest-operators"></a> When using the default parser, rest operators now have type `RestElement`
+
+Previously, when parsing JS code like `const {foo, ...rest} = data` with the `experimentalObjectRestSpread` option enabled, the default parser would generate an `ExperimentalRestProperty` node type for the `...data` rest element.
+
+In ESLint v5, the default parser will now always give the `...data` AST node the `RestElement` type, even if the (now deprecated) [`experimentalObjectRestSpread`](#experimental-object-rest-spread) option is enabled. This makes the AST compliant with the current ESTree spec.
+
+**To address:** If you have written a custom rule that relies on rest operators having the `ExperimentalRestProperty` type, you should update it to also work with rest operators that have the `RestElement` type.
+
+## <a name="jsx-text-nodes"></a> When using the default parser, text nodes in JSX elements now have type `JSXText`
+
+When parsing JSX code like `<a>foo</a>`, the default parser will now give the `foo` AST node the `JSXText` type, rather than the `Literal` type. This makes the AST compliant with a recent update to the JSX spec.
+
+**To address:** If you have written a custom rule that relies on text nodes in JSX elements having the `Literal` type, you should update it to also work with nodes that have the `JSXText` type.
+
+## <a name="context-get-scope"></a> The `context.getScope()` method now returns more proper scopes
+
+Previously, the `context.getScope()` method changed its behavior based on the `parserOptions.ecmaVersion` property. However, this could cause confusing behavior when using a parser that doesn't respond to the `ecmaVersion` option, such as `babel-eslint`.
+
+Additionally, `context.getScope()` incorrectly returned the parent scope of the proper scope on `CatchClause` (in ES5), `ForStatement` (in ≧ES2015), `ForInStatement` (in ≧ES2015), `ForOfStatement`, and `WithStatement` nodes.
+
+In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../extend/scope-manager-interface) for more details on which scopes are returned.
+
+**To address:** If you have written a custom rule that uses the `context.getScope()` method in node handlers, you may need to update it to account for the modified scope information.
+
+## <a name="no-context-linter"></a> The `_linter` property on rule context objects has been removed
+
+Previously, rule context objects had an undocumented `_linter` property, which was used internally within ESLint to process reports from rules. Some rules used this property to achieve functionality that was not intended to be possible for rules. For example, several plugins used the `_linter` property in a rule to monitor reports from other rules, for the purpose of checking for unused `/* eslint-disable */` directive comments. Although this functionality was useful for users, it could also cause stability problems for projects using ESLint. For example, an upgrade to a rule in one plugin could unexpectedly cause a rule in another plugin to start reporting errors.
+
+The `_linter` property has been removed in ESLint v5.0, so it is no longer possible to implement rules with this functionality. However, the [`--report-unused-disable-directives`](command-line-interface#--report-unused-disable-directives) CLI flag can be used to flag unused directive comments.
+
+## <a name="rule-tester-equality"></a> `RuleTester` now uses strict equality checks in its assertions
+
+Previously, `RuleTester` used loose equality when making some of its assertions. For example, if a rule produced the string `"7"` as a result of autofixing, `RuleTester` would allow the number `7` in an `output` assertion, rather than the string `"7"`. In ESLint v5, comparisons from `RuleTester` use strict equality, so an assertion like this will no longer pass.
+
+**To address:** If you use `RuleTester` to write tests for your custom rules, make sure the expected values in your assertions are strictly equal to the actual values.
+
+## <a name="required-report-messages"></a> Rules are now required to provide messages along with reports
+
+Previously, it was possible for rules to report AST nodes without providing a report message. This was not intended behavior, and as a result the default formatter would crash if a rule omitted a message. However, it was possible to avoid a crash when using a non-default formatter, such as `json`.
+
+In ESLint v5, reporting a problem without providing a message always results in an error.
+
+**To address:** If you have written a custom rule that reports a problem without providing a message, update it to provide a message along with the report.
+
+---
+
+## <a name="source-property"></a> The `source` property is no longer available on individual linting messages
+
+As announced in [October 2016](/blog/2016/10/eslint-v3.8.0-released#additional-property-on-linting-results), the `source` property has been removed from individual lint message objects.
+
+**To address:** If you have a formatter or integration which relies on using the `source` property on individual linting messages, you should update it to use the `source` property on file results objects instead.
+
+## <a name="exit-code-two"></a> Fatal errors now result in an exit code of 2
+
+When using ESLint v4, both of the following scenarios resulted in an exit code of 1 when running ESLint on the command line:
+
+* Linting completed successfully, but there are some linting errors
+* Linting was unsuccessful due to a fatal error (e.g. an invalid config file)
+
+As a result, it was difficult for an integration to distinguish between the two cases to determine whether it should try to extract linting results from the output.
+
+In ESLint v5, an unsuccessful linting run due to a fatal error will result in an exit code of 2, rather than 1.
+
+**To address:** If you have an integration that detects all problems with linting runs by checking whether the exit code is equal to 1, update it to check whether the exit code is nonzero instead.
+
+## <a name="non-enumerable-linter"></a> The `eslint.linter` property is now non-enumerable
+
+When using ESLint's Node.js API, the [`linter`](../integrate/nodejs-api#linter-1) property is now non-enumerable. Note that the `linter` property was deprecated in ESLint v4 in favor of the [`Linter`](../integrate/nodejs-api#linter) property.
+
+**To address:** If you rely on enumerating all the properties of the `eslint` object, use something like `Object.getOwnPropertyNames` to ensure that non-enumerable keys are captured.
--- /dev/null
+---
+title: Migrating to v6.0.0
+
+---
+
+ESLint v6.0.0 is a major release of ESLint. We have made a few breaking changes in this release. This guide is intended to walk you through the 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
+
+1. [Node.js 6 is no longer supported](#drop-node-6)
+1. [`eslint:recommended` has been updated](#eslint-recommended-changes)
+1. [Plugins and shareable configs are no longer affected by ESLint's location](#package-loading-simplification)
+1. [The default parser now validates options more strictly](#espree-validation)
+1. [Rule configuration are validated more strictly](#rule-config-validating)
+1. [The `no-redeclare` rule is now more strict by default](#no-redeclare-updates)
+1. [The `comma-dangle` rule is now more strict by default](#comma-dangle-updates)
+1. [The `no-confusing-arrow` rule is now more lenient by default](#no-confusing-arrow-updates)
+1. [Overrides in a config file can now match dotfiles](#overrides-dotfiles)
+1. [Overrides in an extended config file can now be overridden by a parent config file](#overrides-precedence)
+1. [Configuration values for globals are now validated](#globals-validation)
+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
+
+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
+
+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)
+
+---
+
+## <a name="drop-node-6"></a> Node.js 6 is no longer supported
+
+As of April 2019, Node.js 6 will be at EOL and will no longer be receiving security updates. As a result, we have decided to drop support for it in ESLint v6. We now support the following versions of Node.js:
+
+* Node.js 8 (8.10.0 and above)
+* Node.js 10 (10.13.0 and above)
+* Anything above Node.js 11.10.1
+
+**To address:** Make sure you upgrade to at least Node.js 8 when using ESLint v6. If you are unable to upgrade, we recommend continuing to use ESLint v5.x until you are able to upgrade Node.js.
+
+**Related issue(s):** [eslint/eslint#11546](https://github.com/eslint/eslint/issues/11456)
+
+## <a name="eslint-recommended-changes"></a> `eslint:recommended` has been updated
+
+The following rules have been added to the [`eslint:recommended`](../use/configure#using-eslintrecommended) config:
+
+* [`no-async-promise-executor`](../rules/no-async-promise-executor) disallows using an `async` function as the argument to the `Promise` constructor, which is usually a bug.
+* [`no-misleading-character-class`](../rules/no-misleading-character-class) reports character classes in regular expressions that might not behave as expected.
+* [`no-prototype-builtins`](../rules/no-prototype-builtins) reports method calls like `foo.hasOwnProperty("bar")` (which are a frequent source of bugs), and suggests that they be replaced with `Object.prototype.hasOwnProperty.call(foo, "bar")` instead.
+* [`no-shadow-restricted-names`](../rules/no-shadow-restricted-names) disallows shadowing variables like `undefined` (e.g. with code like `let undefined = 5;`), since is likely to confuse readers.
+* [`no-useless-catch`](../rules/no-useless-catch) reports `catch` clauses that are redundant and can be removed from the code without changing its behavior.
+* [`no-with`](../rules/no-with) disallows use of the [`with` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with), which can make code difficult to understand and cause compatibility problems.
+* [`require-atomic-updates`](../rules/require-atomic-updates) reports race condition bugs that can occur when reassigning variables in async functions.
+
+Additionally, the following rule has been *removed* from `eslint:recommended`:
+
+* [`no-console`](../rules/no-console) disallows calling functions like `console.log`. While this rule is useful in many cases (e.g. to avoid inadvertently leaving debugging statements in production code), it is not as broadly applicable as the other rules in `eslint:recommended`, and it was a source of false positives in cases where `console.log` is acceptable (e.g. in CLI applications).
+
+Finally, in ESLint v5 `eslint:recommended` would explicitly disable all core rules that were not considered "recommended". This could cause confusing behavior if `eslint:recommended` was loaded after another config, since `eslint:recommended` would have the effect of turning off some rules. In ESLint v6, `eslint:recommended` has no effect on non-recommended rules.
+
+**To address:** To mimic the `eslint:recommended` behavior from 5.x, you can explicitly disable/enable rules in a config file as follows:
+
+```json
+{
+ "extends": "eslint:recommended",
+
+ "rules": {
+ "no-async-promise-executor": "off",
+ "no-misleading-character-class": "off",
+ "no-prototype-builtins": "off",
+ "no-shadow-restricted-names": "off",
+ "no-useless-catch": "off",
+ "no-with": "off",
+ "require-atomic-updates": "off",
+
+ "no-console": "error"
+ }
+}
+```
+
+In rare cases (if you were relying on the previous behavior where `eslint:recommended` disables core rules), you might need to disable additional rules to restore the previous behavior.
+
+**Related issue(s):** [eslint/eslint#10768](https://github.com/eslint/eslint/issues/10768), [eslint/eslint#10873](https://github.com/eslint/eslint/issues/10873)
+
+## <a name="package-loading-simplification"></a> Plugins and shareable configs are no longer affected by ESLint's location
+
+Previously, ESLint loaded plugins relative to the location of the ESLint package itself. As a result, we suggested that users with global ESLint installations should also install plugins globally, and users with local ESLint installations should install plugins locally. However, due to a design bug, this strategy caused ESLint to randomly fail to load plugins and shareable configs under certain circumstances, particularly when using package management tools like [`lerna`](https://github.com/lerna/lerna) and [Yarn Plug n' Play](https://yarnpkg.com/lang/en/docs/pnp/).
+
+As a rule of thumb: With ESLint v6, plugins should always be installed locally, even if ESLint was installed globally. More precisely, ESLint v6 resolves plugins relative to the end user's project by default, and always resolves shareable configs and parsers relative to the location of the config file that imports them.
+
+**To address:** If you use a global installation of ESLint (e.g. installed with `npm install eslint --global`) along with plugins, you should install those plugins locally in the projects where you run ESLint. If your config file extends shareable configs and/or parsers, you should ensure that those packages are installed as dependencies of the project containing the config file.
+
+If you use a config file located outside of a local project (with the `--config` flag), consider installing the plugins as dependencies of that config file, and setting the [`--resolve-plugins-relative-to`](./command-line-interface#--resolve-plugins-relative-to) flag to the location of the config file.
+
+**Related issue(s):** [eslint/eslint#10125](https://github.com/eslint/eslint/issues/10125), [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
+
+## <a name="espree-validation"></a> The default parser now validates options more strictly
+
+`espree`, the default parser used by ESLint, will now raise an error in the following cases:
+
+* The `ecmaVersion` parser option is set to something other than a number, such as the string `"2015"`. (Previously, a non-number option would simply be ignored.)
+* The `sourceType: "module"` parser option is set while `ecmaVersion` is set to `5` or left unspecified. (Previously, setting `sourceType: "module"` would implicitly cause `ecmaVersion` to be set to a minimum of 2015, which could be surprising.)
+* The `sourceType` is set to anything other than `"script"` or `"module"`.
+
+**To address:** If your config sets `ecmaVersion` to something other than a number, you can restore the previous behavior by removing `ecmaVersion`. (However, you may want to double-check that your config is actually working as expected.) If your config sets `parserOptions: { sourceType: "module" }` without also setting `parserOptions.ecmaVersion`, you should add `parserOptions: { ecmaVersion: 2015 }` to restore the previous behavior.
+
+**Related issue(s):** [eslint/eslint#9687](https://github.com/eslint/eslint/issues/9687), [eslint/espree#384](https://github.com/eslint/espree/issues/384)
+
+## <a name="rule-config-validating"></a> Rule configuration are validated more strictly
+
+To catch config errors earlier, ESLint v6 will report a linting error if you are trying to configure a non-existent rule.
+
+config | ESLint v5 | ESLint v6
+------------- | ------------- | -------------
+`/*eslint-enable foo*/` | no error | linting error
+`/*eslint-disable(-line) foo*/` | no error | linting error
+`/*eslint foo: 0*/` | no error | linting error
+`{rules: {foo: 0}}` | no error | no error
+`{rules: {foo: 1}` | linting warning | linting error
+
+**To address:** You can remove the non-existent rule in your (inline) config.
+
+**Related issue(s):** [eslint/eslint#9505](https://github.com/eslint/eslint/issues/9505)
+
+## <a name="no-redeclare-updates"></a> The `no-redeclare` rule is now more strict by default
+
+The default options for the [`no-redeclare`](../rules/no-redeclare) rule have changed from `{ builtinGlobals: false }` to `{ builtinGlobals: true }`. Additionally, the `no-redeclare` rule will now report an error for globals enabled by comments like `/* global foo */` if those globals were already enabled through configuration anyway.
+
+**To address:**
+
+To restore the previous options for the rule, you can configure it as follows:
+
+```json
+{
+ "rules": {
+ "no-redeclare": ["error", { "builtinGlobals": false }]
+ }
+}
+```
+
+Additionally, if you see new errors for `global` comments in your code, you should remove those comments.
+
+**Related issue(s):** [eslint/eslint#11370](https://github.com/eslint/eslint/issues/11370), [eslint/eslint#11405](https://github.com/eslint/eslint/issues/11405)
+
+## <a name="comma-dangle-updates"></a> The `comma-dangle` rule is now more strict by default
+
+Previously, the [`comma-dangle`](../rules/comma-dangle) rule would ignore trailing function arguments and parameters, unless explicitly configured to check for function commas. In ESLint v6, function commas are treated the same way as other types of trailing commas.
+
+**To address:** You can restore the previous default behavior of the rule with:
+
+```json
+{
+ "rules": {
+ "comma-dangle": ["error", {
+ "arrays": "never",
+ "objects": "never",
+ "imports": "never",
+ "exports": "never",
+ "functions": "ignore"
+ }]
+ }
+}
+```
+
+To restore the previous behavior of a string option like `"always-multiline"`, replace `"never"` with `"always-multiline"` in the example above.
+
+**Related issue(s):** [eslint/eslint#11502](https://github.com/eslint/eslint/issues/11502)
+
+## <a name="no-confusing-arrow-updates"></a> The `no-confusing-arrow` rule is now more lenient by default
+
+The default options for the [`no-confusing-arrow`](../rules/no-confusing-arrow) rule have changed from `{ allowParens: false }` to `{ allowParens: true }`.
+
+**To address:** You can restore the previous default behavior of the rule with:
+
+```json
+{
+ "rules": {
+ "no-confusing-arrow": ["error", { "allowParens": false }]
+ }
+}
+```
+
+**Related issue(s):** [eslint/eslint#11503](https://github.com/eslint/eslint/issues/11503)
+
+## <a name="overrides-dotfiles"></a> Overrides in a config file can now match dotfiles
+
+Due to a bug, the glob patterns in a `files` list in an `overrides` section of a config file would never match dotfiles, making it impossible to have overrides apply to files starting with a dot. This bug has been fixed in ESLint v6.
+
+**To address:** If you don't want dotfiles to be matched by an override, consider adding something like `excludedFiles: [".*"]` to that `overrides` section. See the [documentation](../use/configure#configuration-based-on-glob-patterns) for more details.
+
+**Related issue(s):** [eslint/eslint#11201](https://github.com/eslint/eslint/issues/11201)
+
+## <a name="overrides-precedence"></a> Overrides in an extended config file can now be overridden by a parent config file
+
+Due to a bug, it was previously the case that an `overrides` block in a shareable config had precedence over the top level of a parent config. For example, with the following config setup, the `semi` rule would end up enabled even though it was explicitly disabled in the end user's config:
+
+```js
+// .eslintrc.js
+module.exports = {
+ extends: ["foo"],
+ rules: {
+ semi: "off"
+ }
+};
+```
+
+```js
+// eslint-config-foo/index.js
+module.exports = {
+ overrides: {
+ files: ["*.js"],
+ rules: {
+ semi: "error"
+ }
+ }
+};
+```
+
+In ESLint v6.0.0, a parent config always has precedence over extended configs, even with `overrides` blocks.
+
+**To address:** We expect the impact of this issue to be very low because most shareable configs don't use `overrides` blocks. However, if you use a shareable config with `overrides` blocks, you might encounter a change in behavior due to something that is explicitly specified in your config but was inactive until now. If you would rather inherit the behavior from the shareable config, simply remove the corresponding entry from your own config. (In the example above, the previous behavior could be restored by removing `semi: "off"` from `.eslintrc.js`.)
+
+**Related issue(s):** [eslint/eslint#11510](https://github.com/eslint/eslint/issues/11510)
+
+## <a name="globals-validation"></a> Configuration values for globals are now validated
+
+Previously, when configuring a set of global variables with an object, it was possible to use anything as the values of the object. An unknown value would be treated the same as `"writable"`.
+
+```js
+// .eslintrc.js
+module.exports = {
+ globals: {
+ foo: "readonly",
+ bar: "writable",
+ baz: "hello!" // ???
+ }
+};
+```
+
+With this change, any unknown values in a `globals` object result in a config validation error.
+
+**To address:** If you see config validation errors related to globals after updating, ensure that all values configured for globals are either `readonly`, `writable`, or `off`. (ESLint also accepts some alternate spellings and variants for compatibility.)
+
+## <a name="experimental-object-rest-spread"></a> The deprecated `experimentalObjectRestSpread` option has been removed
+
+Previously, when using the default parser, a config could use the `experimentalObjectRestSpread` option to enable parsing support for object rest/spread properties:
+
+```json
+{
+ "parserOptions": {
+ "ecmaFeatures": {
+ "experimentalObjectRestSpread": true
+ }
+ }
+}
+```
+
+Since ESLint v5, `ecmaFeatures: { experimentalObjectRestSpread: true }` has been equivalent to `ecmaVersion: 2018`, and has also emitted a deprecation warning. In ESLint v6, the `experimentalObjectRestSpread` feature has been removed entirely and has no effect. If your config was relying on `experimentalObjectRestSpread` to enable ES2018 parsing, you might start seeing parsing errors for recent syntax.
+
+**To address:** If you use the `experimentalObjectRestSpread` option, you should change your config to contain this instead:
+
+```json
+{
+ "parserOptions": {
+ "ecmaVersion": 2018
+ }
+}
+```
+
+If you're not sure which config file needs to be updated, it may be useful to run ESLint v5 and look at what config file is mentioned in the deprecation warning.
+
+**Related issue(s):** [eslint/eslint#9990](https://github.com/eslint/eslint/issues/9990)
+
+## <a name="unicode-regexes"></a> User-provided regular expressions in rule options are parsed with the unicode flag
+
+Rules like [`max-len`](../rules/max-len) accept a string option which is interpreted as a regular expression. In ESLint v6.0.0, these regular expressions are interpreted with the [unicode flag](https://mathiasbynens.be/notes/es6-unicode-regex), which should exhibit more reasonable behavior when matching characters like astral symbols. Unicode regexes also validate escape sequences more strictly than non-unicode regexes.
+
+**To address:** If you get rule option validation errors after upgrading, ensure that any regular expressions in your rule options have no invalid escape sequences.
+
+**Related issue(s):** [eslint/eslint#11423](https://github.com/eslint/eslint/issues/11423)
+
+---
+
+## <a name="plugin-documentation"></a> Plugin authors may need to update installation instructions
+
+If you maintain a plugin and provide installation instructions, you should ensure that the installation instructions are up to date with the [user-facing changes to how plugins are loaded](#package-loading-simplification). In particular, if your plugin was generated with the [`generator-eslint`](https://github.com/eslint/generator-eslint) package, it likely contains outdated instructions for how to use the plugin with global ESLint installations.
+
+**Related issue(s):** [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
+
+## <a name="rule-tester-defaults"></a> `RuleTester` now validates against invalid `default` keywords in rule schemas
+
+In some cases, rule schemas can use the `default` keyword to automatically specify default values for rule options. However, the `default` keyword is only effective in certain schema locations, and is ignored elsewhere, which creates a risk of bugs if a rule incorrectly expects a default value to be provided as a rule option. In ESLint v6.0.0, `RuleTester` will raise an error if a rule has an invalid `default` keyword in its schema.
+
+**To address:** If `RuleTester` starts reporting an error about an invalid default, you can remove the `default` property at the indicated location in your rule schema, and the rule will behave the same way. (If this happens, you might also want to verify that the rule behaves correctly when no option value is provided in that location.)
+
+**Related issue(s):** [eslint/eslint#11473](https://github.com/eslint/eslint/issues/11473)
+
+## <a name="rule-tester-parser"></a> `RuleTester` now requires an absolute path on `parser` option
+
+To use custom parsers in tests, we could use `parser` property with a package name or file path. However, if a package name was given, it's unclear where the tester should load the parser package from because the tester doesn't know which files are running the tester. In ESLint v6.0.0, `RuleTester` disallows `parser` property with a package name.
+
+**To address:** If you use `parser` property with package names in test cases, update it with `require.resolve()` function to resolve the package name to the absolute path to the package.
+
+**Related issue(s):** [eslint/eslint#11728](https://github.com/eslint/eslint/issues/11728), [eslint/eslint#10125](https://github.com/eslint/eslint/issues/10125), [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
+
+## <a name="eslintExplicitGlobalComment"></a> The `eslintExplicitGlobalComment` scope analysis property has been removed
+
+Previously, ESLint would add an `eslintExplicitGlobalComment` property to `Variable` objects in scope analysis to indicate that a variable was introduced as a result of a `/* global */` comment. This property was undocumented, and the ESLint team was unable to find any usage of the property outside of ESLint core. The property has been removed in ESLint v6, and replaced with the `eslintExplicitGlobalComments` property, which can contain a list of all `/* global */` comments if a variable was declared with more than one of them.
+
+**To address:** If you maintain a rule that uses the `eslintExplicitGlobalComment` property, update it to use the `eslintExplicitGlobalComments` property as a list instead.
+
+**Related issue(s):** [eslint/rfcs#17](https://github.com/eslint/rfcs/pull/17)
+
+---
+
+## <a name="linter-parsers"></a> `Linter` no longer tries to load missing parsers from the filesystem
+
+Previously, when linting code with a parser that had not been previously defined, the `Linter` API would attempt to load the parser from the filesystem. However, this behavior was confusing because `Linter` never access the filesystem in any other cases, and it was difficult to ensure that the correct parser would be found when loading the parser from the filesystem.
+
+In ESLint v6, `Linter` will no longer perform any filesystem operations, including loading parsers.
+
+**To address:** If you're using `Linter` with a custom parser, use [`Linter#defineParser`](../integrate/nodejs-api#linterdefineparser) to explicitly define the parser before linting any code.
+
+**Related issue(s):** [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
--- /dev/null
+---
+title: Migrating to v7.0.0
+
+---
+
+ESLint v7.0.0 is a major release of ESLint. We have made a few breaking changes in this release. This guide is intended to walk you through the 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.
+
+## Table of Content
+
+### Breaking changes for users
+
+* [Node.js 8 is no longer supported](#drop-node-8)
+* [Lint files matched by `overrides[].files` by default](#additional-lint-targets)
+* [The base path of `overrides` and `ignorePatterns` is changed if the config file is given by the `--config`/`--ignore-path` options](#base-path-change)
+* [The place where ESLint loads plugins from is changed](#plugin-loading-change)
+* [Runtime deprecation warnings for `~/.eslintrc.*` config files](#runtime-deprecation-on-personal-config-files)
+* [Default ignore patterns have changed](#default-ignore-patterns)
+* [Description in directive comments](#description-in-directive-comments)
+* [Node.js/CommonJS rules are deprecated](#deprecate-node-rules)
+* [Several rules have been updated to cover more cases](#rules-strict)
+* [`eslint:recommended` has been updated](#eslint-recommended)
+
+### Breaking changes for plugin developers
+
+* [Node.js 8 is no longer supported](#drop-node-8)
+* [Lint files matched by `overrides[].files` by default](#additional-lint-targets)
+* [Plugin resolution has been updated](#plugin-loading-change)
+* [Additional validation added to the `RuleTester` class](#rule-tester-strict)
+
+### Breaking changes for integration developers
+
+* [Node.js 8 is no longer supported](#drop-node-8)
+* [Plugin resolution has been updated](#plugin-loading-change)
+* [The `CLIEngine` class has been deprecated](#deprecate-cliengine)
+
+---
+
+## <a name="drop-node-8"></a> Node.js 8 is no longer supported
+
+Node.js 8 reached EOL in December 2019, and we are officially dropping support for it in this release. ESLint now supports the following versions of Node.js:
+
+* Node.js 10 (`10.12.0` and above)
+* Node.js 12 and above
+
+**To address:** Make sure you upgrade to at least Node.js `10.12.0` when using ESLint v7.0.0. One important thing to double check is the Node.js version supported by your editor when using ESLint via editor integrations. If you are unable to upgrade, we recommend continuing to use ESLint 6 until you are able to upgrade Node.js.
+
+**Related issue(s):** [RFC44](https://github.com/eslint/rfcs/blob/master/designs/2019-drop-node8/README.md), [#12700](https://github.com/eslint/eslint/pull/12700)
+
+## <a name="additional-lint-targets"></a> Lint files matched by `overrides[].files` by default
+
+Previously to v7.0.0, ESLint would only lint files with a `.js` extension by default if you give directories like `eslint src`.
+
+ESLint v7.0.0 will now additionally lint files with other extensions (`.ts`, `.vue`, etc.) if the extension is explicitly matched by an `overrides[].files` entry. This will allow for users to lint files that don't end with `*.js` to be linted without having to use the `--ext` command line flag, as well as allow shared configuration authors to enable linting of these files without additional overhead for the end user. Please note that patterns that end with `*` are exempt from this behavior and will behave as they did previously. For example, if the following config file is present,
+
+```yml
+# .eslintrc.yml
+extends: my-config-js
+overrides:
+ - files: "*.ts"
+ extends: my-config-ts
+```
+
+then running `eslint src` would check both `*.js` and `*.ts` files in the `src` directory.
+
+**To address:** Using the `--ext` CLI option will override this new behavior. Run ESLint with `--ext .js` if you are using `overrides` but only want to lint files that have a `.js` extension.
+
+If you maintain plugins that check files with extensions other than `.js`, this feature will allow you to check these files by default by configuring an `overrides` setting in your `recommended` preset.
+
+**Related issue(s):** [RFC20](https://github.com/eslint/rfcs/blob/master/designs/2019-additional-lint-targets/README.md), [#12677](https://github.com/eslint/eslint/pull/12677)
+
+## <a name="base-path-change"></a> The base path of `overrides` and `ignorePatterns` has changed when using the `--config`/`--ignore-path` options
+
+Up until now, ESLint has resolved the following paths relative to the directory path of the _entry_ configuration file:
+
+* Configuration files (`.eslintrc.*`)
+ * relative paths in the `overrides[].files` setting
+ * relative paths in the `overrides[].excludedFiles` setting
+ * paths which start with `/` in the `ignorePatterns` setting
+* Ignore files (`.eslintignore`)
+ * paths which start with `/`
+
+Starting in ESLint v7.0.0, configuration files and ignore files passed to ESLint using the `--config path/to/a-config` and `--ignore-path path/to/a-ignore` CLI flags, respectively, will resolve from the current working directory rather than the file location. This allows for users to utilize shared plugins without having to install them directly in their project.
+
+**To address:** Update the affected paths if you are using a configuration or ignore file via the `--config` or `--ignore-path` CLI options.
+
+**Related issue(s):** [RFC37](https://github.com/eslint/rfcs/blob/master/designs/2019-changing-base-path-in-config-files-that-cli-options-specify/README.md), [#12887](https://github.com/eslint/eslint/pull/12887)
+
+## <a name="plugin-loading-change"></a> Plugin resolution has been updated
+
+In previous versions, ESLint resolved all plugins from the current working directory by default.
+
+Starting in ESLint v7.0.0, `plugins` are resolved relative to the directory path of the _entry_ configuration file.
+
+This will not change anything in most cases. If a configuration file in a subdirectory has `plugins` defined, the plugins will be loaded from the subdirectory (or ancestor directories that include the current working directory if not found).
+
+This means that if you are using a config file from a shared location via `--config` option, the plugins that the config file declare will be loaded from the shared config file location.
+
+**To address:** Ensure that plugins are installed in a place that can be resolved relative to your configuration file or use `--resolve-plugins-relative-to .` to override this change.
+
+**Related issue(s):** [RFC47](https://github.com/eslint/rfcs/blob/master/designs/2019-plugin-loading-improvement/README.md), [#12922](https://github.com/eslint/eslint/pull/12922)
+
+## <a name="runtime-deprecation-on-personal-config-files"></a> Runtime deprecation warnings for `~/.eslintrc.*` config files
+
+Personal config files have been deprecated since [v6.7.0](https://eslint.org/blog/2019/11/eslint-v6.7.0-released). ESLint v7.0.0 will start printing runtime deprecation warnings. It will print a warning for the following situations:
+
+1. When a project does not have a configuration file present and ESLint loads configuration from `~/.eslintrc.*`.
+1. When a project has a configuration file and ESLint ignored a `~/.eslintrc.*` configuration file. This occurs when the `$HOME` directory is an ancestor directory of the project and the project's configuration files doesn't contain `root:true`.
+
+**To address:** Remove `~/.eslintrc.*` configuration files and add an `.eslintrc.*` configuration file to your project. Alternatively, use the `--config` option to use shared config files.
+
+**Related issue(s):** [RFC32](https://github.com/eslint/rfcs/tree/master/designs/2019-deprecating-personal-config/README.md), [#12678](https://github.com/eslint/eslint/pull/12678)
+
+## <a name="default-ignore-patterns"></a> Default ignore patterns have changed
+
+Up until now, ESLint has ignored the following files by default:
+
+* Dotfiles (`.*`)
+* `node_modules` in the current working directory (`/node_modules/*`)
+* `bower_components` in the current working directory (`/bower_components/*`)
+
+ESLint v7.0.0 ignores `node_modules/*` of subdirectories as well, but no longer ignores `bower_components/*` and `.eslintrc.js`. Therefore, the new default ignore patterns are:
+
+* Dotfiles except `.eslintrc.*` (`.*` but not `.eslintrc.*`)
+* `node_modules` (`/**/node_modules/*`)
+
+**To address:** Modify your `.eslintignore` or the `ignorePatterns` property of your config file if you don't want to lint `bower_components/*` and `.eslintrc.js`.
+
+**Related issue(s):** [RFC51](https://github.com/eslint/rfcs/blob/master/designs/2019-update-default-ignore-patterns/README.md), [#12888](https://github.com/eslint/eslint/pull/12888)
+
+## <a name="description-in-directive-comments"></a> Descriptions in directive comments
+
+In older version of ESLint, there was no convenient way to indicate why a directive comment – such as `/*eslint-disable*/` – was necessary.
+
+To allow for the colocation of comments that provide context with the directive, ESLint v7.0.0 adds the ability to append arbitrary text in directive comments by ignoring text following `--` surrounded by whitespace. For example:
+
+```js
+// eslint-disable-next-line a-rule, another-rule -- those are buggy!!
+```
+
+**To address:** If you have `--` surrounded by whitespace in directive comments, consider moving it into your configuration file.
+
+**Related issue(s):** [RFC33](https://github.com/eslint/rfcs/blob/master/designs/2019-description-in-directive-comments/README.md), [#12699](https://github.com/eslint/eslint/pull/12699)
+
+## <a name="deprecate-node-rules"></a> Node.js/CommonJS rules have been deprecated
+
+The ten Node.js/CommonJS rules in core have been deprecated and moved to the [eslint-plugin-node](https://github.com/mysticatea/eslint-plugin-node) plugin (for ESLint v8.0.0 and later, use the maintained [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n) fork instead) .
+
+**To address:** As per [our deprecation policy](../use/rule-deprecation), the deprecated rules will remain in core for the foreseeable future and are still available for use. However, we will no longer be updating or fixing any bugs in those rules. To use a supported version of the rules, we recommend using the corresponding rules in the plugin instead.
+
+| Deprecated Rules | Replacement |
+| :--------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------ |
+| [callback-return](../rules/callback-return) | [node/callback-return](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/callback-return.md) |
+| [global-require](../rules/global-require) | [node/global-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/global-require.md) |
+| [handle-callback-err](../rules/handle-callback-err) | [node/handle-callback-err](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/handle-callback-err.md) |
+| [no-mixed-requires](../rules/no-mixed-requires) | [node/no-mixed-requires](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-mixed-requires.md) |
+| [no-new-require](../rules/no-new-require) | [node/no-new-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-new-require.md) |
+| [no-path-concat](../rules/no-path-concat) | [node/no-path-concat](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-path-concat.md) |
+| [no-process-env](../rules/no-process-env) | [node/no-process-env](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-env.md) |
+| [no-process-exit](../rules/no-process-exit) | [node/no-process-exit](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-exit.md) |
+| [no-restricted-modules](../rules/no-restricted-modules) | [node/no-restricted-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-restricted-require.md) |
+| [no-sync](../rules/no-sync) | [node/no-sync](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-sync.md) |
+
+**Related issue(s):** [#12898](https://github.com/eslint/eslint/pull/12898)
+
+## <a name="rules-strict"></a> Several rules have been updated to cover more cases
+
+Several rules have been enhanced and now report additional errors:
+
+* [accessor-pairs](../rules/accessor-pairs) rule now recognizes class members by default.
+* [array-callback-return](../rules/array-callback-return) rule now recognizes `flatMap` method.
+* [computed-property-spacing](../rules/computed-property-spacing) rule now recognizes class members by default.
+* [func-names](../rules/func-names) rule now recognizes function declarations in default exports.
+* [no-extra-parens](../rules/no-extra-parens) rule now recognizes parentheses in assignment targets.
+* [no-dupe-class-members](../rules/no-dupe-class-members) rule now recognizes computed keys for static class members.
+* [no-magic-numbers](../rules/no-magic-numbers) rule now recognizes bigint literals.
+* [radix](../rules/radix) rule now recognizes invalid numbers for the second parameter of `parseInt()`.
+* [use-isnan](../rules/use-isnan) rule now recognizes class members by default.
+* [yoda](../rules/yoda) rule now recognizes bigint literals.
+
+**To address:** Fix errors or disable these rules.
+
+**Related issue(s):** [#12490](https://github.com/eslint/eslint/pull/12490), [#12608](https://github.com/eslint/eslint/pull/12608), [#12670](https://github.com/eslint/eslint/pull/12670), [#12701](https://github.com/eslint/eslint/pull/12701), [#12765](https://github.com/eslint/eslint/pull/12765), [#12837](https://github.com/eslint/eslint/pull/12837), [#12913](https://github.com/eslint/eslint/pull/12913), [#12915](https://github.com/eslint/eslint/pull/12915), [#12919](https://github.com/eslint/eslint/pull/12919)
+
+## <a name="eslint-recommended"></a> `eslint:recommended` has been updated
+
+Three new rules have been enabled in the `eslint:recommended` preset.
+
+* [no-dupe-else-if](../rules/no-dupe-else-if)
+* [no-import-assign](../rules/no-import-assign)
+* [no-setter-return](../rules/no-setter-return)
+
+**To address:** Fix errors or disable these rules.
+
+**Related issue(s):** [#12920](https://github.com/eslint/eslint/pull/12920)
+
+## <a name="rule-tester-strict"></a> Additional validation added to the `RuleTester` class
+
+The `RuleTester` now validates the following:
+
+* It fails test cases if the rule under test uses the non-standard `node.start` or `node.end` properties. Rules should use `node.range` instead.
+* It fails test cases if the rule under test provides an autofix but a test case doesn't have an `output` property. Add an `output` property to test cases to test the rule's autofix functionality.
+* It fails test cases if any unknown properties are found in the objects in the `errors` property.
+
+**To address:** Modify your rule or test case if existing test cases fail.
+
+**Related issue(s):** [RFC25](https://github.com/eslint/rfcs/blob/master/designs/2019-rule-tester-improvements/README.md), [#12096](https://github.com/eslint/eslint/pull/12096), [#12955](https://github.com/eslint/eslint/pull/12955)
+
+## <a name="deprecate-cliengine"></a> The `CLIEngine` class has been deprecated
+
+The [`CLIEngine` class](../integrate/nodejs-api#cliengine) has been deprecated and replaced by the new [`ESLint` class](../integrate/nodejs-api#eslint-class).
+
+The `CLIEngine` class provides a synchronous API that is blocking the implementation of features such as parallel linting, supporting ES modules in shareable configs/parsers/plugins/formatters, and adding the ability to visually display the progress of linting runs. The new `ESLint` class provides an asynchronous API that ESLint core will now using going forward. `CLIEngine` will remain in core for the foreseeable future but may be removed in a future major version.
+
+**To address:** Update your code to use the new `ESLint` class if you are currently using `CLIEngine`. The following table maps the existing `CLIEngine` methods to their `ESLint` counterparts:
+
+| `CLIEngine` | `ESLint` |
+| :------------------------------------------- | :--------------------------------- |
+| `executeOnFiles(patterns)` | `lintFiles(patterns)` |
+| `executeOnText(text, filePath, warnIgnored)` | `lintText(text, options)` |
+| `getFormatter(name)` | `loadFormatter(name)` |
+| `getConfigForFile(filePath)` | `calculateConfigForFile(filePath)` |
+| `isPathIgnored(filePath)` | `isPathIgnored(filePath)` |
+| `static outputFixes(results)` | `static outputFixes(results)` |
+| `static getErrorResults(results)` | `static getErrorResults(results)` |
+| `static getFormatter(name)` | (removed ※1) |
+| `addPlugin(pluginId, definition)` | the `plugins` constructor option |
+| `getRules()` | (not implemented yet) |
+| `resolveFileGlobPatterns()` | (removed ※2) |
+
+* ※1 The `engine.getFormatter()` method currently returns the object of loaded packages as-is, which made it difficult to add new features to formatters for backward compatibility reasons. The new `eslint.loadFormatter()` method returns an adapter object that wraps the object of loaded packages, to ease the process of adding new features. Additionally, the adapter object has access to the `ESLint` instance to calculate default data (using loaded plugin rules to make `rulesMeta`, for example). As a result, the `ESLint` class only implements an instance version of the `loadFormatter()` method.
+* ※2 Since ESLint 6, ESLint uses different logic from the `resolveFileGlobPatterns()` method to iterate files, making this method obsolete.
+
+**Related issue(s):** [RFC40](https://github.com/eslint/rfcs/blob/master/designs/2019-move-to-async-api/README.md), [#12939](https://github.com/eslint/eslint/pull/12939)
--- /dev/null
+---
+title: Rule Deprecation
+
+---
+
+Balancing the trade-offs of improving a tool and the frustration these changes can cause is a difficult task. One key area in which this affects our users is in the removal of rules.
+
+The ESLint team is committed to making upgrading as easy and painless as possible. To that end, the team has agreed upon the following set of guidelines for deprecating rules in the future. The goal of these guidelines is to allow for improvements and changes to be made without breaking existing configurations.
+
+* Rules will never be removed from ESLint.
+* Rules will be deprecated as needed, and marked as such in all documentation.
+* After a rule has been deprecated, the team will no longer do any work on it. This includes bug fixes, enhancements, and updates to the rule's documentation. Issues and pull requests related to deprecated rule will not be accepted and will be closed.
+
+Since deprecated rules will never be removed, you can continue to use them indefinitely if they are working for you. However, keep in mind that deprecated rules will effectively be unmaintained.
+
+We hope that by following these guidelines we will be able to continue improving and working to make ESLint the best tool it can be while causing as little disruption to our users as possible during the process.
+++ /dev/null
----
-title: Command Line Interface
-layout: doc
-eleventyNavigation:
- key: command line interface
- parent: user guide
- title: Command Line Interface
- order: 3
-
----
-
-ESLint requires Node.js for installation. Follow the instructions in the [Getting Started Guide](getting-started) to install ESLint.
-
-Most users use [`npx`](https://docs.npmjs.com/cli/v8/commands/npx) to run ESLint on the command line like this:
-
-```shell
-npx eslint [options] [file|dir|glob]*
-```
-
-Such as:
-
-```shell
-# Run on two files
-npx eslint file1.js file2.js
-
-# Run on multiple files
-npx eslint lib/**
-```
-
-Please note that when passing a glob as a parameter, it will be expanded by your shell. The results of the expansion can vary depending on your shell, and its configuration. If you want to use node `glob` syntax, you have to quote your parameter (using double quotes if you need it to run in Windows), as follows:
-
-```shell
-npx eslint "lib/**"
-```
-
-**Note:** You can also use alternative package managers such as [Yarn](https://yarnpkg.com/) or [pnpm](https://pnpm.io/) to run ESLint. Please refer to your package manager's documentation for the correct syntax.
-
-## Options
-
-The command line utility has several options. You can view the options by running `npx eslint -h`.
-
-```text
-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
- --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:
- --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)
-
-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)
-
-Using stdin:
- --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
-
-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
-
-Inline configuration comments:
- --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 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
- --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).
-
-Example:
-
-```shell
-npx eslint --ext .jsx --ext .js lib/
-
-npx eslint --ext .jsx,.js lib/
-```
-
-### Basic configuration
-
-#### `--no-eslintrc`
-
-Disables use of configuration from `.eslintrc.*` and `package.json` files.
-
-Example:
-
-```shell
-npx eslint --no-eslintrc file.js
-```
-
-#### `-c`, `--config`
-
-This option allows you to specify an additional configuration file for ESLint (see [Configuring ESLint](configuring/) for more).
-
-Example:
-
-```shell
-npx eslint -c ~/my-eslint.json file.js
-```
-
-This example uses the configuration file at `~/my-eslint.json`.
-
-If `.eslintrc.*` and/or `package.json` files are also used for configuration (i.e., `--no-eslintrc` was not specified), the configurations will be merged. Options from this configuration file have precedence over the options from `.eslintrc.*` and `package.json` files.
-
-#### `--env`
-
-This option enables specific environments. Details about the global variables defined by each environment are available on the [Specifying Environments](configuring/language-options#specifying-environments) documentation. This option only enables environments; it does not disable environments set in other configuration files. To specify multiple environments, separate them using commas, or use the option multiple times.
-
-Examples:
-
-```shell
-npx eslint --env browser,node file.js
-npx eslint --env browser --env node file.js
-```
-
-#### `--ext`
-
-This option allows you to specify which file extensions ESLint will use when searching for target files in the directories you specify.
-By default, ESLint lints `*.js` files and the files that match the `overrides` entries of your configuration.
-
-Examples:
-
-```shell
-# Use only .ts extension
-npx eslint . --ext .ts
-
-# Use both .js and .ts
-npx eslint . --ext .js --ext .ts
-
-# Also use both .js and .ts
-npx eslint . --ext .js,.ts
-```
-
-**Note:** `--ext` is only used when the arguments are directories. If you use glob patterns or file names, then `--ext` is ignored.
-
-For example, `npx eslint lib/* --ext .js` will match all files within the `lib/` directory, regardless of extension.
-
-#### `--global`
-
-This option defines global variables so that they will not be flagged as undefined by the `no-undef` rule. Any specified global variables are assumed to be read-only by default, but appending `:true` to a variable's name ensures that `no-undef` will also allow writes. To specify multiple global variables, separate them using commas, or use the option multiple times.
-
-Examples:
-
-```shell
-npx eslint --global require,exports:true file.js
-npx eslint --global require --global exports:true
-```
-
-#### `--parser`
-
-This option allows you to specify a parser to be used by ESLint. By default, `espree` will be used.
-
-#### `--parser-options`
-
-This option allows you to specify parser options to be used by ESLint. Note that the available parser options are determined by the parser being used.
-
-Examples:
-
-```shell
-echo '3 ** 4' | npx eslint --stdin --parser-options=ecmaVersion:6 # will fail with a parsing error
-echo '3 ** 4' | npx eslint --stdin --parser-options=ecmaVersion:7 # succeeds, yay!
-```
-
-#### `--resolve-plugins-relative-to`
-
-Changes the folder where plugins are resolved from. By default, plugins are resolved from the current working directory. This option should be used when plugins were installed by someone other than the end user. It should be set to the project directory of the project that has a dependency on the necessary plugins. For example:
-
-* When using a config file that is located outside of the current project (with the `--config` flag), if the config uses plugins which are installed locally to itself, `--resolve-plugins-relative-to` should be set to the directory containing the config file.
-* If an integration has dependencies on ESLint and a set of plugins, and the tool invokes ESLint on behalf of the user with a preset configuration, the tool should set `--resolve-plugins-relative-to` to the top-level directory of the tool.
-
-### Specifying rules and plugins
-
-#### `--plugin`
-
-This option specifies a plugin to load. You can omit the prefix `eslint-plugin-` from the plugin name.
-
-Before using the plugin, you have to install it using npm.
-
-Examples:
-
-```shell
-npx eslint --plugin jquery file.js
-npx eslint --plugin eslint-plugin-mocha file.js
-```
-
-#### `--rule`
-
-This option specifies rules to be used. These rules will be merged with any rules specified with configuration files. (You can use `--no-eslintrc` to change that behavior.) To define multiple rules, separate them using commas, or use the option multiple times. The [levn](https://github.com/gkz/levn#levn--) format is used for specifying the rules.
-
-If the rule is defined within a plugin, you have to prefix the rule ID with the plugin name and a `/`.
-
-Examples:
-
-```shell
-npx eslint --rule 'quotes: [error, double]'
-npx eslint --rule 'guard-for-in: error' --rule 'brace-style: [error, 1tbs]'
-npx 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:
-
-```shell
-npx 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:
-
-```shell
-npx 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`
-
-This option instructs ESLint to try to fix as many issues as possible. The fixes are made to the actual files themselves and only the remaining unfixed issues are output. Not all problems are fixable using this option, and the option does not work in these situations:
-
-1. This option throws an error when code is piped to ESLint.
-1. This option has no effect on code that uses a processor, unless the processor opts into allowing autofixes.
-
-If you want to fix code from `stdin` or otherwise want to get the fixes without actually writing them to the file, use the [`--fix-dry-run`](#--fix-dry-run) option.
-
-#### `--fix-dry-run`
-
-This option has the same effect as `--fix` with one difference: the fixes are not saved to the file system. This makes it possible to fix code from `stdin` (when used with the `--stdin` flag).
-
-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:
-
-```shell
-getSomeText | npx eslint --stdin --fix-dry-run --format=json
-```
-
-This flag can be useful for integrations (e.g. editor plugins) which need to autofix text from the command line without saving it to the filesystem.
-
-#### `--fix-type`
-
-This option allows you to specify the type of fixes to apply when using either `--fix` or `--fix-dry-run`. The four types of fixes are:
-
-1. `problem` - fix potential errors in the code
-1. `suggestion` - apply fixes to the code that improve it
-1. `layout` - apply fixes that do not change the program structure (AST)
-1. `directive` - apply fixes to inline directives such as `// eslint-disable`
-
-You can specify one or more fix type on the command line. Here are some examples:
-
-```shell
-npx eslint --fix --fix-type suggestion .
-npx eslint --fix --fix-type suggestion --fix-type problem .
-npx eslint --fix --fix-type suggestion,layout .
-```
-
-This option is helpful if you are using another program to format your code but you would still like ESLint to apply other types of fixes.
-
-### Ignoring files
-
-#### `--ignore-path`
-
-This option allows you to specify the file to use as your `.eslintignore`. By default, ESLint looks in the current working directory for `.eslintignore`. You can override this behavior by providing a path to a different file.
-
-Example:
-
-```shell
-npx eslint --ignore-path tmp/.eslintignore file.js
-npx eslint --ignore-path .gitignore file.js
-```
-
-#### `--no-ignore`
-
-Disables excluding of files from `.eslintignore`, `--ignore-path`, `--ignore-pattern`, and `ignorePatterns` property in config files.
-
-Example:
-
-```shell
-npx eslint --no-ignore file.js
-```
-
-#### `--ignore-pattern`
-
-This option allows you to specify patterns of files to ignore (in addition to those in `.eslintignore`). You can repeat the option to provide multiple patterns. The supported syntax is the same as for `.eslintignore` [files](configuring/ignoring-code#the-eslintignore-file), which use the same patterns as the `.gitignore` [specification](https://git-scm.com/docs/gitignore). You should quote your patterns in order to avoid shell interpretation of glob patterns.
-
-Example:
-
-```shell
-npx eslint --ignore-pattern '/lib/' --ignore-pattern '/src/vendor/*' .
-```
-
-### Using stdin
-
-#### `--stdin`
-
-This option tells ESLint to read and lint source code from STDIN instead of from files. You can use this to pipe code to ESLint.
-
-Example:
-
-```shell
-cat myfile.js | npx eslint --stdin
-```
-
-#### `--stdin-filename`
-
-This option allows you to specify a filename to process STDIN as. This is useful when processing files from STDIN and you have rules which depend on the filename.
-
-Example
-
-```shell
-cat myfile.js | npx eslint --stdin --stdin-filename=myfile.js
-```
-
-### Handling warnings
-
-#### `--quiet`
-
-This option allows you to disable reporting on warnings. If you enable this option, only errors are reported by ESLint.
-
-Example:
-
-```shell
-npx eslint --quiet file.js
-```
-
-#### `--max-warnings`
-
-This option allows you to specify a warning threshold, which can be used to force ESLint to exit with an error status if there are too many warning-level rule violations in your project.
-
-Normally, if ESLint runs and finds no errors (only warnings), it will exit with a success exit status. However, if `--max-warnings` is specified and the total warning count is greater than the specified threshold, ESLint will exit with an error status. Specifying a threshold of `-1` or omitting this option will prevent this behavior.
-
-Example:
-
-```shell
-npx eslint --max-warnings 10 file.js
-```
-
-### Output
-
-#### `-o`, `--output-file`
-
-Enable report to be written to a file.
-
-Example:
-
-```shell
-npx eslint -o ./test/test.html
-```
-
-When specified, the given format is output into the provided file name.
-
-#### `-f`, `--format`
-
-This option specifies the output format for the console. Possible formats are:
-
-* [checkstyle](formatters/#checkstyle)
-* [compact](formatters/#compact)
-* [html](formatters/#html)
-* [jslint-xml](formatters/#jslint-xml)
-* [json](formatters/#json)
-* [junit](formatters/#junit)
-* [stylish](formatters/#stylish) (the default)
-* [tap](formatters/#tap)
-* [unix](formatters/#unix)
-* [visualstudio](formatters/#visualstudio)
-
-Example:
-
-```shell
-npx eslint -f compact file.js
-```
-
-You can also use a custom formatter from the command line by specifying a path to the custom formatter file.
-
-Example:
-
-```shell
-npx eslint -f ./customformat.js file.js
-```
-
-An npm-installed formatter is resolved with or without `eslint-formatter-` prefix.
-
-Example:
-
-```shell
-npm install eslint-formatter-pretty
-
-npx eslint -f pretty file.js
-
-// equivalent:
-npx eslint -f eslint-formatter-pretty file.js
-```
-
-When specified, the given format is output to the console. If you'd like to save that output into a file, you can do so on the command line like so:
-
-```shell
-npx eslint -f compact file.js > results.txt
-```
-
-This saves the output into the `results.txt` file.
-
-#### `--color`, `--no-color`
-
-This option forces the enabling/disabling of colorized output. You can use this to override the default behavior, which is to enable colorized output unless no TTY is detected, such as when piping `eslint` through `cat` or `less`.
-
-Examples:
-
-```shell
-npx eslint --color file.js | cat
-npx eslint --no-color file.js
-```
-
-### Inline configuration comments
-
-#### `--no-inline-config`
-
-This option prevents inline comments like `/*eslint-disable*/` or
-`/*global foo*/` from having any effect. This allows you to set an ESLint
-config without files modifying it. All inline config comments are ignored, e.g.:
-
-* `/*eslint-disable*/`
-* `/*eslint-enable*/`
-* `/*global*/`
-* `/*eslint*/`
-* `/*eslint-env*/`
-* `// eslint-disable-line`
-* `// eslint-disable-next-line`
-
-Example:
-
-```shell
-npx eslint --no-inline-config file.js
-```
-
-#### `--report-unused-disable-directives`
-
-This option causes ESLint to report directive comments like `// eslint-disable-line` when no errors would have been reported on that line anyway. This can be useful to prevent future errors from unexpectedly being suppressed, by cleaning up old `eslint-disable` comments which are no longer applicable.
-
-**Warning**: When using this option, it is possible that new errors will start being reported whenever ESLint or custom rules are upgraded. For example, suppose a rule has a bug that causes it to report a false positive, and an `eslint-disable` comment is added to suppress the incorrect report. If the bug is then fixed in a patch release of ESLint, the `eslint-disable` comment will become unused since ESLint is no longer generating an incorrect report. This will result in a new reported error for the unused directive if the `report-unused-disable-directives` option is used.
-
-Example:
-
-```shell
-npx eslint --report-unused-disable-directives file.js
-```
-
-### Caching
-
-#### `--cache`
-
-Store the info about processed files in order to only operate on the changed ones. The cache is stored in `.eslintcache` by default. Enabling this option can dramatically improve ESLint's running time by ensuring that only changed files are linted.
-
-**Note:** If you run ESLint with `--cache` and then run ESLint without `--cache`, the `.eslintcache` file will be deleted. This is necessary because the results of the lint might change and make `.eslintcache` invalid. If you want to control when the cache file is deleted, then use `--cache-location` to specify an alternate location for the cache file.
-
-**Note:** Autofixed files are not placed in the cache. Subsequent linting that does not trigger an autofix will place it in the cache.
-
-#### `--cache-file`
-
-Path to the cache file. If none specified `.eslintcache` will be used. The file will be created in the directory where the `eslint` command is executed. **Deprecated**: Use `--cache-location` instead.
-
-#### `--cache-location`
-
-Path to the cache location. Can be a file or a directory. If no location is specified, `.eslintcache` will be used. In that case, the file will be created in the directory where the `eslint` command is executed.
-
-If a directory is specified, a cache file will be created inside the specified folder. The name of the file will be based on the hash of the current working directory (CWD). e.g.: `.cache_hashOfCWD`
-
-**Important note:** If the directory for the cache does not exist make sure you add a trailing `/` on \*nix systems or `\` in windows. Otherwise the path will be assumed to be a file.
-
-Example:
-
-```shell
-npx eslint "src/**/*.js" --cache --cache-location "/Users/user/.eslintcache/"
-```
-
-#### `--cache-strategy`
-
-Strategy for the cache to use for detecting changed files. Can be either `metadata` or `content`. If no strategy is specified, `metadata` will be used.
-
-The `content` strategy can be useful in cases where the modification time of your files change even if their contents have not. For example, this can happen during git operations like git clone because git does not track file modification time.
-
-Example:
-
-```shell
-npx eslint "src/**/*.js" --cache --cache-strategy content
-```
-
-### Miscellaneous
-
-#### `--init`
-
-This option will run `npm init @eslint/config` to start config initialization wizard. It's designed to help new users quickly create .eslintrc file by answering a few questions, choosing a popular style guide.
-
-The resulting configuration file will be created in the current directory.
-
-#### `--env-info`
-
-This option outputs information about the execution environment, including the version of Node, npm, and local and global installations of ESLint. The ESLint team may ask for this information to help solve bugs.
-
-#### `--no-error-on-unmatched-pattern`
-
-This option prevents errors when a quoted glob pattern or `--ext` is unmatched. This will not prevent errors when your shell can't match a glob.
-
-#### `--exit-on-fatal-error`
-
-This option causes ESLint to exit with exit code 2 if one or more fatal parsing errors occur. Without this option, fatal parsing errors are reported as rule violations.
-
-#### `--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.
-Add this flag to an ESLint command line invocation in order to get extra debug information as the command is run (e.g. `npx eslint --debug test.js` and `npx eslint test.js --debug` are equivalent)
-
-#### `-h`, `--help`
-
-This option outputs the help menu, displaying all of the available options. All other options are ignored when this is present.
-
-#### `-v`, `--version`
-
-This option outputs the current ESLint version onto the console. All other options are ignored when this is present.
-
-#### `--print-config`
-
-This option outputs the configuration to be used for the file passed. When present, no linting is performed and only config-related options are valid.
-
-Example:
-
-```shell
-npx eslint --print-config file.js
-```
-
-## Ignoring files from linting
-
-ESLint supports `.eslintignore` files to exclude files from the linting process when ESLint operates on a directory. Files given as individual CLI arguments will be exempt from exclusion. The `.eslintignore` file is a plain text file containing one pattern per line. It can be located in any of the target directory's ancestors; it will affect files in its containing directory as well as all sub-directories. Here's a simple example of a `.eslintignore` file:
-
-```text
-temp.js
-**/vendor/*.js
-```
-
-A more detailed breakdown of supported patterns and directories ESLint ignores by default can be found in [Ignoring Code](configuring/ignoring-code).
-
-## Exit codes
-
-When linting files, ESLint will exit with one of the following exit codes:
-
-* `0`: Linting was successful and there are no linting errors. If the `--max-warnings` flag is set to `n`, the number of linting warnings is at most `n`.
-* `1`: Linting was successful and there is at least one linting error, or there are more linting warnings than allowed by the `--max-warnings` option.
-* `2`: Linting was unsuccessful due to a configuration problem or an internal error.
+++ /dev/null
----
-title: Configuration Files (New)
-layout: doc
-eleventyNavigation:
- key: configuration files
- parent: configuring
- title: Configuration Files (New)
- order: 1
-
----
-
-::: warning
-This is an experimental feature. To opt-in, place a `eslint.config.js` file in the root of your project. If you are using the API, you can use the configuration system described on this page by using the `FlatESLint` class, the `FlatRuleTester` class, or by setting `configType: "flat"` in the `Linter` class.
-:::
-
-## Configuration File
-
-The ESLint configuration file is named `eslint.config.js` and should be placed in the root directory of your project and export an array of configuration objects. Here's an example:
-
-```js
-export default [
- {
- rules: {
- semi: "error",
- "prefer-const": "error"
- }
- }
-]
-```
-
-Here, the configuration array contains just one configuration object. The configuration object enables two rules: `semi` and `prefer-const`. These rules will be applied to all of the files ESLint processes using this config file.
-
-## Configuration Objects
-
-Each configuration object contains all of the information ESLint needs to execute on a set of files. Each configuration object is made up of these properties:
-
-* `files` - An array of glob patterns indicating the files that the configuration object should apply to. If not specified, the configuration object applies to all files.
-* `ignores` - An array of glob patterns indicating the files that the configuration object should not apply to. If not specified, the configuration object applies to all files matched by `files`.
-* `languageOptions` - An object containing settings related to how JavaScript is configured for linting.
- * `ecmaVersion` - The version of ECMAScript to support. May be any year (i.e., `2022`) or version (i.e., `5`). Set to `"latest"` for the most recent supported version. (default: `"latest"`)
- * `sourceType` - The type of JavaScript source code. Possible values are `"script"` for traditional script files, `"module"` for ECMAScript modules (ESM), and `"commonjs"` for CommonJS files. (default: `"module"` for `.js` and `.mjs` files; `"commonjs"` for `.cjs` files)
- * `globals` - An object specifying additional objects that should be added to the global scope during linting.
- * `parser` - Either an object containing a `parse()` method or a string indicating the name of a parser inside of a plugin (i.e., `"pluginName/parserName"`). (default: `"@/espree"`)
- * `parserOptions` - An object specifying additional options that are passed directly to the `parser()` method on the parser. The available options are parser-dependent.
-* `linterOptions` - An object containing settings related to the linting process.
- * `noInlineConfig` - A Boolean value indicating if inline configuration is allowed.
- * `reportUnusedDisableDirectives` - A Boolean value indicating if unused disable directives should be tracked and reported.
-* `processor` - Either an object containing `preprocess()` and `postprocess()` methods or a string indicating the name of a processor inside of a plugin (i.e., `"pluginName/processorName"`).
-* `plugins` - An object containing a name-value mapping of plugin names to plugin objects. When `files` is specified, these plugins are only available to the matching files.
-* `rules` - An object containing the configured rules. When `files` or `ignores` are specified, these rule configurations are only available to the matching files.
-* `settings` - An object containing name-value pairs of information that should be available to all rules.
-
-### Specifying `files` and `ignores`
-
-::: tip
-Patterns specified in `files` and `ignores` use [`minimatch`](https://www.npmjs.com/package/minimatch) syntax and are evaluated relative to the location of the `eslint.config.js` file.
-:::
-
-You can use a combination of `files` and `ignores` to determine which files should apply the configuration object and which should not. By default, ESLint matches `**/*.js`, `**/*.cjs`, and `**/*.mjs`. Because config objects that don't specify `files` or `ignores` apply to all files that have been matched by any other configuration object, by default config objects will apply to any JavaScript files passed to ESLint. For example:
-
-```js
-export default [
- {
- rules: {
- semi: "error"
- }
- }
-];
-```
-
-With this configuration, the `semi` rule is enabled for all files that match the default files in ESLint. So if you pass `example.js` to ESLint, the `semi` rule will be applied. If you pass a non-JavaScript file, like `example.txt`, the `semi` rule will not be applied because there are no other configuration objects that match that filename. (ESLint will output an error message letting you know that the file was ignored due to missing configuration.)
-
-#### Excluding files with `ignores`
-
-You can limit which files a configuration object applies to by specifying a combination of `files` and `ignores` patterns. For example, you may want certain rules to apply only to files in your `src` directory, like this:
-
-```js
-export default [
- {
- files: ["src/**/*.js"],
- rules: {
- semi: "error"
- }
- }
-];
-```
-
-Here, only the JavaScript files in the `src` directory will have the `semi` rule applied. If you run ESLint on files in another directory, this configuration object will be skipped. By adding `ignores`, you can also remove some of the files in `src` from this configuration object:
-
-```js
-export default [
- {
- files: ["src/**/*.js"],
- ignores: ["**/*.config.js"],
- rules: {
- semi: "error"
- }
- }
-];
-```
-
-This configuration object matches all JavaScript files in the `src` directory except those that end with `.config.js`. You can also use negation patterns in `ignores` to exclude files from the ignore patterns, such as:
-
-```js
-export default [
- {
- files: ["src/**/*.js"],
- ignores: ["**/*.config.js", "!**/eslint.config.js"],
- rules: {
- semi: "error"
- }
- }
-];
-```
-
-Here, the configuration object excludes files ending with `.config.js` except for `eslint.config.js`. That file will still have `semi` applied.
-
-If `ignores` is used without `files` and any other setting, then the configuration object applies to all files except the ones specified in `ignores`, for example:
-
-```js
-export default [
- {
- ignores: ["**/*.config.js"],
- rules: {
- semi: "error"
- }
- }
-];
-```
-
-This configuration object applies to all files except those ending with `.config.js`. Effectively, this is like having `files` set to `**/*`. In general, it's a good idea to always include `files` if you are specifying `ignores`.
-
-#### Globally ignoring files with `ignores`
-
-If `ignores` is used without any other keys in the configuration object, then the patterns act as additional global ignores, similar to those found in `.eslintignore`. Here's an example:
-
-```js
-export default [
- {
- ignores: [".config/*"]
- }
-];
-```
-
-This configuration specifies that all of the files in the `.config` directory should be ignored. This pattern is added after the patterns found in `.eslintignore`.
-
-#### Cascading configuration objects
-
-When more than one configuration object matches a given filename, the configuration objects are merged with later objects overriding previous objects when there is a conflict. For example:
-
-```js
-export default [
- {
- files: ["**/*.js"],
- languageOptions: {
- globals: {
- MY_CUSTOM_GLOBAL: "readonly"
- }
- }
- },
- {
- files: ["tests/**/*.js"],
- languageOptions: {
- globals: {
- it: "readonly",
- describe: "readonly"
- }
- }
- }
-];
-```
-
-Using this configuration, all JavaScript files define a custom global object defined called `MY_CUSTOM_GLOBAL` while those JavaScript files in the `tests` directory have `it` and `describe` defined as global objects in addition to `MY_CUSTOM_GLOBAL`. For any JavaScript file in the tests directory, both configuration objects are applied, so `languageOptions.globals` are merged to create a final result.
-
-### Configuring linter options
-
-Options specific to the linting process can be configured using the `linterOptions` object. These effect how linting proceeds and does not affect how the source code of the file is interpreted.
-
-#### Disabling inline configuration
-
-Inline configuration is implemented using an `/*eslint*/` comment, such as `/*eslint semi: error*/`. You can disallow inline configuration by setting `noInlineConfig` to `true`. When enabled, all inline configuration is ignored. Here's an example:
-
-```js
-export default [
- {
- files: ["**/*.js"],
- linterOptions: {
- noInlineConfig: true
- }
- }
-];
-```
-
-#### Reporting unused disable directives
-
-Disable directives such as `/*eslint-disable*/` and `/*eslint-disable-next-line*/` are used to disable ESLint rules around certain portions of code. As code changes, it's possible for these directives to no longer be needed because the code has changed in such a way that the rule will no longer be triggered. You can enable reporting of these unused disable directives by setting the `reportUnusedDisableDirectives` option to `true`, as in this example:
-
-```js
-export default [
- {
- files: ["**/*.js"],
- linterOptions: {
- reportUnusedDisableDirectives: true
- }
- }
-];
-```
-
-By default, unused disable directives are reported as warnings. You can change this setting using the `--report-unused-disable-directives` command line option.
-
-### Configuring language options
-
-Options specific to how ESLint evaluates your JavaScript code can be configured using the `languageOptions` object.
-
-#### Configuring the JavaScript version
-
-To configure the version of JavaScript (ECMAScript) that ESLint uses to evaluate your JavaScript, use the `ecmaVersion` property. This property determines which global variables and syntax are valid in your code and can be set to the version number (such as `6`), the year number (such as `2022`), or `"latest"` (for the most recent version that ESLint supports). By default, `ecmaVersion` is set to `"latest"` and it's recommended to keep this default unless you need to ensure that your JavaScript code is evaluated as an older version. For example, some older runtimes might only allow ECMAScript 5, in which case you can configure ESLint like this:
-
-```js
-export default [
- {
- files: ["**/*.js"],
- languageOptions: {
- ecmaVersion: 5
- }
- }
-];
-```
-
-#### Configuring the JavaScript source type
-
-ESLint can evaluate your code in one of three ways:
-
-1. ECMAScript module (ESM) - Your code has a module scope and is run in strict mode.
-1. CommonJS - Your code has a top-level function scope and runs in nonstrict mode.
-1. Script - Your code has a shared global scope and runs in nonstrict mode.
-
-You can specify which of these modes your code is intended to run in by specifying the `sourceType` property. This property can be set to `"module"`, `"commonjs"`, or `"script"`. By default, `sourceType` is set to `"module"` for `.js` and `.mjs` files and is set to `"commonjs"` for `.cjs` files. Here's an example:
-
-```js
-export default [
- {
- files: ["**/*.js"],
- languageOptions: {
- sourceType: "script"
- }
- }
-];
-```
-
-#### Configuring a custom parser and its options
-
-In many cases, you can use the default parser that ESLint ships with for parsing your JavaScript code. You can optionally override the default parser by using the `parser` property. The `parser` property can be either a string in the format `"pluginName/parserName"` (indicating to retrieve the parser from a plugin) or an object containing either a `parse()` method or a `parseForESLint()` method. For example, you can use the [`@babel/eslint-parser`](https://www.npmjs.com/package/@babel/eslint-parser) package to allow ESLint to parse experimental syntax:
-
-```js
-import babelParser from "@babel/eslint-parser";
-
-export default [
- {
- files: ["**/*.js", "**/*.mjs"],
- languageOptions: {
- parser: babelParser
- }
- }
-];
-```
-
-This configuration ensures that the Babel parser, rather than the default, will be used to parse all files ending with `.js` and `.mjs`.
-
-You can also pass options directly to the custom parser by using the `parserOptions` property. This property is an object whose name-value pairs are specific to the parser that you are using. For the Babel parser, you might pass in options like this:
-
-```js
-import babelParser from "@babel/eslint-parser";
-
-export default [
- {
- files: ["**/*.js", "**/*.mjs"],
- languageOptions: {
- parser: babelParser,
- parserOptions: {
- requireConfigFile: false,
- babelOptions: {
- babelrc: false,
- configFile: false,
- // your babel options
- presets: ["@babel/preset-env"],
- }
- }
- }
- }
-];
-```
-
-#### Configuring global variables
-
-To configure global variables inside of a configuration object, set the `globals` configuration property to an object containing keys named for each of the global variables you want to use. For each global variable key, set the corresponding value equal to `"writable"` to allow the variable to be overwritten or `"readonly"` to disallow overwriting. For example:
-
-```js
-export default [
- {
- files: ["**/*.js"],
- languageOptions: {
- globals: {
- var1: "writable",
- var2: "readonly"
- }
- }
- }
-];
-```
-
-These examples allow `var1` to be overwritten in your code, but disallow it for `var2`.
-
-Globals can be disabled with the string `"off"`. For example, in an environment where most ES2015 globals are available but `Promise` is unavailable, you might use this config:
-
-```js
-export default [
- {
- languageOptions: {
- globals: {
- Promise: "off"
- }
- }
- }
-];
-```
-
-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.
-
-### Using plugins in your configuration
-
-Plugins are used to share rules, processors, configurations, parsers, and more across ESLint projects. Plugins are specified in a configuration object using the `plugins` key, which is an object where the name of the plugin is the property name and the value is the plugin object itself. Here's an example:
-
-```js
-import jsdoc from "eslint-plugin-jsdoc";
-
-export default [
- {
- files: ["**/*.js"],
- plugins: {
- jsdoc: jsdoc
- }
- rules: {
- "jsdoc/require-description": "error",
- "jsdoc/check-values": "error"
- }
- }
-];
-```
-
-In this configuration, the JSDoc plugin is defined to have the name `jsdoc`. The prefix `jsdoc/` in each rule name indicates that the rule is coming from the plugin with that name rather than from ESLint itself.
-
-Because the name of the plugin and the plugin object are both `jsdoc`, you can also shorten the configuration to this:
-
-```js
-import jsdoc from "eslint-plugin-jsdoc";
-
-export default [
- {
- files: ["**/*.js"],
- plugins: {
- jsdoc
- }
- rules: {
- "jsdoc/require-description": "error",
- "jsdoc/check-values": "error"
- }
- }
-];
-```
-
-While this is the most common convention, you don't need to use the same name that the plugin prescribes. You can specify any prefix that you'd like, such as:
-
-```js
-import jsdoc from "eslint-plugin-jsdoc";
-
-export default [
- {
- files: ["**/*.js"],
- plugins: {
- jsd: jsdoc
- }
- rules: {
- "jsd/require-description": "error",
- "jsd/check-values": "error"
- }
- }
-];
-```
-
-This configuration object uses `jsd` as the prefix plugin instead of `jsdoc`.
-
-### Using processors
-
-Processors allow ESLint to transform text into pieces of code that ESLint can lint. You can specify the processor to use for a given file type by defining a `processor` property that contains either the processor name in the format `"pluginName/processorName"` to reference a processor in a plugin or an object containing both a `preprocess()` and a `postprocess()` method. For example, to extract JavaScript code blocks from a Markdown file, you might add this to your configuration:
-
-```js
-import markdown from "eslint-plugin-markdown";
-
-export default [
- {
- files: ["**/*.md"],
- plugins: {
- markdown
- },
- processor: "markdown/markdown"
- settings: {
- sharedData: "Hello"
- }
- }
-];
-```
-
-This configuration object specifies that there is a processor called `"markdown"` contained in the plugin named `"markdown"` and will apply the processor to all files ending with `.md`.
-
-Processors may make named code blocks that function as filenames in configuration objects, such as `0.js` and `1.js`. ESLint handles such a named code block as a child of the original file. You can specify additional configuration objects for named code blocks. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files.
-
-```js
-import markdown from "eslint-plugin-markdown";
-
-export default [
- {
- files: ["**/*.md"],
- plugins: {
- markdown
- },
- processor: "markdown/markdown"
- settings: {
- sharedData: "Hello"
- }
- },
-
- // applies only to code blocks
- {
- files: ["**/*.md/*.js"],
- rules: {
- strict: "off"
- }
- }
-];
-```
-
-### Configuring rules
-
-You can configure any number of rules in a configuration object by add a `rules` property containing an object with your rule configurations. The names in this object are the names of the rules and the values are the configurations for each of those rules. Here's an example:
-
-```js
-export default [
- {
- rules: {
- semi: "error"
- }
- }
-];
-```
-
-This configuration object specifies that the [`semi`](/docs/latest/rules/semi) rule should be enabled with a severity of `"error"`. You can also provide options to a rule by specifying an array where the first item is the severity and each item after that is an option for the rule. For example, you can switch the `semi` rule to disallow semicolons by passing `"never"` as an option:
-
-```js
-export default [
- {
- rules: {
- semi: ["error", "never"]
- }
- }
-];
-```
-
-Each rule specifies its own options and can be any valid JSON data type. Please check the documentation for the rule you want to configure for more information about its available options.
-
-#### Rule severities
-
-There are three possible severities you can specify for a rule
-
-* `"error"` (or `2`) - the reported problem should be treated as an error. When using the ESLint CLI, errors cause the CLI to exit with a nonzero code.
-* `"warn"` (or `1`) - the reported problem should be treated as a warning. When using the ESLint CLI, warnings are reported but do not change the exit code. If only errors are reported, the exit code will be 0.
-* `"off"` (or `0`) - the rule should be turned off completely.
-
-#### Rule configuration cascade
-
-When more than one configuration object specifies the same rule, the rule configuration is merged with the later object taking precedence over any previous objects. For example:
-
-```js
-export default [
- {
- rules: {
- semi: ["error", "never"]
- }
- },
- {
- rules: {
- semi: ["warn", "always"]
- }
- }
-];
-```
-
-Using this configuration, the final rule configuration for `semi` is `["warn", "always"]` because it appears last in the array. The array indicates that the configuration is for the severity and any options. You can change just the severity by defining only a string or number, as in this example:
-
-```js
-export default [
- {
- rules: {
- semi: ["error", "never"]
- }
- },
- {
- rules: {
- semi: "warn"
- }
- }
-];
-```
-
-Here, the second configuration object only overrides the severity, so the final configuration for `semi` is `["warn", "never"]`.
-
-### Configuring shared settings
-
-ESLint supports adding shared settings into configuration files. Plugins use `settings` to specify information that should be shared across all of its rules. You can add a `settings` object to a configuration object and it will be supplied to every rule being executed. This may be useful if you are adding custom rules and want them to have access to the same information. Here's an example:
-
-```js
-export default [
- {
- settings: {
- sharedData: "Hello"
- }
- }
-];
-```
-
-### Using predefined configurations
-
-ESLint has two predefined configurations:
-
-* `eslint:recommended` - enables the rules that ESLint recommends everyone use to avoid potential errors
-* `eslint:all` - enables all of the rules shipped with ESLint
-
-To include these predefined configurations, you can insert the string values into the returned array and then make any modifications to other properties in subsequent configuration objects:
-
-```js
-export default [
- "eslint:recommended",
- {
- rules: {
- semi: ["warn", "always"]
- }
- }
-];
-```
-
-Here, the `eslint:recommended` predefined configuration is applied first and then another configuration object adds the desired configuration for `semi`.
-
-## Configuration File Resolution
-
-When ESLint is run on the command line, it first checks the current working directory for `eslint.config.js`, and if not found, will look to the next parent directory for the file. This search continues until either the file is found or the root directory is reached.
-
-You can prevent this search for `eslint.config.js` by using the `-c` or `--config--file` option on the command line to specify an alternate configuration file, such as:
-
-```shell
-npx eslint -c some-other-file.js **/*.js
-```
-
-In this case, ESLint will not search for `eslint.config.js` and will instead use `some-other-file.js`.
-
-Each configuration file exports one or more configuration object. A configuration object
+++ /dev/null
----
-title: Configuration Files
-layout: doc
-eleventyNavigation:
- key: configuration files
- parent: configuring
- title: Configuration Files
- order: 1
-
----
-
-## Configuration File Formats
-
-ESLint supports configuration files in several formats:
-
-* **JavaScript** - use `.eslintrc.js` and export an object containing your configuration.
-* **JavaScript (ESM)** - use `.eslintrc.cjs` when running ESLint in JavaScript packages that specify `"type":"module"` in their `package.json`. Note that ESLint does not support ESM configuration at this time.
-* **YAML** - use `.eslintrc.yaml` or `.eslintrc.yml` to define the configuration structure.
-* **JSON** - use `.eslintrc.json` to define the configuration structure. ESLint's JSON files also allow JavaScript-style comments.
-* **package.json** - create an `eslintConfig` property in your `package.json` file and define your configuration there.
-
-If there are multiple configuration files in the same directory, ESLint will only use one. The priority order is as follows:
-
-1. `.eslintrc.js`
-1. `.eslintrc.cjs`
-1. `.eslintrc.yaml`
-1. `.eslintrc.yml`
-1. `.eslintrc.json`
-1. `package.json`
-
-## Using Configuration Files
-
-There are two ways to use configuration files.
-
-The first way to use configuration files is via `.eslintrc.*` and `package.json` files. ESLint will automatically look for them in the directory of the file to be linted, and in successive parent directories all the way up to the root directory of the filesystem (`/`), the home directory of the current user (`~/`), or when `root: true` is specified. See [Cascading and Hierarchy](#cascading-and-hierarchy) below for more details on this. Configuration files can be useful when you want different configurations for different parts of a project or when you want others to be able to use ESLint directly without needing to remember to pass in the configuration file.
-
-The second way to use configuration files is to save the file wherever you would like and pass its location to the CLI using the `--config` option, such as:
-
-```shell
-eslint -c myconfig.json myfiletotest.js
-```
-
-If you are using one configuration file and want ESLint to ignore any `.eslintrc.*` files, make sure to use [`--no-eslintrc`](https://eslint.org/docs/user-guide/command-line-interface#--no-eslintrc) along with the [`-c`](https://eslint.org/docs/user-guide/command-line-interface#-c---config) flag.
-
-Here's an example JSON configuration file that uses the `typescript-eslint` parser to support TypeScript syntax:
-
-```json
-{
- "root": true,
- "extends": [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended"
- ],
- "parser": "@typescript-eslint/parser",
- "parserOptions": { "project": ["./tsconfig.json"] },
- "plugins": [
- "@typescript-eslint"
- ],
- "rules": {
- "@typescript-eslint/strict-boolean-expressions": [
- 2,
- {
- "allowString" : false,
- "allowNumber" : false
- }
- ]
- },
- "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"]
-}
-```
-
-### Comments in configuration files
-
-Both the JSON and YAML configuration file formats support comments (package.json files should not include them). You can use JavaScript-style comments for JSON files and YAML-style comments for YAML files. ESLint safely ignores comments in configuration files. This allows your configuration files to be more human-friendly.
-
-For JavaScript-style comments:
-
-```js
-{
- "env": {
- "browser": true
- },
- "rules": {
- // Override our default settings just for this directory
- "eqeqeq": "warn",
- "strict": "off"
- }
-}
-```
-
-For YAML-style comments:
-
-```yaml
-env:
- browser: true
-rules:
- # Override default settings
- eqeqeq: warn
- strict: off
-```
-
-## Adding Shared Settings
-
-ESLint supports adding shared settings into configuration files. Plugins use `settings` to specify information that should be shared across all of its rules. You can add `settings` object to ESLint configuration file and it will be supplied to every rule being executed. This may be useful if you are adding custom rules and want them to have access to the same information and be easily configurable.
-
-In JSON:
-
-```json
-{
- "settings": {
- "sharedData": "Hello"
- }
-}
-```
-
-And in YAML:
-
-```yaml
----
- settings:
- sharedData: "Hello"
-```
-
-## Cascading and Hierarchy
-
-When using `.eslintrc.*` and `package.json` files for configuration, you can take advantage of configuration cascading. Suppose you have the following structure:
-
-```text
-your-project
-├── .eslintrc.json
-├── lib
-│ └── source.js
-└─┬ tests
- ├── .eslintrc.json
- └── test.js
-```
-
-The configuration cascade works based on the location of the file being linted. If there is a `.eslintrc` file in the same directory as the file being linted, then that configuration takes precedence. ESLint then searches up the directory structure, merging any `.eslintrc` files it finds along the way until reaching either a `.eslintrc` file with `root: true` or the root directory.
-
-In the same way, if there is a `package.json` file in the root directory with an `eslintConfig` field, the configuration it describes will apply to all subdirectories beneath it, but the configuration described by the `.eslintrc` file in the `tests/` directory will override it where there are conflicting specifications.
-
-```text
-your-project
-├── package.json
-├── lib
-│ └── source.js
-└─┬ tests
- ├── .eslintrc.json
- └── test.js
-```
-
-If there is a `.eslintrc` and a `package.json` file found in the same directory, `.eslintrc` will take priority and `package.json` file will not be used.
-
-By default, ESLint will look for configuration files in all parent folders up to the root directory. This can be useful if you want all of your projects to follow a certain convention, but can sometimes lead to unexpected results. To limit ESLint to a specific project, place `"root": true` inside the `.eslintrc.*` file or `eslintConfig` field of the `package.json` file or in the `.eslintrc.*` file at your project's root level. ESLint will stop looking in parent folders once it finds a configuration with `"root": true`.
-
-```js
-{
- "root": true
-}
-```
-
-And in YAML:
-
-```yaml
----
- root: true
-```
-
-For example, consider `projectA` which has `"root": true` set in the `.eslintrc` file in the `lib/` directory. In this case, while linting `main.js`, the configurations within `lib/` will be used, but the `.eslintrc` file in `projectA/` will not.
-
-```text
-home
-└── user
- └── projectA
- ├── .eslintrc.json <- Not used
- └── lib
- ├── .eslintrc.json <- { "root": true }
- └── main.js
-```
-
-The complete configuration hierarchy, from highest to lowest precedence, is as follows:
-
-1. Inline configuration
- 1. `/*eslint-disable*/` and `/*eslint-enable*/`
- 1. `/*global*/`
- 1. `/*eslint*/`
- 1. `/*eslint-env*/`
-1. Command line options (or CLIEngine equivalents):
- 1. `--global`
- 1. `--rule`
- 1. `--env`
- 1. `-c`, `--config`
-1. Project-level configuration:
- 1. `.eslintrc.*` or `package.json` file in the same directory as the linted file
- 1. Continue searching for `.eslintrc.*` and `package.json` files in ancestor directories up to and including the root directory or until a config with `"root": true` is found.
-
-Please note that the [home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir) (`~/`) is also considered a root directory in this context and searching for configuration files will stop there as well. And with the [removal of support for Personal Configuration Files](https://eslint.org/docs/user-guide/configuring/configuration-files#personal-configuration-files-deprecated) from the 8.0.0 release forward, configuration files present in that directory will be ignored.
-
-## Extending Configuration Files
-
-A configuration file, once extended, can inherit all the traits of another configuration file (including rules, plugins, and language options) and modify all the options. As a result, there are three configurations, as defined below:
-
-* Base config: the configuration that is extended.
-* Derived config: the configuration that extends the base configuration.
-* Resulting actual config: the result of merging the derived configuration into the base configuration.
-
-The `extends` property value is either:
-
-* a string that specifies a configuration (either a path to a config file, the name of a shareable config, `eslint:recommended`, or `eslint:all`)
-* an array of strings where each additional configuration extends the preceding configurations
-
-ESLint extends configurations recursively, so a base configuration can also have an `extends` property. Relative paths and shareable config names in an `extends` property are resolved from the location of the config file where they appear.
-
-The `eslint-config-` prefix can be omitted from the configuration name. For example, `airbnb` resolves as `eslint-config-airbnb`.
-
-The `rules` property can do any of the following to extend (or override) the set of rules:
-
-* enable additional rules
-* change an inherited rule's severity without changing its options:
- * Base config: `"eqeqeq": ["error", "allow-null"]`
- * Derived config: `"eqeqeq": "warn"`
- * Resulting actual config: `"eqeqeq": ["warn", "allow-null"]`
-* override options for rules from base configurations:
- * Base config: `"quotes": ["error", "single", "avoid-escape"]`
- * Derived config: `"quotes": ["error", "single"]`
- * Resulting actual config: `"quotes": ["error", "single"]`
-* override options for rules given as object from base configurations:
- * Base config: `"max-lines": ["error", { "max": 200, "skipBlankLines": true, "skipComments": true }]`
- * Derived config: `"max-lines": ["error", { "max": 100 }]`
- * Resulting actual config: `"max-lines": ["error", { "max": 100 }]` where `skipBlankLines` and `skipComments` default to `false`
-
-### Using a shareable configuration package
-
-A [sharable configuration](https://eslint.org/docs/developer-guide/shareable-configs) is an npm package that exports a configuration object. Make sure that you have installed the package in your project root directory, so that ESLint can require it.
-
-The `extends` property value can omit the `eslint-config-` prefix of the package name.
-
-The `npm init @eslint/config` command can create a configuration so you can extend a popular style guide (for example, `eslint-config-standard`).
-
-Example of a configuration file in YAML format:
-
-```yaml
-extends: standard
-rules:
- comma-dangle:
- - error
- - always
- no-empty: warn
-```
-
-### Using `eslint:recommended`
-
-Using `"eslint:recommended"` in the `extends` property enables a subset of core rules that report common problems (these rules are identified with a checkmark (recommended) on the [rules page](https://eslint.org/docs/rules/)).
-
-Here's an example of extending `eslint:recommended` and overriding some of the set configuration options:
-
-Example of a configuration file in JavaScript format:
-
-```js
-module.exports = {
- "extends": "eslint:recommended",
- "rules": {
- // enable additional rules
- "indent": ["error", 4],
- "linebreak-style": ["error", "unix"],
- "quotes": ["error", "double"],
- "semi": ["error", "always"],
-
- // override configuration set by extending "eslint:recommended"
- "no-empty": "warn",
- "no-cond-assign": ["error", "always"],
-
- // disable rules from base configurations
- "for-direction": "off",
- }
-}
-```
-
-### Using a configuration from a plugin
-
-A [plugin](https://eslint.org/docs/developer-guide/working-with-plugins) is an npm package that can add various extensions to ESLint. A plugin can perform numerous functions, including but not limited to adding new rules and exporting [shareable configurations](https://eslint.org/docs/developer-guide/working-with-plugins#configs-in-plugins). Make sure the package has been installed in a directory where ESLint can require it.
-
-The `plugins` [property value](./plugins#configuring-plugins) can omit the `eslint-plugin-` prefix of the package name.
-
-The `extends` property value can consist of:
-
-* `plugin:`
-* the package name (from which you can omit the prefix, for example, `react` is short for `eslint-plugin-react`)
-* `/`
-* the configuration name (for example, `recommended`)
-
-Example of a configuration file in JSON format:
-
-```json
-{
- "plugins": [
- "react"
- ],
- "extends": [
- "eslint:recommended",
- "plugin:react/recommended"
- ],
- "rules": {
- "react/no-set-state": "off"
- }
-}
-```
-
-### Using a configuration file
-
-The `extends` property value can be an absolute or relative path to a base [configuration file](#using-configuration-files). ESLint resolves a relative path to a base configuration file relative to the configuration file that uses it.
-
-Example of a configuration file in JSON format:
-
-```json
-{
- "extends": [
- "./node_modules/coding-standard/eslintDefaults.js",
- "./node_modules/coding-standard/.eslintrc-es6",
- "./node_modules/coding-standard/.eslintrc-jsx"
- ],
- "rules": {
- "eqeqeq": "warn"
- }
-}
-```
-
-### Using `"eslint:all"`
-
-The `extends` property value can be `"eslint:all"` to enable all core rules in the currently installed version of ESLint. The set of core rules can change at any minor or major version of ESLint.
-
-**Important:** This configuration is **not recommended for production use** because it changes with every minor and major version of ESLint. Use it at your own risk.
-
-You might enable all core rules as a shortcut to explore rules and options while you decide on the configuration for a project, especially if you rarely override options or disable rules. The default options for rules are not endorsements by ESLint (for example, the default option for the [`quotes`](https://eslint.org/docs/rules/quotes) rule does not mean double quotes are better than single quotes).
-
-If your configuration extends `eslint:all`, after you upgrade to a newer major or minor version of ESLint, review the reported problems before you use the `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#--fix), so you know if a new fixable rule will make changes to the code.
-
-Example of a configuration file in JavaScript format:
-
-```js
-module.exports = {
- "extends": "eslint:all",
- "rules": {
- // override default options
- "comma-dangle": ["error", "always"],
- "indent": ["error", 2],
- "no-cond-assign": ["error", "always"],
-
- // disable now, but enable in the future
- "one-var": "off", // ["error", "never"]
-
- // disable
- "init-declarations": "off",
- "no-console": "off",
- "no-inline-comments": "off",
- }
-}
-```
-
-## Configuration Based on Glob Patterns
-
-<b>v4.1.0+.</b> Sometimes a more fine-controlled configuration is necessary, for example, if the configuration for files within the same directory has to be different. Therefore you can provide configurations under the `overrides` key that will only apply to files that match specific glob patterns, using the same format you would pass on the command line (e.g., `app/**/*.test.js`).
-
-Glob patterns in overrides use [minimatch syntax](https://github.com/isaacs/minimatch).
-
-### How do overrides work?
-
-It is possible to override settings based on file glob patterns in your configuration by using the `overrides` key. An example of using the `overrides` key is as follows:
-
-In your `.eslintrc.json`:
-
-```json
-{
- "rules": {
- "quotes": ["error", "double"]
- },
-
- "overrides": [
- {
- "files": ["bin/*.js", "lib/*.js"],
- "excludedFiles": "*.test.js",
- "rules": {
- "quotes": ["error", "single"]
- }
- }
- ]
-}
-```
-
-Here is how overrides work in a configuration file:
-
-* The patterns are applied against the file path relative to the directory of the config file. For example, if your config file has the path `/Users/john/workspace/any-project/.eslintrc.js` and the file you want to lint has the path `/Users/john/workspace/any-project/lib/util.js`, then the pattern provided in `.eslintrc.js` will be executed against the relative path `lib/util.js`.
-* Glob pattern overrides have higher precedence than the regular configuration in the same config file. Multiple overrides within the same config are applied in order. That is, the last override block in a config file always has the highest precedence.
-* A glob specific configuration works almost the same as any other ESLint config. Override blocks can contain any configuration options that are valid in a regular config, with the exception of `root` and `ignorePatterns`.
- * A glob specific configuration can have an `extends` setting, but the `root` property in the extended configs is ignored. The `ignorePatterns` property in the extended configs is used only for the files the glob specific configuration matched.
- * Nested `overrides` setting will be applied only if the glob patterns of both of the parent config and the child config matched. This is the same when the extended configs have an `overrides` setting.
-* Multiple glob patterns can be provided within a single override block. A file must match at least one of the supplied patterns for the configuration to apply.
-* Override blocks can also specify patterns to exclude from matches. If a file matches any of the excluded patterns, the configuration won't apply.
-
-### Relative glob patterns
-
-```txt
-project-root
-├── app
-│ ├── lib
-│ │ ├── foo.js
-│ │ ├── fooSpec.js
-│ ├── components
-│ │ ├── bar.js
-│ │ ├── barSpec.js
-│ ├── .eslintrc.json
-├── server
-│ ├── server.js
-│ ├── serverSpec.js
-├── .eslintrc.json
-```
-
-The config in `app/.eslintrc.json` defines the glob pattern `**/*Spec.js`. This pattern is relative to the base directory of `app/.eslintrc.json`. So, this pattern would match `app/lib/fooSpec.js` and `app/components/barSpec.js` but **NOT** `server/serverSpec.js`. If you defined the same pattern in the `.eslintrc.json` file within in the `project-root` folder, it would match all three of the `*Spec` files.
-
-If a config is provided via the `--config` CLI option, the glob patterns in the config are relative to the current working directory rather than the base directory of the given config. For example, if `--config configs/.eslintrc.json` is present, the glob patterns in the config are relative to `.` rather than `./configs`.
-
-### Specifying target files to lint
-
-If you specified directories with CLI (e.g., `eslint lib`), ESLint searches target files in the directory to lint. The target files are `*.js` or the files that match any of `overrides` entries (but exclude entries that are any of `files` end with `*`).
-
-If you specified the [`--ext`](https://eslint.org/docs/user-guide/command-line-interface#ext) command line option along with directories, the target files are only the files that have specified file extensions regardless of `overrides` entries.
-
-## Personal Configuration Files (deprecated)
-
-⚠️ **This feature has been deprecated**. This feature will be removed in the 8.0.0 release. If you want to continue to use personal configuration files, please use the [`--config` CLI option](https://eslint.org/docs/user-guide/command-line-interface#-c---config). For more information regarding this decision, please see [RFC 28](https://github.com/eslint/rfcs/pull/28) and [RFC 32](https://github.com/eslint/rfcs/pull/32).
-
-`~/` refers to [the home directory of the current user on your preferred operating system](https://nodejs.org/api/os.html#os_os_homedir). The personal configuration file being referred to here is `~/.eslintrc.*` file, which is currently handled differently than other configuration files.
-
-### How does ESLint find personal configuration files?
-
-If `eslint` could not find any configuration file in the project, `eslint` loads `~/.eslintrc.*` file.
-
-If `eslint` could find configuration files in the project, `eslint` ignores `~/.eslintrc.*` file even if it's in an ancestor directory of the project directory.
-
-### How do personal configuration files behave?
-
-`~/.eslintrc.*` files behave similarly to regular configuration files, with some exceptions:
-
-`~/.eslintrc.*` files load shareable configs and custom parsers from `~/node_modules/` – similarly to `require()` – in the user's home directory. Please note that it doesn't load global-installed packages.
-
-`~/.eslintrc.*` files load plugins from `$CWD/node_modules` by default in order to identify plugins uniquely. If you want to use plugins with `~/.eslintrc.*` files, plugins must be installed locally per project. Alternatively, you can use the [`--resolve-plugins-relative-to` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--resolve-plugins-relative-to) to change the location from which ESLint loads plugins.
+++ /dev/null
----
-title: Ignoring Code
-layout: doc
-eleventyNavigation:
- key: ignoring code
- parent: configuring
- title: Ignoring Code
- order: 5
-
----
-
-## `ignorePatterns` in Config Files
-
-You can tell ESLint to ignore specific files and directories using `ignorePatterns` in your config files. `ignorePatterns` patterns follow the same rules as `.eslintignore`. Please see the [the `.eslintignore` file documentation](./ignoring-code#the-eslintignore-file) to learn more.
-
-```json
-{
- "ignorePatterns": ["temp.js", "**/vendor/*.js"],
- "rules": {
- //...
- }
-}
-```
-
-* Glob patterns in `ignorePatterns` are relative to the directory that the config file is placed in.
-* You cannot write `ignorePatterns` property under `overrides` property.
-* Patterns defined in `.eslintignore` take precedence over the `ignorePatterns` property of config files.
-
-If a glob pattern starts with `/`, the pattern is relative to the base directory of the config file. For example, `/foo.js` in `lib/.eslintrc.json` matches to `lib/foo.js` but not `lib/subdir/foo.js`.
-
-If a config is provided via the `--config` CLI option, the ignore patterns that start with `/` in the config are relative to the current working directory rather than the base directory of the given config. For example, if `--config configs/.eslintrc.json` is present, the ignore patterns in the config are relative to `.` rather than `./configs`.
-
-## The `.eslintignore` File
-
-You can tell ESLint to ignore specific files and directories by creating an `.eslintignore` file in your project's root directory. The `.eslintignore` file is a plain text file where each line is a glob pattern indicating which paths should be omitted from linting. For example, the following will omit all JavaScript files:
-
-```text
-**/*.js
-```
-
-When ESLint is run, it looks in the current working directory to find an `.eslintignore` file before determining which files to lint. If this file is found, then those preferences are applied when traversing directories. Only one `.eslintignore` file can be used at a time, so `.eslintignore` files other than the one in the current working directory will not be used.
-
-Globs are matched using [node-ignore](https://github.com/kaelzhang/node-ignore), so a number of features are available:
-
-* Lines beginning with `#` are treated as comments and do not affect the ignore patterns.
-* Paths are relative to the current working directory. This is also true of paths passed in via the `--ignore-pattern` [command](../command-line-interface#--ignore-pattern).
-* Lines preceded by `!` are negated patterns that re-include a pattern that was ignored by an earlier pattern.
-* Ignore patterns behave according to the `.gitignore` [specification](https://git-scm.com/docs/gitignore).
-
-Of particular note is that like `.gitignore` files, all paths used as patterns for both `.eslintignore` and `--ignore-pattern` must use forward slashes as their path separators.
-
-```text
-# Valid
-/root/src/*.js
-
-# Invalid
-\root\src\*.js
-```
-
-Please see [`.gitignore`](https://git-scm.com/docs/gitignore)'s specification for further examples of valid syntax.
-
-In addition to any patterns in the `.eslintignore` file, ESLint always follows a couple of implicit ignore rules even if the `--no-ignore` flag is passed. The implicit rules are as follows:
-
-* `node_modules/` is ignored.
-* dot-files (except for `.eslintrc.*`), as well as dot-folders and their contents, are ignored.
-
-There are also some exceptions to these rules:
-
-* If the path to lint is a glob pattern or directory path and contains a dot-folder, all dot-files and dot-folders will be linted. This includes dot-files and dot-folders that are buried deeper in the directory structure.
-
- For example, `eslint .config/` will lint all dot-folders and dot-files in the `.config` directory, including immediate children as well as children that are deeper in the directory structure.
-
-* If the path to lint is a specific file path and the `--no-ignore` flag has been passed, ESLint will lint the file regardless of the implicit ignore rules.
-
- For example, `eslint .config/my-config-file.js --no-ignore` will cause `my-config-file.js` to be linted. It should be noted that the same command without the `--no-ignore` line will not lint the `my-config-file.js` file.
-
-* Allowlist and denylist rules specified via `--ignore-pattern` or `.eslintignore` are prioritized above implicit ignore rules.
-
- For example, in this scenario, `.build/test.js` is the desired file to allowlist. Because all dot-folders and their children are ignored by default, `.build` must first be allowlisted so that eslint becomes aware of its children. Then, `.build/test.js` must be explicitly allowlisted, while the rest of the content is denylisted. This is done with the following `.eslintignore` file:
-
- ```text
- # Allowlist 'test.js' in the '.build' folder
- # But do not allow anything else in the '.build' folder to be linted
- !.build
- .build/*
- !.build/test.js
- ```
-
- The following `--ignore-pattern` is also equivalent:
-
- ```shell
- eslint --ignore-pattern '!.build' --ignore-pattern '.build/*' --ignore-pattern '!.build/test.js' parent-folder/
- ```
-
-## Using an Alternate File
-
-If you'd prefer to use a different file than the `.eslintignore` in the current working directory, you can specify it on the command line using the `--ignore-path` option. For example, you can use `.jshintignore` file because it has the same format:
-
-```shell
-eslint --ignore-path .jshintignore file.js
-```
-
-You can also use your `.gitignore` file:
-
-```shell
-eslint --ignore-path .gitignore file.js
-```
-
-Any file that follows the standard ignore file format can be used. Keep in mind that specifying `--ignore-path` means that any existing `.eslintignore` file will not be used. Note that globbing rules in `.eslintignore` follow those of `.gitignore`.
-
-## Using eslintIgnore in package.json
-
-If an `.eslintignore` file is not found and an alternate file is not specified, ESLint will look in package.json for an `eslintIgnore` key to check for files to ignore.
-
-```json
-{
- "name": "mypackage",
- "version": "0.0.1",
- "eslintConfig": {
- "env": {
- "browser": true,
- "node": true
- }
- },
- "eslintIgnore": ["hello.js", "world.js"]
-}
-```
-
-## Ignored File Warnings
-
-When you pass directories to ESLint, files and directories are silently ignored. If you pass a specific file to ESLint, then you will see a warning indicating that the file was skipped. For example, suppose you have an `.eslintignore` file that looks like this:
-
-```text
-foo.js
-```
-
-And then you run:
-
-```shell
-eslint foo.js
-```
-
-You'll see this warning:
-
-```text
-foo.js
- 0:0 warning File ignored because of a matching ignore pattern. Use "--no-ignore" to override.
-
-✖ 1 problem (0 errors, 1 warning)
-```
-
-This message occurs because ESLint is unsure if you wanted to actually lint the file or not. As the message indicates, you can use `--no-ignore` to omit using the ignore rules.
-
-Consider another scenario where you may want to run ESLint on a specific dot-file or dot-folder, but have forgotten to specifically allow those files in your `.eslintignore` file. You would run something like this:
-
-```shell
-eslint .config/foo.js
-```
-
-You would see this warning:
-
-```text
-.config/foo.js
- 0:0 warning File ignored by default. Use a negated ignore pattern (like "--ignore-pattern '!<relative/path/to/filename>'") to override
-
-✖ 1 problem (0 errors, 1 warning)
-```
-
-This message occurs because, normally, this file would be ignored by ESLint's implicit ignore rules (as mentioned above). A negated ignore rule in your `.eslintignore` file would override the implicit rule and reinclude this file for linting. Additionally, in this specific case, `--no-ignore` could be used to lint the file as well.
+++ /dev/null
----
-title: Configuring ESLint
-layout: doc
-eleventyNavigation:
- key: configuring
- parent: user guide
- title: Configuring
- order: 2
-
----
-
-ESLint is designed to be flexible and configurable for your use case. You can turn off every rule and run only with basic syntax validation or mix and match the bundled rules and your custom rules to fit the needs of your project. There are two primary ways to configure ESLint:
-
-1. **Configuration Comments** - use JavaScript comments to embed configuration information directly into a file.
-2. **Configuration Files** - use a JavaScript, JSON, or YAML file to specify configuration information for an entire directory and all of its subdirectories. This can be in the form of a [`.eslintrc.*`](./configuration-files#configuration-file-formats) file or an `eslintConfig` field in a [`package.json`](https://docs.npmjs.com/files/package.json) file, both of which ESLint will look for and read automatically, or you can specify a configuration file on the [command line](../command-line-interface).
-
-Here are some of the options that you can configure in ESLint:
-
-* [**Environments**](./language-options#specifying-environments) - which environments your script is designed to run in. Each environment brings with it a certain set of predefined global variables.
-* [**Globals**](./language-options#specifying-globals) - the additional global variables your script accesses during execution.
-* [**Rules**](rules) - which rules are enabled and at what error level.
-* [**Plugins**](plugins) - which third-party plugins define additional rules, environments, configs, etc. for ESLint to use.
-
-All of these options give you fine-grained control over how ESLint treats your code.
-
-## Table of Contents
-
-[**Configuration Files**](configuration-files)
-
-* [Configuration File Formats](./configuration-files#configuration-file-formats)
-* [Using Configuration Files](./configuration-files#using-configuration-files)
-* [Adding Shared Settings](./configuration-files#adding-shared-settings)
-* [Cascading and Hierarchy](./configuration-files#cascading-and-hierarchy)
-* [Extending Configuration Files](./configuration-files#extending-configuration-files)
-* [Configuration Based on Glob Patterns](./configuration-files#configuration-based-on-glob-patterns)
-* [Personal Configuration Files](./configuration-files#personal-configuration-files-deprecated)
-
-[**Language Options**](language-options)
-
-* [Specifying Environments](./language-options#specifying-environments)
-* [Specifying Globals](./language-options#specifying-globals)
-* [Specifying Parser Options](./language-options#specifying-parser-options)
-
-[**Rules**](rules)
-
-* [Configuring Rules](./rules#configuring-rules)
-* [Disabling Rules](./rules#disabling-rules)
-
-[**Plugins**](plugins)
-
-* [Specifying Parser](./plugins#specifying-parser)
-* [Specifying Processor](./plugins#specifying-processor)
-* [Configuring Plugins](./plugins#configuring-plugins)
-
-[**Ignoring Code**](ignoring-code)
-
-* [`ignorePatterns` in Config Files](./ignoring-code#ignorepatterns-in-config-files)
-* [The `.eslintignore` File](./ignoring-code#the-eslintignore-file)
-* [Using an Alternate File](./ignoring-code#using-an-alternate-file)
-* [Using eslintIgnore in package.json](./ignoring-code#using-eslintignore-in-packagejson)
-* [Ignored File Warnings](./ignoring-code#ignored-file-warnings)
+++ /dev/null
----
-title: Language Options
-layout: doc
-eleventyNavigation:
- key: configuring language options
- parent: configuring
- title: Configuring Language Options
- order: 2
-
----
-
-## Specifying Environments
-
-An environment provides predefined global variables. The available environments are:
-
-* `browser` - browser global variables.
-* `node` - Node.js global variables and Node.js scoping.
-* `commonjs` - CommonJS global variables and CommonJS scoping (use this for browser-only code that uses Browserify/WebPack).
-* `shared-node-browser` - Globals common to both Node.js and Browser.
-* `es6` - enable all ECMAScript 6 features except for modules (this automatically sets the `ecmaVersion` parser option to 6).
-* `es2016` - adds all ECMAScript 2016 globals and automatically sets the `ecmaVersion` parser option to 7.
-* `es2017` - adds all ECMAScript 2017 globals and automatically sets the `ecmaVersion` parser option to 8.
-* `es2018` - adds all ECMAScript 2018 globals and automatically sets the `ecmaVersion` parser option to 9.
-* `es2019` - adds all ECMAScript 2019 globals and automatically sets the `ecmaVersion` parser option to 10.
-* `es2020` - adds all ECMAScript 2020 globals and automatically sets the `ecmaVersion` parser option to 11.
-* `es2021` - adds all ECMAScript 2021 globals and automatically sets the `ecmaVersion` parser option to 12.
-* `es2022` - adds all ECMAScript 2022 globals and automatically sets the `ecmaVersion` parser option to 13.
-* `worker` - web workers global variables.
-* `amd` - defines `require()` and `define()` as global variables as per the [amd](https://github.com/amdjs/amdjs-api/wiki/AMD) spec.
-* `mocha` - adds all of the Mocha testing global variables.
-* `jasmine` - adds all of the Jasmine testing global variables for version 1.3 and 2.0.
-* `jest` - Jest global variables.
-* `phantomjs` - PhantomJS global variables.
-* `protractor` - Protractor global variables.
-* `qunit` - QUnit global variables.
-* `jquery` - jQuery global variables.
-* `prototypejs` - Prototype.js global variables.
-* `shelljs` - ShellJS global variables.
-* `meteor` - Meteor global variables.
-* `mongo` - MongoDB global variables.
-* `applescript` - AppleScript global variables.
-* `nashorn` - Java 8 Nashorn global variables.
-* `serviceworker` - Service Worker global variables.
-* `atomtest` - Atom test helper globals.
-* `embertest` - Ember test helper globals.
-* `webextensions` - WebExtensions globals.
-* `greasemonkey` - GreaseMonkey globals.
-
-These environments are not mutually exclusive, so you can define more than one at a time.
-
-Environments can be specified inside of a file, in configuration files or using the `--env` [command line](../command-line-interface) flag.
-
-### Using configuration comments
-
-To specify environments using a comment inside of your JavaScript file, use the following format:
-
-```js
-/* eslint-env node, mocha */
-```
-
-This enables Node.js and Mocha environments.
-
-### Using configuration files
-
-To specify environments in a configuration file, use the `env` key and specify which environments you want to enable by setting each to `true`. For example, the following enables the browser and Node.js environments:
-
-```json
-{
- "env": {
- "browser": true,
- "node": true
- }
-}
-```
-
-Or in a `package.json` file
-
-```json
-{
- "name": "mypackage",
- "version": "0.0.1",
- "eslintConfig": {
- "env": {
- "browser": true,
- "node": true
- }
- }
-}
-```
-
-And in YAML:
-
-```yaml
----
- env:
- browser: true
- node: true
-```
-
-### Using a plugin
-
-If you want to use an environment from a plugin, be sure to specify the plugin name in the `plugins` array and then use the unprefixed plugin name, followed by a slash, followed by the environment name. For example:
-
-```json
-{
- "plugins": ["example"],
- "env": {
- "example/custom": true
- }
-}
-```
-
-Or in a `package.json` file
-
-```json
-{
- "name": "mypackage",
- "version": "0.0.1",
- "eslintConfig": {
- "plugins": ["example"],
- "env": {
- "example/custom": true
- }
- }
-}
-```
-
-## Specifying Globals
-
-Some of ESLint's core rules rely on knowledge of the global variables available to your code at runtime. Since these can vary greatly between different environments as well as be modified at runtime, ESLint makes no assumptions about what global variables exist in your execution environment. If you would like to use rules that require knowledge of what global variables are available, you can define global variables in your configuration file or by using configuration comments in your source code.
-
-### Using configuration comments
-
-To specify globals using a comment inside of your JavaScript file, use the following format:
-
-```js
-/* global var1, var2 */
-```
-
-This defines two global variables, `var1` and `var2`. If you want to optionally specify that these global variables can be written to (rather than only being read), then you can set each with a `"writable"` flag:
-
-```js
-/* global var1:writable, var2:writable */
-```
-
-### Using configuration files
-
-To configure global variables inside of a configuration file, set the `globals` configuration property to an object containing keys named for each of the global variables you want to use. For each global variable key, set the corresponding value equal to `"writable"` to allow the variable to be overwritten or `"readonly"` to disallow overwriting. For example:
-
-```json
-{
- "globals": {
- "var1": "writable",
- "var2": "readonly"
- }
-}
-```
-
-And in YAML:
-
-```yaml
----
- globals:
- var1: writable
- var2: readonly
-```
-
-These examples allow `var1` to be overwritten in your code, but disallow it for `var2`.
-
-Globals can be disabled with the string `"off"`. For example, in an environment where most ES2015 globals are available but `Promise` is unavailable, you might use this config:
-
-```json
-{
- "env": {
- "es6": true
- },
- "globals": {
- "Promise": "off"
- }
-}
-```
-
-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.
-
-Please note that supporting JSX syntax is not the same as supporting React. React applies specific semantics to JSX syntax that ESLint doesn't recognize. We recommend using [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react) if you are using React and want React semantics.
-By the same token, supporting ES6 syntax is not the same as supporting new ES6 globals (e.g., new types such as
-`Set`).
-For ES6 syntax, use `{ "parserOptions": { "ecmaVersion": 6 } }`; for new ES6 global variables, use `{ "env":
-{ "es6": true } }`. `{ "env": { "es6": true } }` enables ES6 syntax automatically, but `{ "parserOptions": { "ecmaVersion": 6 } }` does not enable ES6 globals automatically.
-
-Parser options are set in your `.eslintrc.*` file by using the `parserOptions` property. The available options are:
-
-* `ecmaVersion` - set to 3, 5 (default), 6, 7, 8, 9, 10, 11, 12, 13, or 14 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), 2022 (same as 13), or 2023 (same as 14) 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)
- * `jsx` - enable [JSX](https://facebook.github.io/jsx/)
-
-Here's an example `.eslintrc.json` file:
-
-```json
-{
- "parserOptions": {
- "ecmaVersion": "latest",
- "sourceType": "module",
- "ecmaFeatures": {
- "jsx": true
- }
- },
- "rules": {
- "semi": "error"
- }
-}
-```
-
-Setting parser options helps ESLint determine what is a parsing error. All language options are `false` by default.
+++ /dev/null
----
-title: Plugins
-layout: doc
-eleventyNavigation:
- key: configuring plugins
- parent: configuring
- title: Configuring Plugins
- order: 4
-
----
-
-## Specifying Parser
-
-By default, ESLint uses [Espree](https://github.com/eslint/espree) as its parser. You can optionally specify that a different parser should be used in your configuration file so long as the parser meets the following requirements:
-
-1. It must be a Node module loadable from the config file where the parser is used. Usually, this means you should install the parser package separately using npm.
-1. It must conform to the [parser interface](../../developer-guide/working-with-custom-parsers).
-
-Note that even with these compatibilities, there are no guarantees that an external parser will work correctly with ESLint and ESLint will not fix bugs related to incompatibilities with other parsers.
-
-To indicate the npm module to use as your parser, specify it using the `parser` option in your `.eslintrc` file. For example, the following specifies to use Esprima instead of Espree:
-
-```json
-{
- "parser": "esprima",
- "rules": {
- "semi": "error"
- }
-}
-```
-
-The following parsers are compatible with ESLint:
-
-* [Esprima](https://www.npmjs.com/package/esprima)
-* [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) - A wrapper around the [Babel](https://babeljs.io) parser that makes it compatible with ESLint.
-* [@typescript-eslint/parser](https://www.npmjs.com/package/@typescript-eslint/parser) - A parser that converts TypeScript into an ESTree-compatible form so it can be used in ESLint.
-
-Note when using a custom parser, the `parserOptions` configuration property is still required for ESLint to work properly with features not in ECMAScript 5 by default. Parsers are all passed `parserOptions` and may or may not use them to determine which features to enable.
-
-## Specifying Processor
-
-Plugins may provide processors. Processors can extract JavaScript code from other kinds of files, then let ESLint lint the JavaScript code or processors can convert JavaScript code in preprocessing for some purpose.
-
-To specify processors in a configuration file, use the `processor` key with the concatenated string of a plugin name and a processor name by a slash. For example, the following enables the processor `a-processor` that the plugin `a-plugin` provided:
-
-```json
-{
- "plugins": ["a-plugin"],
- "processor": "a-plugin/a-processor"
-}
-```
-
-To specify processors for specific kinds of files, use the combination of the `overrides` key and the `processor` key. For example, the following uses the processor `a-plugin/markdown` for `*.md` files.
-
-```json
-{
- "plugins": ["a-plugin"],
- "overrides": [
- {
- "files": ["*.md"],
- "processor": "a-plugin/markdown"
- }
- ]
-}
-```
-
-Processors may make named code blocks such as `0.js` and `1.js`. ESLint handles such a named code block as a child file of the original file. You can specify additional configurations for named code blocks in the `overrides` section of the config. For example, the following disables the `strict` rule for the named code blocks which end with `.js` in markdown files.
-
-```json
-{
- "plugins": ["a-plugin"],
- "overrides": [
- {
- "files": ["*.md"],
- "processor": "a-plugin/markdown"
- },
- {
- "files": ["**/*.md/*.js"],
- "rules": {
- "strict": "off"
- }
- }
- ]
-}
-```
-
-ESLint checks the file path of named code blocks then ignores those if any `overrides` entry didn't match the file path. Be sure to add an `overrides` entry if you want to lint named code blocks other than `*.js`.
-
-## Configuring Plugins
-
-ESLint supports the use of third-party plugins. Before using the plugin, you have to install it using npm.
-
-To configure plugins inside of a configuration file, use the `plugins` key, which contains a list of plugin names. The `eslint-plugin-` prefix can be omitted from the plugin name.
-
-```json
-{
- "plugins": [
- "plugin1",
- "eslint-plugin-plugin2"
- ]
-}
-```
-
-And in YAML:
-
-```yaml
----
- plugins:
- - plugin1
- - eslint-plugin-plugin2
-```
-
-**Notes:**
-
-1. Plugins are resolved relative to the config file. In other words, ESLint will load the plugin as a user would obtain by running `require('eslint-plugin-pluginname')` in the config file.
-2. Plugins in the base configuration (loaded by `extends` setting) are relative to the derived config file. For example, if `./.eslintrc` has `extends: ["foo"]` and the `eslint-config-foo` has `plugins: ["bar"]`, ESLint finds the `eslint-plugin-bar` from `./node_modules/` (rather than `./node_modules/eslint-config-foo/node_modules/`) or ancestor directories. Thus every plugin in the config file and base configurations is resolved uniquely.
-
-### Naming convention
-
-#### Include a plugin
-
-The `eslint-plugin-` prefix can be omitted for non-scoped packages
-
-```js
-{
- // ...
- "plugins": [
- "jquery", // means eslint-plugin-jquery
- ]
- // ...
-}
-```
-
-The same rule does apply to scoped packages:
-
-```js
-{
- // ...
- "plugins": [
- "@jquery/jquery", // means @jquery/eslint-plugin-jquery
- "@foobar" // means @foobar/eslint-plugin
- ]
- // ...
-}
-```
-
-#### Use a plugin
-
-When using rules, environments or configs defined by plugins, they must be referenced following the convention:
-
-* `eslint-plugin-foo` → `foo/a-rule`
-* `@foo/eslint-plugin` → `@foo/a-config`
-* `@foo/eslint-plugin-bar` → `@foo/bar/a-environment`
-
-For example:
-
-```js
-{
- // ...
- "plugins": [
- "jquery", // eslint-plugin-jquery
- "@foo/foo", // @foo/eslint-plugin-foo
- "@bar" // @bar/eslint-plugin
- ],
- "extends": [
- "plugin:@foo/foo/recommended",
- "plugin:@bar/recommended"
- ],
- "rules": {
- "jquery/a-rule": "error",
- "@foo/foo/some-rule": "error",
- "@bar/another-rule": "error"
- },
- "env": {
- "jquery/jquery": true,
- "@foo/foo/env-foo": true,
- "@bar/env-bar": true,
- }
- // ...
-}
-```
+++ /dev/null
----
-title: Rules
-layout: doc
-eleventyNavigation:
- key: configuring rules
- parent: configuring
- title: Configuring Rules
- order: 3
-
----
-
-## Configuring Rules
-
-ESLint comes with a large number of built-in rules and you can add more rules through plugins. You can modify which rules your project uses either using configuration comments or configuration files. To change a rule setting, you must set the rule ID equal to one of these values:
-
-* `"off"` or `0` - turn the rule off
-* `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
-* `"error"` or `2` - turn the rule on as an error (exit code is 1 when triggered)
-
-### Using configuration comments
-
-To configure rules inside of a file using configuration comments, use a comment in the following format:
-
-```js
-/* eslint eqeqeq: "off", curly: "error" */
-```
-
-In this example, [`eqeqeq`](../../rules/eqeqeq) is turned off and [`curly`](../../rules/curly) is turned on as an error. You can also use the numeric equivalent for the rule severity:
-
-```js
-/* eslint eqeqeq: 0, curly: 2 */
-```
-
-This example is the same as the last example, only it uses the numeric codes instead of the string values. The `eqeqeq` rule is off and the `curly` rule is set to be an error.
-
-If a rule has additional options, you can specify them using array literal syntax, such as:
-
-```js
-/* eslint quotes: ["error", "double"], curly: 2 */
-```
-
-This comment specifies the "double" option for the [`quotes`](../../rules/quotes) rule. The first item in the array is always the rule severity (number or string).
-
-Configuration comments can include descriptions to explain why the comment is necessary. The description must occur after the configuration and is separated from the configuration by two or more consecutive `-` characters. For example:
-
-```js
-/* eslint eqeqeq: "off", curly: "error" -- Here's a description about why this configuration is necessary. */
-```
-
-```js
-/* eslint eqeqeq: "off", curly: "error"
- --------
- Here's a description about why this configuration is necessary. */
-```
-
-```js
-/* eslint eqeqeq: "off", curly: "error"
- * --------
- * This will not work due to the line above starting with a '*' character.
- */
-```
-
-### Using configuration files
-
-To configure rules inside of a configuration file, use the `rules` key along with an error level and any options you want to use. For example:
-
-```json
-{
- "rules": {
- "eqeqeq": "off",
- "curly": "error",
- "quotes": ["error", "double"]
- }
-}
-```
-
-And in YAML:
-
-```yaml
----
-rules:
- eqeqeq: off
- curly: error
- quotes:
- - error
- - double
-```
-
-To configure a rule which is defined within a plugin you have to prefix the rule ID with the plugin name and a `/`. For example:
-
-```json
-{
- "plugins": [
- "plugin1"
- ],
- "rules": {
- "eqeqeq": "off",
- "curly": "error",
- "quotes": ["error", "double"],
- "plugin1/rule1": "error"
- }
-}
-```
-
-And in YAML:
-
-```yaml
----
-plugins:
- - plugin1
-rules:
- eqeqeq: 0
- curly: error
- quotes:
- - error
- - "double"
- plugin1/rule1: error
-```
-
-In these configuration files, the rule `plugin1/rule1` comes from the plugin named `plugin1`. You can also use this format with configuration comments, such as:
-
-```js
-/* eslint "plugin1/rule1": "error" */
-```
-
-**Note:** When specifying rules from plugins, make sure to omit `eslint-plugin-`. ESLint uses only the unprefixed name internally to locate rules.
-
-## Disabling Rules
-
-### Using configuration comments
-
-To temporarily disable rule warnings in your file, use block comments in the following format:
-
-```js
-/* eslint-disable */
-
-alert('foo');
-
-/* eslint-enable */
-```
-
-You can also disable or enable warnings for specific rules:
-
-```js
-/* eslint-disable no-alert, no-console */
-
-alert('foo');
-console.log('bar');
-
-/* eslint-enable no-alert, no-console */
-```
-
-**Note:** `/* eslint-enable */` without any specific rules listed will cause all disabled rules to be re-enabled.
-
-To disable rule warnings in an entire file, put a `/* eslint-disable */` block comment at the top of the file:
-
-```js
-/* eslint-disable */
-
-alert('foo');
-```
-
-You can also disable or enable specific rules for an entire file:
-
-```js
-/* eslint-disable no-alert */
-
-alert('foo');
-```
-
-To ensure that a rule is never applied (regardless of any future enable/disable lines):
-
-```js
-/* eslint no-alert: "off" */
-
-alert('foo');
-```
-
-To disable all rules on a specific line, use a line or block comment in one of the following formats:
-
-```js
-alert('foo'); // eslint-disable-line
-
-// eslint-disable-next-line
-alert('foo');
-
-/* eslint-disable-next-line */
-alert('foo');
-
-alert('foo'); /* eslint-disable-line */
-```
-
-To disable a specific rule on a specific line:
-
-```js
-alert('foo'); // eslint-disable-line no-alert
-
-// eslint-disable-next-line no-alert
-alert('foo');
-
-alert('foo'); /* eslint-disable-line no-alert */
-
-/* eslint-disable-next-line no-alert */
-alert('foo');
-```
-
-To disable multiple rules on a specific line:
-
-```js
-alert('foo'); // eslint-disable-line no-alert, quotes, semi
-
-// eslint-disable-next-line no-alert, quotes, semi
-alert('foo');
-
-alert('foo'); /* eslint-disable-line no-alert, quotes, semi */
-
-/* eslint-disable-next-line no-alert, quotes, semi */
-alert('foo');
-
-/* eslint-disable-next-line
- no-alert,
- quotes,
- semi
-*/
-alert('foo');
-```
-
-All of the above methods also work for plugin rules. For example, to disable `eslint-plugin-example`'s `rule-name` rule, combine the plugin's name (`example`) and the rule's name (`rule-name`) into `example/rule-name`:
-
-```js
-foo(); // eslint-disable-line example/rule-name
-foo(); /* eslint-disable-line example/rule-name */
-```
-
-Configuration comments can include descriptions to explain why the comment is necessary. The description must come after the configuration and needs to be separated from the configuration by two or more consecutive `-` characters. For example:
-
-```js
-// eslint-disable-next-line no-console -- Here's a description about why this configuration is necessary.
-console.log('hello');
-
-/* eslint-disable-next-line no-console --
- * Here's a very long description about why this configuration is necessary
- * along with some additional information
-**/
-console.log('hello');
-```
-
-**Note:** Comments that disable warnings for a portion of a file tell ESLint not to report rule violations for the disabled code. ESLint still parses the entire file, however, so disabled code still needs to be syntactically valid JavaScript.
-
-### Using configuration files
-
-To disable rules inside of a configuration file for a group of files, use the `overrides` key along with a `files` key. For example:
-
-```json
-{
- "rules": {...},
- "overrides": [
- {
- "files": ["*-test.js","*.spec.js"],
- "rules": {
- "no-unused-expressions": "off"
- }
- }
- ]
-}
-```
-
-### Disabling Inline Comments
-
-To disable all inline config comments, use the `noInlineConfig` setting. For example:
-
-```json
-{
- "rules": {...},
- "noInlineConfig": true
-}
-```
-
-This setting is similar to [--no-inline-config](../command-line-interface#--no-inline-config) CLI option.
-
-#### Report unused `eslint-disable` comments
-
-To report unused `eslint-disable` comments, use the `reportUnusedDisableDirectives` setting. For example:
-
-```json
-{
- "rules": {...},
- "reportUnusedDisableDirectives": true
-}
-```
-
-This setting is similar to [--report-unused-disable-directives](../command-line-interface#--report-unused-disable-directives) CLI option, but doesn't fail linting (reports as `"warn"` severity).
+++ /dev/null
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="UTF-8">
- <title>ESLint Report</title>
- <link rel="icon" type="image/png" sizes="any" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAHaAAAB2gGFomX7AAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAABD1JREFUWMPFl11sk2UUx3/nbYtjxS1MF7MLMTECMgSTtSSyrQkLhAj7UBPnDSEGoxegGzMwojhXVpmTAA5iYpSoMQa8GBhFOrMFk03buei6yRAlcmOM0SEmU9d90b19jxcM1o5+sGnsc/e+z/l6ztf/HFFVMnns6QieeOCHBePGsHM+wrOtvLG2C4WRVDSSygNV7sCjlspxwDnPB44aols/DXk+mbMBmx/6OseITF1CuOtfevkPh2Uu+/jbdX8lujSScRlT5r7/QDlAfsRmfzmpnkQ/H3H13gf6bBrBn1uqK8WylgEnU8eZmk1repbfchJG1TyKyIKEwuBHFd3lD3naY3O1siiwXsVoBV2VgM1ht/QQUJk2ByqKghsQziYQ8ifKgexIXmuyzC4r67Y7R+xPAfuB/Nn3Cpva+0s7khpQVtZtd4bt51BWxtBYAiciprG7c7D4SixzU9PYalDL6110Ifb/w8W9eY7JqFeFHbO8fPGyLHwwFHJNJTSgwtVTB9oaw9BlQ+tO93vOxypoaQnfEYlI43SeCHDC4TDq9+51/h5fxr33q0ZfV9g04wat9Q943rjJgCp3952W2i8Bi6eDvdsfKj0cK/DYMRyXL4/sUJUmIHd2zYMezsvLaamp4WpcWN3BXSiHpuMwbGbZlnZ8tXY4rgosy+G7oRwQ0cAsd28YGgqfU5UjCZQDLALxDg+Hv/P5Rqvj4hwrS8izXzWb4spwc1GgENFnkpWRzxeuB+ssUHgLdb9UVdt8vpGdKQpze7n7y1U3DBChNRUuqOo9c+0+qpKKxyZqtAIYla7gY4JszAAQri93BSsMRZoyBcUC+w3Q3AyOA4sNhAOZ0q7Iq0b2vUNvK5zPgP+/H8+Zetdoa6uOikhdGurxebwvJY8Iz3V1rTMNAH+opEuQj5KTT/qA1yC+wyUjBm12OidaUtCcPNNX2h0Hx2JG69VulANZAJZJwfU7rzd/FHixuXniTdM0m4GtSQT7bTartqEh9yfImUEzkwKZmTwmo5a5JwkYBfcDL01/RkR5y8iWhtPBknB8ZxwtU9UjwOrrKCeizzc25nTGg1F/turEHoU9wMLpDvWKf8DTmNCAKnd/tqUTF4ElMXJ+A5rWDJS+41WsGWzALhJ+ErBWrLj9g+pqojHxlXJX8HGUg0BsR/x1yhxf3jm4cSzpQFLp6tmi6PEE7g1ZhtZ91ufpSZUAFa6gC+UoQslNaSmypT1U8mHKiUgEKS8KfgF4EpYunFI16tsHin+OG0LcgQK7yj7g6cSzpva2D3hKVNG0Y3mVO1BkqfSlmJrHBQ4uvM12gJHc6ETW8HZVfMRmXvyxxNC1Z/o839zyXlDuCr4nsC11J+MXueaVJWn6yPv+/pJtc9oLTNN4AeTvNGByd3rlhE2x9s5pLwDoHCy+grDzWmOZ95lUtLYj5Bma126Y8eX0/zj/ADxGyViSg4BXAAAAAElFTkSuQmCC">
- <link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PScwIDAgMjk0LjgyNSAyNTguOTgyJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPg0KPHBhdGggZmlsbD0nIzgwODBGMicgZD0nTTk3LjAyMSw5OS4wMTZsNDguNDMyLTI3Ljk2MmMxLjIxMi0wLjcsMi43MDYtMC43LDMuOTE4LDBsNDguNDMzLDI3Ljk2MiBjMS4yMTEsMC43LDEuOTU5LDEuOTkzLDEuOTU5LDMuMzkzdjU1LjkyNGMwLDEuMzk5LTAuNzQ4LDIuNjkzLTEuOTU5LDMuMzk0bC00OC40MzMsMjcuOTYyYy0xLjIxMiwwLjctMi43MDYsMC43LTMuOTE4LDAgbC00OC40MzItMjcuOTYyYy0xLjIxMi0wLjctMS45NTktMS45OTQtMS45NTktMy4zOTR2LTU1LjkyNEM5NS4wNjMsMTAxLjAwOSw5NS44MSw5OS43MTYsOTcuMDIxLDk5LjAxNicvPg0KPHBhdGggZmlsbD0nIzRCMzJDMycgZD0nTTI3My4zMzYsMTI0LjQ4OEwyMTUuNDY5LDIzLjgxNmMtMi4xMDItMy42NC01Ljk4NS02LjMyNS0xMC4xODgtNi4zMjVIODkuNTQ1IGMtNC4yMDQsMC04LjA4OCwyLjY4NS0xMC4xOSw2LjMyNWwtNTcuODY3LDEwMC40NWMtMi4xMDIsMy42NDEtMi4xMDIsOC4yMzYsMCwxMS44NzdsNTcuODY3LDk5Ljg0NyBjMi4xMDIsMy42NCw1Ljk4Niw1LjUwMSwxMC4xOSw1LjUwMWgxMTUuNzM1YzQuMjAzLDAsOC4wODctMS44MDUsMTAuMTg4LTUuNDQ2bDU3Ljg2Ny0xMDAuMDEgQzI3NS40MzksMTMyLjM5NiwyNzUuNDM5LDEyOC4xMjgsMjczLjMzNiwxMjQuNDg4IE0yMjUuNDE5LDE3Mi44OThjMCwxLjQ4LTAuODkxLDIuODQ5LTIuMTc0LDMuNTlsLTczLjcxLDQyLjUyNyBjLTEuMjgyLDAuNzQtMi44ODgsMC43NC00LjE3LDBsLTczLjc2Ny00Mi41MjdjLTEuMjgyLTAuNzQxLTIuMTc5LTIuMTA5LTIuMTc5LTMuNTlWODcuODQzYzAtMS40ODEsMC44ODQtMi44NDksMi4xNjctMy41OSBsNzMuNzA3LTQyLjUyN2MxLjI4Mi0wLjc0MSwyLjg4Ni0wLjc0MSw0LjE2OCwwbDczLjc3Miw0Mi41MjdjMS4yODMsMC43NDEsMi4xODYsMi4xMDksMi4xODYsMy41OVYxNzIuODk4eicvPg0KPC9zdmc+">
- <style>
- body {
- font-family:Arial, "Helvetica Neue", Helvetica, sans-serif;
- font-size:16px;
- font-weight:normal;
- margin:0;
- padding:0;
- color:#333
- }
- #overview {
- padding:20px 30px
- }
- td, th {
- padding:5px 10px
- }
- h1 {
- margin:0
- }
- table {
- margin:30px;
- width:calc(100% - 60px);
- max-width:1000px;
- border-radius:5px;
- border:1px solid #ddd;
- border-spacing:0px;
- }
- th {
- font-weight:400;
- font-size:medium;
- text-align:left;
- cursor:pointer
- }
- td.clr-1, td.clr-2, th span {
- font-weight:700
- }
- th span {
- float:right;
- margin-left:20px
- }
- th span:after {
- content:"";
- clear:both;
- display:block
- }
- tr:last-child td {
- border-bottom:none
- }
- tr td:first-child, tr td:last-child {
- color:#9da0a4
- }
- #overview.bg-0, tr.bg-0 th {
- color:#468847;
- background:#dff0d8;
- border-bottom:1px solid #d6e9c6
- }
- #overview.bg-1, tr.bg-1 th {
- color:#f0ad4e;
- background:#fcf8e3;
- border-bottom:1px solid #fbeed5
- }
- #overview.bg-2, tr.bg-2 th {
- color:#b94a48;
- background:#f2dede;
- border-bottom:1px solid #eed3d7
- }
- td {
- border-bottom:1px solid #ddd
- }
- td.clr-1 {
- color:#f0ad4e
- }
- td.clr-2 {
- color:#b94a48
- }
- td a {
- color:#3a33d1;
- text-decoration:none
- }
- td a:hover {
- color:#272296;
- text-decoration:underline
- }
- </style>
- </head>
- <body>
- <div id="overview" class="bg-2">
- <h1>ESLint Report</h1>
- <div>
- <span>9 problems (5 errors, 4 warnings)</span> - Generated on Mon Sep 12 2022 01:24:39 GMT-0400 (Eastern Daylight Time)
- </div>
- </div>
- <table>
- <tbody>
- <tr class="bg-2" data-group="f-0">
- <th colspan="4">
- [+] /var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js
- <span>9 problems (5 errors, 4 warnings)</span>
- </th>
-</tr>
-<tr style="display:none" class="f-0">
- <td>1:10</td>
- <td class="clr-2">Error</td>
- <td>'addOne' is defined but never used.</td>
- <td>
- <a href="" target="_blank" rel="noopener noreferrer">no-unused-vars</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>2:9</td>
- <td class="clr-2">Error</td>
- <td>Use the isNaN function to compare with NaN.</td>
- <td>
- <a href="" target="_blank" rel="noopener noreferrer">use-isnan</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>3:16</td>
- <td class="clr-2">Error</td>
- <td>Unexpected space before unary operator '++'.</td>
- <td>
- <a href="https://eslint.org/docs/rules/space-unary-ops" target="_blank" rel="noopener noreferrer">space-unary-ops</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>3:20</td>
- <td class="clr-1">Warning</td>
- <td>Missing semicolon.</td>
- <td>
- <a href="https://eslint.org/docs/rules/semi" target="_blank" rel="noopener noreferrer">semi</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>4:12</td>
- <td class="clr-1">Warning</td>
- <td>Unnecessary 'else' after 'return'.</td>
- <td>
- <a href="https://eslint.org/docs/rules/no-else-return" target="_blank" rel="noopener noreferrer">no-else-return</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>5:1</td>
- <td class="clr-1">Warning</td>
- <td>Expected indentation of 8 spaces but found 6.</td>
- <td>
- <a href="https://eslint.org/docs/rules/indent" target="_blank" rel="noopener noreferrer">indent</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>5:7</td>
- <td class="clr-2">Error</td>
- <td>Function 'addOne' expected a return value.</td>
- <td>
- <a href="https://eslint.org/docs/rules/consistent-return" target="_blank" rel="noopener noreferrer">consistent-return</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>5:13</td>
- <td class="clr-1">Warning</td>
- <td>Missing semicolon.</td>
- <td>
- <a href="https://eslint.org/docs/rules/semi" target="_blank" rel="noopener noreferrer">semi</a>
- </td>
-</tr>
-
-<tr style="display:none" class="f-0">
- <td>7:2</td>
- <td class="clr-2">Error</td>
- <td>Unnecessary semicolon.</td>
- <td>
- <a href="" target="_blank" rel="noopener noreferrer">no-extra-semi</a>
- </td>
-</tr>
-
- </tbody>
- </table>
- <script type="text/javascript">
- var groups = document.querySelectorAll("tr[data-group]");
- for (i = 0; i < groups.length; i++) {
- groups[i].addEventListener("click", function() {
- var inGroup = document.getElementsByClassName(this.getAttribute("data-group"));
- this.innerHTML = (this.innerHTML.indexOf("+") > -1) ? this.innerHTML.replace("+", "-") : this.innerHTML.replace("-", "+");
- for (var j = 0; j < inGroup.length; j++) {
- inGroup[j].style.display = (inGroup[j].style.display !== "none") ? "none" : "table-row";
- }
- });
- }
- </script>
- </body>
-</html>
+++ /dev/null
----
-title: Formatters
-layout: doc
-eleventyNavigation:
- key: formatters
- parent: user guide
- title: Formatters
- order: 5
-edit_link: https://github.com/eslint/eslint/edit/main/templates/formatter-examples.md.ejs
----
-
-ESLint comes with several built-in formatters to control the appearance of the linting results, and supports third-party formatters as well.
-
-You can specify a formatter using the `--format` or `-f` flag on the command line. For example, `--format json` uses the `json` formatter.
-
-The built-in formatter options are:
-
-* [checkstyle](#checkstyle)
-* [compact](#compact)
-* [html](#html)
-* [jslint-xml](#jslint-xml)
-* [json-with-metadata](#json-with-metadata)
-* [json](#json)
-* [junit](#junit)
-* [stylish](#stylish)
-* [tap](#tap)
-* [unix](#unix)
-* [visualstudio](#visualstudio)
-
-## Example Source
-
-Examples of each formatter were created from linting `fullOfProblems.js` using the `.eslintrc` configuration shown below.
-
-### `fullOfProblems.js`
-
-```js
-function addOne(i) {
- if (i != NaN) {
- return i ++
- } else {
- return
- }
-};
-```
-
-### `.eslintrc`:
-
-```json
-{
- "extends": "eslint:recommended",
- "rules": {
- "consistent-return": 2,
- "indent" : [1, 4],
- "no-else-return" : 1,
- "semi" : [1, "always"],
- "space-unary-ops" : 2
- }
-}
-```
-
-## Output Examples
-
-### checkstyle
-
-```text
-<?xml version="1.0" encoding="utf-8"?><checkstyle version="4.3"><file name="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js"><error line="1" column="10" severity="error" message="&apos;addOne&apos; is defined but never used. (no-unused-vars)" source="eslint.rules.no-unused-vars" /><error line="2" column="9" severity="error" message="Use the isNaN function to compare with NaN. (use-isnan)" source="eslint.rules.use-isnan" /><error line="3" column="16" severity="error" message="Unexpected space before unary operator &apos;++&apos;. (space-unary-ops)" source="eslint.rules.space-unary-ops" /><error line="3" column="20" severity="warning" message="Missing semicolon. (semi)" source="eslint.rules.semi" /><error line="4" column="12" severity="warning" message="Unnecessary &apos;else&apos; after &apos;return&apos;. (no-else-return)" source="eslint.rules.no-else-return" /><error line="5" column="1" severity="warning" message="Expected indentation of 8 spaces but found 6. (indent)" source="eslint.rules.indent" /><error line="5" column="7" severity="error" message="Function &apos;addOne&apos; expected a return value. (consistent-return)" source="eslint.rules.consistent-return" /><error line="5" column="13" severity="warning" message="Missing semicolon. (semi)" source="eslint.rules.semi" /><error line="7" column="2" severity="error" message="Unnecessary semicolon. (no-extra-semi)" source="eslint.rules.no-extra-semi" /></file></checkstyle>
-```
-
-### compact
-
-```text
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 1, col 10, Error - 'addOne' is defined but never used. (no-unused-vars)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 2, col 9, Error - Use the isNaN function to compare with NaN. (use-isnan)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 3, col 16, Error - Unexpected space before unary operator '++'. (space-unary-ops)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 3, col 20, Warning - Missing semicolon. (semi)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 4, col 12, Warning - Unnecessary 'else' after 'return'. (no-else-return)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 1, Warning - Expected indentation of 8 spaces but found 6. (indent)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 7, Error - Function 'addOne' expected a return value. (consistent-return)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 5, col 13, Warning - Missing semicolon. (semi)
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js: line 7, col 2, Error - Unnecessary semicolon. (no-extra-semi)
-
-9 problems
-```
-
-### html
-
-<iframe src="html-formatter-example.html" width="100%" height="460px"></iframe>
-
-### jslint-xml
-
-```text
-<?xml version="1.0" encoding="utf-8"?><jslint><file name="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js"><issue line="1" char="10" evidence="" reason="&apos;addOne&apos; is defined but never used. (no-unused-vars)" /><issue line="2" char="9" evidence="" reason="Use the isNaN function to compare with NaN. (use-isnan)" /><issue line="3" char="16" evidence="" reason="Unexpected space before unary operator &apos;++&apos;. (space-unary-ops)" /><issue line="3" char="20" evidence="" reason="Missing semicolon. (semi)" /><issue line="4" char="12" evidence="" reason="Unnecessary &apos;else&apos; after &apos;return&apos;. (no-else-return)" /><issue line="5" char="1" evidence="" reason="Expected indentation of 8 spaces but found 6. (indent)" /><issue line="5" char="7" evidence="" reason="Function &apos;addOne&apos; expected a return value. (consistent-return)" /><issue line="5" char="13" evidence="" reason="Missing semicolon. (semi)" /><issue line="7" char="2" evidence="" reason="Unnecessary semicolon. (no-extra-semi)" /></file></jslint>
-```
-
-### json-with-metadata
-
-```text
-{"results":[{"filePath":"/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js","messages":[{"ruleId":"no-unused-vars","severity":2,"message":"'addOne' is defined but never used.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":16},{"ruleId":"use-isnan","severity":2,"message":"Use the isNaN function to compare with NaN.","line":2,"column":9,"nodeType":"BinaryExpression","messageId":"comparisonWithNaN","endLine":2,"endColumn":17},{"ruleId":"space-unary-ops","severity":2,"message":"Unexpected space before unary operator '++'.","line":3,"column":16,"nodeType":"UpdateExpression","messageId":"unexpectedBefore","endLine":3,"endColumn":20,"fix":{"range":[57,58],"text":""}},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":3,"column":20,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":4,"endColumn":1,"fix":{"range":[60,60],"text":";"}},{"ruleId":"no-else-return","severity":1,"message":"Unnecessary 'else' after 'return'.","line":4,"column":12,"nodeType":"BlockStatement","messageId":"unexpected","endLine":6,"endColumn":6,"fix":{"range":[0,94],"text":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } \n return\n \n}"}},{"ruleId":"indent","severity":1,"message":"Expected indentation of 8 spaces but found 6.","line":5,"column":1,"nodeType":"Keyword","messageId":"wrongIndentation","endLine":5,"endColumn":7,"fix":{"range":[74,80],"text":" "}},{"ruleId":"consistent-return","severity":2,"message":"Function 'addOne' expected a return value.","line":5,"column":7,"nodeType":"ReturnStatement","messageId":"missingReturnValue","endLine":5,"endColumn":13},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":5,"column":13,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":6,"endColumn":1,"fix":{"range":[86,86],"text":";"}},{"ruleId":"no-extra-semi","severity":2,"message":"Unnecessary semicolon.","line":7,"column":2,"nodeType":"EmptyStatement","messageId":"unexpected","endLine":7,"endColumn":3,"fix":{"range":[93,95],"text":"}"}}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":2,"fixableWarningCount":4,"source":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } else {\n return\n }\n};"}],"metadata":{"rulesMeta":{"no-else-return":{"type":"suggestion","docs":{"description":"Disallow `else` blocks after `return` statements in `if` statements","recommended":false,"url":"https://eslint.org/docs/rules/no-else-return"},"schema":[{"type":"object","properties":{"allowElseIf":{"type":"boolean","default":true}},"additionalProperties":false}],"fixable":"code","messages":{"unexpected":"Unnecessary 'else' after 'return'."}},"indent":{"type":"layout","docs":{"description":"Enforce consistent indentation","recommended":false,"url":"https://eslint.org/docs/rules/indent"},"fixable":"whitespace","schema":[{"oneOf":[{"enum":["tab"]},{"type":"integer","minimum":0}]},{"type":"object","properties":{"SwitchCase":{"type":"integer","minimum":0,"default":0},"VariableDeclarator":{"oneOf":[{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},{"type":"object","properties":{"var":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"let":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"const":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]}},"additionalProperties":false}]},"outerIIFEBody":{"oneOf":[{"type":"integer","minimum":0},{"enum":["off"]}]},"MemberExpression":{"oneOf":[{"type":"integer","minimum":0},{"enum":["off"]}]},"FunctionDeclaration":{"type":"object","properties":{"parameters":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"body":{"type":"integer","minimum":0}},"additionalProperties":false},"FunctionExpression":{"type":"object","properties":{"parameters":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"body":{"type":"integer","minimum":0}},"additionalProperties":false},"StaticBlock":{"type":"object","properties":{"body":{"type":"integer","minimum":0}},"additionalProperties":false},"CallExpression":{"type":"object","properties":{"arguments":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]}},"additionalProperties":false},"ArrayExpression":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"ObjectExpression":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"ImportDeclaration":{"oneOf":[{"type":"integer","minimum":0},{"enum":["first","off"]}]},"flatTernaryExpressions":{"type":"boolean","default":false},"offsetTernaryExpressions":{"type":"boolean","default":false},"ignoredNodes":{"type":"array","items":{"type":"string","not":{"pattern":":exit$"}}},"ignoreComments":{"type":"boolean","default":false}},"additionalProperties":false}],"messages":{"wrongIndentation":"Expected indentation of {{expected}} but found {{actual}}."}},"space-unary-ops":{"type":"layout","docs":{"description":"Enforce consistent spacing before or after unary operators","recommended":false,"url":"https://eslint.org/docs/rules/space-unary-ops"},"fixable":"whitespace","schema":[{"type":"object","properties":{"words":{"type":"boolean","default":true},"nonwords":{"type":"boolean","default":false},"overrides":{"type":"object","additionalProperties":{"type":"boolean"}}},"additionalProperties":false}],"messages":{"unexpectedBefore":"Unexpected space before unary operator '{{operator}}'.","unexpectedAfter":"Unexpected space after unary operator '{{operator}}'.","unexpectedAfterWord":"Unexpected space after unary word operator '{{word}}'.","wordOperator":"Unary word operator '{{word}}' must be followed by whitespace.","operator":"Unary operator '{{operator}}' must be followed by whitespace.","beforeUnaryExpressions":"Space is required before unary expressions '{{token}}'."}},"semi":{"type":"layout","docs":{"description":"Require or disallow semicolons instead of ASI","recommended":false,"url":"https://eslint.org/docs/rules/semi"},"fixable":"code","schema":{"anyOf":[{"type":"array","items":[{"enum":["never"]},{"type":"object","properties":{"beforeStatementContinuationChars":{"enum":["always","any","never"]}},"additionalProperties":false}],"minItems":0,"maxItems":2},{"type":"array","items":[{"enum":["always"]},{"type":"object","properties":{"omitLastInOneLineBlock":{"type":"boolean"}},"additionalProperties":false}],"minItems":0,"maxItems":2}]},"messages":{"missingSemi":"Missing semicolon.","extraSemi":"Extra semicolon."}},"consistent-return":{"type":"suggestion","docs":{"description":"Require `return` statements to either always or never specify values","recommended":false,"url":"https://eslint.org/docs/rules/consistent-return"},"schema":[{"type":"object","properties":{"treatUndefinedAsUnspecified":{"type":"boolean","default":false}},"additionalProperties":false}],"messages":{"missingReturn":"Expected to return a value at the end of {{name}}.","missingReturnValue":"{{name}} expected a return value.","unexpectedReturnValue":"{{name}} expected no return value."}}}}}
-```
-
-### json
-
-```text
-[{"filePath":"/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js","messages":[{"ruleId":"no-unused-vars","severity":2,"message":"'addOne' is defined but never used.","line":1,"column":10,"nodeType":"Identifier","messageId":"unusedVar","endLine":1,"endColumn":16},{"ruleId":"use-isnan","severity":2,"message":"Use the isNaN function to compare with NaN.","line":2,"column":9,"nodeType":"BinaryExpression","messageId":"comparisonWithNaN","endLine":2,"endColumn":17},{"ruleId":"space-unary-ops","severity":2,"message":"Unexpected space before unary operator '++'.","line":3,"column":16,"nodeType":"UpdateExpression","messageId":"unexpectedBefore","endLine":3,"endColumn":20,"fix":{"range":[57,58],"text":""}},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":3,"column":20,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":4,"endColumn":1,"fix":{"range":[60,60],"text":";"}},{"ruleId":"no-else-return","severity":1,"message":"Unnecessary 'else' after 'return'.","line":4,"column":12,"nodeType":"BlockStatement","messageId":"unexpected","endLine":6,"endColumn":6,"fix":{"range":[0,94],"text":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } \n return\n \n}"}},{"ruleId":"indent","severity":1,"message":"Expected indentation of 8 spaces but found 6.","line":5,"column":1,"nodeType":"Keyword","messageId":"wrongIndentation","endLine":5,"endColumn":7,"fix":{"range":[74,80],"text":" "}},{"ruleId":"consistent-return","severity":2,"message":"Function 'addOne' expected a return value.","line":5,"column":7,"nodeType":"ReturnStatement","messageId":"missingReturnValue","endLine":5,"endColumn":13},{"ruleId":"semi","severity":1,"message":"Missing semicolon.","line":5,"column":13,"nodeType":"ReturnStatement","messageId":"missingSemi","endLine":6,"endColumn":1,"fix":{"range":[86,86],"text":";"}},{"ruleId":"no-extra-semi","severity":2,"message":"Unnecessary semicolon.","line":7,"column":2,"nodeType":"EmptyStatement","messageId":"unexpected","endLine":7,"endColumn":3,"fix":{"range":[93,95],"text":"}"}}],"suppressedMessages":[],"errorCount":5,"fatalErrorCount":0,"warningCount":4,"fixableErrorCount":2,"fixableWarningCount":4,"source":"function addOne(i) {\n if (i != NaN) {\n return i ++\n } else {\n return\n }\n};"}]
-```
-
-### junit
-
-```text
-<?xml version="1.0" encoding="utf-8"?>
-<testsuites>
-<testsuite package="org.eslint" time="0" tests="9" errors="9" name="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js">
-<testcase time="0" name="org.eslint.no-unused-vars" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="&apos;addOne&apos; is defined but never used."><![CDATA[line 1, col 10, Error - &apos;addOne&apos; is defined but never used. (no-unused-vars)]]></failure></testcase>
-<testcase time="0" name="org.eslint.use-isnan" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Use the isNaN function to compare with NaN."><![CDATA[line 2, col 9, Error - Use the isNaN function to compare with NaN. (use-isnan)]]></failure></testcase>
-<testcase time="0" name="org.eslint.space-unary-ops" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Unexpected space before unary operator &apos;++&apos;."><![CDATA[line 3, col 16, Error - Unexpected space before unary operator &apos;++&apos;. (space-unary-ops)]]></failure></testcase>
-<testcase time="0" name="org.eslint.semi" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Missing semicolon."><![CDATA[line 3, col 20, Warning - Missing semicolon. (semi)]]></failure></testcase>
-<testcase time="0" name="org.eslint.no-else-return" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Unnecessary &apos;else&apos; after &apos;return&apos;."><![CDATA[line 4, col 12, Warning - Unnecessary &apos;else&apos; after &apos;return&apos;. (no-else-return)]]></failure></testcase>
-<testcase time="0" name="org.eslint.indent" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Expected indentation of 8 spaces but found 6."><![CDATA[line 5, col 1, Warning - Expected indentation of 8 spaces but found 6. (indent)]]></failure></testcase>
-<testcase time="0" name="org.eslint.consistent-return" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Function &apos;addOne&apos; expected a return value."><![CDATA[line 5, col 7, Error - Function &apos;addOne&apos; expected a return value. (consistent-return)]]></failure></testcase>
-<testcase time="0" name="org.eslint.semi" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Missing semicolon."><![CDATA[line 5, col 13, Warning - Missing semicolon. (semi)]]></failure></testcase>
-<testcase time="0" name="org.eslint.no-extra-semi" classname="/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems"><failure message="Unnecessary semicolon."><![CDATA[line 7, col 2, Error - Unnecessary semicolon. (no-extra-semi)]]></failure></testcase>
-</testsuite>
-</testsuites>
-
-```
-
-### stylish
-
-```text
-
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js
- 1:10 error 'addOne' is defined but never used no-unused-vars
- 2:9 error Use the isNaN function to compare with NaN use-isnan
- 3:16 error Unexpected space before unary operator '++' space-unary-ops
- 3:20 warning Missing semicolon semi
- 4:12 warning Unnecessary 'else' after 'return' no-else-return
- 5:1 warning Expected indentation of 8 spaces but found 6 indent
- 5:7 error Function 'addOne' expected a return value consistent-return
- 5:13 warning Missing semicolon semi
- 7:2 error Unnecessary semicolon no-extra-semi
-
-✖ 9 problems (5 errors, 4 warnings)
- 2 errors and 4 warnings potentially fixable with the `--fix` option.
-
-```
-
-### tap
-
-```text
-TAP version 13
-1..1
-not ok 1 - /var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js
- ---
- message: '''addOne'' is defined but never used.'
- severity: error
- data:
- line: 1
- column: 10
- ruleId: no-unused-vars
- messages:
- - message: Use the isNaN function to compare with NaN.
- severity: error
- data:
- line: 2
- column: 9
- ruleId: use-isnan
- - message: Unexpected space before unary operator '++'.
- severity: error
- data:
- line: 3
- column: 16
- ruleId: space-unary-ops
- - message: Missing semicolon.
- severity: warning
- data:
- line: 3
- column: 20
- ruleId: semi
- - message: Unnecessary 'else' after 'return'.
- severity: warning
- data:
- line: 4
- column: 12
- ruleId: no-else-return
- - message: Expected indentation of 8 spaces but found 6.
- severity: warning
- data:
- line: 5
- column: 1
- ruleId: indent
- - message: Function 'addOne' expected a return value.
- severity: error
- data:
- line: 5
- column: 7
- ruleId: consistent-return
- - message: Missing semicolon.
- severity: warning
- data:
- line: 5
- column: 13
- ruleId: semi
- - message: Unnecessary semicolon.
- severity: error
- data:
- line: 7
- column: 2
- ruleId: no-extra-semi
- ...
-
-```
-
-### unix
-
-```text
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:1:10: 'addOne' is defined but never used. [Error/no-unused-vars]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:2:9: Use the isNaN function to compare with NaN. [Error/use-isnan]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:3:16: Unexpected space before unary operator '++'. [Error/space-unary-ops]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:3:20: Missing semicolon. [Warning/semi]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:4:12: Unnecessary 'else' after 'return'. [Warning/no-else-return]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:1: Expected indentation of 8 spaces but found 6. [Warning/indent]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:7: Function 'addOne' expected a return value. [Error/consistent-return]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:5:13: Missing semicolon. [Warning/semi]
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js:7:2: Unnecessary semicolon. [Error/no-extra-semi]
-
-9 problems
-```
-
-### visualstudio
-
-```text
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(1,10): error no-unused-vars : 'addOne' is defined but never used.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(2,9): error use-isnan : Use the isNaN function to compare with NaN.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(3,16): error space-unary-ops : Unexpected space before unary operator '++'.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(3,20): warning semi : Missing semicolon.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(4,12): warning no-else-return : Unnecessary 'else' after 'return'.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,1): warning indent : Expected indentation of 8 spaces but found 6.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,7): error consistent-return : Function 'addOne' expected a return value.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(5,13): warning semi : Missing semicolon.
-/var/lib/jenkins/workspace/Releases/eslint Release/eslint/fullOfProblems.js(7,2): error no-extra-semi : Unnecessary semicolon.
-
-9 problems
-```
+++ /dev/null
----
-title: Getting Started with ESLint
-layout: doc
-eleventyNavigation:
- key: getting started
- parent: user guide
- title: Getting Started
- order: 1
-
----
-
-ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs. In many ways, it is similar to JSLint and JSHint with a few exceptions:
-
-* ESLint uses [Espree](https://github.com/eslint/espree) for JavaScript parsing.
-* ESLint uses an AST to evaluate patterns in code.
-* ESLint is completely pluggable, every single rule is a plugin and you can add more at runtime.
-
-## Installation and Usage
-
-Prerequisites: [Node.js](https://nodejs.org/en/) (`^12.22.0`, `^14.17.0`, or `>=16.0.0`) built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
-
-You can install and configure ESLint using this command:
-
-```shell
-npm init @eslint/config
-```
-
-**Note:** `npm init @eslint/config` assumes you have a `package.json` file already. If you don't, make sure to run `npm init` or `yarn init` beforehand.
-
-After that, you can run ESLint on any file or directory like this:
-
-```shell
-npx eslint yourfile.js
-
-# or
-
-yarn run eslint yourfile.js
-```
-
-It is also possible to install ESLint globally rather than locally (using `npm install eslint --global`). However, this is not recommended, and any plugins or shareable configs that you use must be installed locally in either case.
-
-## Configuration
-
-**Note:** If you are coming from a version before 1.0.0 please see the [migration guide](migrating-to-1.0.0).
-
-After running `npm init @eslint/config`, you'll have a `.eslintrc.{js,yml,json}` file in your directory. In it, you'll see some rules configured like this:
-
-```json
-{
- "rules": {
- "semi": ["error", "always"],
- "quotes": ["error", "double"]
- }
-}
-```
-
-The names `"semi"` and `"quotes"` are the names of [rules](/docs/rules) in ESLint. The first value is the error level of the rule and can be one of these values:
-
-* `"off"` or `0` - turn the rule off
-* `"warn"` or `1` - turn the rule on as a warning (doesn't affect exit code)
-* `"error"` or `2` - turn the rule on as an error (exit code will be 1)
-
-The three error levels allow you fine-grained control over how ESLint applies rules (for more configuration options and details, see the [configuration docs](configuring/)).
-
-Your `.eslintrc.{js,yml,json}` configuration file will also include the line:
-
-```json
-{
- "extends": "eslint:recommended"
-}
-```
-
-Because of this line, all of the rules marked "(recommended)" on the [rules page](/docs/rules) will be turned on. Alternatively, you can use configurations that others have created by searching for "eslint-config" on [npmjs.com](https://www.npmjs.com/search?q=eslint-config). ESLint will not lint your code unless you extend from a shared configuration or explicitly turn rules on in your configuration.
-
----
-
-## Next Steps
-
-* Learn about [advanced configuration](configuring/) of ESLint.
-* Get familiar with the [command line options](command-line-interface).
-* Explore [ESLint integrations](integrations) into other tools like editors, build systems, and more.
-* Can't find just the right rule? Make your own [custom rule](/docs/developer-guide/working-with-rules).
-* Make ESLint even better by [contributing](/docs/developer-guide/contributing/).
+++ /dev/null
----
-title: User Guide
-layout: doc
-eleventyNavigation:
- key: user guide
- title: User Guide
- order: 1
----
-
-This guide is intended for those who wish to use ESLint as an end-user. If you're looking for how to extend ESLint or work with the ESLint source code, please see the [Developer Guide](../developer-guide/).
-
-## [Getting Started](getting-started)
-
-Want to skip ahead and just start using ESLint? This section gives a high-level overview of installation, setup, and configuration options.
-
-## [Rules](../rules/)
-
-ESLint has a lot of rules that you can configure to fine-tune it to your project. This section is an exhaustive list of every rule and link to each rule's documentation.
-
-## [Configuring](configuring/)
-
-Once you've got ESLint running, you'll probably want to adjust the configuration to better suit your project. This section explains all the different ways you can configure ESLint.
-
-## [Command Line Interface](command-line-interface)
-
-There are a lot of command line flags for ESLint and this section explains what they do.
-
-## [Integrations](integrations)
-
-Wondering if ESLint will work with your favorite editor or build system? This section has a list of all known integrations (submitted by their authors).
-
-## [Rule Deprecation](rule-deprecation)
-
-The ESLint team is committed to making upgrading as easy and painless as possible. This section outlines the guidelines the team has set in place for the deprecation of rules in future releases.
-
-## Migrating
-
-If you were using a prior version of ESLint, you can get help with the transition by reading:
-
-* [migrating-to-1.0.0](migrating-to-1.0.0)
-* [migrating-to-2.0.0](migrating-to-2.0.0)
-* [migrating-to-3.0.0](migrating-to-3.0.0)
-* [migrating-to-4.0.0](migrating-to-4.0.0)
-* [migrating-to-5.0.0](migrating-to-5.0.0)
-* [migrating-to-6.0.0](migrating-to-6.0.0)
-* [migrating-to-7.0.0](migrating-to-7.0.0)
-* [migrating-to-8.0.0](migrating-to-8.0.0)
+++ /dev/null
----
-title: Integrations
-layout: doc
-eleventyNavigation:
- key: integrations
- parent: user guide
- title: Integrations
- order: 6
-
----
-
-## Editors
-
-* Sublime Text 3:
- * [SublimeLinter-eslint](https://github.com/roadhump/SublimeLinter-eslint)
- * [Build Next](https://github.com/albertosantini/sublimetext-buildnext)
-* Vim:
- * [ALE](https://github.com/w0rp/ale)
- * [Syntastic](https://github.com/vim-syntastic/syntastic/tree/master/syntax_checkers/javascript)
-* Emacs: [Flycheck](http://www.flycheck.org/) supports ESLint with the [javascript-eslint](http://www.flycheck.org/en/latest/languages.html#javascript) checker.
-* Eclipse Orion: ESLint is the [default linter](https://dev.eclipse.org/mhonarc/lists/orion-dev/msg02718.html)
-* Eclipse IDE: [Tern ESLint linter](https://github.com/angelozerr/tern.java/wiki/Tern-Linter-ESLint)
-* TextMate 2:
- * [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)
- * [fast-eslint-8](https://atom.io/packages/fast-eslint-8)
-* 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)
-
-## Build tools
-
-* Grunt: [grunt-eslint](https://www.npmjs.com/package/grunt-eslint)
-* Gulp: [gulp-eslint](https://www.npmjs.com/package/gulp-eslint)
-* Mimosa: [mimosa-eslint](https://www.npmjs.com/package/mimosa-eslint)
-* Broccoli: [broccoli-eslint](https://www.npmjs.com/package/broccoli-eslint)
-* Browserify: [eslintify](https://www.npmjs.com/package/eslintify)
-* Webpack: [eslint-webpack-plugin](https://www.npmjs.com/package/eslint-webpack-plugin)
-* Rollup: [@rollup/plugin-eslint](https://www.npmjs.com/package/@rollup/plugin-eslint)
-* Ember-cli: [ember-cli-eslint](https://www.npmjs.com/package/ember-cli-eslint)
-* Sails.js: [sails-hook-lint](https://www.npmjs.com/package/sails-hook-lint), [sails-eslint](https://www.npmjs.com/package/sails-eslint)
-* Start: [@start/plugin-lib-eslint](https://www.npmjs.com/package/@start/plugin-lib-eslint)
-* Brunch: [eslint-brunch](https://www.npmjs.com/package/eslint-brunch)
-
-## Command Line Tools
-
-* [ESLint Watch](https://www.npmjs.com/package/eslint-watch)
-* [Code Climate CLI](https://github.com/codeclimate/codeclimate)
-* [ESLint Nibble](https://github.com/IanVS/eslint-nibble)
-
-## Source Control
-
-* [Git Precommit Hook](https://coderwall.com/p/zq8jlq/eslint-pre-commit-hook)
-* [Git pre-commit hook that only lints staged changes](https://gist.github.com/dahjelle/8ddedf0aebd488208a9a7c829f19b9e8)
-* [overcommit Git hook manager](https://github.com/brigade/overcommit)
-* [Mega-Linter](https://nvuillam.github.io/mega-linter): Linters aggregator for CI, [embedding eslint](https://nvuillam.github.io/mega-linter/descriptors/javascript_eslint/)
-
-## Testing
-
-* Mocha.js: [mocha-eslint](https://www.npmjs.com/package/mocha-eslint)
-
-## External ESLint rules
-
-* [AngularJS](https://github.com/Gillespie59/eslint-plugin-angular)
-* [BackboneJS](https://github.com/ilyavolodin/eslint-plugin-backbone)
-* [Jasmine](https://github.com/tlvince/eslint-plugin-jasmine)
-* [React](https://github.com/yannickcr/eslint-plugin-react)
-
-… and many more published on npm with the [eslintplugin](https://www.npmjs.com/browse/keyword/eslintplugin) keyword.
-
-## Other Integration Lists
-
-You can find a curated list of other popular integrations for ESLint in the [awesome-eslint](https://github.com/dustinspecker/awesome-eslint) GitHub repository.
+++ /dev/null
----
-title: Migrating from JSCS
-layout: doc
-
----
-
-In April 2016, we [announced](https://eslint.org/blog/2016/04/welcoming-jscs-to-eslint) that the JSCS project was shutting down and the JSCS team would be joining the ESLint team. This guide is intended to help those who are using JSCS to migrate their settings and projects to use ESLint. We've tried to automate as much of the conversion as possible, but there are some manual changes that are needed.
-
-## Terminology
-
-Before beginning the process of migrating to ESLint, it's helpful to understand some of the terminology that ESLint uses and how it relates to terminology that JSCS uses.
-
-* **Configuration File** - In JSCS, the configuration file is `.jscsrc`, `.jscsrc.json`, `.jscsrc.yaml`, or `.jscsrs.js`. In ESLint, the configuration file can be `.eslintrc.json`, `.eslintrc.yml`, `.eslintrc.yaml`, or `.eslintrc.js` (there is also a deprecated `.eslintrc` file format).
-* **Presets** - In JSCS, there were numerous predefined configurations shipped directly within JSCS. ESLint ships with just one predefined configuration (`eslint:recommended`) that has no style rules enabled. However, ESLint does support [shareable configs](https://eslint.org/docs/developer-guide/shareable-configs). Shareable configs are configurations that are published on their own to npm and there are shareable configs available for almost all of the JSCS presets (see [the "Converting Presets" section](#converting-presets) below). Additionally, the `preset` option in a configuration file is the equivalent of the ESLint `extends` option.
-
-## Convert Configuration Files Using Polyjuice
-
-[Polyjuice](https://github.com/brenolf/polyjuice) is a utility for converting JSCS (and JSHint) configuration files into ESLint configuration files automatically. It understands the equivalent rules from each utility and will automatically output an ESLint configuration file that is a good approximation of your existing JSCS file.
-
-To install Polyjuice:
-
-```shell
-npm install -g polyjuice
-```
-
-Polyjuice works with JSON configuration files, so if you're using a JavaScript or YAML JSCS configuration file, you should first convert it into a JSON configuration file.
-
-To convert your configuration file, pass in the location of your `.jscs.json` file using the `--jscs` flag:
-
-```shell
-polyjuice --jscs .jscsrc.json > .eslintrc.json
-```
-
-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:
-
-```shell
-polyjuice --jscs .jscsrc.json ./foo/.jscsrc.json > .eslintrc.json
-```
-
-**Note:** Polyjuice does a good job of creating a reasonable ESLint configuration from your JSCS configuration, but it may not be 100%. You may still see different warnings than you saw with JSCS, and so you may need to further modify your configuration after using Polyjuice. This is especially true if you're using inline comments to enable/disable certain rules in JSCS (you'll need to manually convert those to use ESLint-style comments instead, [see "Disabling Rules Inline"](#disabling-rules-inline) later in this page).
-
-### Creating a New Configuration From Scratch
-
-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:
-
-```shell
-npm init @eslint/config
-```
-
-You'll be guided through a series of questions that will help you setup a basic configuration file to get you started.
-
-## Converting Presets
-
-There are shareable configs available for most JSCS presets. The equivalent shareable configs for each JSCS preset are listed in the following table:
-
-| **JSCS Preset** | **ESLint Shareable Config** |
-|-----------------|-----------------------------|
-| `airbnb` | [`eslint-config-airbnb-base`](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base) |
-| `crockford` | (not available) |
-| `google` | [`eslint-config-google`](https://github.com/google/eslint-config-google) |
-| `grunt` | [`eslint-config-grunt`](https://github.com/markelog/eslint-config-grunt) |
-| `idiomatic` | [`eslint-config-idiomatic`](https://github.com/jamespamplin/eslint-config-idiomatic) |
-| `jquery` | [`eslint-config-jquery`](https://github.com/jquery/eslint-config-jquery) |
-| `mdcs` | [`eslint-config-mdcs`](https://github.com/zz85/mrdoobapproves) |
-| `node-style-guide` | [`eslint-config-node-style-guide`](https://github.com/pdehaan/eslint-config-node-style-guide) |
-| `wikimedia` | [`eslint-config-wikimedia`](https://github.com/wikimedia/eslint-config-wikimedia) |
-| `wordpress` | [`eslint-config-wordpress`](https://github.com/WordPress-Coding-Standards/eslint-config-wordpress) |
-
-As an example, suppose that you are using the `airbnb` preset, so your `.jscsrc` file looks like this:
-
-```json
-{
- "preset": "airbnb"
-}
-```
-
-In order to get the same functionality in ESLint, you would first need to install the `eslint-config-airbnb` shareable config package:
-
-```shell
-npm install eslint-config-airbnb-base --save-dev
-```
-
-And then you would modify your configuration file like this:
-
-```json
-{
- "extends": "airbnb-base"
-}
-```
-
-ESLint sees `"airbnb-base"` and will look for `eslint-config-airbnb-base` (to save you some typing).
-
-## Disabling Rules Inline
-
-Both JSCS and ESLint use comments inside of files to disable rules around certain parts of your code. The following table lists out the JSCS inline configuration comments and their ESLint equivalents.
-
-| **Description** | **JSCS Comment** | **ESLint Comment** |
-|-----------------|------------------|--------------------|
-| Disable all rules | `// jscs:disable` or `/* jscs:disable */` | `/* eslint-disable */` |
-| Enable all rules | `// jscs:enable` or `/* jscs:enable */` | `/* eslint-enable */` |
-| Disable one rule | `// jscs:disable ruleName` or `/* jscs:disable ruleName */` | `/* eslint-disable rule-name */` |
-| Enable one rule | `// jscs:enable ruleName` or `/* jscs:enable ruleName */` | `/* eslint-enable rule-name */` |
-| Disable multiple rules | `// jscs:disable ruleName1, ruleName2` or `/* jscs:disable ruleName1, ruleName2 */` | `/* eslint-disable rule-name1, rule-name2 */` |
-| Enable multiple rules | `// jscs:enable ruleName1, ruleName2` or `/* jscs:enable ruleName1, ruleName2 */` | `/* eslint-enable rule-name1, rule-name2 */` |
-| Disable one rule on single line | `// jscs:ignore ruleName` | `// eslint-disable-line rule-name` |
-
-## Command Line Options
-
-Both JSCS and ESLint have command line arguments corresponding to many of their configuration options. The following are the ESLint equivalents of JSCS command line options.
-
-### `--fix`
-
-JSCS uses the `--fix` option to apply automatic fixes to code:
-
-```shell
-jscs --fix file.js
-```
-
-ESLint has the same option:
-
-```shell
-eslint --fix file.js
-```
-
-### `--auto-configure`
-
-The JSCS `--auto-configure` option created a configuration based on what it found in a given file:
-
-```shell
-jscs --auto-configure file.js
-```
-
-In ESLint, there's a similar option when you use `--init`. Just select "Inspect your JavaScript file(s)":
-
-```shell
-eslint --init
-? How would you like to configure ESLint? (Use arrow keys)
-> Answer questions about your style
- Use a popular style guide
- Inspect your JavaScript file(s)
-```
-
-## `--config`, `-c`
-
-JSCS allows you to specify a configuration file to use on the command line using either `--config` or `-c`, such as:
-
-```shell
-jscs --config myconfig.json file.js
-jscs -c myconfig.json file.js
-```
-
-Both flags are also supported by ESLint:
-
-```shell
-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:
-
-```shell
-cat file.js | jscs
-```
-
-In ESLint, you can also pipe in code, but you need to use the `--stdin` flag:
-
-```shell
-cat file.js | eslint --stdin
-```
+++ /dev/null
----
-title: Migrating to v1.0.0
-layout: doc
-
----
-
-ESLint v1.0.0 is the first major version release. As a result, there are some significant changes between how ESLint worked during its life in 0.x and how it will work going forward. These changes are the direct result of feedback from the ESLint community of users and were not made without due consideration for the upgrade path. We believe that these changes make ESLint even better, and while some work is necessary to upgrade, we hope the pain of this upgrade is small enough that you will see the benefit of upgrading.
-
-## All Rules Off by Default
-
-The most important difference in v1.0.0 is that all rules are off by default. We made this change after numerous requests to allow turning off the default rules from within configuration files. While that wasn't technically feasible, it was feasible to have all rules off by default and then re-enable rules in configuration files using `extends`. As such, we've made the `--reset` behavior the default and removed this command line option.
-
-When using `--init`, your configuration file will automatically include the following line:
-
-```json
-{
- "extends": "eslint:recommended"
-}
-```
-
-This setting mimics some of the default behavior from 0.x, but not all. If you don't want to use any of the recommended rules, you can delete this line.
-
-**To address:** If you are currently using `--reset`, then you should stop passing `--reset` on the command line; no other changes are necessary. If you are not using `--reset`, then you should review your configuration to determine which rules should be on by default. You can partially restore some of the default behavior by adding the following to your configuration file:
-
-The `"eslint:recommended"` configuration contains many of the same default rule settings from 0.x, but not all. These rules are no longer on by default, so you should review your settings to ensure they are still as you expect:
-
-* [no-alert](https://eslint.org/docs/rules/no-alert)
-* [no-array-constructor](https://eslint.org/docs/rules/no-array-constructor)
-* [no-caller](https://eslint.org/docs/rules/no-caller)
-* [no-catch-shadow](https://eslint.org/docs/rules/no-catch-shadow)
-* [no-empty-label](https://eslint.org/docs/rules/no-empty-label)
-* [no-eval](https://eslint.org/docs/rules/no-eval)
-* [no-extend-native](https://eslint.org/docs/rules/no-extend-native)
-* [no-extra-bind](https://eslint.org/docs/rules/no-extra-bind)
-* [no-extra-strict](https://eslint.org/docs/rules/no-extra-strict)
-* [no-implied-eval](https://eslint.org/docs/rules/no-implied-eval)
-* [no-iterator](https://eslint.org/docs/rules/no-iterator)
-* [no-label-var](https://eslint.org/docs/rules/no-label-var)
-* [no-labels](https://eslint.org/docs/rules/no-labels)
-* [no-lone-blocks](https://eslint.org/docs/rules/no-lone-blocks)
-* [no-loop-func](https://eslint.org/docs/rules/no-loop-func)
-* [no-multi-spaces](https://eslint.org/docs/rules/no-multi-spaces)
-* [no-multi-str](https://eslint.org/docs/rules/no-multi-str)
-* [no-native-reassign](https://eslint.org/docs/rules/no-native-reassign)
-* [no-new](https://eslint.org/docs/rules/no-new)
-* [no-new-func](https://eslint.org/docs/rules/no-new-func)
-* [no-new-object](https://eslint.org/docs/rules/no-new-object)
-* [no-new-wrappers](https://eslint.org/docs/rules/no-new-wrappers)
-* [no-octal-escape](https://eslint.org/docs/rules/no-octal-escape)
-* [no-process-exit](https://eslint.org/docs/rules/no-process-exit)
-* [no-proto](https://eslint.org/docs/rules/no-proto)
-* [no-return-assign](https://eslint.org/docs/rules/no-return-assign)
-* [no-script-url](https://eslint.org/docs/rules/no-script-url)
-* [no-sequences](https://eslint.org/docs/rules/no-sequences)
-* [no-shadow](https://eslint.org/docs/rules/no-shadow)
-* [no-shadow-restricted-names](https://eslint.org/docs/rules/no-shadow-restricted-names)
-* [no-spaced-func](https://eslint.org/docs/rules/no-spaced-func)
-* [no-trailing-spaces](https://eslint.org/docs/rules/no-trailing-spaces)
-* [no-undef-init](https://eslint.org/docs/rules/no-undef-init)
-* [no-underscore-dangle](https://eslint.org/docs/rules/no-underscore-dangle)
-* [no-unused-expressions](https://eslint.org/docs/rules/no-unused-expressions)
-* [no-use-before-define](https://eslint.org/docs/rules/no-use-before-define)
-* [no-with](https://eslint.org/docs/rules/no-with)
-* [no-wrap-func](https://eslint.org/docs/rules/no-wrap-func)
-* [camelcase](https://eslint.org/docs/rules/camelcase)
-* [comma-spacing](https://eslint.org/docs/rules/comma-spacing)
-* [consistent-return](https://eslint.org/docs/rules/consistent-return)
-* [curly](https://eslint.org/docs/rules/curly)
-* [dot-notation](https://eslint.org/docs/rules/dot-notation)
-* [eol-last](https://eslint.org/docs/rules/eol-last)
-* [eqeqeq](https://eslint.org/docs/rules/eqeqeq)
-* [key-spacing](https://eslint.org/docs/rules/key-spacing)
-* [new-cap](https://eslint.org/docs/rules/new-cap)
-* [new-parens](https://eslint.org/docs/rules/new-parens)
-* [quotes](https://eslint.org/docs/rules/quotes)
-* [semi](https://eslint.org/docs/rules/semi)
-* [semi-spacing](https://eslint.org/docs/rules/semi-spacing)
-* [space-infix-ops](https://eslint.org/docs/rules/space-infix-ops)
-* [space-return-throw-case](https://eslint.org/docs/rules/space-return-throw-case)
-* [space-unary-ops](https://eslint.org/docs/rules/space-unary-ops)
-* [strict](https://eslint.org/docs/rules/strict)
-* [yoda](https://eslint.org/docs/rules/yoda)
-
-See also: the [full diff](https://github.com/eslint/eslint/commit/e3e9dbd9876daf4bdeb4e15f8a76a9d5e6e03e39#diff-b01a5cfd9361ca9280a460fd6bb8edbbL1) where the defaults were changed.
-
-Here's a configuration file with the closest equivalent of the old defaults:
-
-```json
-{
- "extends": "eslint:recommended",
- "rules": {
- "no-alert": 2,
- "no-array-constructor": 2,
- "no-caller": 2,
- "no-catch-shadow": 2,
- "no-empty-label": 2,
- "no-eval": 2,
- "no-extend-native": 2,
- "no-extra-bind": 2,
- "no-implied-eval": 2,
- "no-iterator": 2,
- "no-label-var": 2,
- "no-labels": 2,
- "no-lone-blocks": 2,
- "no-loop-func": 2,
- "no-multi-spaces": 2,
- "no-multi-str": 2,
- "no-native-reassign": 2,
- "no-new": 2,
- "no-new-func": 2,
- "no-new-object": 2,
- "no-new-wrappers": 2,
- "no-octal-escape": 2,
- "no-process-exit": 2,
- "no-proto": 2,
- "no-return-assign": 2,
- "no-script-url": 2,
- "no-sequences": 2,
- "no-shadow": 2,
- "no-shadow-restricted-names": 2,
- "no-spaced-func": 2,
- "no-trailing-spaces": 2,
- "no-undef-init": 2,
- "no-underscore-dangle": 2,
- "no-unused-expressions": 2,
- "no-use-before-define": 2,
- "no-with": 2,
- "camelcase": 2,
- "comma-spacing": 2,
- "consistent-return": 2,
- "curly": [2, "all"],
- "dot-notation": [2, { "allowKeywords": true }],
- "eol-last": 2,
- "no-extra-parens": [2, "functions"],
- "eqeqeq": 2,
- "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
- "new-cap": 2,
- "new-parens": 2,
- "quotes": [2, "double"],
- "semi": 2,
- "semi-spacing": [2, {"before": false, "after": true}],
- "space-infix-ops": 2,
- "space-return-throw-case": 2,
- "space-unary-ops": [2, { "words": true, "nonwords": false }],
- "strict": [2, "function"],
- "yoda": [2, "never"]
- }
-}
-```
-
-## Removed Rules
-
-Over the past several releases, we have been deprecating rules and introducing new rules to take their place. The following is a list of the removed rules and their replacements:
-
-* [generator-star](https://eslint.org/docs/rules/generator-star) is replaced by [generator-star-spacing](https://eslint.org/docs/rules/generator-star-spacing)
-* [global-strict](https://eslint.org/docs/rules/global-strict) is replaced by [strict](https://eslint.org/docs/rules/strict)
-* [no-comma-dangle](https://eslint.org/docs/rules/no-comma-dangle) is replaced by [comma-dangle](https://eslint.org/docs/rules/comma-dangle)
-* [no-empty-class](https://eslint.org/docs/rules/no-empty-class) is replaced by [no-empty-character-class](https://eslint.org/docs/rules/no-empty-character-class)
-* [no-extra-strict](https://eslint.org/docs/rules/no-extra-strict) is replaced by [strict](https://eslint.org/docs/rules/strict)
-* [no-reserved-keys](https://eslint.org/docs/rules/no-reserved-keys) is replaced by [quote-props](https://eslint.org/docs/rules/quote-props)
-* [no-space-before-semi](https://eslint.org/docs/rules/no-space-before-semi) is replaced by [semi-spacing](https://eslint.org/docs/rules/semi-spacing)
-* [no-wrap-func](https://eslint.org/docs/rules/no-wrap-func) is replaced by [no-extra-parens](https://eslint.org/docs/rules/no-extra-parens)
-* [space-after-function-name](https://eslint.org/docs/rules/space-after-function-name) is replaced by [space-before-function-paren](https://eslint.org/docs/rules/space-before-function-paren)
-* [space-before-function-parentheses](https://eslint.org/docs/rules/space-before-function-parentheses) is replaced by [space-before-function-paren](https://eslint.org/docs/rules/space-before-function-paren)
-* [space-in-brackets](https://eslint.org/docs/rules/space-in-brackets) is replaced by[object-curly-spacing](https://eslint.org/docs/rules/object-curly-spacing) and [array-bracket-spacing](https://eslint.org/docs/rules/array-bracket-spacing)
-* [space-unary-word-ops](https://eslint.org/docs/rules/space-unary-word-ops) is replaced by [space-unary-ops](https://eslint.org/docs/rules/space-unary-ops)
-* [spaced-line-comment](https://eslint.org/docs/rules/spaced-line-comment) is replaced by [spaced-comment](https://eslint.org/docs/rules/spaced-comment)
-
-**To address:** You'll need to update your rule configurations to use the new rules. ESLint v1.0.0 will also warn you when you're using a rule that has been removed and will suggest the replacement rules. Hopefully, this will result in few surprises during the upgrade process.
-
-## Column Numbers are 1-based
-
-From the beginning, ESLint has reported errors using 0-based columns because that's what Esprima, and later Espree, reported. However, most tools and editors use 1-based columns, which made for some tricky integrations with ESLint. In v1.0.0, we've switched over to reporting errors using 1-based columns to fall into line with the tools developers use everyday.
-
-**To address:** If you've created an editor integration, or a tool that had to correct the column number, you'll need to update to just pass through the column number from ESLint. Otherwise, no change is necessary.
-
-## No Longer Exporting cli
-
-In 0.x, the `cli` object was exported for use by external tools. It was later deprecated in favor of `CLIEngine`. In v1.0.0, we are no longer exporting `cli` as it should not be used by external tools. This will break existing tools that make use of it.
-
-**To address:** If you are using the exported `cli` object, switch to using `CLIEngine` instead.
-
-## Deprecating eslint-tester
-
-The `eslint-tester` module, which has long been the primary tester for ESLint rules, has now been moved into the `eslint` module. This was the result of a difficult relationship between these two modules that created circular dependencies and was causing a lot of problems in rule tests. Moving the tester into the `eslint` module fixed a lot of those issues.
-
-The replacement for `eslint-tester` is called `RuleTester`. It's a simplified version of `ESLintTester` that's designed to work with any testing framework. This object is exposed by the package.
-
-**To address:** Convert all of your rule tests to use `RuleTester`. If you have this as a test using `ESLintTester`:
-
-```js
-var eslint = require("../../../lib/eslint"),
- ESLintTester = require("eslint-tester");
-
-var eslintTester = new ESLintTester(eslint);
-eslintTester.addRuleTest("lib/rules/your-rule", {
- valid: [],
- invalid: []
-});
-```
-
-Then you can change to:
-
-```js
-var rule = require("../../../lib/rules/your-rule"),
- RuleTester = require("eslint").RuleTester;
-
-var ruleTester = new RuleTester();
-ruleTester.run("your-rule", rule, {
- valid: [],
- invalid: []
-});
-```
+++ /dev/null
----
-title: Migrating to v2.0.0
-layout: doc
-
----
-
-ESLint v2.0.0 is the second major version release. As a result, there are some significant changes between how ESLint worked during its life in 0.x and 1.x and how it will work going forward. These changes are the direct result of feedback from the ESLint community of users and were not made without due consideration for the upgrade path. We believe that these changes make ESLint even better, and while some work is necessary to upgrade, we hope the pain of this upgrade is small enough that you will see the benefit of upgrading.
-
-**Important:** If you are upgrading from 0.x, please refer to [Migrating to 1.0.0](./migrating-to-1.0.0) as your starting point.
-
-## Rule Schema Changes
-
-Due to a quirk in the way rule schemas worked, it was possible that you'd need to account for the rule severity (0, 1, or 2) in a rule schema if the options were sufficiently complex. That would result in a schema such as:
-
-```js
-module.exports = {
- "type": "array",
- "items": [
- {
- "enum": [0, 1, 2]
- },
- {
- "enum": ["always", "never"]
- }
- ],
- "minItems": 1,
- "maxItems": 2
-};
-```
-
-This was confusing to rule developers as it seemed that rules shouldn't be in charge of validating their own severity. In 2.0.0, rules no longer need to check their own severity.
-
-**To address:** If you are exporting a rule schema that checks severity, you need to make several changes:
-
-1. Remove the severity from the schema
-1. Adjust `minItems` from 1 to 0
-1. Adjust `maxItems` by subtracting 1
-
-Here's what the schema from above looks like when properly converted:
-
-```js
-module.exports = {
- "type": "array",
- "items": [
- {
- "enum": ["always", "never"]
- }
- ],
- "minItems": 0,
- "maxItems": 1
-};
-```
-
-## Removed Rules
-
-The following rules have been deprecated with new rules created to take their place. The following is a list of the removed rules and their replacements:
-
-* [no-arrow-condition](https://eslint.org/docs/rules/no-arrow-condition) is replaced by a combination of [no-confusing-arrow](https://eslint.org/docs/rules/no-confusing-arrow) and [no-constant-condition](https://eslint.org/docs/rules/no-constant-condition). Turn on both of these rules to get the same functionality as `no-arrow-condition`.
-* [no-empty-label](https://eslint.org/docs/rules/no-empty-label) is replaced by [no-labels](https://eslint.org/docs/rules/no-labels) with `{"allowLoop": true, "allowSwitch": true}` option.
-* [space-after-keywords](https://eslint.org/docs/rules/space-after-keywords) is replaced by [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing).
-* [space-before-keywords](https://eslint.org/docs/rules/space-before-keywords) is replaced by [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing).
-* [space-return-throw-case](https://eslint.org/docs/rules/space-return-throw-case) is replaced by [keyword-spacing](https://eslint.org/docs/rules/keyword-spacing).
-
-**To address:** You'll need to update your rule configurations to use the new rules. ESLint v2.0.0 will also warn you when you're using a rule that has been removed and will suggest the replacement rules. Hopefully, this will result in few surprises during the upgrade process.
-
-## Configuration Cascading Changes
-
-Prior to 2.0.0, if a directory contained both an `.eslintrc` file and a `package.json` file with ESLint configuration information, the settings from the two files would be merged together. In 2.0.0, only the settings from the `.eslintrc.*` file are used and the ones in `package.json` are ignored when both are present. Otherwise, `package.json` can still be used with ESLint configuration, but only if no other `.eslintrc.*` files are present.
-
-**To address:** If you have both an `.eslintrc.*` and `package.json` with ESLint configuration information in the same directory, combine your configurations into just one of those files.
-
-## Built-In Global Variables
-
-Prior to 2.0.0, new global variables that were standardized as part of ES6 such as `Promise`, `Map`, `Set`, and `Symbol` were included in the built-in global environment. This could lead to potential issues when, for example, `no-undef` permitted use of the `Promise` constructor even in ES5 code where promises are unavailable. In 2.0.0, the built-in environment only includes the standard ES5 global variables, and the new ES6 global variables have been moved to the `es6` environment.
-
-**To address:** If you are writing ES6 code, enable the `es6` environment if you have not already done so:
-
-```js
-// In your .eslintrc
-{
- env: {
- es6: true
- }
-}
-
-// Or in a configuration comment
-/*eslint-env es6*/
-```
-
-## Language Options
-
-Prior to 2.0.0, the way to enable language options was by using `ecmaFeatures` in your configuration. In 2.0.0:
-
-* The `ecmaFeatures` property is now under a top-level `parserOptions` property.
-* All ECMAScript 6 `ecmaFeatures` flags have been removed in favor of a `ecmaVersion` property under `parserOptions` that can be set to 3, 5 (default), or 6.
-* The `ecmaFeatures.modules` flag has been replaced by a `sourceType` property under `parserOptions` which can be set to `"script"` (default) or `"module"` for ES6 modules.
-
-**To address:** If you are using any ECMAScript 6 feature flags in `ecmaFeatures`, you'll need to use `ecmaVersion: 6` instead. The ECMAScript 6 feature flags are:
-
-* `arrowFunctions` - enable [arrow functions](https://leanpub.com/understandinges6/read#leanpub-auto-arrow-functions)
-* `binaryLiterals` - enable [binary literals](https://leanpub.com/understandinges6/read#leanpub-auto-octal-and-binary-literals)
-* `blockBindings` - enable `let` and `const` (aka [block bindings](https://leanpub.com/understandinges6/read#leanpub-auto-block-bindings))
-* `classes` - enable classes
-* `defaultParams` - enable [default function parameters](https://leanpub.com/understandinges6/read/#leanpub-auto-default-parameters)
-* `destructuring` - enable [destructuring](https://leanpub.com/understandinges6/read#leanpub-auto-destructuring-assignment)
-* `forOf` - enable [`for-of` loops](https://leanpub.com/understandinges6/read#leanpub-auto-iterables-and-for-of)
-* `generators` - enable [generators](https://leanpub.com/understandinges6/read#leanpub-auto-generators)
-* `modules` - enable modules and global strict mode
-* `objectLiteralComputedProperties` - enable [computed object literal property names](https://leanpub.com/understandinges6/read#leanpub-auto-computed-property-names)
-* `objectLiteralDuplicateProperties` - enable [duplicate object literal properties](https://leanpub.com/understandinges6/read#leanpub-auto-duplicate-object-literal-properties) in strict mode
-* `objectLiteralShorthandMethods` - enable [object literal shorthand methods](https://leanpub.com/understandinges6/read#leanpub-auto-method-initializer-shorthand)
-* `objectLiteralShorthandProperties` - enable [object literal shorthand properties](https://leanpub.com/understandinges6/read#leanpub-auto-property-initializer-shorthand)
-* `octalLiterals` - enable [octal literals](https://leanpub.com/understandinges6/read#leanpub-auto-octal-and-binary-literals)
-* `regexUFlag` - enable the [regular expression `u` flag](https://leanpub.com/understandinges6/read#leanpub-auto-the-regular-expression-u-flag)
-* `regexYFlag` - enable the [regular expression `y` flag](https://leanpub.com/understandinges6/read#leanpub-auto-the-regular-expression-y-flag)
-* `restParams` - enable the [rest parameters](https://leanpub.com/understandinges6/read#leanpub-auto-rest-parameters)
-* `spread` - enable the [spread operator](https://leanpub.com/understandinges6/read#leanpub-auto-the-spread-operator) for arrays
-* `superInFunctions` - enable `super` references inside of functions
-* `templateStrings` - enable [template strings](https://leanpub.com/understandinges6/read/#leanpub-auto-template-strings)
-* `unicodeCodePointEscapes` - enable [code point escapes](https://leanpub.com/understandinges6/read/#leanpub-auto-escaping-non-bmp-characters)
-
-If you're using any of these flags, such as:
-
-```js
-{
- ecmaFeatures: {
- arrowFunctions: true
- }
-}
-```
-
-Then you should enable ES6 using `ecmaVersion`:
-
-```js
-{
- parserOptions: {
- ecmaVersion: 6
- }
-}
-```
-
-If you're using any non-ES6 flags in `ecmaFeatures`, you need to move those inside of `parserOptions`. For instance:
-
-```js
-{
- ecmaFeatures: {
- jsx: true
- }
-}
-```
-
-Then you should move `ecmaFeatures` under `parserOptions`:
-
-```js
-{
- parserOptions: {
- ecmaFeatures: {
- jsx: true
- }
- }
-}
-```
-
-If you were using `ecmaFeatures.modules` to enable ES6 module support like this:
-
-```js
-{
- ecmaFeatures: {
- modules: true
- }
-}
-```
-
-```js
-{
- parserOptions: {
- sourceType: "module"
- }
-}
-```
-
-Additionally, if you are using `context.ecmaFeatures` inside of your rules, then you'll need to update your code in the following ways:
-
-1. If you're using an ES6 feature flag such as `context.ecmaFeatures.blockBindings`, rewrite to check for `context.parserOptions.ecmaVersion > 5`.
-1. If you're using `context.ecmaFeatures.modules`, rewrite to check that the `sourceType` property of the Program node is `"module"`.
-1. If you're using a non-ES6 feature flag such as `context.ecmaFeatures.jsx`, rewrite to check for `context.parserOptions.ecmaFeatures.jsx`.
-
-If you have a plugin with rules and you are using RuleTester, then you also need to update the options you pass for rules that use `ecmaFeatures`. For example:
-
-```js
-var ruleTester = new RuleTester();
-ruleTester.run("no-var", rule, {
- valid: [
- {
- code: "let x;",
- parserOptions: { ecmaVersion: 6 }
- }
- ]
-});
-```
-
-If you're not using `ecmaFeatures` in your configuration or your custom/plugin rules and tests, then no change is needed.
-
-## New Rules in `"eslint:recommended"`
-
-```json
-{
- "extends": "eslint:recommended"
-}
-```
-
-In 2.0.0, the following 11 rules were added to `"eslint:recommended"`.
-
-* [constructor-super](https://eslint.org/docs/rules/constructor-super)
-* [no-case-declarations](https://eslint.org/docs/rules/no-case-declarations)
-* [no-class-assign](https://eslint.org/docs/rules/no-class-assign)
-* [no-const-assign](https://eslint.org/docs/rules/no-const-assign)
-* [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members)
-* [no-empty-pattern](https://eslint.org/docs/rules/no-empty-pattern)
-* [no-new-symbol](https://eslint.org/docs/rules/no-new-symbol)
-* [no-self-assign](https://eslint.org/docs/rules/no-self-assign)
-* [no-this-before-super](https://eslint.org/docs/rules/no-this-before-super)
-* [no-unexpected-multiline](https://eslint.org/docs/rules/no-unexpected-multiline)
-* [no-unused-labels](https://eslint.org/docs/rules/no-unused-labels)
-
-**To address:** If you don't want to be notified by those rules, you can simply disable those rules.
-
-```json
-{
- "extends": "eslint:recommended",
- "rules": {
- "no-case-declarations": 0,
- "no-class-assign": 0,
- "no-const-assign": 0,
- "no-dupe-class-members": 0,
- "no-empty-pattern": 0,
- "no-new-symbol": 0,
- "no-self-assign": 0,
- "no-this-before-super": 0,
- "no-unexpected-multiline": 0,
- "no-unused-labels": 0,
- "constructor-super": 0
- }
-}
-```
-
-## Scope Analysis Changes
-
-We found some bugs in our scope analysis that needed to be addressed. Specifically, we were not properly accounting for global variables in all the ways they are defined.
-
-Originally, `Variable` objects and `Reference` objects refer each other:
-
-* `Variable#references` property is an array of `Reference` objects which are referencing the variable.
-* `Reference#resolved` property is a `Variable` object which are referenced.
-
-But until 1.x, the following variables and references had the wrong value (empty) in those properties:
-
-* `var` declarations in the global.
-* `function` declarations in the global.
-* Variables defined in config files.
-* Variables defined in `/* global */` comments.
-
-Now, those variables and references have correct values in these properties.
-
-`Scope#through` property has references where `Reference#resolved` is `null`. So as a result of this change, the value of `Scope#through` property was changed also.
-
-**To address:** If you are using `Scope#through` to find references of a built-in global variable, you need to make several changes.
-
-For example, this is how you might locate the `window` global variable in 1.x:
-
-```js
-var globalScope = context.getScope();
-globalScope.through.forEach(function(reference) {
- if (reference.identifier.name === "window") {
- checkForWindow(reference);
- }
-});
-```
-
-This was a roundabout way to find the variable because it was added after the fact by ESLint. The `window` variable was in `Scope#through` because the definition couldn't be found.
-
-In 2.0.0, `window` is no longer located in `Scope#through` because we have added back the correct declaration. That means you can reference the `window` object (or any other global object) directly. So the previous example would change to this:
-
-```js
-var globalScope = context.getScope();
-var variable = globalScope.set.get("window");
-if (variable) {
- variable.references.forEach(checkForWindow);
-}
-```
-
-Further Reading: <https://estools.github.io/escope/>
-
-## Default Changes When Using `eslint:recommended`
-
-This will affect you if you are extending from `eslint:recommended`, and are enabling [`no-multiple-empty-lines`] or [`func-style`] with only a severity, such as:
-
-```json
-{
- "extends": "eslint:recommended",
- "rules": {
- "no-multiple-empty-lines": 2,
- "func-style": 2
- }
-}
-```
-
-The rule `no-multiple-empty-lines` has no default exceptions, but in ESLint `1.x`, a default from `eslint:recommended` was applied such that a maximum of two empty lines would be permitted.
-
-The rule `func-style` has a default configuration of `"expression"`, but in ESLint `1.x`, `eslint:recommended` defaulted it to `"declaration"`.
-
-ESLint 2.0.0 removes these conflicting defaults, and so you may begin seeing linting errors related to these rules.
-
-**To address:** If you would like to maintain the previous behavior, update your configuration for `no-multiple-empty-lines` by adding `{"max": 2}`, and change `func-style` to `"declaration"`. For example:
-
-```json
-{
- "extends": "eslint:recommended",
- "rules": {
- "no-multiple-empty-lines": [2, {"max": 2}],
- "func-style": [2, "declaration"]
- }
-}
-```
-
-[`no-multiple-empty-lines`]: ../rules/no-multiple-empty-lines
-[`func-style`]: ../rules/func-style
-
-## SourceCode constructor (Node API) changes
-
-`SourceCode` constructor got to handle Unicode BOM.
-If the first argument `text` has BOM, `SourceCode` constructor sets `true` to `this.hasBOM` and strips BOM from the text.
-
-```js
-var SourceCode = require("eslint").SourceCode;
-
-var code = new SourceCode("\uFEFFvar foo = bar;", ast);
-
-assert(code.hasBOM === true);
-assert(code.text === "var foo = bar;");
-```
-
-So the second argument `ast` also should be parsed from stripped text.
-
-**To address:** If you are using `SourceCode` constructor in your code, please parse the source code after it stripped BOM:
-
-```js
-var ast = yourParser.parse(text.replace(/^\uFEFF/, ""), options);
-var sourceCode = new SourceCode(text, ast);
-```
-
-## Rule Changes
-
-* [`strict`](../rules/strict) - defaults to `"safe"` (previous default was `"function"`)
-
-## Plugins No Longer Have Default Configurations
-
-Prior to v2.0.0, plugins could specify a `rulesConfig` for the plugin. The `rulesConfig` would automatically be applied whenever someone uses the plugin, which is the opposite of what ESLint does in every other situation (where nothing is on by default). To bring plugins behavior in line, we have removed support for `rulesConfig` in plugins.
-
-**To address:** If you are using a plugin in your configuration file, you will need to manually enable the plugin rules in the configuration file.
+++ /dev/null
----
-title: Migrating to v3.0.0
-layout: doc
-
----
-
-ESLint v3.0.0 is the third major version release. We have made several breaking changes in this release, however, we believe the changes to be small enough that they should not require significant changes for ESLint users. This guide is intended to walk you through the changes.
-
-## Dropping Support for Node.js < 4
-
-With ESLint v3.0.0, we are dropping support for Node.js versions prior to 4. Node.js 0.10 and 0.12 are in [maintenance mode](https://github.com/nodejs/Release) and Node.js 4 is the current LTS version. If you are using an older version of Node.js, we recommend upgrading to at least Node.js 4 as soon as possible. If you are unable to upgrade to Node.js 4 or higher, then we recommend continuing to use ESLint v2.x until you are ready to upgrade Node.js.
-
-**Important:** We will not be updating the ESLint v2.x versions going forward. All bug fixes and enhancements will land in ESLint v3.x.
-
-## Requiring Configuration to Run
-
-ESLint v3.0.0 now requires that you use a configuration to run. A configuration can be any of the following:
-
-1. A `.eslintrc.js`, `.eslintrc.json`, `.eslintrc.yml`, `.eslintrc.yaml`, or `.eslintrc` file either in your project or home directory.
-2. Configuration options passed on the command line using `--rule` (or to CLIEngine using `rules`).
-3. A configuration file passed on the command line using `-c` (or to CLIEngine using `configFile`).
-4. A base configuration is provided to CLIEngine using the `baseConfig` option.
-
-If ESLint can't find a configuration, then it will throw an error and ask you to provide one.
-
-This change was made to help new ESLint users who are frequently confused that ESLint does nothing by default besides reporting parser errors. We anticipate this change will have minimal impact on most established users because you're more likely to have configuration files already.
-
-**To Address:** You should be sure to use a configuration whenever you run ESLint. However, you can still run ESLint without a configuration by passing the `--no-eslintrc` option on the command line or setting the `useEslintrc` option to `false` for `CLIEngine`.
-
-To create a new configuration, use `eslint --init`.
-
-## Changes to `"eslint:recommended"`
-
-```json
-{
- "extends": "eslint:recommended"
-}
-```
-
-In 3.0.0, the following rules were added to `"eslint:recommended"`:
-
-* [`no-unsafe-finally`](https://eslint.org/docs/rules/no-unsafe-finally) helps catch `finally` clauses that may not behave as you think.
-* [`no-native-reassign`](https://eslint.org/docs/rules/no-native-reassign) was previously part of `no-undef`, but was split out because it didn't make sense as part of another rule. The `no-native-reassign` rule warns whenever you try to overwrite a read-only global variable.
-* [`require-yield`](https://eslint.org/docs/rules/require-yield) helps to identify generator functions that do not have the `yield` keyword.
-
-The following rules were removed from `"eslint:recommended"`:
-
-* [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle) used to be recommended because Internet Explorer 8 and earlier threw a syntax error when it found a dangling comma on object literal properties. However, [Internet Explorer 8 was end-of-lifed](https://www.microsoft.com/en-us/WindowsForBusiness/End-of-IE-support) in January 2016 and all other active browsers allow dangling commas. As such, we consider dangling commas to now be a stylistic issue instead of a possible error.
-
-The following rules were modified:
-
-* [`complexity`](https://eslint.org/docs/rules/complexity) used to have a hardcoded default of 11 in `eslint:recommended` that would be used if you turned the rule on without specifying a maximum. The default is now 20. The rule actually always had a default of 20, but `eslint:recommended` was overriding it by mistake.
-
-**To address:** If you want to mimic how `eslint:recommended` worked in v2.x, you can use the following:
-
-```json
-{
- "extends": "eslint:recommended",
- "rules": {
- "no-unsafe-finally": "off",
- "no-native-reassign": "off",
- "complexity": ["off", 11],
- "comma-dangle": "error",
- "require-yield": "error"
- }
-}
-```
-
-## Changes to `CLIEngine#executeOnText()`
-
-The `CLIEngine#executeOnText()` method has changed to work more like `CLIEngine#executeOnFiles()`. In v2.x, `CLIEngine#executeOnText()` warned about ignored files by default and didn't have a way to opt-out of those warnings whereas `CLIEngine#executeOnFiles()` did not warn about ignored files by default and allowed you to opt-in to warning about them. The `CLIEngine#executeOnText()` method now also does not warn about ignored files by default and allows you to opt-in with a new, third argument (a boolean, `true` to warn about ignored files and `false` to not warn).
-
-**To address:** If you are currently using `CLIEngine#executeOnText()` in your project like this:
-
-```js
-var result = engine.executeOnText(text, filename);
-```
-
-You can get the equivalent behavior using this:
-
-```js
-var result = engine.executeOnText(text, filename, true);
-```
-
-If you do not want ignored file warnings output to the console, you can omit the third argument or pass `false`.
+++ /dev/null
----
-title: Migrating to v4.0.0
-layout: doc
-
----
-
-ESLint v4.0.0 is the fourth major version release. We have made several breaking changes in this release; however, we expect that most of the changes will only affect a very small percentage of users. This guide is intended to walk you through the 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
-
-1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
-1. [The `indent` rule is more strict](#indent-rewrite)
-1. [Unrecognized properties in config files now cause a fatal error](#config-validation)
-1. [.eslintignore patterns are now resolved from the location of the file](#eslintignore-patterns)
-1. [The `padded-blocks` rule is more strict by default](#padded-blocks-defaults)
-1. [The `space-before-function-paren` rule is more strict by default](#space-before-function-paren-defaults)
-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
-
-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
-
-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)
-1. [Some exposed APIs are now ES2015 classes](#exposed-es2015-classes)
-
----
-
-## <a name="eslint-recommended-changes"></a> `eslint:recommended` changes
-
-Two new rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config:
-
-* [`no-compare-neg-zero`](/docs/rules/no-compare-neg-zero) disallows comparisons to `-0`
-* [`no-useless-escape`](/docs/rules/no-useless-escape) disallows uselessly-escaped characters in strings and regular expressions
-
-**To address:** To mimic the `eslint:recommended` behavior from 3.x, you can disable these rules in a config file:
-
-```json
-{
- "extends": "eslint:recommended",
-
- "rules": {
- "no-compare-neg-zero": "off",
- "no-useless-escape": "off"
- }
-}
-```
-
-## <a name="indent-rewrite"></a> The `indent` rule is more strict
-
-Previously, the [`indent`](/docs/rules/indent) rule was fairly lenient about checking indentation; there were many code patterns where indentation was not validated by the rule. This caused confusion for users, because they were accidentally writing code with incorrect indentation, and they expected ESLint to catch the issues.
-
-In 4.0.0, the `indent` rule has been rewritten. The new version of the rule will report some indentation errors that the old version of the rule did not catch. Additionally, the indentation of `MemberExpression` nodes, function parameters, and function arguments will now be checked by default (it was previously ignored by default for backwards compatibility).
-
-To make the upgrade process easier, we've introduced the [`indent-legacy`](/docs/rules/indent-legacy) rule as a snapshot of the `indent` rule from 3.x. If you run into issues from the `indent` rule when you upgrade, you should be able to use the `indent-legacy` rule to replicate the 3.x behavior. However, the `indent-legacy` rule is deprecated and will not receive bugfixes or improvements in the future, so you should eventually switch back to the `indent` rule.
-
-**To address:** We recommend upgrading without changing your `indent` configuration, and fixing any new indentation errors that appear in your codebase. However, if you want to mimic how the `indent` rule worked in 3.x, you can update your configuration:
-
-```js
-{
- rules: {
- indent: "off",
- "indent-legacy": "error" // replace this with your previous `indent` configuration
- }
-}
-```
-
-## <a name="config-validation"></a> Unrecognized properties in config files now cause a fatal error
-
-When creating a config, users sometimes make typos or misunderstand how the config is supposed to be structured. Previously, ESLint did not validate the properties of a config file, so a typo in a config could be very tedious to debug. Starting in 4.0.0, ESLint will raise an error if a property in a config file is unrecognized or has the wrong type.
-
-**To address:** If you see a config validation error after upgrading, verify that your config doesn't contain any typos. If you are using an unrecognized property, you should be able to remove it from your config to restore the previous behavior.
-
-## <a name="eslintignore-patterns"></a> .eslintignore patterns are now resolved from the location of the file
-
-Due to a bug, glob patterns in an `.eslintignore` file were previously resolved from the current working directory of the process, rather than the location of the `.eslintignore` file. Starting in 4.0, patterns in an `.eslintignore` file will be resolved from the `.eslintignore` file's location.
-
-**To address:** If you use an `.eslintignore` file and you frequently run ESLint from somewhere other than the project root, it's possible that the patterns will be matched differently. You should update the patterns in the `.eslintignore` file to ensure they are relative to the file, not to the working directory.
-
-## <a name="padded-blocks-defaults"></a> The `padded-blocks` rule is more strict by default
-
-By default, the [`padded-blocks`](/docs/rules/padded-blocks) rule will now enforce padding in class bodies and switch statements. Previously, the rule would ignore these cases unless the user opted into enforcing them.
-
-**To address:** If this change results in more linting errors in your codebase, you should fix them or reconfigure the rule.
-
-## <a name="space-before-function-paren-defaults"></a> The `space-before-function-paren` rule is more strict by default
-
-By default, the [`space-before-function-paren`](/docs/rules/space-before-function-paren) rule will now enforce spacing for async arrow functions. Previously, the rule would ignore these cases unless the user opted into enforcing them.
-
-**To address:** To mimic the default config from 3.x, you can use:
-
-```json
-{
- "rules": {
- "space-before-function-paren": ["error", {
- "anonymous": "always",
- "named": "always",
- "asyncArrow": "ignore"
- }]
- }
-}
-```
-
-## <a name="no-multi-spaces-eol-comments"></a> The `no-multi-spaces` rule is more strict by default
-
-By default, the [`no-multi-spaces`](/docs/rules/no-multi-spaces) rule will now disallow multiple spaces before comments at the end of a line. Previously, the rule did not check this case.
-
-**To address:** To mimic the default config from 3.x, you can use:
-
-```json
-{
- "rules": {
- "no-multi-spaces": ["error", {"ignoreEOLComments": true}]
- }
-}
-```
-
-## <a name="scoped-plugin-resolution"></a> References to scoped plugins in config files are now required to include the scope
-
-In 3.x, there was a bug where references to scoped NPM packages as plugins in config files could omit the scope. For example, in 3.x the following config was legal:
-
-```json
-{
- "plugins": [
- "@my-organization/foo"
- ],
- "rules": {
- "foo/some-rule": "error"
- }
-}
-```
-
-In other words, it was possible to reference a rule from a scoped plugin (such as `foo/some-rule`) without explicitly stating the `@my-organization` scope. This was a bug because it could lead to ambiguous rule references if there was also an unscoped plugin called `eslint-plugin-foo` loaded at the same time.
-
-To avoid this ambiguity, in 4.0 references to scoped plugins must include the scope. The config from above should be fixed to:
-
-```json
-{
- "plugins": [
- "@my-organization/foo"
- ],
- "rules": {
- "@my-organization/foo/some-rule": "error"
- }
-}
-```
-
-**To address:** If you reference a scoped NPM package as a plugin in a config file, be sure to include the scope wherever you reference it.
-
----
-
-## <a name="rule-tester-validation"></a> `RuleTester` now validates properties of test cases
-
-Starting in 4.0, the `RuleTester` utility will validate properties of test case objects, and an error will be thrown if an unknown property is encountered. This change was added because we found that it was relatively common for developers to make typos in rule tests, often invalidating the assertions that the test cases were trying to make.
-
-**To address:** If your tests for custom rules have extra properties, you should remove those properties.
-
-## <a name="comment-attachment"></a> AST Nodes no longer have comment properties
-
-Prior to 4.0, ESLint required parsers to implement comment attachment, a process where AST nodes would gain additional properties corresponding to their leading and trailing comments in the source file. This made it difficult for users to develop custom parsers, because they would have to replicate the confusing comment attachment semantics required by ESLint.
-
-In 4.0, we have moved away from the concept of comment attachment and have moved all comment handling logic into ESLint itself. This should make it easier to develop custom parsers, but it also means that AST nodes will no longer have `leadingComments` and `trailingComments` properties. Conceptually, rule authors can now think of comments in the context of tokens rather than AST nodes.
-
-**To address:** If you have a custom rule that depends on the `leadingComments` or `trailingComments` properties of an AST node, you can now use `sourceCode.getCommentsBefore()` and `sourceCode.getCommentsAfter()` instead, respectively.
-
-Additionally, the `sourceCode` object now also has `sourceCode.getCommentsInside()` (which returns all the comments inside a node), `sourceCode.getAllComments()` (which returns all the comments in the file), and allows comments to be accessed through various other token iterator methods (such as `getTokenBefore()` and `getTokenAfter()`) with the `{ includeComments: true }` option.
-
-For rule authors concerned about supporting ESLint v3.0 in addition to v4.0, the now deprecated `sourceCode.getComments()` is still available and will work for both versions.
-
-Finally, please note that the following `SourceCode` methods have been deprecated and will be removed in a future version of ESLint:
-
-* `getComments()` - replaced by `getCommentsBefore()`, `getCommentsAfter()`, and `getCommentsInside()`
-* `getTokenOrCommentBefore()` - replaced by `getTokenBefore()` with the `{ includeComments: true }` option
-* `getTokenOrCommentAfter()` - replaced by `getTokenAfter()` with the `{ includeComments: true }` option
-
-## <a name="event-comments"></a> `LineComment` and `BlockComment` events will no longer be emitted during AST traversal
-
-Starting in 4.0, `LineComment` and `BlockComments` events will not be emitted during AST traversal. There are two reasons for this:
-
-* This behavior was relying on comment attachment happening at the parser level, which does not happen anymore, to ensure that all comments would be accounted for
-* Thinking of comments in the context of tokens is more predictable and easier to reason about than thinking about comment tokens in the context of AST nodes
-
-**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");
-```
-
-## <a name="shebangs"></a> Shebangs are now returned from comment APIs
-
-Prior to 4.0, shebang comments in a source file would not appear in the output of `sourceCode.getAllComments()` or `sourceCode.getComments()`, but they would appear in the output of `sourceCode.getTokenOrCommentBefore` as line comments. This inconsistency led to some confusion for rule developers.
-
-In 4.0, shebang comments are treated as comment tokens of type `Shebang` and will be returned by any `SourceCode` method that returns comments. The goal of this change is to make working with shebang comments more consistent with how other tokens are handled.
-
-**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");
-```
-
----
-
-## <a name="global-property"></a> The `global` property in the `linter.verify()` API is no longer supported
-
-Previously, the `linter.verify()` API accepted a `global` config option, which was a synonym for the documented `globals` property. The `global` option was never documented or officially supported, and did not work in config files. It has been removed in 4.0.
-
-**To address:** If you were using the `global` property, please use the `globals` property instead, which does the same thing.
-
-## <a name="report-locations"></a> More report messages now have full location ranges
-
-Starting in 3.1.0, rules have been able to specify the *end* location of a reported problem, in addition to the start location, by explicitly specifying an end location in the `report` call. This is useful for tools like editor integrations, which can use the range to precisely display where a reported problem occurs. Starting in 4.0, if a *node* is reported rather than a location, the end location of the range will automatically be inferred from the end location of the node. As a result, many more reported problems will have end locations.
-
-This is not expected to cause breakage. However, it will likely result in larger report locations than before. For example, if a rule reports the root node of the AST, the reported problem's range will be the entire program. In some integrations, this could result in a poor user experience (e.g. if the entire program is highlighted to indicate an error).
-
-**To address:** If you have an integration that deals with the ranges of reported problems, make sure you handle large report ranges in a user-friendly way.
-
-## <a name="exposed-es2015-classes"></a> Some exposed APIs are now ES2015 classes
-
-The `CLIEngine`, `SourceCode`, and `RuleTester` modules from ESLint's Node.js API are now ES2015 classes. This will not break any documented behavior, but it does have some observable effects (for example, the methods on `CLIEngine.prototype` are now non-enumerable).
-
-**To address:** If you rely on enumerating the methods of ESLint's Node.js APIs, use a function that can also access non-enumerable properties such as `Object.getOwnPropertyNames`.
+++ /dev/null
----
-title: Migrating to v5.0.0
-layout: doc
-
----
-
-ESLint v5.0.0 is the fifth major version release. We have made a few breaking changes in this release, but we expect that most users will be able to upgrade without any modifications to their build. This guide is intended to walk you through the 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
-
-1. [Node.js 4 is no longer supported](#drop-node-4)
-1. [New rules have been added to `eslint:recommended`](#eslint-recommended-changes)
-1. [The `experimentalObjectRestSpread` option has been deprecated](#experimental-object-rest-spread)
-1. [Linting nonexistent files from the command line is now a fatal error](#nonexistent-files)
-1. [The default options for some rules have changed](#rule-default-changes)
-1. [Deprecated globals have been removed from the `node`, `browser`, and `jest` environments](#deprecated-globals)
-1. [Empty files are now linted](#empty-files)
-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
-
-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)
-1. [When using the default parser, rest operators now have type `RestElement`](#rest-operators)
-1. [When using the default parser, text nodes in JSX elements now have type `JSXText`](#jsx-text-nodes)
-1. [The `context.getScope()` method now returns more proper scopes](#context-get-scope)
-1. [The `_linter` property on rule context objects has been removed](#no-context-linter)
-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
-
-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)
-1. [The `eslint.linter` property is now non-enumerable](#non-enumerable-linter)
-
----
-
-## <a name="drop-node-4"></a> Node.js 4 is no longer supported
-
-As of April 30th, 2018, Node.js 4 will be at EOL and will no longer be receiving security updates. As a result, we have decided to drop support for it in ESLint v5. We now support the following versions of Node.js:
-
-* Node.js 6 (6.14.0 and above)
-* Node.js 8 (8.10.0 and above)
-* Anything above Node.js 9.10.0
-
-**To address:** Make sure you upgrade to at least Node.js 6 when using ESLint v5. If you are unable to upgrade, we recommend continuing to use ESLint v4.x until you are able to upgrade Node.js.
-
-## <a name="eslint-recommended-changes"/> `eslint:recommended` changes
-
-Two new rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config:
-
-* [`for-direction`](/docs/rules/for-direction) enforces that a `for` loop update clause moves the counter in the right direction.
-* [`getter-return`](/docs/rules/getter-return) enforces that a `return` statement is present in property getters.
-
-**To address:** To mimic the `eslint:recommended` behavior from 4.x, you can disable these rules in a config file:
-
-```json
-{
- "extends": "eslint:recommended",
-
- "rules": {
- "for-direction": "off",
- "getter-return": "off"
- }
-}
-```
-
-## <a name="experimental-object-rest-spread"></a> The `experimentalObjectRestSpread` option has been deprecated
-
-Previously, when using the default parser it was possible to use the `experimentalObjectRestSpread` option to enable support for [rest/spread properties](https://developers.google.com/web/updates/2017/06/object-rest-spread), as follows:
-
-```json
-{
- "parserOptions": {
- "ecmaFeatures": {
- "experimentalObjectRestSpread": true
- }
- }
-}
-```
-
-Object rest/spread is now an official part of the JavaScript language, so our support for it is no longer experimental. In both ESLint v4 and ESLint v5, object rest/spread can now be enabled with the `"ecmaVersion": 2018` option:
-
-```json
-{
- "parserOptions": {
- "ecmaVersion": 2018
- }
-}
-```
-
-Note that this also enables parsing for other features from ES2018, such as [async iteration](https://github.com/tc39/proposal-async-iteration). When using ESLint v5 with the default parser, it is no longer possible to toggle syntax support for object rest/spread independently of other features.
-
-For compatibility, ESLint v5 will treat `ecmaFeatures: { experimentalObjectRestSpread: true }` as an alias for `ecmaVersion: 2018` when the former is found in a config file. As a result, if you use object rest/spread, your code should still parse successfully with ESLint v5. However, note that this alias will be removed in ESLint v6.
-
-**To address:** If you use the `experimentalObjectRestSpread` option, you should be able to upgrade to ESLint v5 without any changes, but you will encounter a deprecation warning. To avoid the warning, use `ecmaVersion: 2018` in your config file rather than `ecmaFeatures: { experimentalObjectRestSpread: true }`. If you would like to disallow the use of other ES2018 features, consider using rules such as [`no-restricted-syntax`](/docs/rules/no-restricted-syntax).
-
-## <a name="nonexistent-files"></a> Linting nonexistent files from the command line is now a fatal error
-
-Previous versions of ESLint silently ignored any nonexistent files and globs provided on the command line:
-
-```bash
-eslint nonexistent-file.js 'nonexistent-folder/**/*.js' # exits without any errors in ESLint v4
-```
-
-Many users found this behavior confusing, because if they made a typo in a filename, ESLint would appear to lint that file successfully while actually not linting anything.
-
-ESLint v5 will report a fatal error when either of the following conditions is met:
-
-* A file provided on the command line does not exist
-* A glob or folder provided on the command line does not match any lintable files
-
-Note that this also affects the [`CLIEngine.executeOnFiles()`](https://eslint.org/docs/developer-guide/nodejs-api#cliengineexecuteonfiles) API.
-
-**To address:** If you encounter an error about missing files after upgrading to ESLint v5, you may want to double-check that there are no typos in the paths you provide to ESLint. To make the error go away, you can simply remove the given files or globs from the list of arguments provided to ESLint on the command line.
-
-If you use a boilerplate generator that relies on this behavior (e.g. to generate a script that runs `eslint tests/` in a new project before any test files are actually present), you can work around this issue by adding a dummy file that matches the given pattern (e.g. an empty `tests/index.js` file).
-
-## <a name="rule-default-changes"></a> The default options for some rules have changed
-
-* The default options for the [`object-curly-newline`](/docs/rules/object-curly-newline) rule have changed from `{ multiline: true }` to `{ consistent: true }`.
-* The default options object for the [`no-self-assign`](/docs/rules/no-self-assign) rule has changed from `{ props: false }` to `{ props: true }`.
-
-**To address:** To restore the rule behavior from ESLint v4, you can update your config file to include the previous options:
-
-```json
-{
- "rules": {
- "object-curly-newline": ["error", { "multiline": true }],
- "no-self-assign": ["error", { "props": false }]
- }
-}
-```
-
-## <a name="deprecated-globals"></a> Deprecated globals have been removed from the `node`, `browser`, and `jest` environments
-
-Some global variables have been deprecated or removed for code running in Node.js, browsers, and Jest. (For example, browsers used to expose an `SVGAltGlyphElement` global variable to JavaScript code, but this global has been removed from web standards and is no longer present in browsers.) As a result, we have removed these globals from the corresponding `eslint` environments, so use of these globals will trigger an error when using rules such as [`no-undef`](/docs/rules/no-undef).
-
-**To address:** If you use deprecated globals in the `node`, `browser`, or `jest` environments, you can add a `globals` section to your configuration to re-enable any globals you need. For example:
-
-```json
-{
- "env": {
- "browser": true
- },
- "globals": {
- "SVGAltGlyphElement": false
- }
-}
-```
-
-## <a name="empty-files"></a> Empty files are now linted
-
-ESLint v4 had a special behavior when linting files that only contain whitespace: it would skip running the parser and rules, and it would always return zero errors. This led to some confusion for users and rule authors, particularly when writing tests for rules. (When writing a stylistic rule, rule authors would occasionally write a test where the source code only contained whitespace, to ensure that the rule behaved correctly when no applicable code was found. However, a test like this would actually not run the rule at all, so an aspect of the rule would end up untested.)
-
-ESLint v5 treats whitespace-only files the same way as all other files: it parses them and runs enabled rules on them as appropriate. This could lead to additional linting problems if you use a custom rule that reports errors on empty files.
-
-**To address:** If you have an empty file in your project and you don't want it to be linted, consider adding it to an [`.eslintignore` file](/docs/user-guide/configuring#ignoring-files-and-directories).
-
-If you have a custom rule, you should make sure it handles empty files appropriately. (In most cases, no changes should be necessary.)
-
-## <a name="scoped-plugins"></a> Plugins in scoped packages are now resolvable in configs
-
-When ESLint v5 encounters a plugin name in a config starting with `@`, the plugin will be resolved as a [scoped npm package](https://docs.npmjs.com/misc/scope). For example, if a config contains `"plugins": ["@foo"]`, ESLint v5 will attempt to load a package called `@foo/eslint-plugin`. (On the other hand, ESLint v4 would attempt to load a package called `eslint-plugin-@foo`.) This is a breaking change because users might have been relying on ESLint finding a package at `node_modules/eslint-plugin-@foo`. However, we think it is unlikely that many users were relying on this behavior, because packages published to npm cannot contain an `@` character in the middle.
-
-**To address:** If you rely on ESLint loading a package like `eslint-config-@foo`, consider renaming the package to something else.
-
-## <a name="multiline-directives"></a> Multi-line `eslint-disable-line` directives are now reported as problems
-
-`eslint-disable-line` and `eslint-disable-next-line` directive comments are only allowed to span a single line. For example, the following directive comment is invalid:
-
-```js
-alert('foo'); /* eslint-disable-line
- no-alert */ alert('bar');
-
-// (which line is the rule disabled on?)
-```
-
-Previously, ESLint would ignore these malformed directive comments. ESLint v5 will report an error when it sees a problem like this, so that the issue can be more easily corrected.
-
-**To address:** If you see new reported errors as a result of this change, ensure that your `eslint-disable-line` directives only span a single line. Note that "block comments" (delimited by `/* */`) are still allowed to be used for directives, provided that the block comments do not contain linebreaks.
-
----
-
-## <a name="parent-before-rules"></a> The `parent` property of AST nodes is now set before rules start running
-
-Previously, ESLint would set the `parent` property on each AST node immediately before running rule listeners for that node. This caused some confusion for rule authors, because the `parent` property would not initially be present on any nodes, and it was sometimes necessary to complicate the structure of a rule to ensure that the `parent` property of a given node would be available when needed.
-
-In ESLint v5, the `parent` property is set on all AST nodes before any rules have access to the AST. This makes it easier to write some rules, because the `parent` property is always available rather than being mutated behind the scenes. However, as a side-effect of having `parent` properties, the AST object has a circular structure the first time a rule sees it (previously, it only had a circular structure after the first rule listeners were called). As a result, a custom rule that enumerates all properties of a node in order to traverse the AST might now loop forever or run out of memory if it does not check for cycles properly.
-
-**To address:** If you have written a custom rule that enumerates all properties of an AST node, consider excluding the `parent` property or implementing cycle detection to ensure that you obtain the correct result.
-
-## <a name="spread-operators"></a> When using the default parser, spread operators now have type `SpreadElement`
-
-Previously, when parsing JS code like `const foo = {...data}` with the `experimentalObjectRestSpread` option enabled, the default parser would generate an `ExperimentalSpreadProperty` node type for the `...data` spread element.
-
-In ESLint v5, the default parser will now always give the `...data` AST node the `SpreadElement` type, even if the (now deprecated) [`experimentalObjectRestSpread`](#experimental-object-rest-spread) option is enabled. This makes the AST compliant with the current ESTree spec.
-
-**To address:** If you have written a custom rule that relies on spread operators having the `ExperimentalSpreadProperty` type, you should update it to also work with spread operators that have the `SpreadElement` type.
-
-## <a name="rest-operators"></a> When using the default parser, rest operators now have type `RestElement`
-
-Previously, when parsing JS code like `const {foo, ...rest} = data` with the `experimentalObjectRestSpread` option enabled, the default parser would generate an `ExperimentalRestProperty` node type for the `...data` rest element.
-
-In ESLint v5, the default parser will now always give the `...data` AST node the `RestElement` type, even if the (now deprecated) [`experimentalObjectRestSpread`](#experimental-object-rest-spread) option is enabled. This makes the AST compliant with the current ESTree spec.
-
-**To address:** If you have written a custom rule that relies on rest operators having the `ExperimentalRestProperty` type, you should update it to also work with rest operators that have the `RestElement` type.
-
-## <a name="jsx-text-nodes"></a> When using the default parser, text nodes in JSX elements now have type `JSXText`
-
-When parsing JSX code like `<a>foo</a>`, the default parser will now give the `foo` AST node the `JSXText` type, rather than the `Literal` type. This makes the AST compliant with a recent update to the JSX spec.
-
-**To address:** If you have written a custom rule that relies on text nodes in JSX elements having the `Literal` type, you should update it to also work with nodes that have the `JSXText` type.
-
-## <a name="context-get-scope"></a> The `context.getScope()` method now returns more proper scopes
-
-Previously, the `context.getScope()` method changed its behavior based on the `parserOptions.ecmaVersion` property. However, this could cause confusing behavior when using a parser that doesn't respond to the `ecmaVersion` option, such as `babel-eslint`.
-
-Additionally, `context.getScope()` incorrectly returned the parent scope of the proper scope on `CatchClause` (in ES5), `ForStatement` (in ≧ES2015), `ForInStatement` (in ≧ES2015), `ForOfStatement`, and `WithStatement` nodes.
-
-In ESLint v5, the `context.getScope()` method has the same behavior regardless of `parserOptions.ecmaVersion` and returns the proper scope. See [the documentation](../developer-guide/working-with-rules#contextgetscope) for more details on which scopes are returned.
-
-**To address:** If you have written a custom rule that uses the `context.getScope()` method in node handlers, you may need to update it to account for the modified scope information.
-
-## <a name="no-context-linter"></a> The `_linter` property on rule context objects has been removed
-
-Previously, rule context objects had an undocumented `_linter` property, which was used internally within ESLint to process reports from rules. Some rules used this property to achieve functionality that was not intended to be possible for rules. For example, several plugins used the `_linter` property in a rule to monitor reports from other rules, for the purpose of checking for unused `/* eslint-disable */` directive comments. Although this functionality was useful for users, it could also cause stability problems for projects using ESLint. For example, an upgrade to a rule in one plugin could unexpectedly cause a rule in another plugin to start reporting errors.
-
-The `_linter` property has been removed in ESLint v5.0, so it is no longer possible to implement rules with this functionality. However, the [`--report-unused-disable-directives`](/docs/user-guide/command-line-interface#--report-unused-disable-directives) CLI flag can be used to flag unused directive comments.
-
-## <a name="rule-tester-equality"></a> `RuleTester` now uses strict equality checks in its assertions
-
-Previously, `RuleTester` used loose equality when making some of its assertions. For example, if a rule produced the string `"7"` as a result of autofixing, `RuleTester` would allow the number `7` in an `output` assertion, rather than the string `"7"`. In ESLint v5, comparisons from `RuleTester` use strict equality, so an assertion like this will no longer pass.
-
-**To address:** If you use `RuleTester` to write tests for your custom rules, make sure the expected values in your assertions are strictly equal to the actual values.
-
-## <a name="required-report-messages"></a> Rules are now required to provide messages along with reports
-
-Previously, it was possible for rules to report AST nodes without providing a report message. This was not intended behavior, and as a result the default formatter would crash if a rule omitted a message. However, it was possible to avoid a crash when using a non-default formatter, such as `json`.
-
-In ESLint v5, reporting a problem without providing a message always results in an error.
-
-**To address:** If you have written a custom rule that reports a problem without providing a message, update it to provide a message along with the report.
-
----
-
-## <a name="source-property"></a> The `source` property is no longer available on individual linting messages
-
-As announced in [October 2016](/blog/2016/10/eslint-v3.8.0-released#additional-property-on-linting-results), the `source` property has been removed from individual lint message objects.
-
-**To address:** If you have a formatter or integration which relies on using the `source` property on individual linting messages, you should update it to use the `source` property on file results objects instead.
-
-## <a name="exit-code-two"></a> Fatal errors now result in an exit code of 2
-
-When using ESLint v4, both of the following scenarios resulted in an exit code of 1 when running ESLint on the command line:
-
-* Linting completed successfully, but there are some linting errors
-* Linting was unsuccessful due to a fatal error (e.g. an invalid config file)
-
-As a result, it was difficult for an integration to distinguish between the two cases to determine whether it should try to extract linting results from the output.
-
-In ESLint v5, an unsuccessful linting run due to a fatal error will result in an exit code of 2, rather than 1.
-
-**To address:** If you have an integration that detects all problems with linting runs by checking whether the exit code is equal to 1, update it to check whether the exit code is nonzero instead.
-
-## <a name="non-enumerable-linter"></a> The `eslint.linter` property is now non-enumerable
-
-When using ESLint's Node.js API, the [`linter`](/docs/developer-guide/nodejs-api#linter-1) property is now non-enumerable. Note that the `linter` property was deprecated in ESLint v4 in favor of the [`Linter`](/docs/developer-guide/nodejs-api#linter) property.
-
-**To address:** If you rely on enumerating all the properties of the `eslint` object, use something like `Object.getOwnPropertyNames` to ensure that non-enumerable keys are captured.
+++ /dev/null
----
-title: Migrating to v6.0.0
-layout: doc
-
----
-
-ESLint v6.0.0 is a major release of ESLint. We have made a few breaking changes in this release. This guide is intended to walk you through the 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
-
-1. [Node.js 6 is no longer supported](#drop-node-6)
-1. [`eslint:recommended` has been updated](#eslint-recommended-changes)
-1. [Plugins and shareable configs are no longer affected by ESLint's location](#package-loading-simplification)
-1. [The default parser now validates options more strictly](#espree-validation)
-1. [Rule configuration are validated more strictly](#rule-config-validating)
-1. [The `no-redeclare` rule is now more strict by default](#no-redeclare-updates)
-1. [The `comma-dangle` rule is now more strict by default](#comma-dangle-updates)
-1. [The `no-confusing-arrow` rule is now more lenient by default](#no-confusing-arrow-updates)
-1. [Overrides in a config file can now match dotfiles](#overrides-dotfiles)
-1. [Overrides in an extended config file can now be overridden by a parent config file](#overrides-precedence)
-1. [Configuration values for globals are now validated](#globals-validation)
-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
-
-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
-
-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)
-
----
-
-## <a name="drop-node-6"></a> Node.js 6 is no longer supported
-
-As of April 2019, Node.js 6 will be at EOL and will no longer be receiving security updates. As a result, we have decided to drop support for it in ESLint v6. We now support the following versions of Node.js:
-
-* Node.js 8 (8.10.0 and above)
-* Node.js 10 (10.13.0 and above)
-* Anything above Node.js 11.10.1
-
-**To address:** Make sure you upgrade to at least Node.js 8 when using ESLint v6. If you are unable to upgrade, we recommend continuing to use ESLint v5.x until you are able to upgrade Node.js.
-
-**Related issue(s):** [eslint/eslint#11546](https://github.com/eslint/eslint/issues/11456)
-
-## <a name="eslint-recommended-changes"></a> `eslint:recommended` has been updated
-
-The following rules have been added to the [`eslint:recommended`](https://eslint.org/docs/user-guide/configuring#using-eslintrecommended) config:
-
-* [`no-async-promise-executor`](https://eslint.org/docs/rules/no-async-promise-executor) disallows using an `async` function as the argument to the `Promise` constructor, which is usually a bug.
-* [`no-misleading-character-class`](https://eslint.org/docs/rules/no-misleading-character-class) reports character classes in regular expressions that might not behave as expected.
-* [`no-prototype-builtins`](https://eslint.org/docs/rules/no-prototype-builtins) reports method calls like `foo.hasOwnProperty("bar")` (which are a frequent source of bugs), and suggests that they be replaced with `Object.prototype.hasOwnProperty.call(foo, "bar")` instead.
-* [`no-shadow-restricted-names`](https://eslint.org/docs/rules/no-shadow-restricted-names) disallows shadowing variables like `undefined` (e.g. with code like `let undefined = 5;`), since is likely to confuse readers.
-* [`no-useless-catch`](https://eslint.org/docs/rules/no-useless-catch) reports `catch` clauses that are redundant and can be removed from the code without changing its behavior.
-* [`no-with`](https://eslint.org/docs/rules/no-with) disallows use of the [`with` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with), which can make code difficult to understand and cause compatibility problems.
-* [`require-atomic-updates`](https://eslint.org/docs/rules/require-atomic-updates) reports race condition bugs that can occur when reassigning variables in async functions.
-
-Additionally, the following rule has been *removed* from `eslint:recommended`:
-
-* [`no-console`](https://eslint.org/docs/rules/no-console) disallows calling functions like `console.log`. While this rule is useful in many cases (e.g. to avoid inadvertently leaving debugging statements in production code), it is not as broadly applicable as the other rules in `eslint:recommended`, and it was a source of false positives in cases where `console.log` is acceptable (e.g. in CLI applications).
-
-Finally, in ESLint v5 `eslint:recommended` would explicitly disable all core rules that were not considered "recommended". This could cause confusing behavior if `eslint:recommended` was loaded after another config, since `eslint:recommended` would have the effect of turning off some rules. In ESLint v6, `eslint:recommended` has no effect on non-recommended rules.
-
-**To address:** To mimic the `eslint:recommended` behavior from 5.x, you can explicitly disable/enable rules in a config file as follows:
-
-```json
-{
- "extends": "eslint:recommended",
-
- "rules": {
- "no-async-promise-executor": "off",
- "no-misleading-character-class": "off",
- "no-prototype-builtins": "off",
- "no-shadow-restricted-names": "off",
- "no-useless-catch": "off",
- "no-with": "off",
- "require-atomic-updates": "off",
-
- "no-console": "error"
- }
-}
-```
-
-In rare cases (if you were relying on the previous behavior where `eslint:recommended` disables core rules), you might need to disable additional rules to restore the previous behavior.
-
-**Related issue(s):** [eslint/eslint#10768](https://github.com/eslint/eslint/issues/10768), [eslint/eslint#10873](https://github.com/eslint/eslint/issues/10873)
-
-## <a name="package-loading-simplification"></a> Plugins and shareable configs are no longer affected by ESLint's location
-
-Previously, ESLint loaded plugins relative to the location of the ESLint package itself. As a result, we suggested that users with global ESLint installations should also install plugins globally, and users with local ESLint installations should install plugins locally. However, due to a design bug, this strategy caused ESLint to randomly fail to load plugins and shareable configs under certain circumstances, particularly when using package management tools like [`lerna`](https://github.com/lerna/lerna) and [Yarn Plug n' Play](https://yarnpkg.com/lang/en/docs/pnp/).
-
-As a rule of thumb: With ESLint v6, plugins should always be installed locally, even if ESLint was installed globally. More precisely, ESLint v6 resolves plugins relative to the end user's project by default, and always resolves shareable configs and parsers relative to the location of the config file that imports them.
-
-**To address:** If you use a global installation of ESLint (e.g. installed with `npm install eslint --global`) along with plugins, you should install those plugins locally in the projects where you run ESLint. If your config file extends shareable configs and/or parsers, you should ensure that those packages are installed as dependencies of the project containing the config file.
-
-If you use a config file located outside of a local project (with the `--config` flag), consider installing the plugins as dependencies of that config file, and setting the [`--resolve-plugins-relative-to`](./command-line-interface#--resolve-plugins-relative-to) flag to the location of the config file.
-
-**Related issue(s):** [eslint/eslint#10125](https://github.com/eslint/eslint/issues/10125), [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
-
-## <a name="espree-validation"></a> The default parser now validates options more strictly
-
-`espree`, the default parser used by ESLint, will now raise an error in the following cases:
-
-* The `ecmaVersion` parser option is set to something other than a number, such as the string `"2015"`. (Previously, a non-number option would simply be ignored.)
-* The `sourceType: "module"` parser option is set while `ecmaVersion` is set to `5` or left unspecified. (Previously, setting `sourceType: "module"` would implicitly cause `ecmaVersion` to be set to a minimum of 2015, which could be surprising.)
-* The `sourceType` is set to anything other than `"script"` or `"module"`.
-
-**To address:** If your config sets `ecmaVersion` to something other than a number, you can restore the previous behavior by removing `ecmaVersion`. (However, you may want to double-check that your config is actually working as expected.) If your config sets `parserOptions: { sourceType: "module" }` without also setting `parserOptions.ecmaVersion`, you should add `parserOptions: { ecmaVersion: 2015 }` to restore the previous behavior.
-
-**Related issue(s):** [eslint/eslint#9687](https://github.com/eslint/eslint/issues/9687), [eslint/espree#384](https://github.com/eslint/espree/issues/384)
-
-## <a name="rule-config-validating"></a> Rule configuration are validated more strictly
-
-To catch config errors earlier, ESLint v6 will report a linting error if you are trying to configure a non-existent rule.
-
-config | ESLint v5 | ESLint v6
-------------- | ------------- | -------------
-`/*eslint-enable foo*/` | no error | linting error
-`/*eslint-disable(-line) foo*/` | no error | linting error
-`/*eslint foo: 0*/` | no error | linting error
-`{rules: {foo: 0}}` | no error | no error
-`{rules: {foo: 1}` | linting warning | linting error
-
-**To address:** You can remove the non-existent rule in your (inline) config.
-
-**Related issue(s):** [eslint/eslint#9505](https://github.com/eslint/eslint/issues/9505)
-
-## <a name="no-redeclare-updates"></a> The `no-redeclare` rule is now more strict by default
-
-The default options for the [`no-redeclare`](https://eslint.org/docs/rules/no-redeclare) rule have changed from `{ builtinGlobals: false }` to `{ builtinGlobals: true }`. Additionally, the `no-redeclare` rule will now report an error for globals enabled by comments like `/* global foo */` if those globals were already enabled through configuration anyway.
-
-**To address:**
-
-To restore the previous options for the rule, you can configure it as follows:
-
-```json
-{
- "rules": {
- "no-redeclare": ["error", { "builtinGlobals": false }]
- }
-}
-```
-
-Additionally, if you see new errors for `global` comments in your code, you should remove those comments.
-
-**Related issue(s):** [eslint/eslint#11370](https://github.com/eslint/eslint/issues/11370), [eslint/eslint#11405](https://github.com/eslint/eslint/issues/11405)
-
-## <a name="comma-dangle-updates"></a> The `comma-dangle` rule is now more strict by default
-
-Previously, the [`comma-dangle`](https://eslint.org/docs/rules/comma-dangle) rule would ignore trailing function arguments and parameters, unless explicitly configured to check for function commas. In ESLint v6, function commas are treated the same way as other types of trailing commas.
-
-**To address:** You can restore the previous default behavior of the rule with:
-
-```json
-{
- "rules": {
- "comma-dangle": ["error", {
- "arrays": "never",
- "objects": "never",
- "imports": "never",
- "exports": "never",
- "functions": "ignore"
- }]
- }
-}
-```
-
-To restore the previous behavior of a string option like `"always-multiline"`, replace `"never"` with `"always-multiline"` in the example above.
-
-**Related issue(s):** [eslint/eslint#11502](https://github.com/eslint/eslint/issues/11502)
-
-## <a name="no-confusing-arrow-updates"></a> The `no-confusing-arrow` rule is now more lenient by default
-
-The default options for the [`no-confusing-arrow`](https://eslint.org/docs/rules/no-confusing-arrow) rule have changed from `{ allowParens: false }` to `{ allowParens: true }`.
-
-**To address:** You can restore the previous default behavior of the rule with:
-
-```json
-{
- "rules": {
- "no-confusing-arrow": ["error", { "allowParens": false }]
- }
-}
-```
-
-**Related issue(s):** [eslint/eslint#11503](https://github.com/eslint/eslint/issues/11503)
-
-## <a name="overrides-dotfiles"></a> Overrides in a config file can now match dotfiles
-
-Due to a bug, the glob patterns in a `files` list in an `overrides` section of a config file would never match dotfiles, making it impossible to have overrides apply to files starting with a dot. This bug has been fixed in ESLint v6.
-
-**To address:** If you don't want dotfiles to be matched by an override, consider adding something like `excludedFiles: [".*"]` to that `overrides` section. See the [documentation](https://eslint.org/docs/user-guide/configuring#configuration-based-on-glob-patterns) for more details.
-
-**Related issue(s):** [eslint/eslint#11201](https://github.com/eslint/eslint/issues/11201)
-
-## <a name="overrides-precedence"></a> Overrides in an extended config file can now be overridden by a parent config file
-
-Due to a bug, it was previously the case that an `overrides` block in a shareable config had precedence over the top level of a parent config. For example, with the following config setup, the `semi` rule would end up enabled even though it was explicitly disabled in the end user's config:
-
-```js
-// .eslintrc.js
-module.exports = {
- extends: ["foo"],
- rules: {
- semi: "off"
- }
-};
-```
-
-```js
-// eslint-config-foo/index.js
-module.exports = {
- overrides: {
- files: ["*.js"],
- rules: {
- semi: "error"
- }
- }
-};
-```
-
-In ESLint v6.0.0, a parent config always has precedence over extended configs, even with `overrides` blocks.
-
-**To address:** We expect the impact of this issue to be very low because most shareable configs don't use `overrides` blocks. However, if you use a shareable config with `overrides` blocks, you might encounter a change in behavior due to something that is explicitly specified in your config but was inactive until now. If you would rather inherit the behavior from the shareable config, simply remove the corresponding entry from your own config. (In the example above, the previous behavior could be restored by removing `semi: "off"` from `.eslintrc.js`.)
-
-**Related issue(s):** [eslint/eslint#11510](https://github.com/eslint/eslint/issues/11510)
-
-## <a name="globals-validation"></a> Configuration values for globals are now validated
-
-Previously, when configuring a set of global variables with an object, it was possible to use anything as the values of the object. An unknown value would be treated the same as `"writable"`.
-
-```js
-// .eslintrc.js
-module.exports = {
- globals: {
- foo: "readonly",
- bar: "writable",
- baz: "hello!" // ???
- }
-};
-```
-
-With this change, any unknown values in a `globals` object result in a config validation error.
-
-**To address:** If you see config validation errors related to globals after updating, ensure that all values configured for globals are either `readonly`, `writable`, or `off`. (ESLint also accepts some alternate spellings and variants for compatibility.)
-
-## <a name="experimental-object-rest-spread"></a> The deprecated `experimentalObjectRestSpread` option has been removed
-
-Previously, when using the default parser, a config could use the `experimentalObjectRestSpread` option to enable parsing support for object rest/spread properties:
-
-```json
-{
- "parserOptions": {
- "ecmaFeatures": {
- "experimentalObjectRestSpread": true
- }
- }
-}
-```
-
-Since ESLint v5, `ecmaFeatures: { experimentalObjectRestSpread: true }` has been equivalent to `ecmaVersion: 2018`, and has also emitted a deprecation warning. In ESLint v6, the `experimentalObjectRestSpread` feature has been removed entirely and has no effect. If your config was relying on `experimentalObjectRestSpread` to enable ES2018 parsing, you might start seeing parsing errors for recent syntax.
-
-**To address:** If you use the `experimentalObjectRestSpread` option, you should change your config to contain this instead:
-
-```json
-{
- "parserOptions": {
- "ecmaVersion": 2018
- }
-}
-```
-
-If you're not sure which config file needs to be updated, it may be useful to run ESLint v5 and look at what config file is mentioned in the deprecation warning.
-
-**Related issue(s):** [eslint/eslint#9990](https://github.com/eslint/eslint/issues/9990)
-
-## <a name="unicode-regexes"></a> User-provided regular expressions in rule options are parsed with the unicode flag
-
-Rules like [`max-len`](/docs/rules/max-len) accept a string option which is interpreted as a regular expression. In ESLint v6.0.0, these regular expressions are interpreted with the [unicode flag](https://mathiasbynens.be/notes/es6-unicode-regex), which should exhibit more reasonable behavior when matching characters like astral symbols. Unicode regexes also validate escape sequences more strictly than non-unicode regexes.
-
-**To address:** If you get rule option validation errors after upgrading, ensure that any regular expressions in your rule options have no invalid escape sequences.
-
-**Related issue(s):** [eslint/eslint#11423](https://github.com/eslint/eslint/issues/11423)
-
----
-
-## <a name="plugin-documentation"></a> Plugin authors may need to update installation instructions
-
-If you maintain a plugin and provide installation instructions, you should ensure that the installation instructions are up to date with the [user-facing changes to how plugins are loaded](#package-loading-simplification). In particular, if your plugin was generated with the [`generator-eslint`](https://github.com/eslint/generator-eslint) package, it likely contains outdated instructions for how to use the plugin with global ESLint installations.
-
-**Related issue(s):** [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
-
-## <a name="rule-tester-defaults"></a> `RuleTester` now validates against invalid `default` keywords in rule schemas
-
-In some cases, rule schemas can use the `default` keyword to automatically specify default values for rule options. However, the `default` keyword is only effective in certain schema locations, and is ignored elsewhere, which creates a risk of bugs if a rule incorrectly expects a default value to be provided as a rule option. In ESLint v6.0.0, `RuleTester` will raise an error if a rule has an invalid `default` keyword in its schema.
-
-**To address:** If `RuleTester` starts reporting an error about an invalid default, you can remove the `default` property at the indicated location in your rule schema, and the rule will behave the same way. (If this happens, you might also want to verify that the rule behaves correctly when no option value is provided in that location.)
-
-**Related issue(s):** [eslint/eslint#11473](https://github.com/eslint/eslint/issues/11473)
-
-## <a name="rule-tester-parser"></a> `RuleTester` now requires an absolute path on `parser` option
-
-To use custom parsers in tests, we could use `parser` property with a package name or file path. However, if a package name was given, it's unclear where the tester should load the parser package from because the tester doesn't know which files are running the tester. In ESLint v6.0.0, `RuleTester` disallows `parser` property with a package name.
-
-**To address:** If you use `parser` property with package names in test cases, update it with `require.resolve()` function to resolve the package name to the absolute path to the package.
-
-**Related issue(s):** [eslint/eslint#11728](https://github.com/eslint/eslint/issues/11728), [eslint/eslint#10125](https://github.com/eslint/eslint/issues/10125), [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
-
-## <a name="eslintExplicitGlobalComment"></a> The `eslintExplicitGlobalComment` scope analysis property has been removed
-
-Previously, ESLint would add an `eslintExplicitGlobalComment` property to `Variable` objects in scope analysis to indicate that a variable was introduced as a result of a `/* global */` comment. This property was undocumented, and the ESLint team was unable to find any usage of the property outside of ESLint core. The property has been removed in ESLint v6, and replaced with the `eslintExplicitGlobalComments` property, which can contain a list of all `/* global */` comments if a variable was declared with more than one of them.
-
-**To address:** If you maintain a rule that uses the `eslintExplicitGlobalComment` property, update it to use the `eslintExplicitGlobalComments` property as a list instead.
-
-**Related issue(s):** [eslint/rfcs#17](https://github.com/eslint/rfcs/pull/17)
-
----
-
-## <a name="linter-parsers"></a> `Linter` no longer tries to load missing parsers from the filesystem
-
-Previously, when linting code with a parser that had not been previously defined, the `Linter` API would attempt to load the parser from the filesystem. However, this behavior was confusing because `Linter` never access the filesystem in any other cases, and it was difficult to ensure that the correct parser would be found when loading the parser from the filesystem.
-
-In ESLint v6, `Linter` will no longer perform any filesystem operations, including loading parsers.
-
-**To address:** If you're using `Linter` with a custom parser, use [`Linter#defineParser`](https://eslint.org/docs/developer-guide/nodejs-api#linterdefineparser) to explicitly define the parser before linting any code.
-
-**Related issue(s):** [eslint/rfcs#7](https://github.com/eslint/rfcs/pull/7)
+++ /dev/null
----
-title: Migrating to v7.0.0
-layout: doc
-
----
-
-ESLint v7.0.0 is a major release of ESLint. We have made a few breaking changes in this release. This guide is intended to walk you through the 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.
-
-## Table of Content
-
-### Breaking changes for users
-
-* [Node.js 8 is no longer supported](#drop-node-8)
-* [Lint files matched by `overrides[].files` by default](#additional-lint-targets)
-* [The base path of `overrides` and `ignorePatterns` is changed if the config file is given by the `--config`/`--ignore-path` options](#base-path-change)
-* [The place where ESLint loads plugins from is changed](#plugin-loading-change)
-* [Runtime deprecation warnings for `~/.eslintrc.*` config files](#runtime-deprecation-on-personal-config-files)
-* [Default ignore patterns have changed](#default-ignore-patterns)
-* [Description in directive comments](#description-in-directive-comments)
-* [Node.js/CommonJS rules are deprecated](#deprecate-node-rules)
-* [Several rules have been updated to cover more cases](#rules-strict)
-* [`eslint:recommended` has been updated](#eslint-recommended)
-
-### Breaking changes for plugin developers
-
-* [Node.js 8 is no longer supported](#drop-node-8)
-* [Lint files matched by `overrides[].files` by default](#additional-lint-targets)
-* [Plugin resolution has been updated](#plugin-loading-change)
-* [Additional validation added to the `RuleTester` class](#rule-tester-strict)
-
-### Breaking changes for integration developers
-
-* [Node.js 8 is no longer supported](#drop-node-8)
-* [Plugin resolution has been updated](#plugin-loading-change)
-* [The `CLIEngine` class has been deprecated](#deprecate-cliengine)
-
----
-
-## <a name="drop-node-8"></a> Node.js 8 is no longer supported
-
-Node.js 8 reached EOL in December 2019, and we are officially dropping support for it in this release. ESLint now supports the following versions of Node.js:
-
-* Node.js 10 (`10.12.0` and above)
-* Node.js 12 and above
-
-**To address:** Make sure you upgrade to at least Node.js `10.12.0` when using ESLint v7.0.0. One important thing to double check is the Node.js version supported by your editor when using ESLint via editor integrations. If you are unable to upgrade, we recommend continuing to use ESLint 6 until you are able to upgrade Node.js.
-
-**Related issue(s):** [RFC44](https://github.com/eslint/rfcs/blob/master/designs/2019-drop-node8/README.md), [#12700](https://github.com/eslint/eslint/pull/12700)
-
-## <a name="additional-lint-targets"></a> Lint files matched by `overrides[].files` by default
-
-Previously to v7.0.0, ESLint would only lint files with a `.js` extension by default if you give directories like `eslint src`.
-
-ESLint v7.0.0 will now additionally lint files with other extensions (`.ts`, `.vue`, etc.) if the extension is explicitly matched by an `overrides[].files` entry. This will allow for users to lint files that don't end with `*.js` to be linted without having to use the `--ext` command line flag, as well as allow shared configuration authors to enable linting of these files without additional overhead for the end user. Please note that patterns that end with `*` are exempt from this behavior and will behave as they did previously. For example, if the following config file is present,
-
-```yml
-# .eslintrc.yml
-extends: my-config-js
-overrides:
- - files: "*.ts"
- extends: my-config-ts
-```
-
-then running `eslint src` would check both `*.js` and `*.ts` files in the `src` directory.
-
-**To address:** Using the `--ext` CLI option will override this new behavior. Run ESLint with `--ext .js` if you are using `overrides` but only want to lint files that have a `.js` extension.
-
-If you maintain plugins that check files with extensions other than `.js`, this feature will allow you to check these files by default by configuring an `overrides` setting in your `recommended` preset.
-
-**Related issue(s):** [RFC20](https://github.com/eslint/rfcs/blob/master/designs/2019-additional-lint-targets/README.md), [#12677](https://github.com/eslint/eslint/pull/12677)
-
-## <a name="base-path-change"></a> The base path of `overrides` and `ignorePatterns` has changed when using the `--config`/`--ignore-path` options
-
-Up until now, ESLint has resolved the following paths relative to the directory path of the _entry_ configuration file:
-
-* Configuration files (`.eslintrc.*`)
- * relative paths in the `overrides[].files` setting
- * relative paths in the `overrides[].excludedFiles` setting
- * paths which start with `/` in the `ignorePatterns` setting
-* Ignore files (`.eslintignore`)
- * paths which start with `/`
-
-Starting in ESLint v7.0.0, configuration files and ignore files passed to ESLint using the `--config path/to/a-config` and `--ignore-path path/to/a-ignore` CLI flags, respectively, will resolve from the current working directory rather than the file location. This allows for users to utilize shared plugins without having to install them directly in their project.
-
-**To address:** Update the affected paths if you are using a configuration or ignore file via the `--config` or `--ignore-path` CLI options.
-
-**Related issue(s):** [RFC37](https://github.com/eslint/rfcs/blob/master/designs/2019-changing-base-path-in-config-files-that-cli-options-specify/README.md), [#12887](https://github.com/eslint/eslint/pull/12887)
-
-## <a name="plugin-loading-change"></a> Plugin resolution has been updated
-
-In previous versions, ESLint resolved all plugins from the current working directory by default.
-
-Starting in ESLint v7.0.0, `plugins` are resolved relative to the directory path of the _entry_ configuration file.
-
-This will not change anything in most cases. If a configuration file in a subdirectory has `plugins` defined, the plugins will be loaded from the subdirectory (or ancestor directories that include the current working directory if not found).
-
-This means that if you are using a config file from a shared location via `--config` option, the plugins that the config file declare will be loaded from the shared config file location.
-
-**To address:** Ensure that plugins are installed in a place that can be resolved relative to your configuration file or use `--resolve-plugins-relative-to .` to override this change.
-
-**Related issue(s):** [RFC47](https://github.com/eslint/rfcs/blob/master/designs/2019-plugin-loading-improvement/README.md), [#12922](https://github.com/eslint/eslint/pull/12922)
-
-## <a name="runtime-deprecation-on-personal-config-files"></a> Runtime deprecation warnings for `~/.eslintrc.*` config files
-
-Personal config files have been deprecated since [v6.7.0](https://eslint.org/blog/2019/11/eslint-v6.7.0-released). ESLint v7.0.0 will start printing runtime deprecation warnings. It will print a warning for the following situations:
-
-1. When a project does not have a configuration file present and ESLint loads configuration from `~/.eslintrc.*`.
-1. When a project has a configuration file and ESLint ignored a `~/.eslintrc.*` configuration file. This occurs when the `$HOME` directory is an ancestor directory of the project and the project's configuration files doesn't contain `root:true`.
-
-**To address:** Remove `~/.eslintrc.*` configuration files and add a `.eslintrc.*` configuration file to your project. Alternatively, use the `--config` option to use shared config files.
-
-**Related issue(s):** [RFC32](https://github.com/eslint/rfcs/tree/master/designs/2019-deprecating-personal-config/README.md), [#12678](https://github.com/eslint/eslint/pull/12678)
-
-## <a name="default-ignore-patterns"></a> Default ignore patterns have changed
-
-Up until now, ESLint has ignored the following files by default:
-
-* Dotfiles (`.*`)
-* `node_modules` in the current working directory (`/node_modules/*`)
-* `bower_components` in the current working directory (`/bower_components/*`)
-
-ESLint v7.0.0 ignores `node_modules/*` of subdirectories as well, but no longer ignores `bower_components/*` and `.eslintrc.js`. Therefore, the new default ignore patterns are:
-
-* Dotfiles except `.eslintrc.*` (`.*` but not `.eslintrc.*`)
-* `node_modules` (`/**/node_modules/*`)
-
-**To address:** Modify your `.eslintignore` or the `ignorePatterns` property of your config file if you don't want to lint `bower_components/*` and `.eslintrc.js`.
-
-**Related issue(s):** [RFC51](https://github.com/eslint/rfcs/blob/master/designs/2019-update-default-ignore-patterns/README.md), [#12888](https://github.com/eslint/eslint/pull/12888)
-
-## <a name="description-in-directive-comments"></a> Descriptions in directive comments
-
-In older version of ESLint, there was no convenient way to indicate why a directive comment – such as `/*eslint-disable*/` – was necessary.
-
-To allow for the colocation of comments that provide context with the directive, ESLint v7.0.0 adds the ability to append arbitrary text in directive comments by ignoring text following `--` surrounded by whitespace. For example:
-
-```js
-// eslint-disable-next-line a-rule, another-rule -- those are buggy!!
-```
-
-**To address:** If you have `--` surrounded by whitespace in directive comments, consider moving it into your configuration file.
-
-**Related issue(s):** [RFC33](https://github.com/eslint/rfcs/blob/master/designs/2019-description-in-directive-comments/README.md), [#12699](https://github.com/eslint/eslint/pull/12699)
-
-## <a name="deprecate-node-rules"></a> Node.js/CommonJS rules have been deprecated
-
-The ten Node.js/CommonJS rules in core have been deprecated and moved to the [eslint-plugin-node](https://github.com/mysticatea/eslint-plugin-node) plugin.
-
-**To address:** As per [our deprecation policy](https://eslint.org/docs/user-guide/rule-deprecation), the deprecated rules will remain in core for the foreseeable future and are still available for use. However, we will no longer be updating or fixing any bugs in those rules. To use a supported version of the rules, we recommend using the corresponding rules in the plugin instead.
-
-| Deprecated Rules | Replacement |
-| :--------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------ |
-| [callback-return](https://eslint.org/docs/rules/callback-return) | [node/callback-return](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/callback-return.md) |
-| [global-require](https://eslint.org/docs/rules/global-require) | [node/global-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/global-require.md) |
-| [handle-callback-err](https://eslint.org/docs/rules/handle-callback-err) | [node/handle-callback-err](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/handle-callback-err.md) |
-| [no-mixed-requires](https://eslint.org/docs/rules/no-mixed-requires) | [node/no-mixed-requires](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-mixed-requires.md) |
-| [no-new-require](https://eslint.org/docs/rules/no-new-require) | [node/no-new-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-new-require.md) |
-| [no-path-concat](https://eslint.org/docs/rules/no-path-concat) | [node/no-path-concat](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-path-concat.md) |
-| [no-process-env](https://eslint.org/docs/rules/no-process-env) | [node/no-process-env](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-env.md) |
-| [no-process-exit](https://eslint.org/docs/rules/no-process-exit) | [node/no-process-exit](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-process-exit.md) |
-| [no-restricted-modules](https://eslint.org/docs/rules/no-restricted-modules) | [node/no-restricted-require](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-restricted-require.md) |
-| [no-sync](https://eslint.org/docs/rules/no-sync) | [node/no-sync](https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-sync.md) |
-
-**Related issue(s):** [#12898](https://github.com/eslint/eslint/pull/12898)
-
-## <a name="rules-strict"></a> Several rules have been updated to cover more cases
-
-Several rules have been enhanced and now report additional errors:
-
-* [accessor-pairs](https://eslint.org/docs/rules/accessor-pairs) rule now recognizes class members by default.
-* [array-callback-return](https://eslint.org/docs/rules/array-callback-return) rule now recognizes `flatMap` method.
-* [computed-property-spacing](https://eslint.org/docs/rules/computed-property-spacing) rule now recognizes class members by default.
-* [func-names](https://eslint.org/docs/rules/func-names) rule now recognizes function declarations in default exports.
-* [no-extra-parens](https://eslint.org/docs/rules/no-extra-parens) rule now recognizes parentheses in assignment targets.
-* [no-dupe-class-members](https://eslint.org/docs/rules/no-dupe-class-members) rule now recognizes computed keys for static class members.
-* [no-magic-numbers](https://eslint.org/docs/rules/no-magic-numbers) rule now recognizes bigint literals.
-* [radix](https://eslint.org/docs/rules/radix) rule now recognizes invalid numbers for the second parameter of `parseInt()`.
-* [use-isnan](https://eslint.org/docs/rules/use-isnan) rule now recognizes class members by default.
-* [yoda](https://eslint.org/docs/rules/yoda) rule now recognizes bigint literals.
-
-**To address:** Fix errors or disable these rules.
-
-**Related issue(s):** [#12490](https://github.com/eslint/eslint/pull/12490), [#12608](https://github.com/eslint/eslint/pull/12608), [#12670](https://github.com/eslint/eslint/pull/12670), [#12701](https://github.com/eslint/eslint/pull/12701), [#12765](https://github.com/eslint/eslint/pull/12765), [#12837](https://github.com/eslint/eslint/pull/12837), [#12913](https://github.com/eslint/eslint/pull/12913), [#12915](https://github.com/eslint/eslint/pull/12915), [#12919](https://github.com/eslint/eslint/pull/12919)
-
-## <a name="eslint-recommended"></a> `eslint:recommended` has been updated
-
-Three new rules have been enabled in the `eslint:recommended` preset.
-
-* [no-dupe-else-if](https://eslint.org/docs/rules/no-dupe-else-if)
-* [no-import-assign](https://eslint.org/docs/rules/no-import-assign)
-* [no-setter-return](https://eslint.org/docs/rules/no-setter-return)
-
-**To address:** Fix errors or disable these rules.
-
-**Related issue(s):** [#12920](https://github.com/eslint/eslint/pull/12920)
-
-## <a name="rule-tester-strict"></a> Additional validation added to the `RuleTester` class
-
-The `RuleTester` now validates the following:
-
-* It fails test cases if the rule under test uses the non-standard `node.start` or `node.end` properties. Rules should use `node.range` instead.
-* It fails test cases if the rule under test provides an autofix but a test case doesn't have an `output` property. Add an `output` property to test cases to test the rule's autofix functionality.
-* It fails test cases if any unknown properties are found in the objects in the `errors` property.
-
-**To address:** Modify your rule or test case if existing test cases fail.
-
-**Related issue(s):** [RFC25](https://github.com/eslint/rfcs/blob/master/designs/2019-rule-tester-improvements/README.md), [#12096](https://github.com/eslint/eslint/pull/12096), [#12955](https://github.com/eslint/eslint/pull/12955)
-
-## <a name="deprecate-cliengine"></a> The `CLIEngine` class has been deprecated
-
-The [`CLIEngine` class](https://eslint.org/docs/developer-guide/nodejs-api#cliengine) has been deprecated and replaced by the new [`ESLint` class](https://eslint.org/docs/developer-guide/nodejs-api#eslint-class).
-
-The `CLIEngine` class provides a synchronous API that is blocking the implementation of features such as parallel linting, supporting ES modules in shareable configs/parsers/plugins/formatters, and adding the ability to visually display the progress of linting runs. The new `ESLint` class provides an asynchronous API that ESLint core will now using going forward. `CLIEngine` will remain in core for the foreseeable future but may be removed in a future major version.
-
-**To address:** Update your code to use the new `ESLint` class if you are currently using `CLIEngine`. The following table maps the existing `CLIEngine` methods to their `ESLint` counterparts:
-
-| `CLIEngine` | `ESLint` |
-| :------------------------------------------- | :--------------------------------- |
-| `executeOnFiles(patterns)` | `lintFiles(patterns)` |
-| `executeOnText(text, filePath, warnIgnored)` | `lintText(text, options)` |
-| `getFormatter(name)` | `loadFormatter(name)` |
-| `getConfigForFile(filePath)` | `calculateConfigForFile(filePath)` |
-| `isPathIgnored(filePath)` | `isPathIgnored(filePath)` |
-| `static outputFixes(results)` | `static outputFixes(results)` |
-| `static getErrorResults(results)` | `static getErrorResults(results)` |
-| `static getFormatter(name)` | (removed ※1) |
-| `addPlugin(pluginId, definition)` | the `plugins` constructor option |
-| `getRules()` | (not implemented yet) |
-| `resolveFileGlobPatterns()` | (removed ※2) |
-
-* ※1 The `engine.getFormatter()` method currently returns the object of loaded packages as-is, which made it difficult to add new features to formatters for backward compatibility reasons. The new `eslint.loadFormatter()` method returns an adapter object that wraps the object of loaded packages, to ease the process of adding new features. Additionally, the adapter object has access to the `ESLint` instance to calculate default data (using loaded plugin rules to make `rulesMeta`, for example). As a result, the `ESLint` class only implements an instance version of the `loadFormatter()` method.
-* ※2 Since ESLint 6, ESLint uses different logic from the `resolveFileGlobPatterns()` method to iterate files, making this method obsolete.
-
-**Related issue(s):** [RFC40](https://github.com/eslint/rfcs/blob/master/designs/2019-move-to-async-api/README.md), [#12939](https://github.com/eslint/eslint/pull/12939)
+++ /dev/null
----
-title: Migrating to v8.0.0
-layout: doc
-eleventyNavigation:
- key: migrating to v8
- parent: user guide
- title: Migrating to v8.x
- order: 6
-
----
-
-ESLint v8.0.0 is a major release of ESLint. We have made a few breaking changes in this release. This guide is intended to walk you through the 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.
-
-## Table of Contents
-
-### Breaking changes for users
-
-* [Node.js 10, 13, and 15 are no longer supported](#drop-old-node)
-* [Removed `codeframe` and `table` formatters](#removed-formatters)
-* [`comma-dangle` rule schema is stricter](#comma-dangle)
-* [Unused disable directives are now fixable](#directives)
-* [`eslint:recommended` has been updated](#eslint-recommended)
-
-### Breaking changes for plugin developers
-
-* [Node.js 10, 13, and 15 are no longer supported](#drop-old-node)
-* [Rules require `meta.hasSuggestions` to provide suggestions](#suggestions)
-* [Rules require `meta.fixable` to provide fixes](#fixes)
-* [`SourceCode#getComments()` fails in `RuleTester`](#get-comments)
-* [Changes to shorthand property AST format](#ast-format)
-
-### Breaking changes for integration developers
-
-* [Node.js 10, 13, and 15 are no longer supported](#drop-old-node)
-* [The `CLIEngine` class has been removed](#remove-cliengine)
-* [The `linter` object has been removed](#remove-linter)
-* [The `/lib` entrypoint has been removed](#remove-lib)
-
----
-
-## <a name="drop-old-node"></a> Node.js 10, 13, and 15 are no longer supported
-
-Node.js 10, 13, 15 all reached end of life either in 2020 or early 2021. ESLint is officially dropping support for these versions of Node.js starting with ESLint v8.0.0. ESLint now supports the following versions of Node.js:
-
-* Node.js 12.22 and above
-* Node.js 14 and above
-* Node.js 16 and above
-
-**To address:** Make sure you upgrade to at least Node.js `12.22.0` when using ESLint v8.0.0. One important thing to double check is the Node.js version supported by your editor when using ESLint via editor integrations. If you are unable to upgrade, we recommend continuing to use ESLint 7 until you are able to upgrade Node.js.
-
-**Related issue(s):** [#14023](https://github.com/eslint/eslint/issues/14023)
-
-## <a name="removed-formatters"></a> Removed `codeframe` and `table` formatters
-
-ESLint v8.0.0 has removed the `codeframe` and `table` formatters from the core. These formatters required dependencies that weren't used anywhere else in ESLint, and removing them allows us to reduce the size of ESLint, allowing for faster installation.
-
-**To address:** If you are using the `codeframe` or `table` formatters, you'll need to install the standalone [`eslint-formatter-codeframe`](https://github.com/fregante/eslint-formatter-codeframe) or [`eslint-formatter-table`](https://github.com/fregante/eslint-formatter-table) packages, respectively, to be able to use them in ESLint v8.0.0.
-
-**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:
-
-```json
-{
- "rules": {
- "comma-dangle": ["error", "never", { "arrays": "always" }]
- }
-}
-```
-
-With this configuration, the rule would ignore the third element in the array because only the second element is read. In ESLint v8.0.0, this configuration will cause ESLint to throw an error.
-
-**To address:** Change your rule configuration so that there are only two elements in the array, and the second element is either a string or an object, such as:
-
-```json
-{
- "comma-dangle": ["error", "never"],
-}
-```
-
-or
-
-```json
-{
- "comma-dangle": ["error", {
- "arrays": "never",
- "objects": "never",
- "imports": "never",
- "exports": "never",
- "functions": "never"
- }]
-}
-```
-
-**Related issue(s):** [#13739](https://github.com/eslint/eslint/issues/13739)
-
-## <a name="directives"></a> Unused disable directives are now fixable
-
-In ESLint v7.0.0, using both `--report-unused-disable-directives` and `--fix` on the command line would fix only rules but leave unused disable directives in place. In ESLint v8.0.0, this combination of command-line options will result in the unused disable directives being removed.
-
-**To address:** If you are using `--report-unused-disable-directives` and `--fix` together on the command line, and you don't want unused disable directives to be removed, add `--fix-type problem,suggestion,layout` as a command line option.
-
-**Related issue(s):** [#11815](https://github.com/eslint/eslint/issues/11815)
-
-## <a name="eslint-recommended"></a> `eslint:recommended` has been updated
-
-Four new rules have been enabled in the `eslint:recommended` preset.
-
-* [`no-loss-of-precision`](https://eslint.org/docs/rules/no-loss-of-precision)
-* [`no-nonoctal-decimal-escape`](https://eslint.org/docs/rules/no-nonoctal-decimal-escape)
-* [`no-unsafe-optional-chaining`](https://eslint.org/docs/rules/no-unsafe-optional-chaining)
-* [`no-useless-backreference`](https://eslint.org/docs/rules/no-useless-backreference)
-
-**To address:** Fix errors or disable these rules.
-
-**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.
-
-**To address:** If your rule provides suggestions, add `meta.hasSuggestions` to the object, such as:
-
-```js
-module.exports = {
- meta: {
- hasSuggestions: true
- },
- create(context) {
- // your rule
- }
-};
-```
-
-The [eslint-plugin/require-meta-has-suggestions](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-has-suggestions.md) rule can automatically fix and enforce that your rules are properly specifying `meta.hasSuggestions`.
-
-**Related issue(s):** [#14312](https://github.com/eslint/eslint/issues/14312)
-
-## <a name="fixes"></a> Rules require `meta.fixable` to provide fixes
-
-In ESLint v7.0.0, rules that were written as a function (rather than object) were able to provide fixes. In ESLint v8.0.0, only rules written as an object are allowed to provide fixes and must have a `meta.fixable` property set to either `"code"` or `"whitespace"`.
-
-**To address:** If your rule makes fixes and is written as a function, such as:
-
-```js
-module.exports = function(context) {
- // your rule
-};
-```
-
-Then rewrite your rule in this format:
-
-```js
-module.exports = {
- meta: {
- fixable: "code" // or "whitespace"
- },
- create(context) {
- // your rule
- }
-};
-```
-
-The [eslint-plugin/require-meta-fixable](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-fixable.md) rule can automatically fix and enforce that your rules are properly specifying `meta.fixable`.
-
-The [eslint-plugin/prefer-object-rule](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-object-rule.md) rule can automatically fix and enforce that your rules are written with the object format instead of the deprecated function format.
-
-See the [rule documentation](https://eslint.org/docs/developer-guide/working-with-rules) for more information on writing rules.
-
-**Related issue(s):** [#13349](https://github.com/eslint/eslint/issues/13349)
-
-## <a name="get-comments"></a> `SourceCode#getComments()` fails in `RuleTester`
-
-Back in ESLint v4.0.0, we deprecated `SourceCode#getComments()`, but we neglected to remove it. Rather than removing it completely in v8.0.0, we are taking the intermediate step of updating `RuleTester` to fail when `SourceCode#getComments()` is used inside of a rule. As such, all existing rules will continue to work, but when the developer runs tests for the rule there will be a failure.
-
-The `SourceCode#getComments()` method will be removed in v9.0.0.
-
-**To address:** If your rule uses `SourceCode#getComments()`, please use [`SourceCode#getCommentsBefore()`, `SourceCode#getCommentsAfter()`, or `SourceCode#getCommentsInside()`](https://eslint.org/docs/developer-guide/working-with-rules#sourcecodegetcommentsbefore-sourcecodegetcommentsafter-and-sourcecodegetcommentsinside).
-
-**Related issue(s):** [#14744](https://github.com/eslint/eslint/issues/14744)
-
-## <a name="ast-format"></a> Changes to shorthand property AST format
-
-ESLint v8.0.0 includes an upgrade to Espree v8.0.0 to support new syntax. This Espree upgrade, in turn, contains an upgrade to Acorn v8.0.0, which changed how shorthand properties were represented in the AST. Here's an example:
-
-```js
-const version = 8;
-const x = {
- version
-};
-```
-
-This code creates a property node that looks like this:
-
-```json
-{
- "type": "Property",
- "method": false,
- "shorthand": true,
- "computed": false,
- "key": {
- "type": "Identifier",
- "name": "version"
- },
- "kind": "init",
- "value": {
- "type": "Identifier",
- "name": "version"
- }
-}
-```
-
-Note that both the `key` and the `value` properties contain the same information. Prior to Acorn v8.0.0 (and therefore prior to ESLint v8.0.0), these two nodes were represented by the same object, so you could use `===` to determine if they represented the same node, such as:
-
-```js
-// true in ESLint v7.x, false in ESLint v8.0.0
-if (propertyNode.key === propertyNode.value) {
- // do something
-}
-```
-
-In ESLint v8.0.0 (via Acorn v8.0.0), the key and value are now separate objects and therefore no longer equivalent.
-
-**To address:** If your rule makes a comparison between the key and value of a shorthand object literal property to determine if they are the same node, you'll need to change your code in one of two ways:
-
-1. Use `propertyNode.shorthand` to determine if the property is a shorthand property node.
-1. Use the `range` property of each node to determine if the key and value occupy the same location.
-
-**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).
-
-**To address:** Update your code to use the new `ESLint` class if you are currently using `CLIEngine`. The following table maps the existing `CLIEngine` methods to their `ESLint` counterparts:
-
-| `CLIEngine` | `ESLint` |
-| :------------------------------------------- | :--------------------------------- |
-| `executeOnFiles(patterns)` | `lintFiles(patterns)` |
-| `executeOnText(text, filePath, warnIgnored)` | `lintText(text, options)` |
-| `getFormatter(name)` | `loadFormatter(name)` |
-| `getConfigForFile(filePath)` | `calculateConfigForFile(filePath)` |
-| `isPathIgnored(filePath)` | `isPathIgnored(filePath)` |
-| `static outputFixes(results)` | `static outputFixes(results)` |
-| `static getErrorResults(results)` | `static getErrorResults(results)` |
-| `static getFormatter(name)` | (removed ※1) |
-| `addPlugin(pluginId, definition)` | the `plugins` constructor option |
-| `getRules()` | (removed ※2) |
-| `resolveFileGlobPatterns()` | (removed ※3) |
-
-* ※1 The `engine.getFormatter()` method currently returns the object of loaded packages as-is, which made it difficult to add new features to formatters for backward compatibility reasons. The new `eslint.loadFormatter()` method returns an adapter object that wraps the object of loaded packages, to ease the process of adding new features. Additionally, the adapter object has access to the `ESLint` instance to calculate default data (using loaded plugin rules to make `rulesMeta`, for example). As a result, the `ESLint` class only implements an instance version of the `loadFormatter()` method.
-* ※2 The `CLIEngine#getRules()` method had side effects and so was removed. If you were using `CLIEngine#getRules()` to retrieve meta information about rules based on linting results, use `ESLint#getRulesMetaForResults()` instead. If you were using `CLIEngine#getRules()` to retrieve all built-in rules, import `builtinRules` from `eslint/use-at-your-own-risk` for an unsupported API that allows access to internal rules.
-* ※3 Since ESLint v6.0.0, ESLint uses different logic from the `resolveFileGlobPatterns()` method to iterate files, making this method obsolete.
-
-**Related issue(s):** [RFC80](https://github.com/eslint/rfcs/tree/main/designs/2021-package-exports), [#14716](https://github.com/eslint/eslint/pull/14716), [#13654](https://github.com/eslint/eslint/issues/13654)
-
-## <a name="remove-linter"></a> The `linter` object has been removed
-
-The deprecated `linter` object has been removed from the ESLint package in v8.0.0.
-
-**To address:** If you are using the `linter` object, such as:
-
-```js
-const { linter } = require("eslint");
-```
-
-Change your code to this:
-
-```js
-const { Linter } = require("eslint");
-const linter = new Linter();
-```
-
-**Related issue(s):** [RFC80](https://github.com/eslint/rfcs/tree/main/designs/2021-package-exports), [#14716](https://github.com/eslint/eslint/pull/14716), [#13654](https://github.com/eslint/eslint/issues/13654)
-
-## <a name="remove-lib"></a> The `/lib` entrypoint has been removed
-
-Beginning in v8.0.0, ESLint is strictly defining its public API. Previously, you could reach into individual files such as `require("eslint/lib/rules/semi")` and this is no longer allowed. There are a limited number of existing APIs that are now available through the `/use-at-your-own-risk` entrypoint for backwards compatibility, but these APIs are not formally supported and may break or disappear at any point in time.
-
-**To address:** If you are accessing rules directly through the `/lib` entrypoint, such as:
-
-```js
-const rule = require("eslint/lib/rules/semi");
-```
-
-Change your code to this:
-
-```js
-const { builtinRules } = require("eslint/use-at-your-own-risk");
-const rule = builtinRules.get("semi");
-```
-
-If you are accessing `FileEnumerator` directly through the `/lib` entrypoint, such as:
-
-```js
-const { FileEnumerator } = require("eslint/lib/cli-engine/file-enumerator");
-```
-
-Change your code to this:
-
-```js
-const { FileEnumerator } = require("eslint/use-at-your-own-risk");
-```
-
-**Related issue(s):** [RFC80](https://github.com/eslint/rfcs/tree/main/designs/2021-package-exports), [#14716](https://github.com/eslint/eslint/pull/14716), [#13654](https://github.com/eslint/eslint/issues/13654)
+++ /dev/null
----
-title: Rule Deprecation
-layout: doc
-
----
-
-Balancing the trade-offs of improving a tool and the frustration these changes can cause is a difficult task. One key area in which this affects our users is in the removal of rules.
-
-The ESLint team is committed to making upgrading as easy and painless as possible. To that end, the team has agreed upon the following set of guidelines for deprecating rules in the future. The goal of these guidelines is to allow for improvements and changes to be made without breaking existing configurations.
-
-* Rules will never be removed from ESLint.
-* Rules will be deprecated as needed, and marked as such in all documentation.
-* After a rule has been deprecated, the team will no longer do any work on it. This includes bug fixes, enhancements, and updates to the rule's documentation. Issues and pull requests related to deprecated rule will not be accepted and will be closed.
-
-Since deprecated rules will never be removed, you can continue to use them indefinitely if they are working for you. However, keep in mind that deprecated rules will effectively be unmaintained.
-
-We hope that by following these guidelines we will be able to continue improving and working to make ESLint the best tool it can be while causing as little disruption to our users as possible during the process.
--- /dev/null
+"use strict";
+
+const path = require("path");
+const TapRender = require("@munter/tap-render");
+const spot = require("tap-spot");
+const hyperlink = require("hyperlink");
+
+const tapRenderInstance = new TapRender();
+
+tapRenderInstance.pipe(spot()).pipe(process.stdout);
+
+const skipPatterns = [
+ "https://",
+ "fragment-redirect",
+ "migrating-to",
+ "/blog",
+ "/play",
+ "/team",
+ "/donate",
+ "/docs/latest",
+ 'src="null"'
+];
+
+/**
+ * Filter function to mark tests as skipped.
+ * Tests for which this function returns `true' are not considered failed.
+ * @param {Object} report hyperlink's test report for a link.
+ * @returns {boolean} `true` if the report contains any of `skipPatterns`.
+ */
+function skipFilter(report) {
+ return Object.values(report).some(value =>
+ skipPatterns.some(pattern => String(value).includes(pattern)));
+}
+
+(async () => {
+ try {
+ await hyperlink(
+ {
+ inputUrls: ["../_site/index.html"],
+ root: path.resolve(__dirname, "../_site"),
+ canonicalRoot: "https://eslint.org/docs/head/",
+ recursive: true,
+ internalOnly: true,
+ pretty: true,
+ concurrency: 25,
+ skipFilter
+ },
+ tapRenderInstance
+ );
+ } catch (err) {
+ console.log(err.stack);
+ process.exit(1);
+ }
+ const results = tapRenderInstance.close();
+
+ process.exit(results.fail ? 1 : 0);
+})();
const internalPlugin = require("eslint-plugin-internal-rules");
const eslintPlugin = require("eslint-plugin-eslint-plugin");
const { FlatCompat } = require("@eslint/eslintrc");
+const js = require("./packages/js");
const globals = require("globals");
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
const compat = new FlatCompat({
- baseDirectory: __dirname
+ baseDirectory: __dirname,
+ recommendedConfig: js.configs.recommended
});
const INTERNAL_FILES = {
module.exports = [
...compat.extends("eslint"),
+ {
+ ignores: [
+ "build/**",
+ "coverage/**",
+ "docs/*",
+ "!docs/*.js",
+ "!docs/tools/",
+ "jsdoc/**",
+ "templates/**",
+ "tests/bench/**",
+ "tests/fixtures/**",
+ "tests/performance/**",
+ "tmp/**",
+ "tools/internal-rules/node_modules/**",
+ "**/test.js"
+ ]
+ },
{
plugins: {
"internal-rules": internalPlugin,
}
},
{
- files: ["tools/*.js"],
+ files: ["tools/*.js", "docs/tools/*.js"],
rules: {
- "no-console": "off"
+ "no-console": "off",
+ "n/no-process-exit": "off"
}
},
{
"eslint-plugin/prefer-placeholders": "error",
"eslint-plugin/prefer-replace-text": "error",
"eslint-plugin/report-message-format": ["error", "[^a-z].*\\.$"],
- "eslint-plugin/require-meta-docs-description": ["error", { pattern: "^(Enforce|Require|Disallow)" }],
+ "eslint-plugin/require-meta-docs-description": ["error", { pattern: "^(Enforce|Require|Disallow) .+[^. ]$" }],
"internal-rules/no-invalid-meta": "error"
}
},
files: ["lib/rules/*"],
ignores: ["index.js"],
rules: {
- "eslint-plugin/require-meta-docs-url": ["error", { pattern: "https://eslint.org/docs/rules/{{name}}" }]
+ "eslint-plugin/require-meta-docs-url": ["error", { pattern: "https://eslint.org/docs/latest/rules/{{name}}" }]
}
},
{
filePath: path.resolve(filePath),
messages: [
{
+ ruleId: null,
fatal: false,
severity: 1,
- message
+ message,
+ nodeType: null
}
],
suppressedMessages: [],
useEslintrc: options.useEslintrc,
builtInRules,
loadRules,
- getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
- getEslintAllConfig: () => require("../../conf/eslint-all.js")
+ getEslintRecommendedConfig: () => require("@eslint/js").configs.recommended,
+ getEslintAllConfig: () => require("@eslint/js").configs.all
});
const fileEnumerator = new FileEnumerator({
configArrayFactory,
cwd = process.cwd(),
configArrayFactory = new CascadingConfigArrayFactory({
cwd,
- getEslintRecommendedConfig: () => require("../../conf/eslint-recommended.js"),
- getEslintAllConfig: () => require("../../conf/eslint-all.js")
+ getEslintRecommendedConfig: () => require("@eslint/js").configs.recommended,
+ getEslintAllConfig: () => require("@eslint/js").configs.all
}),
extensions = null,
globInputPaths = true,
return this._iterateFilesWithFile(absolutePath);
}
if (globInputPaths && isGlobPattern(pattern)) {
- return this._iterateFilesWithGlob(absolutePath, isDot);
+ return this._iterateFilesWithGlob(pattern, isDot);
}
return [];
_iterateFilesWithGlob(pattern, dotfiles) {
debug(`Glob: ${pattern}`);
- const directoryPath = path.resolve(getGlobParent(pattern));
- const globPart = pattern.slice(directoryPath.length + 1);
+ const { cwd } = internalSlotsMap.get(this);
+ const directoryPath = path.resolve(cwd, getGlobParent(pattern));
+ const absolutePath = path.resolve(cwd, pattern);
+ const globPart = absolutePath.slice(directoryPath.length + 1);
/*
* recursive if there are `**` or path separators in the glob part.
* Otherwise, patterns such as `src/*.js`, it doesn't need recursive.
*/
const recursive = /\*\*|\/|\\/u.test(globPart);
- const selector = new Minimatch(pattern, minimatchOpts);
+ const selector = new Minimatch(absolutePath, minimatchOpts);
debug(`recursive? ${recursive}`);
--- /dev/null
+[
+ {
+ "name": "checkstyle",
+ "description": "Outputs results to the [Checkstyle](https://checkstyle.sourceforge.io/) format."
+ },
+ {
+ "name": "compact",
+ "description": "Human-readable output format. Mimics the default output of JSHint."
+ },
+ {
+ "name": "html",
+ "description": "Outputs results to HTML. The `html` formatter is useful for visual presentation in the browser."
+ },
+ {
+ "name": "jslint-xml",
+ "description": "Outputs results to format compatible with the [JSLint Jenkins plugin](https://plugins.jenkins.io/jslint/)."
+ },
+ {
+ "name": "json-with-metadata",
+ "description": "Outputs JSON-serialized results. The `json-with-metadata` provides the same linting results as the [`json`](#json) formatter with additional metadata about the rules applied. The linting results are included in the `results` property and the rules metadata is included in the `metadata` property.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
+ },
+ {
+ "name": "json",
+ "description": "Outputs JSON-serialized results. The `json` formatter is useful when you want to programmatically work with the CLI's linting results.\n\nAlternatively, you can use the [ESLint Node.js API](../../integrate/nodejs-api) to programmatically use ESLint."
+ },
+ {
+ "name": "junit",
+ "description": "Outputs results to format compatible with the [JUnit Jenkins plugin](https://plugins.jenkins.io/junit/)."
+ },
+ {
+ "name": "stylish",
+ "description": "Human-readable output format. This is the default formatter."
+ },
+ {
+ "name": "tap",
+ "description": "Outputs results to the [Test Anything Protocol (TAP)](https://testanything.org/) specification format."
+ },
+ {
+ "name": "unix",
+ "description": "Outputs results to a format similar to many commands in UNIX-like systems. Parsable with tools such as [grep](https://www.gnu.org/software/grep/manual/grep.html), [sed](https://www.gnu.org/software/sed/manual/sed.html), and [awk](https://www.gnu.org/software/gawk/manual/gawk.html)."
+ },
+ {
+ "name": "visualstudio",
+ "description": "Outputs results to format compatible with the integrated terminal of the [Visual Studio](https://visualstudio.microsoft.com/) IDE. When using Visual Studio, you can click on the linting results in the integrated terminal to go to the issue in the source code."
+ }
+]
\ No newline at end of file
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PScwIDAgMjk0LjgyNSAyNTguOTgyJyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnPg0KPHBhdGggZmlsbD0nIzgwODBGMicgZD0nTTk3LjAyMSw5OS4wMTZsNDguNDMyLTI3Ljk2MmMxLjIxMi0wLjcsMi43MDYtMC43LDMuOTE4LDBsNDguNDMzLDI3Ljk2MiBjMS4yMTEsMC43LDEuOTU5LDEuOTkzLDEuOTU5LDMuMzkzdjU1LjkyNGMwLDEuMzk5LTAuNzQ4LDIuNjkzLTEuOTU5LDMuMzk0bC00OC40MzMsMjcuOTYyYy0xLjIxMiwwLjctMi43MDYsMC43LTMuOTE4LDAgbC00OC40MzItMjcuOTYyYy0xLjIxMi0wLjctMS45NTktMS45OTQtMS45NTktMy4zOTR2LTU1LjkyNEM5NS4wNjMsMTAxLjAwOSw5NS44MSw5OS43MTYsOTcuMDIxLDk5LjAxNicvPg0KPHBhdGggZmlsbD0nIzRCMzJDMycgZD0nTTI3My4zMzYsMTI0LjQ4OEwyMTUuNDY5LDIzLjgxNmMtMi4xMDItMy42NC01Ljk4NS02LjMyNS0xMC4xODgtNi4zMjVIODkuNTQ1IGMtNC4yMDQsMC04LjA4OCwyLjY4NS0xMC4xOSw2LjMyNWwtNTcuODY3LDEwMC40NWMtMi4xMDIsMy42NDEtMi4xMDIsOC4yMzYsMCwxMS44NzdsNTcuODY3LDk5Ljg0NyBjMi4xMDIsMy42NCw1Ljk4Niw1LjUwMSwxMC4xOSw1LjUwMWgxMTUuNzM1YzQuMjAzLDAsOC4wODctMS44MDUsMTAuMTg4LTUuNDQ2bDU3Ljg2Ny0xMDAuMDEgQzI3NS40MzksMTMyLjM5NiwyNzUuNDM5LDEyOC4xMjgsMjczLjMzNiwxMjQuNDg4IE0yMjUuNDE5LDE3Mi44OThjMCwxLjQ4LTAuODkxLDIuODQ5LTIuMTc0LDMuNTlsLTczLjcxLDQyLjUyNyBjLTEuMjgyLDAuNzQtMi44ODgsMC43NC00LjE3LDBsLTczLjc2Ny00Mi41MjdjLTEuMjgyLTAuNzQxLTIuMTc5LTIuMTA5LTIuMTc5LTMuNTlWODcuODQzYzAtMS40ODEsMC44ODQtMi44NDksMi4xNjctMy41OSBsNzMuNzA3LTQyLjUyN2MxLjI4Mi0wLjc0MSwyLjg4Ni0wLjc0MSw0LjE2OCwwbDczLjc3Miw0Mi41MjdjMS4yODMsMC43NDEsMi4xODYsMi4xMDksMi4xODYsMy41OVYxNzIuODk4eicvPg0KPC9zdmc+">
<style>
body {
- font-family:Arial, "Helvetica Neue", Helvetica, sans-serif;
- font-size:16px;
- font-weight:normal;
- margin:0;
- padding:0;
- color:#333
+ font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
+ font-size: 16px;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+ color: #333;
}
+
#overview {
- padding:20px 30px
+ padding: 20px 30px;
}
- td, th {
- padding:5px 10px
+
+ td,
+ th {
+ padding: 5px 10px;
}
+
h1 {
- margin:0
+ margin: 0;
}
+
table {
- margin:30px;
- width:calc(100% - 60px);
- max-width:1000px;
- border-radius:5px;
- border:1px solid #ddd;
- border-spacing:0px;
+ margin: 30px;
+ width: calc(100% - 60px);
+ max-width: 1000px;
+ border-radius: 5px;
+ border: 1px solid #ddd;
+ border-spacing: 0;
}
+
th {
- font-weight:400;
- font-size:medium;
- text-align:left;
- cursor:pointer
+ font-weight: 400;
+ font-size: medium;
+ text-align: left;
+ cursor: pointer;
}
- td.clr-1, td.clr-2, th span {
- font-weight:700
+
+ td.clr-1,
+ td.clr-2,
+ th span {
+ font-weight: 700;
}
+
th span {
- float:right;
- margin-left:20px
+ float: right;
+ margin-left: 20px;
}
- th span:after {
- content:"";
- clear:both;
- display:block
+
+ th span::after {
+ content: "";
+ clear: both;
+ display: block;
}
+
tr:last-child td {
- border-bottom:none
+ border-bottom: none;
}
- tr td:first-child, tr td:last-child {
- color:#9da0a4
+
+ tr td:first-child,
+ tr td:last-child {
+ color: #9da0a4;
}
- #overview.bg-0, tr.bg-0 th {
- color:#468847;
- background:#dff0d8;
- border-bottom:1px solid #d6e9c6
+
+ #overview.bg-0,
+ tr.bg-0 th {
+ color: #468847;
+ background: #dff0d8;
+ border-bottom: 1px solid #d6e9c6;
}
- #overview.bg-1, tr.bg-1 th {
- color:#f0ad4e;
- background:#fcf8e3;
- border-bottom:1px solid #fbeed5
+
+ #overview.bg-1,
+ tr.bg-1 th {
+ color: #f0ad4e;
+ background: #fcf8e3;
+ border-bottom: 1px solid #fbeed5;
}
- #overview.bg-2, tr.bg-2 th {
- color:#b94a48;
- background:#f2dede;
- border-bottom:1px solid #eed3d7
+
+ #overview.bg-2,
+ tr.bg-2 th {
+ color: #b94a48;
+ background: #f2dede;
+ border-bottom: 1px solid #eed3d7;
}
+
td {
- border-bottom:1px solid #ddd
+ border-bottom: 1px solid #ddd;
}
+
td.clr-1 {
- color:#f0ad4e
+ color: #f0ad4e;
}
+
td.clr-2 {
- color:#b94a48
+ color: #b94a48;
}
+
td a {
- color:#3a33d1;
- text-decoration:none
+ color: #3a33d1;
+ text-decoration: none;
}
+
td a:hover {
- color:#272296;
- text-decoration:underline
+ color: #272296;
+ text-decoration: underline;
}
</style>
</head>
} = it;
return `
-<tr style="display:none" class="f-${parentIndex}">
+<tr style="display: none;" class="f-${parentIndex}">
<td>${lineNumber}:${columnNumber}</td>
<td class="clr-${severityNumber}">${severityName}</td>
<td>${encodeHTML(message)}</td>
path = require("path"),
{ promisify } = require("util"),
{ ESLint } = require("./eslint"),
- { FlatESLint } = require("./eslint/flat-eslint"),
+ { FlatESLint, shouldUseFlatConfig } = require("./eslint/flat-eslint"),
createCLIOptions = require("./options"),
log = require("./shared/logging"),
RuntimeInfo = require("./shared/runtime-info");
const { Legacy: { naming } } = require("@eslint/eslintrc");
-const { findFlatConfigFile } = require("./eslint/flat-eslint");
-const { gitignoreToMinimatch } = require("@humanwhocodes/gitignore-to-minimatch");
const { ModuleImporter } = require("@humanwhocodes/module-importer");
const debug = require("debug")("eslint:cli");
/** @typedef {import("./eslint/eslint").LintMessage} LintMessage */
/** @typedef {import("./eslint/eslint").LintResult} LintResult */
/** @typedef {import("./options").ParsedCLIOptions} ParsedCLIOptions */
+/** @typedef {import("./shared/types").ResultsMeta} ResultsMeta */
//------------------------------------------------------------------------------
// Helpers
overrideConfig[0].plugins = plugins;
}
- if (ignorePattern) {
- overrideConfig.push({
- ignores: ignorePattern.map(gitignoreToMinimatch)
- });
- }
-
} else {
overrideConfigFile = config;
fix: (fix || fixDryRun) && (quiet ? quietFixPredicate : true),
fixTypes: fixType,
ignore,
- ignorePath,
overrideConfig,
overrideConfigFile,
reportUnusedDisableDirectives: reportUnusedDisableDirectives ? "error" : void 0
};
- if (configType !== "flat") {
+ if (configType === "flat") {
+ options.ignorePatterns = ignorePattern;
+ } else {
options.resolvePluginsRelativeTo = resolvePluginsRelativeTo;
options.rulePaths = rulesdir;
options.useEslintrc = eslintrc;
options.extensions = ext;
+ options.ignorePath = ignorePath;
}
return options;
/**
* Count error messages.
* @param {LintResult[]} results The lint results.
- * @returns {{errorCount:number;warningCount:number}} The number of error messages.
+ * @returns {{errorCount:number;fatalErrorCount:number,warningCount:number}} The number of error messages.
*/
function countErrors(results) {
let errorCount = 0;
* @param {LintResult[]} results The results to print.
* @param {string} format The name of the formatter to use or the path to the formatter.
* @param {string} outputFile The path for the output file.
+ * @param {ResultsMeta} resultsMeta Warning count and max threshold.
* @returns {Promise<boolean>} True if the printing succeeds, false if not.
* @private
*/
-async function printResults(engine, results, format, outputFile) {
+async function printResults(engine, results, format, outputFile, resultsMeta) {
let formatter;
try {
return false;
}
- const output = await formatter.format(results);
+ const output = await formatter.format(results, resultsMeta);
if (output) {
if (outputFile) {
* switch to flat config we can remove this logic.
*/
- const usingFlatConfig = allowFlatConfig && !!(await findFlatConfigFile(process.cwd()));
+ const usingFlatConfig = allowFlatConfig && await shouldUseFlatConfig();
debug("Using flat config?", usingFlatConfig);
resultsToPrint = ActiveESLint.getErrorResults(resultsToPrint);
}
- if (await printResults(engine, resultsToPrint, options.format, options.outputFile)) {
+ const resultCounts = countErrors(results);
+ const tooManyWarnings = options.maxWarnings >= 0 && resultCounts.warningCount > options.maxWarnings;
+ const resultsMeta = tooManyWarnings
+ ? {
+ maxWarningsExceeded: {
+ maxWarnings: options.maxWarnings,
+ foundWarnings: resultCounts.warningCount
+ }
+ }
+ : {};
- // Errors and warnings from the original unfiltered results should determine the exit code
- const { errorCount, fatalErrorCount, warningCount } = countErrors(results);
+ if (await printResults(engine, resultsToPrint, options.format, options.outputFile, resultsMeta)) {
- const tooManyWarnings =
- options.maxWarnings >= 0 && warningCount > options.maxWarnings;
+ // Errors and warnings from the original unfiltered results should determine the exit code
const shouldExitForFatalErrors =
- options.exitOnFatalError && fatalErrorCount > 0;
+ options.exitOnFatalError && resultCounts.fatalErrorCount > 0;
- if (!errorCount && tooManyWarnings) {
+ if (!resultCounts.errorCount && tooManyWarnings) {
log.error(
"ESLint found too many warnings (maximum: %s).",
options.maxWarnings
return 2;
}
- return (errorCount || tooManyWarnings) ? 1 : 0;
+ return (resultCounts.errorCount || tooManyWarnings) ? 1 : 0;
}
return 2;
{
plugins: {
"@": {
- parsers: {
- espree: require("espree")
- },
/*
* Because we try to delay loading rules until absolutely
languageOptions: {
sourceType: "module",
ecmaVersion: "latest",
- parser: "@/espree",
+ parser: require("espree"),
parserOptions: {}
}
},
// default ignores are listed here
{
ignores: [
- "**/node_modules/**",
- ".git/**"
+ "**/node_modules/",
+ ".git/"
]
},
const { flatConfigSchema } = require("./flat-config-schema");
const { RuleValidator } = require("./rule-validator");
const { defaultConfig } = require("./default-config");
-const recommendedConfig = require("../../conf/eslint-recommended");
+const jsPlugin = require("@eslint/js");
//-----------------------------------------------------------------------------
// Helpers
};
}
+/**
+ * Returns the name of an object in the config by reading its `meta` key.
+ * @param {Object} object The object to check.
+ * @returns {string?} The name of the object if found or `null` if there
+ * is no name.
+ */
+function getObjectId(object) {
+
+ // first check old-style name
+ let name = object.name;
+
+ if (!name) {
+
+ if (!object.meta) {
+ return null;
+ }
+
+ name = object.meta.name;
+
+ if (!name) {
+ return null;
+ }
+ }
+
+ // now check for old-style version
+ let version = object.version;
+
+ if (!version) {
+ version = object.meta && object.meta.version;
+ }
+
+ // if there's a version then append that
+ if (version) {
+ return `${name}@${version}`;
+ }
+
+ return name;
+}
+
const originalBaseConfig = Symbol("originalBaseConfig");
//-----------------------------------------------------------------------------
}
/**
- * The baes config used to build the config array.
+ * The base config used to build the config array.
* @type {Array<FlatConfig>}
*/
this[originalBaseConfig] = baseConfig;
*/
[ConfigArraySymbol.preprocessConfig](config) {
if (config === "eslint:recommended") {
- return recommendedConfig;
+
+ // if we are in a Node.js environment warn the user
+ if (typeof process !== "undefined" && process.emitWarning) {
+ process.emitWarning("The 'eslint:recommended' string configuration is deprecated and will be replaced by the @eslint/js package's 'recommended' config.");
+ }
+
+ return jsPlugin.configs.recommended;
}
if (config === "eslint:all") {
- /*
- * Load `eslint-all.js` here instead of at the top level to avoid loading all rule modules
- * when it isn't necessary. `eslint-all.js` reads `meta` of rule objects to filter out deprecated ones,
- * so requiring `eslint-all.js` module loads all rule modules as a consequence.
- */
- return require("../../conf/eslint-all");
+ // if we are in a Node.js environment warn the user
+ if (typeof process !== "undefined" && process.emitWarning) {
+ process.emitWarning("The 'eslint:all' string configuration is deprecated and will be replaced by the @eslint/js package's 'all' config.");
+ }
+
+ return jsPlugin.configs.all;
}
/*
// Check parser value
if (languageOptions && languageOptions.parser) {
- if (typeof languageOptions.parser === "string") {
- const { pluginName, objectName: localParserName } = splitPluginIdentifier(languageOptions.parser);
+ const { parser } = languageOptions;
- parserName = languageOptions.parser;
+ if (typeof parser === "object") {
+ parserName = getObjectId(parser);
- if (!plugins || !plugins[pluginName] || !plugins[pluginName].parsers || !plugins[pluginName].parsers[localParserName]) {
- throw new TypeError(`Key "parser": Could not find "${localParserName}" in plugin "${pluginName}".`);
+ if (!parserName) {
+ invalidParser = true;
}
- languageOptions.parser = plugins[pluginName].parsers[localParserName];
} else {
invalidParser = true;
}
}
config.processor = plugins[pluginName].processors[localProcessorName];
+ } else if (typeof processor === "object") {
+ processorName = getObjectId(processor);
+
+ if (!processorName) {
+ invalidProcessor = true;
+ }
+
} else {
invalidProcessor = true;
}
value: function() {
if (invalidParser) {
- throw new Error("Caching is not supported when parser is an object.");
+ throw new Error("Could not serialize parser object (missing 'meta' object).");
}
if (invalidProcessor) {
- throw new Error("Caching is not supported when processor is an object.");
+ throw new Error("Could not serialize processor object (missing 'meta' object).");
}
return {
...this,
- plugins: Object.keys(plugins),
+ plugins: Object.entries(plugins).map(([namespace, plugin]) => {
+
+ const pluginId = getObjectId(plugin);
+
+ if (!pluginId) {
+ return namespace;
+ }
+
+ return `${namespace}:${pluginId}`;
+ }),
languageOptions: {
...languageOptions,
parser: parserName
// Assertions
//-----------------------------------------------------------------------------
+/**
+ * The error type when a rule's options are configured with an invalid type.
+ */
+class InvalidRuleOptionsError extends Error {
+
+ /**
+ * @param {string} ruleId Rule name being configured.
+ * @param {any} value The invalid value.
+ */
+ constructor(ruleId, value) {
+ super(`Key "${ruleId}": Expected severity of "off", 0, "warn", 1, "error", or 2.`);
+ this.messageTemplate = "invalid-rule-options";
+ this.messageData = { ruleId, value };
+ }
+}
+
/**
* Validates that a value is a valid rule options entry.
+ * @param {string} ruleId Rule name being configured.
* @param {any} value The value to check.
* @returns {void}
- * @throws {TypeError} If the value isn't a valid rule options.
+ * @throws {InvalidRuleOptionsError} If the value isn't a valid rule options.
*/
-function assertIsRuleOptions(value) {
-
+function assertIsRuleOptions(ruleId, value) {
if (typeof value !== "string" && typeof value !== "number" && !Array.isArray(value)) {
- throw new TypeError("Expected a string, number, or array.");
+ throw new InvalidRuleOptionsError(ruleId, value);
+ }
+}
+
+/**
+ * The error type when a rule's severity is invalid.
+ */
+class InvalidRuleSeverityError extends Error {
+
+ /**
+ * @param {string} ruleId Rule name being configured.
+ * @param {any} value The invalid value.
+ */
+ constructor(ruleId, value) {
+ super(`Key "${ruleId}": Expected severity of "off", 0, "warn", 1, "error", or 2.`);
+ this.messageTemplate = "invalid-rule-severity";
+ this.messageData = { ruleId, value };
}
}
/**
* Validates that a value is valid rule severity.
+ * @param {string} ruleId Rule name being configured.
* @param {any} value The value to check.
* @returns {void}
- * @throws {TypeError} If the value isn't a valid rule severity.
+ * @throws {InvalidRuleSeverityError} If the value isn't a valid rule severity.
*/
-function assertIsRuleSeverity(value) {
+function assertIsRuleSeverity(ruleId, value) {
const severity = typeof value === "string"
? ruleSeverities.get(value.toLowerCase())
: ruleSeverities.get(value);
if (typeof severity === "undefined") {
- throw new TypeError("Expected severity of \"off\", 0, \"warn\", 1, \"error\", or 2.");
+ throw new InvalidRuleSeverityError(ruleId, value);
}
}
}
}
-/**
- * Validates that a value is an object or a string.
- * @param {any} value The value to check.
- * @returns {void}
- * @throws {TypeError} If the value isn't an object or a string.
- */
-function assertIsObjectOrString(value) {
- if ((!value || typeof value !== "object") && typeof value !== "string") {
- throw new TypeError("Expected an object or string.");
- }
-}
-
//-----------------------------------------------------------------------------
// Low-Level Schemas
//-----------------------------------------------------------------------------
const parserSchema = {
merge: "replace",
validate(value) {
- assertIsObjectOrString(value);
- if (typeof value === "object" && typeof value.parse !== "function" && typeof value.parseForESLint !== "function") {
- throw new TypeError("Expected object to have a parse() or parseForESLint() method.");
+ if (!value || typeof value !== "object" ||
+ (typeof value.parse !== "function" && typeof value.parseForESLint !== "function")
+ ) {
+ throw new TypeError("Expected object with parse() or parseForESLint() method.");
}
- if (typeof value === "string") {
- assertIsPluginMemberName(value);
- }
}
};
validate(value) {
assertIsObject(value);
- let lastRuleId;
-
- // Performance: One try-catch has less overhead than one per loop iteration
- try {
+ /*
+ * We are not checking the rule schema here because there is no
+ * guarantee that the rule definition is present at this point. Instead
+ * we wait and check the rule schema during the finalization step
+ * of calculating a config.
+ */
+ for (const ruleId of Object.keys(value)) {
- /*
- * We are not checking the rule schema here because there is no
- * guarantee that the rule definition is present at this point. Instead
- * we wait and check the rule schema during the finalization step
- * of calculating a config.
- */
- for (const ruleId of Object.keys(value)) {
-
- // avoid hairy edge case
- if (ruleId === "__proto__") {
- continue;
- }
-
- lastRuleId = ruleId;
+ // avoid hairy edge case
+ if (ruleId === "__proto__") {
+ continue;
+ }
- const ruleOptions = value[ruleId];
+ const ruleOptions = value[ruleId];
- assertIsRuleOptions(ruleOptions);
+ assertIsRuleOptions(ruleId, ruleOptions);
- if (Array.isArray(ruleOptions)) {
- assertIsRuleSeverity(ruleOptions[0]);
- } else {
- assertIsRuleSeverity(ruleOptions);
- }
+ if (Array.isArray(ruleOptions)) {
+ assertIsRuleSeverity(ruleId, ruleOptions[0]);
+ } else {
+ assertIsRuleSeverity(ruleId, ruleOptions);
}
- } catch (error) {
- error.message = `Key "${lastRuleId}": ${error.message}`;
- throw error;
}
}
};
/** @typedef {import("../shared/types").Plugin} Plugin */
/** @typedef {import("../shared/types").Rule} Rule */
/** @typedef {import("../shared/types").LintResult} LintResult */
+/** @typedef {import("../shared/types").ResultsMeta} ResultsMeta */
/**
* The main formatter object.
* @typedef LoadedFormatter
- * @property {function(LintResult[]): string | Promise<string>} format format function.
+ * @property {(results: LintResult[], resultsMeta: ResultsMeta) => string | Promise<string>} format format function.
*/
/**
/**
* The main formatter method.
* @param {LintResult[]} results The lint results to format.
+ * @param {ResultsMeta} resultsMeta Warning count and max threshold.
* @returns {string | Promise<string>} The formatted lint results.
*/
- format(results) {
+ format(results, resultsMeta) {
let rulesMeta = null;
results.sort(compareResultsByFilePath);
return formatter(results, {
+ ...resultsMeta,
get cwd() {
return options.cwd;
},
const { version } = require("../../package.json");
const { Linter } = require("../linter");
const { getRuleFromConfig } = require("../config/flat-config-helpers");
-const { gitignoreToMinimatch } = require("@humanwhocodes/gitignore-to-minimatch");
const {
Legacy: {
ConfigOps: {
} = require("@eslint/eslintrc");
const {
- fileExists,
findFiles,
getCacheFile,
/** @typedef {import("../shared/types").ConfigData} ConfigData */
/** @typedef {import("../shared/types").DeprecatedRuleInfo} DeprecatedRuleInfo */
/** @typedef {import("../shared/types").LintMessage} LintMessage */
+/** @typedef {import("../shared/types").LintResult} LintResult */
/** @typedef {import("../shared/types").ParserOptions} ParserOptions */
/** @typedef {import("../shared/types").Plugin} Plugin */
+/** @typedef {import("../shared/types").ResultsMeta} ResultsMeta */
/** @typedef {import("../shared/types").RuleConf} RuleConf */
/** @typedef {import("../shared/types").Rule} Rule */
/** @typedef {ReturnType<ConfigArray.extractConfig>} ExtractedConfig */
* @property {boolean|Function} [fix] Execute in autofix mode. If a function, should return a boolean.
* @property {string[]} [fixTypes] Array of rule types to apply fixes for.
* @property {boolean} [globInputPaths] Set to false to skip glob resolution of input file paths to lint (default: true). If false, each input file paths is assumed to be a non-glob path to an existing file.
- * @property {boolean} [ignore] False disables use of .eslintignore.
- * @property {string} [ignorePath] The ignore file to use instead of .eslintignore.
- * @property {string[]} [ignorePatterns] Ignore file patterns to use in addition to .eslintignore.
+ * @property {boolean} [ignore] False disables all ignore patterns except for the default ones.
+ * @property {string[]} [ignorePatterns] Ignore file patterns to use in addition to config ignores. These patterns are relative to `cwd`.
* @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance
* @property {boolean|string} [overrideConfigFile] Searches for default config file when falsy;
* doesn't do any config file lookup when `true`; considered to be a config filename
const debug = require("debug")("eslint:flat-eslint");
const removedFormatters = new Set(["table", "codeframe"]);
const privateMembers = new WeakMap();
+const importedConfigFileModificationTime = new Map();
/**
* It will calculate the error and warning count for collection of messages per file
});
}
-/**
- * Loads global ignore patterns from an ignore file (usually .eslintignore).
- * @param {string} filePath The filename to load.
- * @returns {ignore} A function encapsulating the ignore patterns.
- * @throws {Error} If the file cannot be read.
- * @private
- */
-async function loadIgnoreFilePatterns(filePath) {
- debug(`Loading ignore file: ${filePath}`);
-
- try {
- const ignoreFileText = await fs.readFile(filePath, { encoding: "utf8" });
-
- return ignoreFileText
- .split(/\r?\n/gu)
- .filter(line => line.trim() !== "" && !line.startsWith("#"));
-
- } catch (e) {
- debug(`Error reading ignore file: ${filePath}`);
- e.message = `Cannot read ignore file: ${filePath}\nError: ${e.message}`;
- throw e;
- }
-}
-
/**
* Create rulesMeta object.
* @param {Map<string,Rule>} rules a map of rules from which to generate the object.
}, {});
}
+/**
+ * Return the absolute path of a file named `"__placeholder__.js"` in a given directory.
+ * This is used as a replacement for a missing file path.
+ * @param {string} cwd An absolute directory path.
+ * @returns {string} The absolute path of a file named `"__placeholder__.js"` in the given directory.
+ */
+function getPlaceholderPath(cwd) {
+ return path.join(cwd, "__placeholder__.js");
+}
+
/** @type {WeakMap<ExtractedConfig, DeprecatedRuleInfo[]>} */
const usedDeprecatedRulesCache = new WeakMap();
} = privateMembers.get(eslint);
const filePath = path.isAbsolute(maybeFilePath)
? maybeFilePath
- : path.join(cwd, "__placeholder__.js");
+ : getPlaceholderPath(cwd);
const config = configs.getConfig(filePath);
// Most files use the same config, so cache it.
* Searches from the current working directory up until finding the
* given flat config filename.
* @param {string} cwd The current working directory to search from.
- * @returns {Promise<string|null>} The filename if found or `null` if not.
+ * @returns {Promise<string|undefined>} The filename if found or `undefined` if not.
*/
function findFlatConfigFile(cwd) {
return findUp(
/**
* Load the config array from the given filename.
* @param {string} filePath The filename to load from.
- * @param {Object} options Options to help load the config file.
- * @param {string} options.basePath The base path for the config array.
- * @param {boolean} options.shouldIgnore Whether to honor ignore patterns.
- * @returns {Promise<FlatConfigArray>} The config array loaded from the config file.
+ * @returns {Promise<any>} The config loaded from the config file.
*/
-async function loadFlatConfigFile(filePath, { basePath, shouldIgnore }) {
+async function loadFlatConfigFile(filePath) {
debug(`Loading config from ${filePath}`);
const fileURL = pathToFileURL(filePath);
debug(`Config file URL is ${fileURL}`);
- const module = await import(fileURL);
+ const mtime = (await fs.stat(filePath)).mtime.getTime();
+
+ /*
+ * Append a query with the config file's modification time (`mtime`) in order
+ * to import the current version of the config file. Without the query, `import()` would
+ * cache the config file module by the pathname only, and then always return
+ * the same version (the one that was actual when the module was imported for the first time).
+ *
+ * This ensures that the config file module is loaded and executed again
+ * if it has been changed since the last time it was imported.
+ * If it hasn't been changed, `import()` will just return the cached version.
+ *
+ * Note that we should not overuse queries (e.g., by appending the current time
+ * to always reload the config file module) as that could cause memory leaks
+ * because entries are never removed from the import cache.
+ */
+ fileURL.searchParams.append("mtime", mtime);
- return new FlatConfigArray(module.default, {
+ /*
+ * With queries, we can bypass the import cache. However, when import-ing a CJS module,
+ * Node.js uses the require infrastructure under the hood. That includes the require cache,
+ * which caches the config file module by its file path (queries have no effect).
+ * Therefore, we also need to clear the require cache before importing the config file module.
+ * In order to get the same behavior with ESM and CJS config files, in particular - to reload
+ * the config file only if it has been changed, we track file modification times and clear
+ * the require cache only if the file has been changed.
+ */
+ if (importedConfigFileModificationTime.get(filePath) !== mtime) {
+ delete require.cache[filePath];
+ }
+
+ const config = (await import(fileURL)).default;
+
+ importedConfigFileModificationTime.set(filePath, mtime);
+
+ return config;
+}
+
+/**
+ * Determines which config file to use. This is determined by seeing if an
+ * override config file was passed, and if so, using it; otherwise, as long
+ * as override config file is not explicitly set to `false`, it will search
+ * upwards from the cwd for a file named `eslint.config.js`.
+ * @param {import("./eslint").ESLintOptions} options The ESLint instance options.
+ * @returns {{configFilePath:string|undefined,basePath:string,error:Error|null}} Location information for
+ * the config file.
+ */
+async function locateConfigFileToUse({ configFile, cwd }) {
+
+ // determine where to load config file from
+ let configFilePath;
+ let basePath = cwd;
+ let error = null;
+
+ if (typeof configFile === "string") {
+ debug(`Override config file path is ${configFile}`);
+ configFilePath = path.resolve(cwd, configFile);
+ } else if (configFile !== false) {
+ debug("Searching for eslint.config.js");
+ configFilePath = await findFlatConfigFile(cwd);
+
+ if (configFilePath) {
+ basePath = path.resolve(path.dirname(configFilePath));
+ } else {
+ error = new Error("Could not find config file.");
+ }
+
+ }
+
+ return {
+ configFilePath,
basePath,
- shouldIgnore
- });
+ error
+ };
+
}
/**
*/
async function calculateConfigArray(eslint, {
cwd,
+ baseConfig,
overrideConfig,
configFile,
ignore: shouldIgnore,
- ignorePath,
ignorePatterns
}) {
return slots.configs;
}
- // determine where to load config file from
- let configFilePath;
- let basePath = cwd;
+ const { configFilePath, basePath, error } = await locateConfigFileToUse({ configFile, cwd });
- if (typeof configFile === "string") {
- debug(`Override config file path is ${configFile}`);
- configFilePath = path.resolve(cwd, configFile);
- } else if (configFile !== false) {
- debug("Searching for eslint.config.js");
- configFilePath = await findFlatConfigFile(cwd);
-
- if (!configFilePath) {
- throw new Error("Could not find config file.");
- }
-
- basePath = path.resolve(path.dirname(configFilePath));
+ // config file is required to calculate config
+ if (error) {
+ throw error;
}
- // load config array
- let configs;
+ const configs = new FlatConfigArray(baseConfig || [], { basePath, shouldIgnore });
+ // load config file
if (configFilePath) {
- configs = await loadFlatConfigFile(configFilePath, {
- basePath,
- shouldIgnore
- });
- } else {
- configs = new FlatConfigArray([], { basePath, shouldIgnore });
- }
+ const fileConfig = await loadFlatConfigFile(configFilePath);
- // add in any configured defaults
- configs.push(...slots.defaultConfigs);
-
- let allIgnorePatterns = [];
- let ignoreFilePath;
-
- // load ignore file if necessary
- if (shouldIgnore) {
- if (ignorePath) {
- ignoreFilePath = path.resolve(cwd, ignorePath);
- allIgnorePatterns = await loadIgnoreFilePatterns(ignoreFilePath);
+ if (Array.isArray(fileConfig)) {
+ configs.push(...fileConfig);
} else {
- ignoreFilePath = path.resolve(cwd, ".eslintignore");
-
- // no error if .eslintignore doesn't exist`
- if (fileExists(ignoreFilePath)) {
- allIgnorePatterns = await loadIgnoreFilePatterns(ignoreFilePath);
- }
+ configs.push(fileConfig);
}
}
+ // add in any configured defaults
+ configs.push(...slots.defaultConfigs);
+
// append command line ignore patterns
- if (ignorePatterns) {
- if (typeof ignorePatterns === "string") {
- allIgnorePatterns.push(ignorePatterns);
- } else {
- allIgnorePatterns.push(...ignorePatterns);
- }
- }
+ if (ignorePatterns && ignorePatterns.length > 0) {
- /*
- * If the config file basePath is different than the cwd, then
- * the ignore patterns won't work correctly. Here, we adjust the
- * ignore pattern to include the correct relative path. Patterns
- * loaded from ignore files are always relative to the cwd, whereas
- * the config file basePath can be an ancestor of the cwd.
- */
- if (basePath !== cwd && allIgnorePatterns.length) {
+ let relativeIgnorePatterns;
- const relativeIgnorePath = path.relative(basePath, cwd);
+ /*
+ * If the config file basePath is different than the cwd, then
+ * the ignore patterns won't work correctly. Here, we adjust the
+ * ignore pattern to include the correct relative path. Patterns
+ * passed as `ignorePatterns` are relative to the cwd, whereas
+ * the config file basePath can be an ancestor of the cwd.
+ */
+ if (basePath === cwd) {
+ relativeIgnorePatterns = ignorePatterns;
+ } else {
- allIgnorePatterns = allIgnorePatterns.map(pattern => {
- const negated = pattern.startsWith("!");
- const basePattern = negated ? pattern.slice(1) : pattern;
+ const relativeIgnorePath = path.relative(basePath, cwd);
- /*
- * Ignore patterns are considered relative to a directory
- * when the pattern contains a slash in a position other
- * than the last character. If that's the case, we need to
- * add the relative ignore path to the current pattern to
- * get the correct behavior. Otherwise, no change is needed.
- */
- if (!basePattern.includes("/") || basePattern.endsWith("/")) {
- return pattern;
- }
+ relativeIgnorePatterns = ignorePatterns.map(pattern => {
+ const negated = pattern.startsWith("!");
+ const basePattern = negated ? pattern.slice(1) : pattern;
- return (negated ? "!" : "") +
+ return (negated ? "!" : "") +
path.posix.join(relativeIgnorePath, basePattern);
- });
- }
-
- if (allIgnorePatterns.length) {
+ });
+ }
/*
* Ignore patterns are added to the end of the config array
* so they can override default ignores.
*/
configs.push({
- ignores: allIgnorePatterns.map(gitignoreToMinimatch)
+ ignores: relativeIgnorePatterns
});
}
* `config.extractConfig(filePath)` requires an absolute path, but `linter`
* doesn't know CWD, so it gives `linter` an absolute path always.
*/
- const filePathToVerify = filePath === "<text>" ? path.join(cwd, "__placeholder__.js") : filePath;
+ const filePathToVerify = filePath === "<text>" ? getPlaceholderPath(cwd) : filePath;
const { fixed, messages, output } = linter.verifyAndFix(
text,
configs,
}
}
+/**
+ * Creates an error to be thrown when an array of results passed to `getRulesMetaForResults` was not created by the current engine.
+ * @returns {TypeError} An error object.
+ */
+function createExtraneousResultsError() {
+ return new TypeError("Results object was not created from this ESLint instance.");
+}
+
//-----------------------------------------------------------------------------
// Main API
//-----------------------------------------------------------------------------
*/
getRulesMetaForResults(results) {
- const resultRules = new Map();
-
// short-circuit simple case
if (results.length === 0) {
- return resultRules;
+ return {};
}
- const { configs } = privateMembers.get(this);
+ const resultRules = new Map();
+ const {
+ configs,
+ options: { cwd }
+ } = privateMembers.get(this);
/*
* We can only accurately return rules meta information for linting results if the
* to let the user know we can't do anything here.
*/
if (!configs) {
- throw new TypeError("Results object was not created from this ESLint instance.");
+ throw createExtraneousResultsError();
}
for (const result of results) {
* Normalize filename for <text>.
*/
const filePath = result.filePath === "<text>"
- ? "__placeholder__.js" : result.filePath;
-
- /*
- * All of the plugin and rule information is contained within the
- * calculated config for the given file.
- */
- const config = configs.getConfig(filePath);
+ ? getPlaceholderPath(cwd) : result.filePath;
const allMessages = result.messages.concat(result.suppressedMessages);
for (const { ruleId } of allMessages) {
+ if (!ruleId) {
+ continue;
+ }
+
+ /*
+ * All of the plugin and rule information is contained within the
+ * calculated config for the given file.
+ */
+ const config = configs.getConfig(filePath);
+
+ if (!config) {
+ throw createExtraneousResultsError();
+ }
const rule = getRuleFromConfig(ruleId, config);
// ensure the rule exists
}
- // set up fixer for fixtypes if necessary
+ // set up fixer for fixTypes if necessary
let fixer = fix;
if (fix && fixTypesSet) {
* The following values are allowed:
* - `undefined` ... Load `stylish` builtin formatter.
* - A builtin formatter name ... Load the builtin formatter.
- * - A thirdparty formatter name:
+ * - A third-party formatter name:
* - `foo` → `eslint-formatter-foo`
* - `@foo` → `@foo/eslint-formatter`
* - `@foo/bar` → `@foo/eslint-formatter-bar`
const npmFormat = naming.normalizePackageName(normalizedFormatName, "eslint-formatter");
// TODO: This is pretty dirty...would be nice to clean up at some point.
- formatterPath = ModuleResolver.resolve(npmFormat, path.join(cwd, "__placeholder__.js"));
+ formatterPath = ModuleResolver.resolve(npmFormat, getPlaceholderPath(cwd));
} catch {
formatterPath = path.resolve(__dirname, "../", "cli-engine", "formatters", `${normalizedFormatName}.js`);
}
/**
* The main formatter method.
* @param {LintResults[]} results The lint results to format.
+ * @param {ResultsMeta} resultsMeta Warning count and max threshold.
* @returns {string} The formatted lint results.
*/
- format(results) {
+ format(results, resultsMeta) {
let rulesMeta = null;
results.sort(compareResultsByFilePath);
return formatter(results, {
+ ...resultsMeta,
cwd,
get rulesMeta() {
if (!rulesMeta) {
return configs.getConfig(absolutePath);
}
+ /**
+ * Finds the config file being used by this instance based on the options
+ * passed to the constructor.
+ * @returns {string|undefined} The path to the config file being used or
+ * `undefined` if no config file is being used.
+ */
+ async findConfigFile() {
+ const options = privateMembers.get(this).options;
+ const { configFilePath } = await locateConfigFileToUse(options);
+
+ return configFilePath;
+ }
+
/**
* Checks if a given path is ignored by ESLint.
* @param {string} filePath The path of the file to check.
}
}
+/**
+ * Returns whether flat config should be used.
+ * @returns {Promise<boolean>} Whether flat config should be used.
+ */
+async function shouldUseFlatConfig() {
+ switch (process.env.ESLINT_USE_FLAT_CONFIG) {
+ case "true":
+ return true;
+ case "false":
+ return false;
+ default:
+
+ /*
+ * If neither explicitly enabled nor disabled, then use the presence
+ * of a flat config file to determine enablement.
+ */
+ return !!(await findFlatConfigFile(process.cwd()));
+ }
+}
+
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
module.exports = {
FlatESLint,
- findFlatConfigFile
+ shouldUseFlatConfig
};
"use strict";
+//------------------------------------------------------------------------------
+// Typedefs
+//------------------------------------------------------------------------------
+
+/** @typedef {import("../shared/types").LintMessage} LintMessage */
+
+//------------------------------------------------------------------------------
+// Module Definition
+//------------------------------------------------------------------------------
+
const escapeRegExp = require("escape-string-regexp");
/**
* @param {Object} options options for applying directives. This is the same as the options
* for the exported function, except that `reportUnusedDisableDirectives` is not supported
* (this function always reports unused disable directives).
- * @returns {{problems: Problem[], unusedDisableDirectives: Problem[]}} An object with a list
+ * @returns {{problems: LintMessage[], unusedDisableDirectives: LintMessage[]}} An object with a list
* of problems (including suppressed ones) and unused eslint-disable directives
*/
function applyDirectives(options) {
const debug = require("debug")("eslint:config-comment-parser");
+//------------------------------------------------------------------------------
+// Typedefs
+//------------------------------------------------------------------------------
+
+/** @typedef {import("../shared/types").LintMessage} LintMessage */
+
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
* Parses a JSON-like config.
* @param {string} string The string to parse.
* @param {Object} location Start line and column of comments for potential error message.
- * @returns {({success: true, config: Object}|{success: false, error: Problem})} Result map object
+ * @returns {({success: true, config: Object}|{success: false, error: LintMessage})} Result map object
*/
parseJsonConfig(string, location) {
debug("Parsing JSON config");
severity: 2,
message: `Failed to parse JSON from '${normalizedString}': ${ex.message}`,
line: location.start.line,
- column: location.start.column + 1
+ column: location.start.column + 1,
+ nodeType: null
}
};
merge = require("lodash.merge"),
pkg = require("../../package.json"),
astUtils = require("../shared/ast-utils"),
+ {
+ directivesPattern
+ } = require("../shared/directives"),
{
Legacy: {
ConfigOps,
if (variable) {
variable.eslintUsed = true;
+ variable.eslintExported = true;
}
});
* @param {ASTNode} ast The top node of the AST.
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
* @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
- * @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: Problem[], disableDirectives: DisableDirective[]}}
+ * @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: LintMessage[], disableDirectives: DisableDirective[]}}
* A collection of the directive comments that were found, along with any problems that occurred when parsing
*/
function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
- const match = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u.exec(directivePart);
+ const match = directivesPattern.exec(directivePart);
if (!match) {
return;
* Convert "/path/to/<text>" to "<text>".
* `CLIEngine#executeOnText()` method gives "/path/to/<text>" if the filename
* was omitted because `configArray.extractConfig()` requires an absolute path.
- * But the linter should pass `<text>` to `RuleContext#getFilename()` in that
+ * But the linter should pass `<text>` to `RuleContext#filename` in that
* case.
* Also, code blocks can have their virtual filename. If the parent filename was
* `<text>`, the virtual filename is `<text>/0_foo.js` or something like (i.e.,
* @param {string} text The text to parse.
* @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}}
+ * @returns {{success: false, error: LintMessage}|{success: true, sourceCode: SourceCode}}
* An object containing the AST and parser services if parsing was successful, or the error if parsing failed
* @private
*/
severity: 2,
message,
line: ex.lineNumber,
- column: ex.column
+ column: ex.column,
+ nodeType: null
}
};
}
}
-/**
- * Gets the scope for the current node
- * @param {ScopeManager} scopeManager The scope manager for this AST
- * @param {ASTNode} currentNode The node to get the scope of
- * @returns {eslint-scope.Scope} The scope information for this node
- */
-function getScope(scopeManager, currentNode) {
-
- // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
- const inner = currentNode.type !== "Program";
-
- for (let node = currentNode; node; node = node.parent) {
- const scope = scopeManager.acquire(node, inner);
-
- if (scope) {
- if (scope.type === "function-expression-name") {
- return scope.childScopes[0];
- }
- return scope;
- }
- }
-
- return scopeManager.scopes[0];
-}
-
-/**
- * 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 {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, 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
- const initialScope = currentScope.type === "global" && specialScope ? currentScope.childScopes[0] : currentScope;
-
- for (let scope = initialScope; scope; scope = scope.upper) {
- const variable = scope.variables.find(scopeVar => scopeVar.name === name);
-
- if (variable) {
- variable.eslintUsed = true;
- return true;
- }
- }
-
- return false;
-}
-
/**
* Runs a rule, and gets its listeners
* @param {Rule} rule A normalized rule with a `create` method
}
}
-/**
- * Gets all the ancestors of a given node
- * @param {ASTNode} node The node
- * @returns {ASTNode[]} All the ancestor nodes in the AST, not including the provided node, starting
- * from the root node and going inwards to the parent node.
- */
-function getAncestors(node) {
- const ancestorsStartingAtParent = [];
-
- for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
- ancestorsStartingAtParent.push(ancestor);
- }
-
- return ancestorsStartingAtParent.reverse();
-}
-
// methods that exist on SourceCode object
const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
getSource: "getText",
(contextInfo, methodName) =>
Object.assign(contextInfo, {
[methodName](...args) {
- return this.getSourceCode()[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
+ return this.sourceCode[DEPRECATED_SOURCECODE_PASSTHROUGHS[methodName]](...args);
}
}),
{}
* @param {boolean} disableFixes If true, it doesn't make `fix` properties.
* @param {string | undefined} cwd cwd of the cli
* @param {string} physicalFilename The full path of the file on disk without any code block information
- * @returns {Problem[]} An array of reported problems
+ * @returns {LintMessage[]} An array of reported problems
*/
function runRules(sourceCode, configuredRules, ruleMapper, parserName, languageOptions, settings, filename, disableFixes, cwd, physicalFilename) {
const emitter = createEmitter();
Object.assign(
Object.create(BASE_TRAVERSAL_CONTEXT),
{
- getAncestors: () => getAncestors(currentNode),
- getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
+ getAncestors: () => sourceCode.getAncestors(currentNode),
+ getDeclaredVariables: node => sourceCode.getDeclaredVariables(node),
getCwd: () => cwd,
+ cwd,
getFilename: () => filename,
+ filename,
getPhysicalFilename: () => physicalFilename || filename,
- getScope: () => getScope(sourceCode.scopeManager, currentNode),
+ physicalFilename: physicalFilename || filename,
+ getScope: () => sourceCode.getScope(currentNode),
getSourceCode: () => sourceCode,
- markVariableAsUsed: name => markVariableAsUsed(sourceCode.scopeManager, currentNode, languageOptions, name),
+ sourceCode,
+ markVariableAsUsed: name => sourceCode.markVariableAsUsed(name, currentNode),
parserOptions: {
...languageOptions.parserOptions
},
severity: 2,
message: `Configured parser '${config.parser}' was not found.`,
line: 0,
- column: 0
+ column: 0,
+ nodeType: null
}];
}
parserName = config.parser;
severity: 2,
message,
line: ex.lineNumber,
- column: ex.column
+ column: ex.column,
+ nodeType: null
}
];
}
languageOptions.ecmaVersion
);
- // add configured globals and language globals
- const configuredGlobals = {
- ...(getGlobalsForEcmaVersion(languageOptions.ecmaVersion)),
- ...(languageOptions.sourceType === "commonjs" ? globals.commonjs : void 0),
- ...languageOptions.globals
- };
+ /*
+ * add configured globals and language globals
+ *
+ * using Object.assign instead of object spread for performance reasons
+ * https://github.com/eslint/eslint/issues/16302
+ */
+ const configuredGlobals = Object.assign(
+ {},
+ getGlobalsForEcmaVersion(languageOptions.ecmaVersion),
+ languageOptions.sourceType === "commonjs" ? globals.commonjs : void 0,
+ languageOptions.globals
+ );
// double check that there is a parser to avoid mysterious error messages
if (!languageOptions.parser) {
severity: 1,
message: `No matching configuration found for ${filename}.`,
line: 0,
- column: 0
+ column: 0,
+ nodeType: null
}
];
}
severity: 2,
message,
line: ex.lineNumber,
- column: ex.column
+ column: ex.column,
+ nodeType: null
}
];
}
/**
* Given a list of reported problems, distinguish problems between normal messages and suppressed messages.
* The normal messages will be returned and the suppressed messages will be stored as lastSuppressedMessages.
- * @param {Problem[]} problems A list of reported problems.
+ * @param {Array<LintMessage|SuppressedLintMessage>} problems A list of reported problems.
* @returns {LintMessage[]} A list of LintMessage.
*/
_distinguishSuppressedMessages(problems) {
// Typedefs
//------------------------------------------------------------------------------
+/** @typedef {import("../shared/types").LintMessage} LintMessage */
+
/**
* An error message description
* @typedef {Object} MessageDescriptor
* @property {Array<{desc?: string, messageId?: string, fix: Function}>} suggest Suggestion descriptions and functions to create a the associated fixes.
*/
-/**
- * Information about the report
- * @typedef {Object} ReportInfo
- * @property {string} ruleId The rule ID
- * @property {(0|1|2)} severity Severity of the error
- * @property {(string|undefined)} message The message
- * @property {(string|undefined)} [messageId] The message ID
- * @property {number} line The line number
- * @property {number} column The column number
- * @property {(number|undefined)} [endLine] The ending line number
- * @property {(number|undefined)} [endColumn] The ending column number
- * @property {(string|null)} nodeType Type of node
- * @property {string} source Source text
- * @property {({text: string, range: (number[]|null)}|null)} [fix] The fix object
- * @property {Array<{text: string, range: (number[]|null)}|null>} [suggestions] Suggestion info
- */
-
//------------------------------------------------------------------------------
// Module Definition
//------------------------------------------------------------------------------
* @param {{start: SourceLocation, end: (SourceLocation|null)}} options.loc Start and end location
* @param {{text: string, range: (number[]|null)}} options.fix The fix object
* @param {Array<{text: string, range: (number[]|null)}>} options.suggestions The array of suggestions objects
- * @returns {function(...args): ReportInfo} Function that returns information about the report
+ * @returns {LintMessage} Information about the report
*/
function createProblem(options) {
const problem = {
* problem for the Node.js API.
* @param {{ruleId: string, severity: number, sourceCode: SourceCode, messageIds: Object, disableFixes: boolean}} metadata Metadata for the reported problem
* @param {SourceCode} sourceCode The `SourceCode` instance for the text being linted
- * @returns {function(...args): ReportInfo} Function that returns information about the report
+ * @returns {function(...args): LintMessage} Function that returns information about the report
*/
module.exports = function createReportTranslator(metadata) {
/**
* Creates the CLI options for ESLint.
* @param {boolean} usingFlatConfig Indicates if flat config is being used.
- * @returns {Object} The opinionator instance.
+ * @returns {Object} The optionator instance.
*/
module.exports = function(usingFlatConfig) {
};
}
+ let ignorePathFlag;
+
+ if (!usingFlatConfig) {
+ ignorePathFlag = {
+ option: "ignore-path",
+ type: "path::String",
+ description: "Specify path of ignore file"
+ };
+ }
+
return optionator({
prepend: "eslint [options] file.js [file.js] [dir]",
defaults: {
},
resolvePluginsFlag,
{
- heading: "Specifying rules and plugins"
+ heading: "Specify Rules and Plugins"
},
{
option: "plugin",
},
rulesDirFlag,
{
- heading: "Fixing problems"
+ heading: "Fix Problems"
},
{
option: "fix",
description: "Specify the types of fixes to apply (directive, problem, suggestion, layout)"
},
{
- heading: "Ignoring files"
- },
- {
- option: "ignore-path",
- type: "path::String",
- description: "Specify path of ignore file"
+ heading: "Ignore Files"
},
+ ignorePathFlag,
{
option: "ignore",
type: "Boolean",
}]
},
{
- heading: "Using stdin"
+ heading: "Use stdin"
},
{
option: "stdin",
description: "Specify filename to process STDIN as"
},
{
- heading: "Handling warnings"
+ heading: "Handle Warnings"
},
{
option: "quiet",
* @returns {void}
*/
static setDefaultConfig(config) {
- if (typeof config !== "object") {
+ if (typeof config !== "object" || config === null) {
throw new TypeError("FlatRuleTester.setDefaultConfig: config must be an object");
}
sharedDefaultConfig = config;
if (typeof this[DESCRIBE] === "function" || typeof this[IT] === "function") {
throw new Error(
"Set `RuleTester.itOnly` to use `only` with a custom test framework.\n" +
- "See https://eslint.org/docs/developer-guide/nodejs-api#customizing-ruletester for more."
+ "See https://eslint.org/docs/latest/integrate/nodejs-api#customizing-ruletester for more."
);
}
if (typeof it === "function") {
plugins: {
"rule-tester": {
rules: {
- "validate-ast"() {
- return {
- Program(node) {
- beforeAST = cloneDeeplyExcludesParent(node);
- },
- "Program:exit"(node) {
- afterAST = node;
- }
- };
+ "validate-ast": {
+ create() {
+ return {
+ Program(node) {
+ beforeAST = cloneDeeplyExcludesParent(node);
+ },
+ "Program:exit"(node) {
+ afterAST = node;
+ }
+ };
+ }
}
}
}
if (!emitLegacyRuleAPIWarning[`warned-${ruleName}`]) {
emitLegacyRuleAPIWarning[`warned-${ruleName}`] = true;
process.emitWarning(
- `"${ruleName}" rule is using the deprecated function-style format and will stop working in ESLint v9. Please use object-style format: https://eslint.org/docs/developer-guide/working-with-rules`,
+ `"${ruleName}" rule is using the deprecated function-style format and will stop working in ESLint v9. Please use object-style format: https://eslint.org/docs/latest/extend/custom-rules`,
"DeprecationWarning"
);
}
if (!emitMissingSchemaWarning[`warned-${ruleName}`]) {
emitMissingSchemaWarning[`warned-${ruleName}`] = true;
process.emitWarning(
- `"${ruleName}" rule has options but is missing the "meta.schema" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/developer-guide/working-with-rules#options-schemas`,
+ `"${ruleName}" rule has options but is missing the "meta.schema" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas`,
"DeprecationWarning"
);
}
* @returns {void}
*/
static setDefaultConfig(config) {
- if (typeof config !== "object") {
+ if (typeof config !== "object" || config === null) {
throw new TypeError("RuleTester.setDefaultConfig: config must be an object");
}
defaultConfig = config;
if (typeof this[DESCRIBE] === "function" || typeof this[IT] === "function") {
throw new Error(
"Set `RuleTester.itOnly` to use `only` with a custom test framework.\n" +
- "See https://eslint.org/docs/developer-guide/nodejs-api#customizing-ruletester for more."
+ "See https://eslint.org/docs/latest/integrate/nodejs-api#customizing-ruletester for more."
);
}
if (typeof it === "function") {
* The goal is to check whether or not AST was modified when
* running the rule under test.
*/
- linter.defineRule("rule-tester/validate-ast", () => ({
- Program(node) {
- beforeAST = cloneDeeplyExcludesParent(node);
- },
- "Program:exit"(node) {
- afterAST = node;
+ linter.defineRule("rule-tester/validate-ast", {
+ create() {
+ return {
+ Program(node) {
+ beforeAST = cloneDeeplyExcludesParent(node);
+ },
+ "Program:exit"(node) {
+ afterAST = node;
+ }
+ };
}
- }));
+ });
if (typeof config.parser === "string") {
assert(path.isAbsolute(config.parser), "Parsers provided as strings to RuleTester must be absolute paths");
docs: {
description: "Enforce getter and setter pairs in objects and classes",
recommended: false,
- url: "https://eslint.org/docs/rules/accessor-pairs"
+ url: "https://eslint.org/docs/latest/rules/accessor-pairs"
},
schema: [{
const checkGetWithoutSet = config.getWithoutSet === true;
const checkSetWithoutGet = config.setWithoutGet !== false;
const enforceForClassMembers = config.enforceForClassMembers !== false;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports the given node.
docs: {
description: "Enforce linebreaks after opening and before closing array brackets",
recommended: false,
- url: "https://eslint.org/docs/rules/array-bracket-newline"
+ url: "https://eslint.org/docs/latest/rules/array-bracket-newline"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//----------------------------------------------------------------------
docs: {
description: "Enforce consistent spacing inside array brackets",
recommended: false,
- url: "https://eslint.org/docs/rules/array-bracket-spacing"
+ url: "https://eslint.org/docs/latest/rules/array-bracket-spacing"
},
fixable: "whitespace",
},
create(context) {
const spaced = context.options[0] === "always",
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
/**
* Determines whether an option is set, relative to the spacing option.
//------------------------------------------------------------------------------
const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
-const TARGET_METHODS = /^(?:every|filter|find(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u;
+const TARGET_METHODS = /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort|toSorted)$/u;
/**
* Checks a given code path segment is reachable.
docs: {
description: "Enforce `return` statements in callbacks of array methods",
recommended: false,
- url: "https://eslint.org/docs/rules/array-callback-return"
+ url: "https://eslint.org/docs/latest/rules/array-callback-return"
},
schema: [
create(context) {
const options = context.options[0] || { allowImplicit: false, checkForEach: false };
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let funcInfo = {
arrayMethodName: null,
docs: {
description: "Enforce line breaks after each array element",
recommended: false,
- url: "https://eslint.org/docs/rules/array-element-newline"
+ url: "https://eslint.org/docs/latest/rules/array-element-newline"
},
fixable: "whitespace",
]
}
},
+ type: "array",
items: [
{
oneOf: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//----------------------------------------------------------------------
// Helpers
docs: {
description: "Require braces around arrow function bodies",
recommended: false,
- url: "https://eslint.org/docs/rules/arrow-body-style"
+ url: "https://eslint.org/docs/latest/rules/arrow-body-style"
},
schema: {
const asNeeded = !options[0] || options[0] === "as-needed";
const never = options[0] === "never";
const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let funcInfo = null;
/**
docs: {
description: "Require parentheses around arrow function arguments",
recommended: false,
- url: "https://eslint.org/docs/rules/arrow-parens"
+ url: "https://eslint.org/docs/latest/rules/arrow-parens"
},
fixable: "code",
const asNeeded = context.options[0] === "as-needed";
const requireForBlockBody = asNeeded && context.options[1] && context.options[1].requireForBlockBody === true;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Finds opening paren of parameters for the given arrow function, if it exists.
docs: {
description: "Enforce consistent spacing before and after the arrow in arrow functions",
recommended: false,
- url: "https://eslint.org/docs/rules/arrow-spacing"
+ url: "https://eslint.org/docs/latest/rules/arrow-spacing"
},
fixable: "whitespace",
rule.before = rule.before !== false;
rule.after = rule.after !== false;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Get tokens of arrow(`=>`) and before/after arrow.
docs: {
description: "Enforce the use of variables within the scope they are defined",
recommended: false,
- url: "https://eslint.org/docs/rules/block-scoped-var"
+ url: "https://eslint.org/docs/latest/rules/block-scoped-var"
},
schema: [],
create(context) {
let stack = [];
+ const sourceCode = context.sourceCode;
/**
* Makes a block scope.
}
// Gets declared variables, and checks its references.
- const variables = context.getDeclaredVariables(node);
+ const variables = sourceCode.getDeclaredVariables(node);
for (let i = 0; i < variables.length; ++i) {
docs: {
description: "Disallow or enforce spaces inside of blocks after opening block and before closing block",
recommended: false,
- url: "https://eslint.org/docs/rules/block-spacing"
+ url: "https://eslint.org/docs/latest/rules/block-spacing"
},
fixable: "whitespace",
create(context) {
const always = (context.options[0] !== "never"),
messageId = always ? "missing" : "extra",
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
/**
* Gets the open brace token from a given node.
docs: {
description: "Enforce consistent brace style for blocks",
recommended: false,
- url: "https://eslint.org/docs/rules/brace-style"
+ url: "https://eslint.org/docs/latest/rules/brace-style"
},
schema: [
create(context) {
const style = context.options[0] || "1tbs",
params = context.options[1] || {},
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Require `return` statements after callbacks",
recommended: false,
- url: "https://eslint.org/docs/rules/callback-return"
+ url: "https://eslint.org/docs/latest/rules/callback-return"
},
schema: [{
create(context) {
const callbacks = context.options[0] || ["callback", "cb", "next"],
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Enforce camelcase naming convention",
recommended: false,
- url: "https://eslint.org/docs/rules/camelcase"
+ url: "https://eslint.org/docs/latest/rules/camelcase"
},
schema: [
const ignoreImports = options.ignoreImports;
const ignoreGlobals = options.ignoreGlobals;
const allow = options.allow || [];
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
return {
// Report camelcase of global variable references ------------------
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
if (!ignoreGlobals) {
"ClassExpression",
"CatchClause"
]](node) {
- for (const variable of context.getDeclaredVariables(node)) {
+ for (const variable of sourceCode.getDeclaredVariables(node)) {
if (isGoodName(variable.name)) {
continue;
}
// Report camelcase in import --------------------------------------
ImportDeclaration(node) {
- for (const variable of context.getDeclaredVariables(node)) {
+ for (const variable of sourceCode.getDeclaredVariables(node)) {
if (isGoodName(variable.name)) {
continue;
}
docs: {
description: "Enforce or disallow capitalization of the first letter of a comment",
recommended: false,
- url: "https://eslint.org/docs/rules/capitalized-comments"
+ url: "https://eslint.org/docs/latest/rules/capitalized-comments"
},
fixable: "code",
const capitalize = context.options[0] || "always",
normalizedOptions = getAllNormalizedOptions(context.options[1]),
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
createRegExpForIgnorePatterns(normalizedOptions);
docs: {
description: "Enforce that class methods utilize `this`",
recommended: false,
- url: "https://eslint.org/docs/rules/class-methods-use-this"
+ url: "https://eslint.org/docs/latest/rules/class-methods-use-this"
},
schema: [{
if (isIncludedInstanceMethod(node.parent) && !methodUsesThis) {
context.report({
node,
- loc: astUtils.getFunctionHeadLoc(node, context.getSourceCode()),
+ loc: astUtils.getFunctionHeadLoc(node, context.sourceCode),
messageId: "missingThis",
data: {
name: astUtils.getFunctionNameWithKind(node)
objects: optionValue,
imports: optionValue,
exports: optionValue,
- functions: (!ecmaVersion || ecmaVersion < 8) ? "ignore" : optionValue
+ functions: ecmaVersion < 2017 ? "ignore" : optionValue
};
}
if (typeof optionValue === "object" && optionValue !== null) {
docs: {
description: "Require or disallow trailing commas",
recommended: false,
- url: "https://eslint.org/docs/rules/comma-dangle"
+ url: "https://eslint.org/docs/latest/rules/comma-dangle"
},
fixable: "code",
},
create(context) {
- const options = normalizeOptions(context.options[0], context.parserOptions.ecmaVersion);
+ const options = normalizeOptions(context.options[0], context.languageOptions.ecmaVersion);
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Gets the last item of the given node.
"always-multiline": forceTrailingCommaIfMultiline,
"only-multiline": allowTrailingCommaIfMultiline,
never: forbidTrailingComma,
- ignore: () => {}
+ ignore() {}
};
return {
docs: {
description: "Enforce consistent spacing before and after commas",
recommended: false,
- url: "https://eslint.org/docs/rules/comma-spacing"
+ url: "https://eslint.org/docs/latest/rules/comma-spacing"
},
fixable: "whitespace",
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const tokensAndComments = sourceCode.tokensAndComments;
const options = {
docs: {
description: "Enforce consistent comma style",
recommended: false,
- url: "https://eslint.org/docs/rules/comma-style"
+ url: "https://eslint.org/docs/latest/rules/comma-style"
},
fixable: "code",
create(context) {
const style = context.options[0] || "last",
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
const exceptions = {
ArrayPattern: true,
ArrowFunctionExpression: true,
docs: {
description: "Enforce a maximum cyclomatic complexity allowed in a program",
recommended: false,
- url: "https://eslint.org/docs/rules/complexity"
+ url: "https://eslint.org/docs/latest/rules/complexity"
},
schema: [
docs: {
description: "Enforce consistent spacing inside computed property brackets",
recommended: false,
- url: "https://eslint.org/docs/rules/computed-property-spacing"
+ url: "https://eslint.org/docs/latest/rules/computed-property-spacing"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
const enforceForClassMembers = !context.options[1] || context.options[1].enforceForClassMembers;
docs: {
description: "Require `return` statements to either always or never specify values",
recommended: false,
- url: "https://eslint.org/docs/rules/consistent-return"
+ url: "https://eslint.org/docs/latest/rules/consistent-return"
},
schema: [{
} else if (node.type === "ArrowFunctionExpression") {
// `=>` token
- loc = context.getSourceCode().getTokenBefore(node.body, astUtils.isArrowToken).loc;
+ loc = context.sourceCode.getTokenBefore(node.body, astUtils.isArrowToken).loc;
} else if (
node.parent.type === "MethodDefinition" ||
(node.parent.type === "Property" && node.parent.method)
} else {
// Function name or `function` keyword.
- loc = (node.id || context.getSourceCode().getFirstToken(node)).loc;
+ loc = (node.id || context.sourceCode.getFirstToken(node)).loc;
}
if (!name) {
docs: {
description: "Enforce consistent naming when capturing the current execution context",
recommended: false,
- url: "https://eslint.org/docs/rules/consistent-this"
+ url: "https://eslint.org/docs/latest/rules/consistent-this"
},
schema: {
create(context) {
let aliases = [];
+ const sourceCode = context.sourceCode;
if (context.options.length === 0) {
aliases.push("that");
/**
* Check each alias to ensure that is was assigned to the correct value.
+ * @param {ASTNode} node The node that represents the scope to check.
* @returns {void}
*/
- function ensureWasAssigned() {
- const scope = context.getScope();
+ function ensureWasAssigned(node) {
+ const scope = sourceCode.getScope(node);
aliases.forEach(alias => {
checkWasAssigned(alias, scope);
docs: {
description: "Require `super()` calls in constructors",
recommended: true,
- url: "https://eslint.org/docs/rules/constructor-super"
+ url: "https://eslint.org/docs/latest/rules/constructor-super"
},
schema: [],
docs: {
description: "Enforce consistent brace style for all control statements",
recommended: false,
- url: "https://eslint.org/docs/rules/curly"
+ url: "https://eslint.org/docs/latest/rules/curly"
},
schema: {
const multiOrNest = (context.options[0] === "multi-or-nest");
const consistent = (context.options[1] === "consistent");
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Enforce default clauses in switch statements to be last",
recommended: false,
- url: "https://eslint.org/docs/rules/default-case-last"
+ url: "https://eslint.org/docs/latest/rules/default-case-last"
},
schema: [],
docs: {
description: "Require `default` cases in `switch` statements",
recommended: false,
- url: "https://eslint.org/docs/rules/default-case"
+ url: "https://eslint.org/docs/latest/rules/default-case"
},
schema: [{
? new RegExp(options.commentPattern, "u")
: DEFAULT_COMMENT_PATTERN;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Enforce default parameters to be last",
recommended: false,
- url: "https://eslint.org/docs/rules/default-param-last"
+ url: "https://eslint.org/docs/latest/rules/default-param-last"
},
schema: [],
docs: {
description: "Enforce consistent newlines before and after dots",
recommended: false,
- url: "https://eslint.org/docs/rules/dot-location"
+ url: "https://eslint.org/docs/latest/rules/dot-location"
},
schema: [
// default to onObject if no preference is passed
const onObject = config === "object" || !config;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports if the dot between object and property is on the correct location.
docs: {
description: "Enforce dot notation whenever possible",
recommended: false,
- url: "https://eslint.org/docs/rules/dot-notation"
+ url: "https://eslint.org/docs/latest/rules/dot-notation"
},
schema: [
create(context) {
const options = context.options[0] || {};
const allowKeywords = options.allowKeywords === void 0 || options.allowKeywords;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let allowPattern;
docs: {
description: "Require or disallow newline at the end of files",
recommended: false,
- url: "https://eslint.org/docs/rules/eol-last"
+ url: "https://eslint.org/docs/latest/rules/eol-last"
},
fixable: "whitespace",
return {
Program: function checkBadEOF(node) {
- const sourceCode = context.getSourceCode(),
+ const sourceCode = context.sourceCode,
src = sourceCode.getText(),
lastLine = sourceCode.lines[sourceCode.lines.length - 1],
location = {
docs: {
description: "Require the use of `===` and `!==`",
recommended: false,
- url: "https://eslint.org/docs/rules/eqeqeq"
+ url: "https://eslint.org/docs/latest/rules/eqeqeq"
},
schema: {
create(context) {
const config = context.options[0] || "always";
const options = context.options[1] || {};
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const nullOption = (config === "always")
? options.null || "always"
type: "problem",
docs: {
- description: "Enforce \"for\" loop update clause moving the counter in the right direction.",
+ description: "Enforce \"for\" loop update clause moving the counter in the right direction",
recommended: true,
- url: "https://eslint.org/docs/rules/for-direction"
+ url: "https://eslint.org/docs/latest/rules/for-direction"
},
fixable: null,
docs: {
description: "Require or disallow spacing between function identifiers and their invocations",
recommended: false,
- url: "https://eslint.org/docs/rules/func-call-spacing"
+ url: "https://eslint.org/docs/latest/rules/func-call-spacing"
},
fixable: "whitespace",
const never = context.options[0] !== "always";
const allowNewlines = !never && context.options[1] && context.options[1].allowNewlines;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const text = sourceCode.getText();
/**
* @returns {boolean} True if the string is a valid identifier
*/
function isIdentifier(name, ecmaVersion) {
- if (ecmaVersion >= 6) {
+ if (ecmaVersion >= 2015) {
return esutils.keyword.isIdentifierES6(name);
}
return esutils.keyword.isIdentifierES5(name);
docs: {
description: "Require function names to match the name of the variable or property to which they are assigned",
recommended: false,
- url: "https://eslint.org/docs/rules/func-name-matching"
+ url: "https://eslint.org/docs/latest/rules/func-name-matching"
},
schema: {
const nameMatches = typeof context.options[0] === "string" ? context.options[0] : "always";
const considerPropertyDescriptor = options.considerPropertyDescriptor;
const includeModuleExports = options.includeCommonJSModuleExports;
- const ecmaVersion = context.parserOptions && context.parserOptions.ecmaVersion ? context.parserOptions.ecmaVersion : 5;
+ const ecmaVersion = context.languageOptions.ecmaVersion;
/**
* Check whether node is a certain CallExpression.
docs: {
description: "Require or disallow named `function` expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/func-names"
+ url: "https://eslint.org/docs/latest/rules/func-names"
},
schema: {
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Returns the config option for the given node.
function handleFunction(node) {
// Skip recursive functions.
- const nameVar = context.getDeclaredVariables(node)[0];
+ const nameVar = sourceCode.getDeclaredVariables(node)[0];
if (isFunctionName(nameVar) && nameVar.references.length > 0) {
return;
docs: {
description: "Enforce the consistent use of either `function` declarations or expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/func-style"
+ url: "https://eslint.org/docs/latest/rules/func-style"
},
schema: [
docs: {
description: "Enforce line breaks between arguments of a function call",
recommended: false,
- url: "https://eslint.org/docs/rules/function-call-argument-newline"
+ url: "https://eslint.org/docs/latest/rules/function-call-argument-newline"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const checkers = {
unexpected: {
docs: {
description: "Enforce consistent line breaks inside function parentheses",
recommended: false,
- url: "https://eslint.org/docs/rules/function-paren-newline"
+ url: "https://eslint.org/docs/latest/rules/function-paren-newline"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const rawOption = context.options[0] || "multiline";
const multilineOption = rawOption === "multiline";
const multilineArgumentsOption = rawOption === "multiline-arguments";
docs: {
description: "Enforce consistent spacing around `*` operators in generator functions",
recommended: false,
- url: "https://eslint.org/docs/rules/generator-star-spacing"
+ url: "https://eslint.org/docs/latest/rules/generator-star-spacing"
},
fixable: "whitespace",
};
}(context.options[0] || {}));
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Checks if the given token is a star token or not.
docs: {
description: "Enforce `return` statements in getters",
recommended: true,
- url: "https://eslint.org/docs/rules/getter-return"
+ url: "https://eslint.org/docs/latest/rules/getter-return"
},
fixable: null,
create(context) {
const options = context.options[0] || { allowImplicit: false };
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let funcInfo = {
upper: null,
}
if (parent.type === "Property" && astUtils.getStaticPropertyName(parent) === "get" && parent.parent.type === "ObjectExpression") {
- // Object.defineProperty()
- if (parent.parent.parent.type === "CallExpression" &&
- astUtils.getStaticPropertyName(parent.parent.parent.callee) === "defineProperty") {
- return true;
+ // Object.defineProperty() or Reflect.defineProperty()
+ if (parent.parent.parent.type === "CallExpression") {
+ const callNode = parent.parent.parent.callee;
+
+ if (astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperty") ||
+ astUtils.isSpecificMemberAccess(callNode, "Reflect", "defineProperty")) {
+ return true;
+ }
}
- // Object.defineProperties()
+ // Object.defineProperties() or Object.create()
if (parent.parent.parent.type === "Property" &&
parent.parent.parent.parent.type === "ObjectExpression" &&
- parent.parent.parent.parent.parent.type === "CallExpression" &&
- astUtils.getStaticPropertyName(parent.parent.parent.parent.parent.callee) === "defineProperties") {
- return true;
+ parent.parent.parent.parent.parent.type === "CallExpression") {
+ const callNode = parent.parent.parent.parent.parent.callee;
+
+ return astUtils.isSpecificMemberAccess(callNode, "Object", "defineProperties") ||
+ astUtils.isSpecificMemberAccess(callNode, "Object", "create");
}
}
}
docs: {
description: "Require `require()` calls to be placed at top-level module scope",
recommended: false,
- url: "https://eslint.org/docs/rules/global-require"
+ url: "https://eslint.org/docs/latest/rules/global-require"
},
schema: [],
},
create(context) {
+ const sourceCode = context.sourceCode;
+
return {
CallExpression(node) {
- const currentScope = context.getScope();
+ const currentScope = sourceCode.getScope(node);
if (node.callee.name === "require" && !isShadowed(currentScope, node.callee)) {
- const isGoodRequire = context.getAncestors().every(parent => ACCEPTABLE_PARENTS.has(parent.type));
+ const isGoodRequire = sourceCode.getAncestors(node).every(parent => ACCEPTABLE_PARENTS.has(parent.type));
if (!isGoodRequire) {
context.report({ node, messageId: "unexpected" });
docs: {
description: "Require grouped accessor pairs in object literals and classes",
recommended: false,
- url: "https://eslint.org/docs/rules/grouped-accessor-pairs"
+ url: "https://eslint.org/docs/latest/rules/grouped-accessor-pairs"
},
schema: [
create(context) {
const order = context.options[0] || "anyOrder";
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports the given accessor pair.
docs: {
description: "Require `for-in` loops to include an `if` statement",
recommended: false,
- url: "https://eslint.org/docs/rules/guard-for-in"
+ url: "https://eslint.org/docs/latest/rules/guard-for-in"
},
schema: [],
docs: {
description: "Require error handling in callbacks",
recommended: false,
- url: "https://eslint.org/docs/rules/handle-callback-err"
+ url: "https://eslint.org/docs/latest/rules/handle-callback-err"
},
schema: [
create(context) {
const errorArgument = context.options[0] || "err";
+ const sourceCode = context.sourceCode;
/**
* Checks if the given argument should be interpreted as a regexp pattern.
* @returns {void}
*/
function checkForError(node) {
- const scope = context.getScope(),
+ const scope = sourceCode.getScope(node),
parameters = getParameters(scope),
firstParameter = parameters[0];
docs: {
description: "Disallow specified identifiers",
recommended: false,
- url: "https://eslint.org/docs/rules/id-blacklist"
+ url: "https://eslint.org/docs/latest/rules/id-blacklist"
},
schema: {
const denyList = new Set(context.options);
const reportedNodes = new Set();
+ const sourceCode = context.sourceCode;
let globalScope;
return {
- Program() {
- globalScope = context.getScope();
+ Program(node) {
+ globalScope = sourceCode.getScope(node);
},
Identifier(node) {
docs: {
description: "Disallow specified identifiers",
recommended: false,
- url: "https://eslint.org/docs/rules/id-denylist"
+ url: "https://eslint.org/docs/latest/rules/id-denylist"
},
schema: {
const denyList = new Set(context.options);
const reportedNodes = new Set();
+ const sourceCode = context.sourceCode;
let globalScope;
return {
- Program() {
- globalScope = context.getScope();
+ Program(node) {
+ globalScope = sourceCode.getScope(node);
},
[[
"use strict";
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const { getGraphemeCount } = require("../shared/string-utils");
+
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
docs: {
description: "Enforce minimum and maximum identifier lengths",
recommended: false,
- url: "https://eslint.org/docs/rules/id-length"
+ url: "https://eslint.org/docs/latest/rules/id-length"
},
schema: [
const name = node.name;
const parent = node.parent;
- const isShort = name.length < minLength;
- const isLong = name.length > maxLength;
+ const nameLength = getGraphemeCount(name);
+
+ const isShort = nameLength < minLength;
+ const isLong = nameLength > maxLength;
if (!(isShort || isLong) || exceptions.has(name) || matchesExceptionPattern(name)) {
return; // Nothing to report
docs: {
description: "Require identifiers to match a specified regular expression",
recommended: false,
- url: "https://eslint.org/docs/rules/id-match"
+ url: "https://eslint.org/docs/latest/rules/id-match"
},
schema: [
onlyDeclarations = !!options.onlyDeclarations,
ignoreDestructuring = !!options.ignoreDestructuring;
+ const sourceCode = context.sourceCode;
let globalScope;
//--------------------------------------------------------------------------
return {
- Program() {
- globalScope = context.getScope();
+ Program(node) {
+ globalScope = sourceCode.getScope(node);
},
Identifier(node) {
docs: {
description: "Enforce the location of arrow function bodies",
recommended: false,
- url: "https://eslint.org/docs/rules/implicit-arrow-linebreak"
+ url: "https://eslint.org/docs/latest/rules/implicit-arrow-linebreak"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const option = context.options[0] || "beside";
/**
docs: {
description: "Enforce consistent indentation",
recommended: false,
- url: "https://eslint.org/docs/rules/indent-legacy"
+ url: "https://eslint.org/docs/latest/rules/indent-legacy"
},
deprecated: true,
ObjectExpression: 1
};
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
if (context.options.length) {
if (context.options[0] === "tab") {
// Requirements
//------------------------------------------------------------------------------
-const { OrderedMap } = require("js-sdsl");
-
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
/**
- * A mutable balanced binary search tree that stores (key, value) pairs. The keys are numeric, and must be unique.
- * This is intended to be a generic wrapper around a balanced binary search tree library, so that the underlying implementation
+ * A mutable map that stores (key, value) pairs. The keys are numeric indices, and must be unique.
+ * This is intended to be a generic wrapper around a map with non-negative integer keys, so that the underlying implementation
* can easily be swapped out.
*/
-class BinarySearchTree {
+class IndexMap {
/**
- * Creates an empty tree
+ * Creates an empty map
+ * @param {number} maxKey The maximum key
*/
- constructor() {
- this._orderedMap = new OrderedMap();
- this._orderedMapEnd = this._orderedMap.end();
+ constructor(maxKey) {
+
+ // Initializing the array with the maximum expected size avoids dynamic reallocations that could degrade performance.
+ this._values = Array(maxKey + 1);
}
/**
- * Inserts an entry into the tree.
+ * Inserts an entry into the map.
* @param {number} key The entry's key
* @param {any} value The entry's value
* @returns {void}
*/
insert(key, value) {
- this._orderedMap.setElement(key, value);
+ this._values[key] = value;
}
/**
- * Finds the entry with the largest key less than or equal to the provided key
+ * Finds the value of the entry with the largest key less than or equal to the provided key
* @param {number} key The provided key
- * @returns {{key: number, value: *}|null} The found entry, or null if no such entry exists.
+ * @returns {*|undefined} The value of the found entry, or undefined if no such entry exists.
*/
- findLe(key) {
- const iterator = this._orderedMap.reverseLowerBound(key);
+ findLastNotAfter(key) {
+ const values = this._values;
- if (iterator.equals(this._orderedMapEnd)) {
- return {};
- }
+ for (let index = key; index >= 0; index--) {
+ const value = values[index];
- return { key: iterator.pointer[0], value: iterator.pointer[1] };
+ if (value) {
+ return value;
+ }
+ }
+ return void 0;
}
/**
* @returns {void}
*/
deleteRange(start, end) {
-
- // Exit without traversing the tree if the range has zero size.
- if (start === end) {
- return;
- }
- const iterator = this._orderedMap.lowerBound(start);
-
- if (iterator.equals(this._orderedMapEnd)) {
- return;
- }
-
- if (end > this._orderedMap.back()[0]) {
- while (!iterator.equals(this._orderedMapEnd)) {
- this._orderedMap.eraseElementByIterator(iterator);
- }
- } else {
- while (iterator.pointer[0] < end) {
- this._orderedMap.eraseElementByIterator(iterator);
- }
- }
+ this._values.fill(void 0, start, end);
}
}
* @param {TokenInfo} tokenInfo a TokenInfo instance
* @param {number} indentSize The desired size of each indentation level
* @param {string} indentType The indentation character
+ * @param {number} maxIndex The maximum end index of any token
*/
- constructor(tokenInfo, indentSize, indentType) {
+ constructor(tokenInfo, indentSize, indentType, maxIndex) {
this._tokenInfo = tokenInfo;
this._indentSize = indentSize;
this._indentType = indentType;
- this._tree = new BinarySearchTree();
- this._tree.insert(0, { offset: 0, from: null, force: false });
+ this._indexMap = new IndexMap(maxIndex);
+ this._indexMap.insert(0, { offset: 0, from: null, force: false });
this._lockedFirstTokens = new WeakMap();
this._desiredIndentCache = new WeakMap();
}
_getOffsetDescriptor(token) {
- return this._tree.findLe(token.range[0]).value;
+ return this._indexMap.findLastNotAfter(token.range[0]);
}
/**
* * key: 820, value: { offset: 1, from: bazToken }
*
* To find the offset descriptor for any given token, one needs to find the node with the largest key
- * which is <= token.start. To make this operation fast, the nodes are stored in a balanced binary
- * search tree indexed by key.
+ * which is <= token.start. To make this operation fast, the nodes are stored in a map indexed by key.
*/
const descriptorToInsert = { offset, from: fromToken, force };
- const descriptorAfterRange = this._tree.findLe(range[1]).value;
+ const descriptorAfterRange = this._indexMap.findLastNotAfter(range[1]);
const fromTokenIsInRange = fromToken && fromToken.range[0] >= range[0] && fromToken.range[1] <= range[1];
const fromTokenDescriptor = fromTokenIsInRange && this._getOffsetDescriptor(fromToken);
- // First, remove any existing nodes in the range from the tree.
- this._tree.deleteRange(range[0] + 1, range[1]);
+ // First, remove any existing nodes in the range from the map.
+ this._indexMap.deleteRange(range[0] + 1, range[1]);
- // Insert a new node into the tree for this range
- this._tree.insert(range[0], descriptorToInsert);
+ // Insert a new node into the map for this range
+ this._indexMap.insert(range[0], descriptorToInsert);
/*
* To avoid circular offset dependencies, keep the `fromToken` token mapped to whatever it was mapped to previously,
* even if it's in the current range.
*/
if (fromTokenIsInRange) {
- this._tree.insert(fromToken.range[0], fromTokenDescriptor);
- this._tree.insert(fromToken.range[1], descriptorToInsert);
+ this._indexMap.insert(fromToken.range[0], fromTokenDescriptor);
+ this._indexMap.insert(fromToken.range[1], descriptorToInsert);
}
/*
* To avoid modifying the offset of tokens after the range, insert another node to keep the offset of the following
* tokens the same as it was before.
*/
- this._tree.insert(range[1], descriptorAfterRange);
+ this._indexMap.insert(range[1], descriptorAfterRange);
}
/**
docs: {
description: "Enforce consistent indentation",
recommended: false,
- url: "https://eslint.org/docs/rules/indent"
+ url: "https://eslint.org/docs/latest/rules/indent"
},
fixable: "whitespace",
}
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const tokenInfo = new TokenInfo(sourceCode);
- const offsets = new OffsetStorage(tokenInfo, indentSize, indentType === "space" ? " " : "\t");
+ const offsets = new OffsetStorage(tokenInfo, indentSize, indentType === "space" ? " " : "\t", sourceCode.text.length);
const parameterParens = new WeakSet();
/**
"lines-around-comment": () => require("./lines-around-comment"),
"lines-around-directive": () => require("./lines-around-directive"),
"lines-between-class-members": () => require("./lines-between-class-members"),
+ "logical-assignment-operators": () => require("./logical-assignment-operators"),
"max-classes-per-file": () => require("./max-classes-per-file"),
"max-depth": () => require("./max-depth"),
"max-len": () => require("./max-len"),
"no-empty-character-class": () => require("./no-empty-character-class"),
"no-empty-function": () => require("./no-empty-function"),
"no-empty-pattern": () => require("./no-empty-pattern"),
+ "no-empty-static-block": () => require("./no-empty-static-block"),
"no-eq-null": () => require("./no-eq-null"),
"no-eval": () => require("./no-eval"),
"no-ex-assign": () => require("./no-ex-assign"),
"no-nested-ternary": () => require("./no-nested-ternary"),
"no-new": () => require("./no-new"),
"no-new-func": () => require("./no-new-func"),
+ "no-new-native-nonconstructor": () => require("./no-new-native-nonconstructor"),
"no-new-object": () => require("./no-new-object"),
"no-new-require": () => require("./no-new-require"),
"no-new-symbol": () => require("./no-new-symbol"),
docs: {
description: "Require or disallow initialization in variable declarations",
recommended: false,
- url: "https://eslint.org/docs/rules/init-declarations"
+ url: "https://eslint.org/docs/latest/rules/init-declarations"
},
schema: {
docs: {
description: "Enforce the consistent use of either double or single quotes in JSX attributes",
recommended: false,
- url: "https://eslint.org/docs/rules/jsx-quotes"
+ url: "https://eslint.org/docs/latest/rules/jsx-quotes"
},
fixable: "whitespace",
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const GraphemeSplitter = require("grapheme-splitter");
-
-const splitter = new GraphemeSplitter();
-
-//------------------------------------------------------------------------------
-// Helpers
-//------------------------------------------------------------------------------
+const { getGraphemeCount } = require("../shared/string-utils");
/**
* Checks whether a string contains a line terminator as defined in
docs: {
description: "Enforce consistent spacing between keys and values in object literal properties",
recommended: false,
- url: "https://eslint.org/docs/rules/key-spacing"
+ url: "https://eslint.org/docs/latest/rules/key-spacing"
},
fixable: "whitespace",
singleLineOptions = ruleOptions.singleLine,
alignmentOptions = ruleOptions.align || null;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
+
+ /**
+ * Determines if the given property is key-value property.
+ * @param {ASTNode} property Property node to check.
+ * @returns {boolean} Whether the property is a key-value property.
+ */
+ function isKeyValueProperty(property) {
+ return !(
+ (property.method ||
+ property.shorthand ||
+ property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadElement"
+ );
+ }
+
+ /**
+ * Starting from the given node (a property.key node here) looks forward
+ * until it finds the colon punctuator and returns it.
+ * @param {ASTNode} node The node to start looking from.
+ * @returns {ASTNode} The colon punctuator.
+ */
+ function getNextColon(node) {
+ return sourceCode.getTokenAfter(node, astUtils.isColonToken);
+ }
+
+ /**
+ * Starting from the given node (a property.key node here) looks forward
+ * until it finds the last token before a colon punctuator and returns it.
+ * @param {ASTNode} node The node to start looking from.
+ * @returns {ASTNode} The last token before a colon punctuator.
+ */
+ function getLastTokenBeforeColon(node) {
+ const colonToken = getNextColon(node);
+
+ return sourceCode.getTokenBefore(colonToken);
+ }
+
+ /**
+ * Starting from the given node (a property.key node here) looks forward
+ * until it finds the first token after a colon punctuator and returns it.
+ * @param {ASTNode} node The node to start looking from.
+ * @returns {ASTNode} The first token after a colon punctuator.
+ */
+ function getFirstTokenAfterColon(node) {
+ const colonToken = getNextColon(node);
+
+ return sourceCode.getTokenAfter(colonToken);
+ }
/**
* Checks whether a property is a member of the property group it follows.
*/
function continuesPropertyGroup(lastMember, candidate) {
const groupEndLine = lastMember.loc.start.line,
- candidateStartLine = candidate.loc.start.line;
+ candidateValueStartLine = (isKeyValueProperty(candidate) ? getFirstTokenAfterColon(candidate.key) : candidate).loc.start.line;
- if (candidateStartLine - groupEndLine <= 1) {
+ if (candidateValueStartLine - groupEndLine <= 1) {
return true;
}
if (
leadingComments.length &&
leadingComments[0].loc.start.line - groupEndLine <= 1 &&
- candidateStartLine - last(leadingComments).loc.end.line <= 1
+ candidateValueStartLine - last(leadingComments).loc.end.line <= 1
) {
for (let i = 1; i < leadingComments.length; i++) {
if (leadingComments[i].loc.start.line - leadingComments[i - 1].loc.end.line > 1) {
return false;
}
- /**
- * Determines if the given property is key-value property.
- * @param {ASTNode} property Property node to check.
- * @returns {boolean} Whether the property is a key-value property.
- */
- function isKeyValueProperty(property) {
- return !(
- (property.method ||
- property.shorthand ||
- property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadElement"
- );
- }
-
- /**
- * Starting from the given a node (a property.key node here) looks forward
- * until it finds the last token before a colon punctuator and returns it.
- * @param {ASTNode} node The node to start looking from.
- * @returns {ASTNode} The last token before a colon punctuator.
- */
- function getLastTokenBeforeColon(node) {
- const colonToken = sourceCode.getTokenAfter(node, astUtils.isColonToken);
-
- return sourceCode.getTokenBefore(colonToken);
- }
-
- /**
- * Starting from the given a node (a property.key node here) looks forward
- * until it finds the colon punctuator and returns it.
- * @param {ASTNode} node The node to start looking from.
- * @returns {ASTNode} The colon punctuator.
- */
- function getNextColon(node) {
- return sourceCode.getTokenAfter(node, astUtils.isColonToken);
- }
-
/**
* Gets an object literal property's key as the identifier name or string value.
* @param {ASTNode} property Property node whose key to retrieve.
const startToken = sourceCode.getFirstToken(property);
const endToken = getLastTokenBeforeColon(property.key);
- return splitter.countGraphemes(sourceCode.getText().slice(startToken.range[0], endToken.range[1]));
+ return getGraphemeCount(sourceCode.getText().slice(startToken.range[0], endToken.range[1]));
}
/**
docs: {
description: "Enforce consistent spacing before and after keywords",
recommended: false,
- url: "https://eslint.org/docs/rules/keyword-spacing"
+ url: "https://eslint.org/docs/latest/rules/keyword-spacing"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const tokensToIgnore = new WeakSet();
docs: {
description: "Enforce position of line comments",
recommended: false,
- url: "https://eslint.org/docs/rules/line-comment-position"
+ url: "https://eslint.org/docs/latest/rules/line-comment-position"
},
schema: [
const defaultIgnoreRegExp = astUtils.COMMENTS_IGNORE_PATTERN;
const fallThroughRegExp = /^\s*falls?\s?through/u;
const customIgnoreRegExp = new RegExp(ignorePattern, "u");
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Public
docs: {
description: "Enforce consistent linebreak style",
recommended: false,
- url: "https://eslint.org/docs/rules/linebreak-style"
+ url: "https://eslint.org/docs/latest/rules/linebreak-style"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
/**
- * Return an array with with any line numbers that are empty.
+ * Return an array with any line numbers that are empty.
* @param {Array} lines An array of each line of the file.
* @returns {Array} An array of line numbers.
*/
}
/**
- * Return an array with with any line numbers that contain comments.
+ * Return an array with any line numbers that contain comments.
* @param {Array} comments An array of comment tokens.
* @returns {Array} An array of line numbers.
*/
docs: {
description: "Require empty lines around comments",
recommended: false,
- url: "https://eslint.org/docs/rules/lines-around-comment"
+ url: "https://eslint.org/docs/latest/rules/lines-around-comment"
},
fixable: "whitespace",
},
applyDefaultIgnorePatterns: {
type: "boolean"
+ },
+ afterHashbangComment: {
+ type: "boolean",
+ default: false
}
},
additionalProperties: false
options.beforeBlockComment = typeof options.beforeBlockComment !== "undefined" ? options.beforeBlockComment : true;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const lines = sourceCode.lines,
numLines = lines.length + 1,
before: options.beforeBlockComment
});
}
+ } else if (token.type === "Shebang") {
+ if (options.afterHashbangComment) {
+ checkForEmptyLine(token, {
+ after: options.afterHashbangComment,
+ before: false
+ });
+ }
}
});
}
docs: {
description: "Require or disallow newlines around directives",
recommended: false,
- url: "https://eslint.org/docs/rules/lines-around-directive"
+ url: "https://eslint.org/docs/latest/rules/lines-around-directive"
},
schema: [{
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const config = context.options[0] || "always";
const expectLineBefore = typeof config === "string" ? config : config.before;
const expectLineAfter = typeof config === "string" ? config : config.after;
docs: {
description: "Require or disallow an empty line between class members",
recommended: false,
- url: "https://eslint.org/docs/rules/lines-between-class-members"
+ url: "https://eslint.org/docs/latest/rules/lines-between-class-members"
},
fixable: "whitespace",
options[0] = context.options[0] || "always";
options[1] = context.options[1] || { exceptAfterSingleLine: false };
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Gets a pair of tokens that should be used to check lines between two class member nodes.
--- /dev/null
+/**
+ * @fileoverview Rule to replace assignment expressions with logical operator assignment
+ * @author Daniel Martens
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+const astUtils = require("./utils/ast-utils.js");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const baseTypes = new Set(["Identifier", "Super", "ThisExpression"]);
+
+/**
+ * Returns true iff either "undefined" or a void expression (eg. "void 0")
+ * @param {ASTNode} expression Expression to check
+ * @param {import('eslint-scope').Scope} scope Scope of the expression
+ * @returns {boolean} True iff "undefined" or "void ..."
+ */
+function isUndefined(expression, scope) {
+ if (expression.type === "Identifier" && expression.name === "undefined") {
+ return astUtils.isReferenceToGlobalVariable(scope, expression);
+ }
+
+ return expression.type === "UnaryExpression" &&
+ expression.operator === "void" &&
+ expression.argument.type === "Literal" &&
+ expression.argument.value === 0;
+}
+
+/**
+ * Returns true iff the reference is either an identifier or member expression
+ * @param {ASTNode} expression Expression to check
+ * @returns {boolean} True for identifiers and member expressions
+ */
+function isReference(expression) {
+ return (expression.type === "Identifier" && expression.name !== "undefined") ||
+ expression.type === "MemberExpression";
+}
+
+/**
+ * Returns true iff the expression checks for nullish with loose equals.
+ * Examples: value == null, value == void 0
+ * @param {ASTNode} expression Test condition
+ * @param {import('eslint-scope').Scope} scope Scope of the expression
+ * @returns {boolean} True iff implicit nullish comparison
+ */
+function isImplicitNullishComparison(expression, scope) {
+ if (expression.type !== "BinaryExpression" || expression.operator !== "==") {
+ return false;
+ }
+
+ const reference = isReference(expression.left) ? "left" : "right";
+ const nullish = reference === "left" ? "right" : "left";
+
+ return isReference(expression[reference]) &&
+ (astUtils.isNullLiteral(expression[nullish]) || isUndefined(expression[nullish], scope));
+}
+
+/**
+ * Condition with two equal comparisons.
+ * @param {ASTNode} expression Condition
+ * @returns {boolean} True iff matches ? === ? || ? === ?
+ */
+function isDoubleComparison(expression) {
+ return expression.type === "LogicalExpression" &&
+ expression.operator === "||" &&
+ expression.left.type === "BinaryExpression" &&
+ expression.left.operator === "===" &&
+ expression.right.type === "BinaryExpression" &&
+ expression.right.operator === "===";
+}
+
+/**
+ * Returns true iff the expression checks for undefined and null.
+ * Example: value === null || value === undefined
+ * @param {ASTNode} expression Test condition
+ * @param {import('eslint-scope').Scope} scope Scope of the expression
+ * @returns {boolean} True iff explicit nullish comparison
+ */
+function isExplicitNullishComparison(expression, scope) {
+ if (!isDoubleComparison(expression)) {
+ return false;
+ }
+ const leftReference = isReference(expression.left.left) ? "left" : "right";
+ const leftNullish = leftReference === "left" ? "right" : "left";
+ const rightReference = isReference(expression.right.left) ? "left" : "right";
+ const rightNullish = rightReference === "left" ? "right" : "left";
+
+ return astUtils.isSameReference(expression.left[leftReference], expression.right[rightReference]) &&
+ ((astUtils.isNullLiteral(expression.left[leftNullish]) && isUndefined(expression.right[rightNullish], scope)) ||
+ (isUndefined(expression.left[leftNullish], scope) && astUtils.isNullLiteral(expression.right[rightNullish])));
+}
+
+/**
+ * Returns true for Boolean(arg) calls
+ * @param {ASTNode} expression Test condition
+ * @param {import('eslint-scope').Scope} scope Scope of the expression
+ * @returns {boolean} Whether the expression is a boolean cast
+ */
+function isBooleanCast(expression, scope) {
+ return expression.type === "CallExpression" &&
+ expression.callee.name === "Boolean" &&
+ expression.arguments.length === 1 &&
+ astUtils.isReferenceToGlobalVariable(scope, expression.callee);
+}
+
+/**
+ * Returns true for:
+ * truthiness checks: value, Boolean(value), !!value
+ * falsiness checks: !value, !Boolean(value)
+ * nullish checks: value == null, value === undefined || value === null
+ * @param {ASTNode} expression Test condition
+ * @param {import('eslint-scope').Scope} scope Scope of the expression
+ * @returns {?{ reference: ASTNode, operator: '??'|'||'|'&&'}} Null if not a known existence
+ */
+function getExistence(expression, scope) {
+ const isNegated = expression.type === "UnaryExpression" && expression.operator === "!";
+ const base = isNegated ? expression.argument : expression;
+
+ switch (true) {
+ case isReference(base):
+ return { reference: base, operator: isNegated ? "||" : "&&" };
+ case base.type === "UnaryExpression" && base.operator === "!" && isReference(base.argument):
+ return { reference: base.argument, operator: "&&" };
+ case isBooleanCast(base, scope) && isReference(base.arguments[0]):
+ return { reference: base.arguments[0], operator: isNegated ? "||" : "&&" };
+ case isImplicitNullishComparison(expression, scope):
+ return { reference: isReference(expression.left) ? expression.left : expression.right, operator: "??" };
+ case isExplicitNullishComparison(expression, scope):
+ return { reference: isReference(expression.left.left) ? expression.left.left : expression.left.right, operator: "??" };
+ default: return null;
+ }
+}
+
+/**
+ * Returns true iff the node is inside a with block
+ * @param {ASTNode} node Node to check
+ * @returns {boolean} True iff passed node is inside a with block
+ */
+function isInsideWithBlock(node) {
+ if (node.type === "Program") {
+ return false;
+ }
+
+ return node.parent.type === "WithStatement" && node.parent.body === node ? true : isInsideWithBlock(node.parent);
+}
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+/** @type {import('../shared/types').Rule} */
+module.exports = {
+ meta: {
+ type: "suggestion",
+
+ docs: {
+ description: "Require or disallow logical assignment operator shorthand",
+ recommended: false,
+ url: "https://eslint.org/docs/latest/rules/logical-assignment-operators"
+ },
+
+ schema: {
+ type: "array",
+ oneOf: [{
+ items: [
+ { const: "always" },
+ {
+ type: "object",
+ properties: {
+ enforceForIfStatements: {
+ type: "boolean"
+ }
+ },
+ additionalProperties: false
+ }
+ ],
+ minItems: 0, // 0 for allowing passing no options
+ maxItems: 2
+ }, {
+ items: [{ const: "never" }],
+ minItems: 1,
+ maxItems: 1
+ }]
+ },
+ fixable: "code",
+ // eslint-disable-next-line eslint-plugin/require-meta-has-suggestions -- Does not detect conditional suggestions
+ hasSuggestions: true,
+ messages: {
+ assignment: "Assignment (=) can be replaced with operator assignment ({{operator}}).",
+ useLogicalOperator: "Convert this assignment to use the operator {{ operator }}.",
+ logical: "Logical expression can be replaced with an assignment ({{ operator }}).",
+ convertLogical: "Replace this logical expression with an assignment with the operator {{ operator }}.",
+ if: "'if' statement can be replaced with a logical operator assignment with operator {{ operator }}.",
+ convertIf: "Replace this 'if' statement with a logical assignment with operator {{ operator }}.",
+ unexpected: "Unexpected logical operator assignment ({{operator}}) shorthand.",
+ separate: "Separate the logical assignment into an assignment with a logical operator."
+ }
+ },
+
+ create(context) {
+ const mode = context.options[0] === "never" ? "never" : "always";
+ const checkIf = mode === "always" && context.options.length > 1 && context.options[1].enforceForIfStatements;
+ const sourceCode = context.sourceCode;
+ const isStrict = sourceCode.getScope(sourceCode.ast).isStrict;
+
+ /**
+ * Returns false if the access could be a getter
+ * @param {ASTNode} node Assignment expression
+ * @returns {boolean} True iff the fix is safe
+ */
+ function cannotBeGetter(node) {
+ return node.type === "Identifier" &&
+ (isStrict || !isInsideWithBlock(node));
+ }
+
+ /**
+ * Check whether only a single property is accessed
+ * @param {ASTNode} node reference
+ * @returns {boolean} True iff a single property is accessed
+ */
+ function accessesSingleProperty(node) {
+ if (!isStrict && isInsideWithBlock(node)) {
+ return node.type === "Identifier";
+ }
+
+ return node.type === "MemberExpression" &&
+ baseTypes.has(node.object.type) &&
+ (!node.computed || (node.property.type !== "MemberExpression" && node.property.type !== "ChainExpression"));
+ }
+
+ /**
+ * Adds a fixer or suggestion whether on the fix is safe.
+ * @param {{ messageId: string, node: ASTNode }} descriptor Report descriptor without fix or suggest
+ * @param {{ messageId: string, fix: Function }} suggestion Adds the fix or the whole suggestion as only element in "suggest" to suggestion
+ * @param {boolean} shouldBeFixed Fix iff the condition is true
+ * @returns {Object} Descriptor with either an added fix or suggestion
+ */
+ function createConditionalFixer(descriptor, suggestion, shouldBeFixed) {
+ if (shouldBeFixed) {
+ return {
+ ...descriptor,
+ fix: suggestion.fix
+ };
+ }
+
+ return {
+ ...descriptor,
+ suggest: [suggestion]
+ };
+ }
+
+
+ /**
+ * Returns the operator token for assignments and binary expressions
+ * @param {ASTNode} node AssignmentExpression or BinaryExpression
+ * @returns {import('eslint').AST.Token} Operator token between the left and right expression
+ */
+ function getOperatorToken(node) {
+ return sourceCode.getFirstTokenBetween(node.left, node.right, token => token.value === node.operator);
+ }
+
+ if (mode === "never") {
+ return {
+
+ // foo ||= bar
+ "AssignmentExpression"(assignment) {
+ if (!astUtils.isLogicalAssignmentOperator(assignment.operator)) {
+ return;
+ }
+
+ const descriptor = {
+ messageId: "unexpected",
+ node: assignment,
+ data: { operator: assignment.operator }
+ };
+ const suggestion = {
+ messageId: "separate",
+ *fix(ruleFixer) {
+ if (sourceCode.getCommentsInside(assignment).length > 0) {
+ return;
+ }
+
+ const operatorToken = getOperatorToken(assignment);
+
+ // -> foo = bar
+ yield ruleFixer.replaceText(operatorToken, "=");
+
+ const assignmentText = sourceCode.getText(assignment.left);
+ const operator = assignment.operator.slice(0, -1);
+
+ // -> foo = foo || bar
+ yield ruleFixer.insertTextAfter(operatorToken, ` ${assignmentText} ${operator}`);
+
+ const precedence = astUtils.getPrecedence(assignment.right) <= astUtils.getPrecedence({ type: "LogicalExpression", operator });
+
+ // ?? and || / && cannot be mixed but have same precedence
+ const mixed = assignment.operator === "??=" && astUtils.isLogicalExpression(assignment.right);
+
+ if (!astUtils.isParenthesised(sourceCode, assignment.right) && (precedence || mixed)) {
+
+ // -> foo = foo || (bar)
+ yield ruleFixer.insertTextBefore(assignment.right, "(");
+ yield ruleFixer.insertTextAfter(assignment.right, ")");
+ }
+ }
+ };
+
+ context.report(createConditionalFixer(descriptor, suggestion, cannotBeGetter(assignment.left)));
+ }
+ };
+ }
+
+ return {
+
+ // foo = foo || bar
+ "AssignmentExpression[operator='='][right.type='LogicalExpression']"(assignment) {
+ if (!astUtils.isSameReference(assignment.left, assignment.right.left)) {
+ return;
+ }
+
+ const descriptor = {
+ messageId: "assignment",
+ node: assignment,
+ data: { operator: `${assignment.right.operator}=` }
+ };
+ const suggestion = {
+ messageId: "useLogicalOperator",
+ data: { operator: `${assignment.right.operator}=` },
+ *fix(ruleFixer) {
+ if (sourceCode.getCommentsInside(assignment).length > 0) {
+ return;
+ }
+
+ // No need for parenthesis around the assignment based on precedence as the precedence stays the same even with changed operator
+ const assignmentOperatorToken = getOperatorToken(assignment);
+
+ // -> foo ||= foo || bar
+ yield ruleFixer.insertTextBefore(assignmentOperatorToken, assignment.right.operator);
+
+ // -> foo ||= bar
+ const logicalOperatorToken = getOperatorToken(assignment.right);
+ const firstRightOperandToken = sourceCode.getTokenAfter(logicalOperatorToken);
+
+ yield ruleFixer.removeRange([assignment.right.range[0], firstRightOperandToken.range[0]]);
+ }
+ };
+
+ context.report(createConditionalFixer(descriptor, suggestion, cannotBeGetter(assignment.left)));
+ },
+
+ // foo || (foo = bar)
+ 'LogicalExpression[right.type="AssignmentExpression"][right.operator="="]'(logical) {
+
+ // Right side has to be parenthesized, otherwise would be parsed as (foo || foo) = bar which is illegal
+ if (isReference(logical.left) && astUtils.isSameReference(logical.left, logical.right.left)) {
+ const descriptor = {
+ messageId: "logical",
+ node: logical,
+ data: { operator: `${logical.operator}=` }
+ };
+ const suggestion = {
+ messageId: "convertLogical",
+ data: { operator: `${logical.operator}=` },
+ *fix(ruleFixer) {
+ if (sourceCode.getCommentsInside(logical).length > 0) {
+ return;
+ }
+
+ const requiresOuterParenthesis = logical.parent.type !== "ExpressionStatement" &&
+ (astUtils.getPrecedence({ type: "AssignmentExpression" }) < astUtils.getPrecedence(logical.parent));
+
+ if (!astUtils.isParenthesised(sourceCode, logical) && requiresOuterParenthesis) {
+ yield ruleFixer.insertTextBefore(logical, "(");
+ yield ruleFixer.insertTextAfter(logical, ")");
+ }
+
+ // Also removes all opening parenthesis
+ yield ruleFixer.removeRange([logical.range[0], logical.right.range[0]]); // -> foo = bar)
+
+ // Also removes all ending parenthesis
+ yield ruleFixer.removeRange([logical.right.range[1], logical.range[1]]); // -> foo = bar
+
+ const operatorToken = getOperatorToken(logical.right);
+
+ yield ruleFixer.insertTextBefore(operatorToken, logical.operator); // -> foo ||= bar
+ }
+ };
+ const fix = cannotBeGetter(logical.left) || accessesSingleProperty(logical.left);
+
+ context.report(createConditionalFixer(descriptor, suggestion, fix));
+ }
+ },
+
+ // if (foo) foo = bar
+ "IfStatement[alternate=null]"(ifNode) {
+ if (!checkIf) {
+ return;
+ }
+
+ const hasBody = ifNode.consequent.type === "BlockStatement";
+
+ if (hasBody && ifNode.consequent.body.length !== 1) {
+ return;
+ }
+
+ const body = hasBody ? ifNode.consequent.body[0] : ifNode.consequent;
+ const scope = sourceCode.getScope(ifNode);
+ const existence = getExistence(ifNode.test, scope);
+
+ if (
+ body.type === "ExpressionStatement" &&
+ body.expression.type === "AssignmentExpression" &&
+ body.expression.operator === "=" &&
+ existence !== null &&
+ astUtils.isSameReference(existence.reference, body.expression.left)
+ ) {
+ const descriptor = {
+ messageId: "if",
+ node: ifNode,
+ data: { operator: `${existence.operator}=` }
+ };
+ const suggestion = {
+ messageId: "convertIf",
+ data: { operator: `${existence.operator}=` },
+ *fix(ruleFixer) {
+ if (sourceCode.getCommentsInside(ifNode).length > 0) {
+ return;
+ }
+
+ const firstBodyToken = sourceCode.getFirstToken(body);
+ const prevToken = sourceCode.getTokenBefore(ifNode);
+
+ if (
+ prevToken !== null &&
+ prevToken.value !== ";" &&
+ prevToken.value !== "{" &&
+ firstBodyToken.type !== "Identifier" &&
+ firstBodyToken.type !== "Keyword"
+ ) {
+
+ // Do not fix if the fixed statement could be part of the previous statement (eg. fn() if (a == null) (a) = b --> fn()(a) ??= b)
+ return;
+ }
+
+
+ const operatorToken = getOperatorToken(body.expression);
+
+ yield ruleFixer.insertTextBefore(operatorToken, existence.operator); // -> if (foo) foo ||= bar
+
+ yield ruleFixer.removeRange([ifNode.range[0], body.range[0]]); // -> foo ||= bar
+
+ yield ruleFixer.removeRange([body.range[1], ifNode.range[1]]); // -> foo ||= bar, only present if "if" had a body
+
+ const nextToken = sourceCode.getTokenAfter(body.expression);
+
+ if (hasBody && (nextToken !== null && nextToken.value !== ";")) {
+ yield ruleFixer.insertTextAfter(ifNode, ";");
+ }
+ }
+ };
+ const shouldBeFixed = cannotBeGetter(existence.reference) ||
+ (ifNode.test.type !== "LogicalExpression" && accessesSingleProperty(existence.reference));
+
+ context.report(createConditionalFixer(descriptor, suggestion, shouldBeFixed));
+ }
+ }
+ };
+ }
+};
docs: {
description: "Enforce a maximum number of classes per file",
recommended: false,
- url: "https://eslint.org/docs/rules/max-classes-per-file"
+ url: "https://eslint.org/docs/latest/rules/max-classes-per-file"
},
schema: [
docs: {
description: "Enforce a maximum depth that blocks can be nested",
recommended: false,
- url: "https://eslint.org/docs/rules/max-depth"
+ url: "https://eslint.org/docs/latest/rules/max-depth"
},
schema: [
docs: {
description: "Enforce a maximum line length",
recommended: false,
- url: "https://eslint.org/docs/rules/max-len"
+ url: "https://eslint.org/docs/latest/rules/max-len"
},
schema: [
*/
const URL_REGEXP = /[^:/?#]:\/\/[^?#]/u;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Computes the length of a line that may contain tabs. The width of each
docs: {
description: "Enforce a maximum number of lines of code in a function",
recommended: false,
- url: "https://eslint.org/docs/rules/max-lines-per-function"
+ url: "https://eslint.org/docs/latest/rules/max-lines-per-function"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const lines = sourceCode.lines;
const option = context.options[0];
docs: {
description: "Enforce a maximum number of lines per file",
recommended: false,
- url: "https://eslint.org/docs/rules/max-lines"
+ url: "https://eslint.org/docs/latest/rules/max-lines"
},
schema: [
const skipComments = option && option.skipComments;
const skipBlankLines = option && option.skipBlankLines;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Returns whether or not a token is a comment node type
docs: {
description: "Enforce a maximum depth that callbacks can be nested",
recommended: false,
- url: "https://eslint.org/docs/rules/max-nested-callbacks"
+ url: "https://eslint.org/docs/latest/rules/max-nested-callbacks"
},
schema: [
docs: {
description: "Enforce a maximum number of parameters in function definitions",
recommended: false,
- url: "https://eslint.org/docs/rules/max-params"
+ url: "https://eslint.org/docs/latest/rules/max-params"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const option = context.options[0];
let numParams = 3;
docs: {
description: "Enforce a maximum number of statements allowed per line",
recommended: false,
- url: "https://eslint.org/docs/rules/max-statements-per-line"
+ url: "https://eslint.org/docs/latest/rules/max-statements-per-line"
},
schema: [
create(context) {
- const sourceCode = context.getSourceCode(),
+ const sourceCode = context.sourceCode,
options = context.options[0] || {},
maxStatementsPerLine = typeof options.max !== "undefined" ? options.max : 1;
docs: {
description: "Enforce a maximum number of statements allowed in function blocks",
recommended: false,
- url: "https://eslint.org/docs/rules/max-statements"
+ url: "https://eslint.org/docs/latest/rules/max-statements"
},
schema: [
docs: {
description: "Enforce a particular style for multiline comments",
recommended: false,
- url: "https://eslint.org/docs/rules/multiline-comment-style"
+ url: "https://eslint.org/docs/latest/rules/multiline-comment-style"
},
fixable: "whitespace",
- schema: [{ enum: ["starred-block", "separate-lines", "bare-block"] }],
+ schema: {
+ anyOf: [
+ {
+ type: "array",
+ items: [
+ {
+ enum: ["starred-block", "bare-block"]
+ }
+ ],
+ additionalItems: false
+ },
+ {
+ type: "array",
+ items: [
+ {
+ enum: ["separate-lines"]
+ },
+ {
+ type: "object",
+ properties: {
+ checkJSDoc: {
+ type: "boolean"
+ }
+ },
+ additionalProperties: false
+ }
+ ],
+ additionalItems: false
+ }
+ ]
+ },
messages: {
expectedBlock: "Expected a block comment instead of consecutive line comments.",
expectedBareBlock: "Expected a block comment without padding stars.",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const option = context.options[0] || "starred-block";
+ const params = context.options[1] || {};
+ const checkJSDoc = !!params.checkJSDoc;
//----------------------------------------------------------------------
// Helpers
"separate-lines"(commentGroup) {
const [firstComment] = commentGroup;
- if (firstComment.type !== "Block" || isJSDocComment(commentGroup)) {
+ const isJSDoc = isJSDocComment(commentGroup);
+
+ if (firstComment.type !== "Block" || (!checkJSDoc && isJSDoc)) {
return;
}
- const commentLines = getCommentLines(commentGroup);
+ let commentLines = getCommentLines(commentGroup);
+
+ if (isJSDoc) {
+ commentLines = commentLines.slice(1, commentLines.length - 1);
+ }
+
const tokenAfter = sourceCode.getTokenAfter(firstComment, { includeComments: true });
if (tokenAfter && firstComment.loc.end.line === tokenAfter.loc.start.line) {
docs: {
description: "Enforce newlines between operands of ternary expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/multiline-ternary"
+ url: "https://eslint.org/docs/latest/rules/multiline-ternary"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const option = context.options[0];
const multiline = option !== "never";
const allowSingleLine = option === "always-multiline";
end: lastTokenOfTest.loc.end
},
messageId: "unexpectedTestCons",
- fix: fixer => {
+ fix(fixer) {
if (hasComments) {
return null;
}
end: lastTokenOfConsequent.loc.end
},
messageId: "unexpectedConsAlt",
- fix: fixer => {
+ fix(fixer) {
if (hasComments) {
return null;
}
docs: {
description: "Require constructor names to begin with a capital letter",
recommended: false,
- url: "https://eslint.org/docs/rules/new-cap"
+ url: "https://eslint.org/docs/latest/rules/new-cap"
},
schema: [
const listeners = {};
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Enforce or disallow parentheses when invoking a constructor with no arguments",
recommended: false,
- url: "https://eslint.org/docs/rules/new-parens"
+ url: "https://eslint.org/docs/latest/rules/new-parens"
},
fixable: "code",
- schema: {
- anyOf: [
- {
- type: "array",
- items: [
- {
- enum: ["always", "never"]
- }
- ],
- minItems: 0,
- maxItems: 1
- }
- ]
- },
+ schema: [
+ {
+ enum: ["always", "never"]
+ }
+ ],
messages: {
missing: "Missing '()' invoking a constructor.",
unnecessary: "Unnecessary '()' invoking a constructor with no arguments."
const options = context.options;
const always = options[0] !== "never"; // Default is always
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
NewExpression(node) {
docs: {
description: "Require or disallow an empty line after variable declarations",
recommended: false,
- url: "https://eslint.org/docs/rules/newline-after-var"
+ url: "https://eslint.org/docs/latest/rules/newline-after-var"
},
schema: [
{
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
// Default `mode` to "always".
const mode = context.options[0] === "never" ? "never" : "always";
docs: {
description: "Require an empty line before `return` statements",
recommended: false,
- url: "https://eslint.org/docs/rules/newline-before-return"
+ url: "https://eslint.org/docs/latest/rules/newline-before-return"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Require a newline after each call in a method chain",
recommended: false,
- url: "https://eslint.org/docs/rules/newline-per-chained-call"
+ url: "https://eslint.org/docs/latest/rules/newline-per-chained-call"
},
fixable: "whitespace",
const options = context.options[0] || {},
ignoreChainWithDepth = options.ignoreChainWithDepth || 2;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Get the prefix of a given MemberExpression node.
docs: {
description: "Disallow the use of `alert`, `confirm`, and `prompt`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-alert"
+ url: "https://eslint.org/docs/latest/rules/no-alert"
},
schema: [],
},
create(context) {
+ const sourceCode = context.sourceCode;
+
return {
CallExpression(node) {
const callee = skipChainExpression(node.callee),
- currentScope = context.getScope();
+ currentScope = sourceCode.getScope(node);
// without window.
if (callee.type === "Identifier") {
docs: {
description: "Disallow `Array` constructors",
recommended: false,
- url: "https://eslint.org/docs/rules/no-array-constructor"
+ url: "https://eslint.org/docs/latest/rules/no-array-constructor"
},
schema: [],
docs: {
description: "Disallow using an async function as a Promise executor",
recommended: true,
- url: "https://eslint.org/docs/rules/no-async-promise-executor"
+ url: "https://eslint.org/docs/latest/rules/no-async-promise-executor"
},
fixable: null,
return {
"NewExpression[callee.name='Promise'][arguments.0.async=true]"(node) {
context.report({
- node: context.getSourceCode().getFirstToken(node.arguments[0], token => token.value === "async"),
+ node: context.sourceCode.getFirstToken(node.arguments[0], token => token.value === "async"),
messageId: "async"
});
}
docs: {
description: "Disallow `await` inside of loops",
recommended: false,
- url: "https://eslint.org/docs/rules/no-await-in-loop"
+ url: "https://eslint.org/docs/latest/rules/no-await-in-loop"
},
schema: [],
docs: {
description: "Disallow bitwise operators",
recommended: false,
- url: "https://eslint.org/docs/rules/no-bitwise"
+ url: "https://eslint.org/docs/latest/rules/no-bitwise"
},
schema: [
docs: {
description: "Disallow use of the `Buffer()` constructor",
recommended: false,
- url: "https://eslint.org/docs/rules/no-buffer-constructor"
+ url: "https://eslint.org/docs/latest/rules/no-buffer-constructor"
},
schema: [],
docs: {
description: "Disallow the use of `arguments.caller` or `arguments.callee`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-caller"
+ url: "https://eslint.org/docs/latest/rules/no-caller"
},
schema: [],
docs: {
description: "Disallow lexical declarations in case clauses",
recommended: true,
- url: "https://eslint.org/docs/rules/no-case-declarations"
+ url: "https://eslint.org/docs/latest/rules/no-case-declarations"
},
schema: [],
docs: {
description: "Disallow `catch` clause parameters from shadowing variables in the outer scope",
recommended: false,
- url: "https://eslint.org/docs/rules/no-catch-shadow"
+ url: "https://eslint.org/docs/latest/rules/no-catch-shadow"
},
replacedBy: ["no-shadow"],
create(context) {
+ const sourceCode = context.sourceCode;
+
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
return {
"CatchClause[param!=null]"(node) {
- let scope = context.getScope();
+ let scope = sourceCode.getScope(node);
/*
* When ecmaVersion >= 6, CatchClause creates its own scope
docs: {
description: "Disallow reassigning class members",
recommended: true,
- url: "https://eslint.org/docs/rules/no-class-assign"
+ url: "https://eslint.org/docs/latest/rules/no-class-assign"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Finds and reports references that are non initializer and writable.
* @param {Variable} variable A variable to check.
* @returns {void}
*/
function checkForClass(node) {
- context.getDeclaredVariables(node).forEach(checkVariable);
+ sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
return {
docs: {
description: "Disallow comparing against -0",
recommended: true,
- url: "https://eslint.org/docs/rules/no-compare-neg-zero"
+ url: "https://eslint.org/docs/latest/rules/no-compare-neg-zero"
},
fixable: null,
docs: {
description: "Disallow assignment operators in conditional expressions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-cond-assign"
+ url: "https://eslint.org/docs/latest/rules/no-cond-assign"
},
schema: [
const prohibitAssign = (context.options[0] || "except-parens");
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Check whether an AST node is the test expression for a conditional statement.
docs: {
description: "Disallow arrow functions where they could be confused with comparisons",
recommended: false,
- url: "https://eslint.org/docs/rules/no-confusing-arrow"
+ url: "https://eslint.org/docs/latest/rules/no-confusing-arrow"
},
fixable: "code",
const config = context.options[0] || {};
const allowParens = config.allowParens || (config.allowParens === void 0);
const onlyOneSimpleParam = config.onlyOneSimpleParam;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
docs: {
description: "Disallow the use of `console`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-console"
+ url: "https://eslint.org/docs/latest/rules/no-console"
},
schema: [
create(context) {
const options = context.options[0] || {};
const allowed = options.allow || [];
+ const sourceCode = context.sourceCode;
/**
* Checks whether the given reference is 'console' or not.
}
return {
- "Program:exit"() {
- const scope = context.getScope();
+ "Program:exit"(node) {
+ const scope = sourceCode.getScope(node);
const consoleVar = astUtils.getVariableByName(scope, "console");
const shadowed = consoleVar && consoleVar.defs.length > 0;
docs: {
description: "Disallow reassigning `const` variables",
recommended: true,
- url: "https://eslint.org/docs/rules/no-const-assign"
+ url: "https://eslint.org/docs/latest/rules/no-const-assign"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Finds and reports references that are non initializer and writable.
* @param {Variable} variable A variable to check.
return {
VariableDeclaration(node) {
if (node.kind === "const") {
- context.getDeclaredVariables(node).forEach(checkVariable);
+ sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
}
};
// Helpers
//------------------------------------------------------------------------------
+/**
+ * Checks whether or not a node is `null` or `undefined`. Similar to the one
+ * found in ast-utils.js, but this one correctly handles the edge case that
+ * `undefined` has been redefined.
+ * @param {Scope} scope Scope in which the expression was found.
+ * @param {ASTNode} node A node to check.
+ * @returns {boolean} Whether or not the node is a `null` or `undefined`.
+ * @public
+ */
+function isNullOrUndefined(scope, node) {
+ return (
+ isNullLiteral(node) ||
+ (node.type === "Identifier" && node.name === "undefined" && isReferenceToGlobalVariable(scope, node)) ||
+ (node.type === "UnaryExpression" && node.operator === "void")
+ );
+}
+
/**
* Test if an AST node has a statically knowable constant nullishness. Meaning,
* it will always resolve to a constant value of either: `null`, `undefined`
* three states at runtime would return `false`.
* @param {Scope} scope The scope in which the node was found.
* @param {ASTNode} node The AST node being tested.
+ * @param {boolean} nonNullish if `true` then nullish values are not considered constant.
* @returns {boolean} Does `node` have constant nullishness?
*/
-function hasConstantNullishness(scope, node) {
+function hasConstantNullishness(scope, node, nonNullish) {
+ if (nonNullish && isNullOrUndefined(scope, node)) {
+ return false;
+ }
+
switch (node.type) {
case "ObjectExpression": // Objects are never nullish
case "ArrayExpression": // Arrays are never nullish
return (functionName === "Boolean" || functionName === "String" || functionName === "Number") &&
isReferenceToGlobalVariable(scope, node.callee);
}
+ case "LogicalExpression": {
+ return node.operator === "??" && hasConstantNullishness(scope, node.right, true);
+ }
case "AssignmentExpression":
if (node.operator === "=") {
- return hasConstantNullishness(scope, node.right);
+ return hasConstantNullishness(scope, node.right, nonNullish);
}
/*
case "SequenceExpression": {
const last = node.expressions[node.expressions.length - 1];
- return hasConstantNullishness(scope, last);
+ return hasConstantNullishness(scope, last, nonNullish);
}
case "Identifier":
return node.name === "undefined" && isReferenceToGlobalVariable(scope, node);
* user-defined constructors could return a sentinel
* object.
*
- * Catching these is especially useful for primitive constructures
+ * Catching these is especially useful for primitive constructors
* which return boxed values, a surprising gotcha' in JavaScript.
*/
return Object.hasOwnProperty.call(globals.builtin, node.callee.name) &&
}
}
-/**
- * Checks whether or not a node is `null` or `undefined`. Similar to the one
- * found in ast-utils.js, but this one correctly handles the edge case that
- * `undefined` has been redefined.
- * @param {Scope} scope Scope in which the expression was found.
- * @param {ASTNode} node A node to check.
- * @returns {boolean} Whether or not the node is a `null` or `undefined`.
- * @public
- */
-function isNullOrUndefined(scope, node) {
- return (
- isNullLiteral(node) ||
- (node.type === "Identifier" && node.name === "undefined" && isReferenceToGlobalVariable(scope, node)) ||
- (node.type === "UnaryExpression" && node.operator === "void")
- );
-}
-
-
/**
* Checks if one operand will cause the result to be constant.
* @param {Scope} scope Scope in which the expression was found.
function findBinaryExpressionConstantOperand(scope, a, b, operator) {
if (operator === "==" || operator === "!=") {
if (
- (isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b)) ||
+ (isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b, false)) ||
(isStaticBoolean(scope, a) && hasConstantLooseBooleanComparison(scope, b))
) {
return b;
}
} else if (operator === "===" || operator === "!==") {
if (
- (isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b)) ||
+ (isNullOrUndefined(scope, a) && hasConstantNullishness(scope, b, false)) ||
(isStaticBoolean(scope, a) && hasConstantStrictBooleanComparison(scope, b))
) {
return b;
docs: {
description: "Disallow expressions where the operation doesn't affect the value",
recommended: false,
- url: "https://eslint.org/docs/rules/no-constant-binary-expression"
+ url: "https://eslint.org/docs/latest/rules/no-constant-binary-expression"
},
schema: [],
messages: {
},
create(context) {
+ const sourceCode = context.sourceCode;
+
return {
LogicalExpression(node) {
const { operator, left } = node;
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
if ((operator === "&&" || operator === "||") && isConstant(scope, left, true)) {
context.report({ node: left, messageId: "constantShortCircuit", data: { property: "truthiness", operator } });
- } else if (operator === "??" && hasConstantNullishness(scope, left)) {
+ } else if (operator === "??" && hasConstantNullishness(scope, left, false)) {
context.report({ node: left, messageId: "constantShortCircuit", data: { property: "nullishness", operator } });
}
},
BinaryExpression(node) {
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
const { right, left, operator } = node;
const rightConstantOperand = findBinaryExpressionConstantOperand(scope, left, right, operator);
const leftConstantOperand = findBinaryExpressionConstantOperand(scope, right, left, operator);
docs: {
description: "Disallow constant expressions in conditions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-constant-condition"
+ url: "https://eslint.org/docs/latest/rules/no-constant-condition"
},
schema: [
const options = context.options[0] || {},
checkLoops = options.checkLoops !== false,
loopSetStack = [];
+ const sourceCode = context.sourceCode;
let loopsInCurrentScope = new Set();
* @private
*/
function trackConstantConditionLoop(node) {
- if (node.test && isConstant(context.getScope(), node.test, true)) {
+ if (node.test && isConstant(sourceCode.getScope(node), node.test, true)) {
loopsInCurrentScope.add(node);
}
}
* @private
*/
function reportIfConstant(node) {
- if (node.test && isConstant(context.getScope(), node.test, true)) {
+ if (node.test && isConstant(sourceCode.getScope(node), node.test, true)) {
context.report({ node: node.test, messageId: "unexpected" });
}
}
docs: {
description: "Disallow returning value from constructor",
recommended: false,
- url: "https://eslint.org/docs/rules/no-constructor-return"
+ url: "https://eslint.org/docs/latest/rules/no-constructor-return"
},
schema: {},
docs: {
description: "Disallow `continue` statements",
recommended: false,
- url: "https://eslint.org/docs/rules/no-continue"
+ url: "https://eslint.org/docs/latest/rules/no-continue"
},
schema: [],
"use strict";
-const RegExpValidator = require("regexpp").RegExpValidator;
+const RegExpValidator = require("@eslint-community/regexpp").RegExpValidator;
const collector = new (class {
constructor() {
this._source = "";
docs: {
description: "Disallow control characters in regular expressions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-control-regex"
+ url: "https://eslint.org/docs/latest/rules/no-control-regex"
},
schema: [],
docs: {
description: "Disallow the use of `debugger`",
recommended: true,
- url: "https://eslint.org/docs/rules/no-debugger"
+ url: "https://eslint.org/docs/latest/rules/no-debugger"
},
fixable: null,
docs: {
description: "Disallow deleting variables",
recommended: true,
- url: "https://eslint.org/docs/rules/no-delete-var"
+ url: "https://eslint.org/docs/latest/rules/no-delete-var"
},
schema: [],
type: "suggestion",
docs: {
- description: "Disallow division operators explicitly at the beginning of regular expressions",
+ description: "Disallow equal signs explicitly at the beginning of regular expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-div-regex"
+ url: "https://eslint.org/docs/latest/rules/no-div-regex"
},
fixable: "code",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
docs: {
description: "Disallow duplicate arguments in `function` definitions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-dupe-args"
+ url: "https://eslint.org/docs/latest/rules/no-dupe-args"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
* @private
*/
function checkParams(node) {
- const variables = context.getDeclaredVariables(node);
+ const variables = sourceCode.getDeclaredVariables(node);
for (let i = 0; i < variables.length; ++i) {
const variable = variables[i];
docs: {
description: "Disallow duplicate class members",
recommended: true,
- url: "https://eslint.org/docs/rules/no-dupe-class-members"
+ url: "https://eslint.org/docs/latest/rules/no-dupe-class-members"
},
schema: [],
docs: {
description: "Disallow duplicate conditions in if-else-if chains",
recommended: true,
- url: "https://eslint.org/docs/rules/no-dupe-else-if"
+ url: "https://eslint.org/docs/latest/rules/no-dupe-else-if"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Determines whether the two given nodes are considered to be equal. In particular, given that the nodes
docs: {
description: "Disallow duplicate keys in object literals",
recommended: true,
- url: "https://eslint.org/docs/rules/no-dupe-keys"
+ url: "https://eslint.org/docs/latest/rules/no-dupe-keys"
},
schema: [],
docs: {
description: "Disallow duplicate case labels",
recommended: true,
- url: "https://eslint.org/docs/rules/no-duplicate-case"
+ url: "https://eslint.org/docs/latest/rules/no-duplicate-case"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Determines whether the two given nodes are considered to be equal.
docs: {
description: "Disallow duplicate module imports",
recommended: false,
- url: "https://eslint.org/docs/rules/no-duplicate-imports"
+ url: "https://eslint.org/docs/latest/rules/no-duplicate-imports"
},
schema: [
docs: {
description: "Disallow `else` blocks after `return` statements in `if` statements",
recommended: false,
- url: "https://eslint.org/docs/rules/no-else-return"
+ url: "https://eslint.org/docs/latest/rules/no-else-return"
},
schema: [{
create(context) {
+ const sourceCode = context.sourceCode;
+
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
/**
* Display the context report if rule is violated
- * @param {Node} node The 'else' node
+ * @param {Node} elseNode The 'else' node
* @returns {void}
*/
- function displayReport(node) {
- const currentScope = context.getScope();
+ function displayReport(elseNode) {
+ const currentScope = sourceCode.getScope(elseNode.parent);
context.report({
- node,
+ node: elseNode,
messageId: "unexpected",
- fix: fixer => {
+ fix(fixer) {
- if (!isSafeFromNameCollisions(node, currentScope)) {
+ if (!isSafeFromNameCollisions(elseNode, currentScope)) {
return null;
}
- const sourceCode = context.getSourceCode();
- const startToken = sourceCode.getFirstToken(node);
+ const startToken = sourceCode.getFirstToken(elseNode);
const elseToken = sourceCode.getTokenBefore(startToken);
- const source = sourceCode.getText(node);
+ const source = sourceCode.getText(elseNode);
const lastIfToken = sourceCode.getTokenBefore(elseToken);
let fixedSource, firstTokenOfElseBlock;
* safe to remove the else keyword, because ASI will not add a semicolon
* after the if block
*/
- const ifBlockMaybeUnsafe = node.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
+ const ifBlockMaybeUnsafe = elseNode.parent.consequent.type !== "BlockStatement" && lastIfToken.value !== ";";
const elseBlockUnsafe = /^[([/+`-]/u.test(firstTokenOfElseBlock.value);
if (ifBlockMaybeUnsafe && elseBlockUnsafe) {
return null;
}
- const endToken = sourceCode.getLastToken(node);
+ const endToken = sourceCode.getLastToken(elseNode);
const lastTokenOfElseBlock = sourceCode.getTokenBefore(endToken);
if (lastTokenOfElseBlock.value !== ";") {
* Also, to avoid name collisions between two else blocks.
*/
return new FixTracker(fixer, sourceCode)
- .retainEnclosingFunction(node)
- .replaceTextRange([elseToken.range[0], node.range[1]], fixedSource);
+ .retainEnclosingFunction(elseNode)
+ .replaceTextRange([elseToken.range[0], elseNode.range[1]], fixedSource);
}
});
}
docs: {
description: "Disallow empty character classes in regular expressions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-empty-character-class"
+ url: "https://eslint.org/docs/latest/rules/no-empty-character-class"
},
schema: [],
docs: {
description: "Disallow empty functions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-empty-function"
+ url: "https://eslint.org/docs/latest/rules/no-empty-function"
},
schema: [
const options = context.options[0] || {};
const allowed = options.allow || [];
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports a given function node if the node matches the following patterns.
docs: {
description: "Disallow empty destructuring patterns",
recommended: true,
- url: "https://eslint.org/docs/rules/no-empty-pattern"
+ url: "https://eslint.org/docs/latest/rules/no-empty-pattern"
},
schema: [],
--- /dev/null
+/**
+ * @fileoverview Rule to disallow empty static blocks.
+ * @author Sosuke Suzuki
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+/** @type {import('../shared/types').Rule} */
+module.exports = {
+ meta: {
+ type: "suggestion",
+
+ docs: {
+ description: "Disallow empty static blocks",
+ recommended: false,
+ url: "https://eslint.org/docs/latest/rules/no-empty-static-block"
+ },
+
+ schema: [],
+
+ messages: {
+ unexpected: "Unexpected empty static block."
+ }
+ },
+
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ return {
+ StaticBlock(node) {
+ if (node.body.length === 0) {
+ const closingBrace = sourceCode.getLastToken(node);
+
+ if (sourceCode.getCommentsBefore(closingBrace).length === 0) {
+ context.report({
+ node,
+ messageId: "unexpected"
+ });
+ }
+ }
+ }
+ };
+ }
+};
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
+ hasSuggestions: true,
type: "suggestion",
docs: {
description: "Disallow empty block statements",
recommended: true,
- url: "https://eslint.org/docs/rules/no-empty"
+ url: "https://eslint.org/docs/latest/rules/no-empty"
},
schema: [
],
messages: {
- unexpected: "Empty {{type}} statement."
+ unexpected: "Empty {{type}} statement.",
+ suggestComment: "Add comment inside empty {{type}} statement."
}
},
const options = context.options[0] || {},
allowEmptyCatch = options.allowEmptyCatch || false;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
BlockStatement(node) {
return;
}
- context.report({ node, messageId: "unexpected", data: { type: "block" } });
+ context.report({
+ node,
+ messageId: "unexpected",
+ data: { type: "block" },
+ suggest: [
+ {
+ messageId: "suggestComment",
+ data: { type: "block" },
+ fix(fixer) {
+ const range = [node.range[0] + 1, node.range[1] - 1];
+
+ return fixer.replaceTextRange(range, " /* empty */ ");
+ }
+ }
+ ]
+ });
},
SwitchStatement(node) {
docs: {
description: "Disallow `null` comparisons without type-checking operators",
recommended: false,
- url: "https://eslint.org/docs/rules/no-eq-null"
+ url: "https://eslint.org/docs/latest/rules/no-eq-null"
},
schema: [],
docs: {
description: "Disallow the use of `eval()`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-eval"
+ url: "https://eslint.org/docs/latest/rules/no-eval"
},
schema: [
context.options[0] &&
context.options[0].allowIndirect
);
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let funcInfo = null;
/**
- * Pushs a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
+ * Pushes a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
* Top-level scopes are handled separately.
*
* This is used in order to check whether or not `this` binding is a
* @returns {void}
*/
function enterThisScope(node) {
- const strict = context.getScope().isStrict;
+ const strict = sourceCode.getScope(node).isStrict;
funcInfo = {
upper: funcInfo,
},
Program(node) {
- const scope = context.getScope(),
+ const scope = sourceCode.getScope(node),
features = context.parserOptions.ecmaFeatures || {},
strict =
scope.isStrict ||
};
},
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
exitThisScope();
reportAccessingEval(globalScope);
docs: {
description: "Disallow reassigning exceptions in `catch` clauses",
recommended: true,
- url: "https://eslint.org/docs/rules/no-ex-assign"
+ url: "https://eslint.org/docs/latest/rules/no-ex-assign"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Finds and reports references that are non initializer and writable.
* @param {Variable} variable A variable to check.
return {
CatchClause(node) {
- context.getDeclaredVariables(node).forEach(checkVariable);
+ sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
};
docs: {
description: "Disallow extending native types",
recommended: false,
- url: "https://eslint.org/docs/rules/no-extend-native"
+ url: "https://eslint.org/docs/latest/rules/no-extend-native"
},
schema: [
create(context) {
const config = context.options[0] || {};
+ const sourceCode = context.sourceCode;
const exceptions = new Set(config.exceptions || []);
const modifiedBuiltins = new Set(
Object.keys(globals.builtin)
return {
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
modifiedBuiltins.forEach(builtin => {
const builtinVar = globalScope.set.get(builtin);
docs: {
description: "Disallow unnecessary calls to `.bind()`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-extra-bind"
+ url: "https://eslint.org/docs/latest/rules/no-extra-bind"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let scopeInfo = null;
/**
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const eslintUtils = require("eslint-utils");
+const eslintUtils = require("@eslint-community/eslint-utils");
const precedence = astUtils.getPrecedence;
docs: {
description: "Disallow unnecessary boolean casts",
recommended: true,
- url: "https://eslint.org/docs/rules/no-extra-boolean-cast"
+ url: "https://eslint.org/docs/latest/rules/no-extra-boolean-cast"
},
schema: [{
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
// Node types which have a test which will coerce values to booleans.
const BOOLEAN_NODE_TYPES = new Set([
docs: {
description: "Disallow unnecessary labels",
recommended: false,
- url: "https://eslint.org/docs/rules/no-extra-label"
+ url: "https://eslint.org/docs/latest/rules/no-extra-label"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let scopeInfo = null;
/**
// Rule Definition
//------------------------------------------------------------------------------
-const { isParenthesized: isParenthesizedRaw } = require("eslint-utils");
+const { isParenthesized: isParenthesizedRaw } = require("@eslint-community/eslint-utils");
const astUtils = require("./utils/ast-utils.js");
/** @type {import('../shared/types').Rule} */
docs: {
description: "Disallow unnecessary parentheses",
recommended: false,
- url: "https://eslint.org/docs/rules/no-extra-parens"
+ url: "https://eslint.org/docs/latest/rules/no-extra-parens"
},
fixable: "code",
enforceForArrowConditionals: { type: "boolean" },
enforceForSequenceExpressions: { type: "boolean" },
enforceForNewInMemberExpressions: { type: "boolean" },
- enforceForFunctionPrototypeMethods: { type: "boolean" }
+ enforceForFunctionPrototypeMethods: { type: "boolean" },
+ allowParensAfterCommentPattern: { type: "string" }
},
additionalProperties: false
}
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const tokensToIgnore = new WeakSet();
const precedence = astUtils.getPrecedence;
context.options[1].enforceForNewInMemberExpressions === false;
const IGNORE_FUNCTION_PROTOTYPE_METHODS = ALL_NODES && context.options[1] &&
context.options[1].enforceForFunctionPrototypeMethods === false;
+ const ALLOW_PARENS_AFTER_COMMENT_PATTERN = ALL_NODES && context.options[1] && context.options[1].allowParensAfterCommentPattern;
const PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" });
const PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" });
if (isIIFE(node) && !isParenthesised(node.callee)) {
return;
}
+
+ if (ALLOW_PARENS_AFTER_COMMENT_PATTERN) {
+ const commentsBeforeLeftParenToken = sourceCode.getCommentsBefore(leftParenToken);
+ const totalCommentsBeforeLeftParenTokenCount = commentsBeforeLeftParenToken.length;
+ const ignorePattern = new RegExp(ALLOW_PARENS_AFTER_COMMENT_PATTERN, "u");
+
+ if (
+ totalCommentsBeforeLeftParenTokenCount > 0 &&
+ ignorePattern.test(commentsBeforeLeftParenToken[totalCommentsBeforeLeftParenTokenCount - 1].value)
+ ) {
+ return;
+ }
+ }
}
/**
return false;
}
+ /**
+ * Checks if the left-hand side of an assignment is an identifier, the operator is one of
+ * `=`, `&&=`, `||=` or `??=` and the right-hand side is an anonymous class or function.
+ *
+ * As per https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation, an
+ * assignment involving one of the operators `=`, `&&=`, `||=` or `??=` where the right-hand
+ * side is an anonymous class or function and the left-hand side is an *unparenthesized*
+ * identifier has different semantics than other assignments.
+ * Specifically, when an expression like `foo = function () {}` is evaluated, `foo.name`
+ * will be set to the string "foo", i.e. the identifier name. The same thing does not happen
+ * when evaluating `(foo) = function () {}`.
+ * Since the parenthesizing of the identifier in the left-hand side is significant in this
+ * special case, the parentheses, if present, should not be flagged as unnecessary.
+ * @param {ASTNode} node an AssignmentExpression node.
+ * @returns {boolean} `true` if the left-hand side of the assignment is an identifier, the
+ * operator is one of `=`, `&&=`, `||=` or `??=` and the right-hand side is an anonymous
+ * class or function; otherwise, `false`.
+ */
+ function isAnonymousFunctionAssignmentException({ left, operator, right }) {
+ if (left.type === "Identifier" && ["=", "&&=", "||=", "??="].includes(operator)) {
+ const rhsType = right.type;
+
+ if (rhsType === "ArrowFunctionExpression") {
+ return true;
+ }
+ if ((rhsType === "FunctionExpression" || rhsType === "ClassExpression") && !right.id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
return {
ArrayExpression(node) {
node.elements
},
AssignmentExpression(node) {
- if (canBeAssignmentTarget(node.left) && hasExcessParens(node.left)) {
+ if (canBeAssignmentTarget(node.left) && hasExcessParens(node.left) &&
+ (!isAnonymousFunctionAssignmentException(node) || isParenthesisedTwice(node.left))) {
report(node.left);
}
docs: {
description: "Disallow unnecessary semicolons",
recommended: true,
- url: "https://eslint.org/docs/rules/no-extra-semi"
+ url: "https://eslint.org/docs/latest/rules/no-extra-semi"
},
fixable: "code",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports an unnecessary semicolon error.
* tokens to avoid conflicting with semi.
* https://github.com/eslint/eslint/issues/7928
*/
- return new FixTracker(fixer, context.getSourceCode())
+ return new FixTracker(fixer, context.sourceCode)
.retainSurroundingTokens(nodeOrToken)
.remove(nodeOrToken);
}
*/
"use strict";
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const { directivesPattern } = require("../shared/directives");
+
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
+/**
+ * Checks whether or not a given comment string is really a fallthrough comment and not an ESLint directive.
+ * @param {string} comment The comment string to check.
+ * @param {RegExp} fallthroughCommentPattern The regular expression used for checking for fallthrough comments.
+ * @returns {boolean} `true` if the comment string is truly a fallthrough comment.
+ */
+function isFallThroughComment(comment, fallthroughCommentPattern) {
+ return fallthroughCommentPattern.test(comment) && !directivesPattern.test(comment.trim());
+}
+
/**
* Checks whether or not a given case has a fallthrough comment.
* @param {ASTNode} caseWhichFallsThrough SwitchCase node which falls through.
* @returns {boolean} `true` if the case has a valid fallthrough comment.
*/
function hasFallthroughComment(caseWhichFallsThrough, subsequentCase, context, fallthroughCommentPattern) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
if (caseWhichFallsThrough.consequent.length === 1 && caseWhichFallsThrough.consequent[0].type === "BlockStatement") {
const trailingCloseBrace = sourceCode.getLastToken(caseWhichFallsThrough.consequent[0]);
const commentInBlock = sourceCode.getCommentsBefore(trailingCloseBrace).pop();
- if (commentInBlock && fallthroughCommentPattern.test(commentInBlock.value)) {
+ if (commentInBlock && isFallThroughComment(commentInBlock.value, fallthroughCommentPattern)) {
return true;
}
}
const comment = sourceCode.getCommentsBefore(subsequentCase).pop();
- return Boolean(comment && fallthroughCommentPattern.test(comment.value));
+ return Boolean(comment && isFallThroughComment(comment.value, fallthroughCommentPattern));
}
/**
docs: {
description: "Disallow fallthrough of `case` statements",
recommended: true,
- url: "https://eslint.org/docs/rules/no-fallthrough"
+ url: "https://eslint.org/docs/latest/rules/no-fallthrough"
},
schema: [
create(context) {
const options = context.options[0] || {};
let currentCodePath = null;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const allowEmptyCase = options.allowEmptyCase || false;
/*
docs: {
description: "Disallow leading or trailing decimal points in numeric literals",
recommended: false,
- url: "https://eslint.org/docs/rules/no-floating-decimal"
+ url: "https://eslint.org/docs/latest/rules/no-floating-decimal"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
Literal(node) {
docs: {
description: "Disallow reassigning `function` declarations",
recommended: true,
- url: "https://eslint.org/docs/rules/no-func-assign"
+ url: "https://eslint.org/docs/latest/rules/no-func-assign"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Reports a reference if is non initializer and writable.
* @param {References} references Collection of reference to check.
* @returns {void}
*/
function checkForFunction(node) {
- context.getDeclaredVariables(node).forEach(checkVariable);
+ sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
return {
docs: {
description: "Disallow assignments to native objects or read-only global variables",
recommended: true,
- url: "https://eslint.org/docs/rules/no-global-assign"
+ url: "https://eslint.org/docs/latest/rules/no-global-assign"
},
schema: [
create(context) {
const config = context.options[0];
+ const sourceCode = context.sourceCode;
const exceptions = (config && config.exceptions) || [];
/**
}
return {
- Program() {
- const globalScope = context.getScope();
+ Program(node) {
+ const globalScope = sourceCode.getScope(node);
globalScope.variables.forEach(checkVariable);
}
);
}
+/**
+ * Checks whether the given node logically represents multiplication by a fraction of `1`.
+ * For example, `a * 1` in `a * 1 / b` is technically multiplication by `1`, but the
+ * whole expression can be logically interpreted as `a * (1 / b)` rather than `(a * 1) / b`.
+ * @param {BinaryExpression} node A BinaryExpression node to check.
+ * @param {SourceCode} sourceCode The source code object.
+ * @returns {boolean} Whether or not the node is a multiplying by a fraction of `1`.
+ */
+function isMultiplyByFractionOfOne(node, sourceCode) {
+ return node.type === "BinaryExpression" &&
+ node.operator === "*" &&
+ (node.right.type === "Literal" && node.right.value === 1) &&
+ node.parent.type === "BinaryExpression" &&
+ node.parent.operator === "/" &&
+ node.parent.left === node &&
+ !astUtils.isParenthesised(sourceCode, node);
+}
+
/**
* Checks whether the result of a node is numeric or not
* @param {ASTNode} node The node to test
docs: {
description: "Disallow shorthand type conversions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-implicit-coercion"
+ url: "https://eslint.org/docs/latest/rules/no-implicit-coercion"
},
fixable: "code",
create(context) {
const options = parseOptions(context.options[0] || {});
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports an error and autofixes the node
// 1 * foo
operatorAllowed = options.allow.includes("*");
- const nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && getNonNumericOperand(node);
+ const nonNumericOperand = !operatorAllowed && options.number && isMultiplyByOne(node) && !isMultiplyByFractionOfOne(node, sourceCode) &&
+ getNonNumericOperand(node);
if (nonNumericOperand) {
const recommendation = `Number(${sourceCode.getText(nonNumericOperand)})`;
docs: {
description: "Disallow declarations in the global scope",
recommended: false,
- url: "https://eslint.org/docs/rules/no-implicit-globals"
+ url: "https://eslint.org/docs/latest/rules/no-implicit-globals"
},
schema: [{
create(context) {
const checkLexicalBindings = context.options[0] && context.options[0].lexicalBindings === true;
+ const sourceCode = context.sourceCode;
/**
* Reports the node.
}
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
scope.variables.forEach(variable => {
return;
}
+ // Variables exported by "exported" block comments
+ if (variable.eslintExported) {
+ return;
+ }
+
variable.defs.forEach(def => {
const defNode = def.node;
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const { getStaticValue } = require("eslint-utils");
+const { getStaticValue } = require("@eslint-community/eslint-utils");
//------------------------------------------------------------------------------
// Rule Definition
docs: {
description: "Disallow the use of `eval()`-like methods",
recommended: false,
- url: "https://eslint.org/docs/rules/no-implied-eval"
+ url: "https://eslint.org/docs/latest/rules/no-implied-eval"
},
schema: [],
create(context) {
const GLOBAL_CANDIDATES = Object.freeze(["global", "window", "globalThis"]);
const EVAL_LIKE_FUNC_PATTERN = /^(?:set(?:Interval|Timeout)|execScript)$/u;
+ const sourceCode = context.sourceCode;
/**
* Checks whether a node is evaluated as a string or not.
if (firstArgument) {
- const staticValue = getStaticValue(firstArgument, context.getScope());
+ const staticValue = getStaticValue(firstArgument, sourceCode.getScope(node));
const isStaticString = staticValue && typeof staticValue.value === "string";
const isString = isStaticString || isEvaluatedString(firstArgument);
reportImpliedEvalCallExpression(node);
}
},
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
GLOBAL_CANDIDATES
.map(candidate => astUtils.getVariableByName(globalScope, candidate))
// Helpers
//------------------------------------------------------------------------------
-const { findVariable } = require("eslint-utils");
+const { findVariable } = require("@eslint-community/eslint-utils");
const astUtils = require("./utils/ast-utils");
const WellKnownMutationFunctions = {
docs: {
description: "Disallow assigning to imported bindings",
recommended: true,
- url: "https://eslint.org/docs/rules/no-import-assign"
+ url: "https://eslint.org/docs/latest/rules/no-import-assign"
},
schema: [],
},
create(context) {
+ const sourceCode = context.sourceCode;
+
return {
ImportDeclaration(node) {
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
- for (const variable of context.getDeclaredVariables(node)) {
+ for (const variable of sourceCode.getDeclaredVariables(node)) {
const shouldCheckMembers = variable.defs.some(
d => d.node.type === "ImportNamespaceSpecifier"
);
docs: {
description: "Disallow inline comments after code",
recommended: false,
- url: "https://eslint.org/docs/rules/no-inline-comments"
+ url: "https://eslint.org/docs/latest/rules/no-inline-comments"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const options = context.options[0];
let customIgnoreRegExp;
docs: {
description: "Disallow variable or `function` declarations in nested blocks",
recommended: true,
- url: "https://eslint.org/docs/rules/no-inner-declarations"
+ url: "https://eslint.org/docs/latest/rules/no-inner-declarations"
},
schema: [
// Requirements
//------------------------------------------------------------------------------
-const RegExpValidator = require("regexpp").RegExpValidator;
+const RegExpValidator = require("@eslint-community/regexpp").RegExpValidator;
const validator = new RegExpValidator();
const validFlags = /[dgimsuy]/gu;
const undefined1 = void 0;
docs: {
description: "Disallow invalid regular expression strings in `RegExp` constructors",
recommended: true,
- url: "https://eslint.org/docs/rules/no-invalid-regexp"
+ url: "https://eslint.org/docs/latest/rules/no-invalid-regexp"
},
schema: [{
}
}
+ /**
+ * Reports error with the provided message.
+ * @param {ASTNode} node The node holding the invalid RegExp
+ * @param {string} message The message to report.
+ * @returns {void}
+ */
+ function report(node, message) {
+ context.report({
+ node,
+ messageId: "regexMessage",
+ data: { message }
+ });
+ }
+
/**
* Check if node is a string
* @param {ASTNode} node node to evaluate
/**
* Check syntax error in a given flags.
- * @param {string} flags The RegExp flags to validate.
+ * @param {string|null} flags The RegExp flags to validate.
* @returns {string|null} The syntax error.
*/
function validateRegExpFlags(flags) {
+ if (!flags) {
+ return null;
+ }
try {
validator.validateFlags(flags);
return null;
return {
"CallExpression, NewExpression"(node) {
- if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp" || !isString(node.arguments[0])) {
+ if (node.callee.type !== "Identifier" || node.callee.name !== "RegExp") {
return;
}
- const pattern = node.arguments[0].value;
+
let flags = getFlags(node);
if (flags && allowedFlags) {
flags = flags.replace(allowedFlags, "");
}
- const message =
- (
- flags && validateRegExpFlags(flags)
- ) ||
- (
+ let message = validateRegExpFlags(flags);
+
+ if (message) {
+ report(node, message);
+ return;
+ }
+
+ if (!isString(node.arguments[0])) {
+ return;
+ }
+
+ const pattern = node.arguments[0].value;
+
+ message = (
- // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag
- flags === null
- ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
- : validateRegExpPattern(pattern, flags.includes("u"))
- );
+ // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag
+ flags === null
+ ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
+ : validateRegExpPattern(pattern, flags.includes("u"))
+ );
if (message) {
- context.report({
- node,
- messageId: "regexMessage",
- data: { message }
- });
+ report(node, message);
}
}
};
docs: {
description: "Disallow use of `this` in contexts where the value of `this` is `undefined`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-invalid-this"
+ url: "https://eslint.org/docs/latest/rules/no-invalid-this"
},
schema: [
const options = context.options[0] || {};
const capIsConstructor = options.capIsConstructor !== false;
const stack = [],
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
/**
* Gets the current checking context.
}
if (codePath.origin === "program") {
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
const features = context.parserOptions.ecmaFeatures || {};
// `this` at the top level of scripts always refers to the global object
* always valid, so we can set `init: true` right away.
*/
stack.push({
- init: !context.getScope().isStrict,
+ init: !sourceCode.getScope(node).isStrict,
node,
valid: true
});
docs: {
description: "Disallow irregular whitespace",
recommended: true,
- url: "https://eslint.org/docs/rules/no-irregular-whitespace"
+ url: "https://eslint.org/docs/latest/rules/no-irregular-whitespace"
},
schema: [
const skipRegExps = !!options.skipRegExps;
const skipTemplates = !!options.skipTemplates;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const commentNodes = sourceCode.getAllComments();
/**
docs: {
description: "Disallow the use of the `__iterator__` property",
recommended: false,
- url: "https://eslint.org/docs/rules/no-iterator"
+ url: "https://eslint.org/docs/latest/rules/no-iterator"
},
schema: [],
docs: {
description: "Disallow labels that share a name with a variable",
recommended: false,
- url: "https://eslint.org/docs/rules/no-label-var"
+ url: "https://eslint.org/docs/latest/rules/no-label-var"
},
schema: [],
},
create(context) {
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
LabeledStatement(node) {
// Fetch the innermost scope.
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
/*
* Recursively find the identifier walking up the scope, starting
docs: {
description: "Disallow labeled statements",
recommended: false,
- url: "https://eslint.org/docs/rules/no-labels"
+ url: "https://eslint.org/docs/latest/rules/no-labels"
},
schema: [
docs: {
description: "Disallow unnecessary nested blocks",
recommended: false,
- url: "https://eslint.org/docs/rules/no-lone-blocks"
+ url: "https://eslint.org/docs/latest/rules/no-lone-blocks"
},
schema: [],
// A stack of lone blocks to be checked for block-level bindings
const loneBlocks = [];
let ruleDef;
+ const sourceCode = context.sourceCode;
/**
* Reports a node as invalid.
/**
* Checks the enclosing block of the current node for block-level bindings,
* and "marks it" as valid if any.
+ * @param {ASTNode} node The current node to check.
* @returns {void}
*/
- function markLoneBlock() {
+ function markLoneBlock(node) {
if (loneBlocks.length === 0) {
return;
}
- const block = context.getAncestors().pop();
+ const block = node.parent;
if (loneBlocks[loneBlocks.length - 1] === block) {
loneBlocks.pop();
ruleDef.VariableDeclaration = function(node) {
if (node.kind === "let" || node.kind === "const") {
- markLoneBlock();
+ markLoneBlock(node);
}
};
- ruleDef.FunctionDeclaration = function() {
- if (context.getScope().isStrict) {
- markLoneBlock();
+ ruleDef.FunctionDeclaration = function(node) {
+ if (sourceCode.getScope(node).isStrict) {
+ markLoneBlock(node);
}
};
docs: {
description: "Disallow `if` statements as the only statement in `else` blocks",
recommended: false,
- url: "https://eslint.org/docs/rules/no-lonely-if"
+ url: "https://eslint.org/docs/latest/rules/no-lonely-if"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
IfStatement(node) {
- const ancestors = context.getAncestors(),
- parent = ancestors.pop(),
- grandparent = ancestors.pop();
+ const parent = node.parent,
+ grandparent = parent.parent;
if (parent && parent.type === "BlockStatement" &&
parent.body.length === 1 && grandparent &&
docs: {
description: "Disallow function declarations that contain unsafe references inside loop statements",
recommended: false,
- url: "https://eslint.org/docs/rules/no-loop-func"
+ url: "https://eslint.org/docs/latest/rules/no-loop-func"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Reports functions which match the following condition:
*
return;
}
- const references = context.getScope().through;
+ const references = sourceCode.getScope(node).through;
const unsafeRefs = references.filter(r => !isSafe(loopNode, r)).map(r => r.identifier.name);
if (unsafeRefs.length > 0) {
docs: {
description: "Disallow literal numbers that lose precision",
recommended: true,
- url: "https://eslint.org/docs/rules/no-loss-of-precision"
+ url: "https://eslint.org/docs/latest/rules/no-loss-of-precision"
},
schema: [],
messages: {
}
/**
- * Converts an integer to to an object containing the integer's coefficient and order of magnitude
+ * Converts an integer to an object containing the integer's coefficient and order of magnitude
* @param {string} stringInteger the string representation of the integer being converted
* @returns {Object} the object containing the integer's coefficient and order of magnitude
*/
/**
*
- * Converts a float to to an object containing the floats's coefficient and order of magnitude
+ * Converts a float to an object containing the floats's coefficient and order of magnitude
* @param {string} stringFloat the string representation of the float being converted
* @returns {Object} the object containing the integer's coefficient and order of magnitude
*/
docs: {
description: "Disallow magic numbers",
recommended: false,
- url: "https://eslint.org/docs/rules/no-magic-numbers"
+ url: "https://eslint.org/docs/latest/rules/no-magic-numbers"
},
schema: [{
ignoreDefaultValues: {
type: "boolean",
default: false
+ },
+ ignoreClassFieldInitialValues: {
+ type: "boolean",
+ default: false
}
},
additionalProperties: false
enforceConst = !!config.enforceConst,
ignore = new Set((config.ignore || []).map(normalizeIgnoreValue)),
ignoreArrayIndexes = !!config.ignoreArrayIndexes,
- ignoreDefaultValues = !!config.ignoreDefaultValues;
+ ignoreDefaultValues = !!config.ignoreDefaultValues,
+ ignoreClassFieldInitialValues = !!config.ignoreClassFieldInitialValues;
const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"];
return parent.type === "AssignmentPattern" && parent.right === fullNumberNode;
}
+ /**
+ * Returns whether the number is the initial value of a class field.
+ * @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
+ * @returns {boolean} true if the number is the initial value of a class field.
+ */
+ function isClassFieldInitialValue(fullNumberNode) {
+ const parent = fullNumberNode.parent;
+
+ return parent.type === "PropertyDefinition" && parent.value === fullNumberNode;
+ }
+
/**
* Returns whether the given node is used as a radix within parseInt() or Number.parseInt()
* @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
if (
isIgnoredValue(value) ||
(ignoreDefaultValues && isDefaultValue(fullNumberNode)) ||
+ (ignoreClassFieldInitialValues && isClassFieldInitialValue(fullNumberNode)) ||
isParseIntRadix(fullNumberNode) ||
isJSXNumber(fullNumberNode) ||
(ignoreArrayIndexes && isArrayIndex(fullNumberNode, value))
*/
"use strict";
-const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils");
-const { RegExpValidator, RegExpParser, visitRegExpAST } = require("regexpp");
+const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("@eslint-community/eslint-utils");
+const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
const { isCombiningCharacter, isEmojiModifier, isRegionalIndicatorSymbol, isSurrogatePair } = require("./utils/unicode");
const astUtils = require("./utils/ast-utils.js");
+const { isValidWithUnicodeFlag } = require("./utils/regular-expressions");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
-const REGEXPP_LATEST_ECMA_VERSION = 2022;
-
/**
* Iterate character sequences of a given nodes.
*
docs: {
description: "Disallow characters which are made with multiple code points in character class syntax",
recommended: true,
- url: "https://eslint.org/docs/rules/no-misleading-character-class"
+ url: "https://eslint.org/docs/latest/rules/no-misleading-character-class"
},
hasSuggestions: true,
}
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const parser = new RegExpParser();
/**
}
}
- /**
- * Checks if the given regular expression pattern would be valid with the `u` flag.
- * @param {string} pattern The regular expression pattern to verify.
- * @returns {boolean} `true` if the pattern would be valid with the `u` flag.
- * `false` if the pattern would be invalid with the `u` flag or the configured
- * ecmaVersion doesn't support the `u` flag.
- */
- function isValidWithUnicodeFlag(pattern) {
- const { ecmaVersion } = context.parserOptions;
-
- // ecmaVersion is unknown or it doesn't support the 'u' flag
- if (typeof ecmaVersion !== "number" || ecmaVersion <= 5) {
- return false;
- }
-
- const validator = new RegExpValidator({
- ecmaVersion: Math.min(ecmaVersion + 2009, REGEXPP_LATEST_ECMA_VERSION)
- });
-
- try {
- validator.validatePattern(pattern, void 0, void 0, /* uFlag = */ true);
- } catch {
- return false;
- }
-
- return true;
- }
-
return {
"Literal[regex]"(node) {
verify(node, node.regex.pattern, node.regex.flags, fixer => {
- if (!isValidWithUnicodeFlag(node.regex.pattern)) {
+ if (!isValidWithUnicodeFlag(context.languageOptions.ecmaVersion, node.regex.pattern)) {
return null;
}
return fixer.insertTextAfter(node, "u");
});
},
- "Program"() {
- const scope = context.getScope();
+ "Program"(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
/*
* E.g., `new RegExp()`, `RegExp()`, `new window.RegExp()`,
* `const {RegExp: a} = window; new a()`, etc...
*/
- for (const { node } of tracker.iterateGlobalReferences({
+ for (const { node: refNode } of tracker.iterateGlobalReferences({
RegExp: { [CALL]: true, [CONSTRUCT]: true }
})) {
- const [patternNode, flagsNode] = node.arguments;
+ const [patternNode, flagsNode] = refNode.arguments;
const pattern = getStringIfConstant(patternNode, scope);
const flags = getStringIfConstant(flagsNode, scope);
if (typeof pattern === "string") {
- verify(node, pattern, flags || "", fixer => {
+ verify(refNode, pattern, flags || "", fixer => {
- if (!isValidWithUnicodeFlag(pattern)) {
+ if (!isValidWithUnicodeFlag(context.languageOptions.ecmaVersion, pattern)) {
return null;
}
- if (node.arguments.length === 1) {
- const penultimateToken = sourceCode.getLastToken(node, { skip: 1 }); // skip closing parenthesis
+ if (refNode.arguments.length === 1) {
+ const penultimateToken = sourceCode.getLastToken(refNode, { skip: 1 }); // skip closing parenthesis
return fixer.insertTextAfter(
penultimateToken,
docs: {
description: "Disallow mixed binary operators",
recommended: false,
- url: "https://eslint.org/docs/rules/no-mixed-operators"
+ url: "https://eslint.org/docs/latest/rules/no-mixed-operators"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const options = normalizeOptions(context.options[0]);
/**
docs: {
description: "Disallow `require` calls to be mixed with regular variable declarations",
recommended: false,
- url: "https://eslint.org/docs/rules/no-mixed-requires"
+ url: "https://eslint.org/docs/latest/rules/no-mixed-requires"
},
schema: [
docs: {
description: "Disallow mixed spaces and tabs for indentation",
recommended: true,
- url: "https://eslint.org/docs/rules/no-mixed-spaces-and-tabs"
+ url: "https://eslint.org/docs/latest/rules/no-mixed-spaces-and-tabs"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let smartTabs;
docs: {
description: "Disallow use of chained assignment expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-multi-assign"
+ url: "https://eslint.org/docs/latest/rules/no-multi-assign"
},
schema: [{
docs: {
description: "Disallow multiple spaces",
recommended: false,
- url: "https://eslint.org/docs/rules/no-multi-spaces"
+ url: "https://eslint.org/docs/latest/rules/no-multi-spaces"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const options = context.options[0] || {};
const ignoreEOLComments = options.ignoreEOLComments;
const exceptions = Object.assign({ Property: true }, options.exceptions);
docs: {
description: "Disallow multiline strings",
recommended: false,
- url: "https://eslint.org/docs/rules/no-multi-str"
+ url: "https://eslint.org/docs/latest/rules/no-multi-str"
},
schema: [],
docs: {
description: "Disallow multiple empty lines",
recommended: false,
- url: "https://eslint.org/docs/rules/no-multiple-empty-lines"
+ url: "https://eslint.org/docs/latest/rules/no-multiple-empty-lines"
},
fixable: "whitespace",
maxBOF = typeof context.options[0].maxBOF !== "undefined" ? context.options[0].maxBOF : max;
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
// Swallow the final newline, as some editors add it automatically and we don't want it to cause an issue
const allLines = sourceCode.lines[sourceCode.lines.length - 1] === "" ? sourceCode.lines.slice(0, -1) : sourceCode.lines;
docs: {
description: "Disallow assignments to native objects or read-only global variables",
recommended: false,
- url: "https://eslint.org/docs/rules/no-native-reassign"
+ url: "https://eslint.org/docs/latest/rules/no-native-reassign"
},
deprecated: true,
create(context) {
const config = context.options[0];
const exceptions = (config && config.exceptions) || [];
+ const sourceCode = context.sourceCode;
/**
* Reports write references.
}
return {
- Program() {
- const globalScope = context.getScope();
+ Program(node) {
+ const globalScope = sourceCode.getScope(node);
globalScope.variables.forEach(checkVariable);
}
docs: {
description: "Disallow negated conditions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-negated-condition"
+ url: "https://eslint.org/docs/latest/rules/no-negated-condition"
},
schema: [],
docs: {
description: "Disallow negating the left operand in `in` expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-negated-in-lhs"
+ url: "https://eslint.org/docs/latest/rules/no-negated-in-lhs"
},
replacedBy: ["no-unsafe-negation"],
docs: {
description: "Disallow nested ternary expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-nested-ternary"
+ url: "https://eslint.org/docs/latest/rules/no-nested-ternary"
},
schema: [],
docs: {
description: "Disallow `new` operators with the `Function` object",
recommended: false,
- url: "https://eslint.org/docs/rules/no-new-func"
+ url: "https://eslint.org/docs/latest/rules/no-new-func"
},
schema: [],
},
create(context) {
+ const sourceCode = context.sourceCode;
return {
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
const variable = globalScope.set.get("Function");
if (variable && variable.defs.length === 0) {
variable.references.forEach(ref => {
- const node = ref.identifier;
- const { parent } = node;
+ const idNode = ref.identifier;
+ const { parent } = idNode;
let evalNode;
if (parent) {
- if (node === parent.callee && (
+ if (idNode === parent.callee && (
parent.type === "NewExpression" ||
parent.type === "CallExpression"
)) {
evalNode = parent;
} else if (
parent.type === "MemberExpression" &&
- node === parent.object &&
+ idNode === parent.object &&
callMethods.has(astUtils.getStaticPropertyName(parent))
) {
const maybeCallee = parent.parent.type === "ChainExpression" ? parent.parent : parent;
--- /dev/null
+/**
+ * @fileoverview Rule to disallow use of the new operator with global non-constructor functions
+ * @author Sosuke Suzuki
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const nonConstructorGlobalFunctionNames = ["Symbol", "BigInt"];
+
+//------------------------------------------------------------------------------
+// Rule Definition
+//------------------------------------------------------------------------------
+
+/** @type {import('../shared/types').Rule} */
+module.exports = {
+ meta: {
+ type: "problem",
+
+ docs: {
+ description: "Disallow `new` operators with global non-constructor functions",
+ recommended: false,
+ url: "https://eslint.org/docs/latest/rules/no-new-native-nonconstructor"
+ },
+
+ schema: [],
+
+ messages: {
+ noNewNonconstructor: "`{{name}}` cannot be called as a constructor."
+ }
+ },
+
+ create(context) {
+
+ const sourceCode = context.sourceCode;
+
+ return {
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
+
+ for (const nonConstructorName of nonConstructorGlobalFunctionNames) {
+ const variable = globalScope.set.get(nonConstructorName);
+
+ if (variable && variable.defs.length === 0) {
+ variable.references.forEach(ref => {
+ const idNode = ref.identifier;
+ const parent = idNode.parent;
+
+ if (parent && parent.type === "NewExpression" && parent.callee === idNode) {
+ context.report({
+ node: idNode,
+ messageId: "noNewNonconstructor",
+ data: { name: nonConstructorName }
+ });
+ }
+ });
+ }
+ }
+ }
+ };
+
+ }
+};
docs: {
description: "Disallow `Object` constructors",
recommended: false,
- url: "https://eslint.org/docs/rules/no-new-object"
+ url: "https://eslint.org/docs/latest/rules/no-new-object"
},
schema: [],
},
create(context) {
+
+ const sourceCode = context.sourceCode;
+
return {
NewExpression(node) {
const variable = astUtils.getVariableByName(
- context.getScope(),
+ sourceCode.getScope(node),
node.callee.name
);
docs: {
description: "Disallow `new` operators with calls to `require`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-new-require"
+ url: "https://eslint.org/docs/latest/rules/no-new-require"
},
schema: [],
docs: {
description: "Disallow `new` operators with the `Symbol` object",
recommended: true,
- url: "https://eslint.org/docs/rules/no-new-symbol"
+ url: "https://eslint.org/docs/latest/rules/no-new-symbol"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
return {
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
const variable = globalScope.set.get("Symbol");
if (variable && variable.defs.length === 0) {
variable.references.forEach(ref => {
- const node = ref.identifier;
- const parent = node.parent;
+ const idNode = ref.identifier;
+ const parent = idNode.parent;
- if (parent && parent.type === "NewExpression" && parent.callee === node) {
+ if (parent && parent.type === "NewExpression" && parent.callee === idNode) {
context.report({
- node,
+ node: idNode,
messageId: "noNewSymbol"
});
}
docs: {
description: "Disallow `new` operators with the `String`, `Number`, and `Boolean` objects",
recommended: false,
- url: "https://eslint.org/docs/rules/no-new-wrappers"
+ url: "https://eslint.org/docs/latest/rules/no-new-wrappers"
},
schema: [],
docs: {
description: "Disallow `new` operators outside of assignments or comparisons",
recommended: false,
- url: "https://eslint.org/docs/rules/no-new"
+ url: "https://eslint.org/docs/latest/rules/no-new"
},
schema: [],
docs: {
description: "Disallow `\\8` and `\\9` escape sequences in string literals",
recommended: true,
- url: "https://eslint.org/docs/rules/no-nonoctal-decimal-escape"
+ url: "https://eslint.org/docs/latest/rules/no-nonoctal-decimal-escape"
},
hasSuggestions: true,
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Creates a new Suggestion object.
// Requirements
//------------------------------------------------------------------------------
-const { CALL, CONSTRUCT, ReferenceTracker } = require("eslint-utils");
+const { CALL, CONSTRUCT, ReferenceTracker } = require("@eslint-community/eslint-utils");
const getPropertyName = require("./utils/ast-utils").getStaticPropertyName;
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
-const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect"];
+const nonCallableGlobals = ["Atomics", "JSON", "Math", "Reflect", "Intl"];
/**
* Returns the name of the node to report
docs: {
description: "Disallow calling global object properties as functions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-obj-calls"
+ url: "https://eslint.org/docs/latest/rules/no-obj-calls"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
const traceMap = {};
};
}
- for (const { node, path } of tracker.iterateGlobalReferences(traceMap)) {
- const name = getReportNodeName(node.callee);
+ for (const { node: refNode, path } of tracker.iterateGlobalReferences(traceMap)) {
+ const name = getReportNodeName(refNode.callee);
const ref = path[0];
const messageId = name === ref ? "unexpectedCall" : "unexpectedRefCall";
- context.report({ node, messageId, data: { name, ref } });
+ context.report({ node: refNode, messageId, data: { name, ref } });
}
}
};
docs: {
description: "Disallow octal escape sequences in string literals",
recommended: false,
- url: "https://eslint.org/docs/rules/no-octal-escape"
+ url: "https://eslint.org/docs/latest/rules/no-octal-escape"
},
schema: [],
docs: {
description: "Disallow octal literals",
recommended: true,
- url: "https://eslint.org/docs/rules/no-octal"
+ url: "https://eslint.org/docs/latest/rules/no-octal"
},
schema: [],
docs: {
description: "Disallow reassigning `function` parameters",
recommended: false,
- url: "https://eslint.org/docs/rules/no-param-reassign"
+ url: "https://eslint.org/docs/latest/rules/no-param-reassign"
},
schema: [
const props = context.options[0] && context.options[0].props;
const ignoredPropertyAssignmentsFor = context.options[0] && context.options[0].ignorePropertyModificationsFor || [];
const ignoredPropertyAssignmentsForRegex = context.options[0] && context.options[0].ignorePropertyModificationsForRegex || [];
+ const sourceCode = context.sourceCode;
/**
* Checks whether or not the reference modifies properties of its variable.
* @returns {void}
*/
function checkForFunction(node) {
- context.getDeclaredVariables(node).forEach(checkVariable);
+ sourceCode.getDeclaredVariables(node).forEach(checkVariable);
}
return {
docs: {
description: "Disallow string concatenation with `__dirname` and `__filename`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-path-concat"
+ url: "https://eslint.org/docs/latest/rules/no-path-concat"
},
schema: [],
docs: {
description: "Disallow the unary operators `++` and `--`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-plusplus"
+ url: "https://eslint.org/docs/latest/rules/no-plusplus"
},
schema: [
docs: {
description: "Disallow the use of `process.env`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-process-env"
+ url: "https://eslint.org/docs/latest/rules/no-process-env"
},
schema: [],
docs: {
description: "Disallow the use of `process.exit()`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-process-exit"
+ url: "https://eslint.org/docs/latest/rules/no-process-exit"
},
schema: [],
// Requirements
//------------------------------------------------------------------------------
-const { findVariable } = require("eslint-utils");
+const { findVariable } = require("@eslint-community/eslint-utils");
//------------------------------------------------------------------------------
// Helpers
docs: {
description: "Disallow returning values from Promise executor functions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-promise-executor-return"
+ url: "https://eslint.org/docs/latest/rules/no-promise-executor-return"
},
schema: [],
create(context) {
let funcInfo = null;
+ const sourceCode = context.sourceCode;
/**
* Reports the given node.
onCodePathStart(_, node) {
funcInfo = {
upper: funcInfo,
- shouldCheck: functionTypesToCheck.has(node.type) && isPromiseExecutor(node, context.getScope())
+ shouldCheck: functionTypesToCheck.has(node.type) && isPromiseExecutor(node, sourceCode.getScope(node))
};
if (funcInfo.shouldCheck && node.type === "ArrowFunctionExpression" && node.expression) {
docs: {
description: "Disallow the use of the `__proto__` property",
recommended: false,
- url: "https://eslint.org/docs/rules/no-proto"
+ url: "https://eslint.org/docs/latest/rules/no-proto"
},
schema: [],
docs: {
description: "Disallow calling some `Object.prototype` methods directly on objects",
recommended: true,
- url: "https://eslint.org/docs/rules/no-prototype-builtins"
+ url: "https://eslint.org/docs/latest/rules/no-prototype-builtins"
},
schema: [],
docs: {
description: "Disallow variable redeclaration",
recommended: true,
- url: "https://eslint.org/docs/rules/no-redeclare"
+ url: "https://eslint.org/docs/latest/rules/no-redeclare"
},
messages: {
context.options[0].builtinGlobals
)
};
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Iterate declarations of a given variable.
* @private
*/
function checkForBlock(node) {
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
/*
* In ES5, some node type such as `BlockStatement` doesn't have that scope.
}
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
findVariablesInScope(scope);
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const regexpp = require("regexpp");
+const regexpp = require("@eslint-community/regexpp");
//------------------------------------------------------------------------------
// Helpers
docs: {
description: "Disallow multiple spaces in regular expressions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-regex-spaces"
+ url: "https://eslint.org/docs/latest/rules/no-regex-spaces"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Validate regular expression
* @param {ASTNode} nodeToReport Node to report.
* @private
*/
function checkFunction(node) {
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
const regExpVar = astUtils.getVariableByName(scope, "RegExp");
const shadowed = regExpVar && regExpVar.defs.length > 0;
const patternNode = node.arguments[0];
docs: {
description: "Disallow specified names in exports",
recommended: false,
- url: "https://eslint.org/docs/rules/no-restricted-exports"
+ url: "https://eslint.org/docs/latest/rules/no-restricted-exports"
},
schema: [{
- type: "object",
- properties: {
- restrictedNamedExports: {
- type: "array",
- items: {
- type: "string"
+ anyOf: [
+ {
+ type: "object",
+ properties: {
+ restrictedNamedExports: {
+ type: "array",
+ items: {
+ type: "string"
+ },
+ uniqueItems: true
+ }
},
- uniqueItems: true
+ additionalProperties: false
+ },
+ {
+ type: "object",
+ properties: {
+ restrictedNamedExports: {
+ type: "array",
+ items: {
+ type: "string",
+ pattern: "^(?!default$)"
+ },
+ uniqueItems: true
+ },
+ restrictDefaultExports: {
+ type: "object",
+ properties: {
+
+ // Allow/Disallow `export default foo; export default 42; export default function foo() {}` format
+ direct: {
+ type: "boolean"
+ },
+
+ // Allow/Disallow `export { foo as default };` declarations
+ named: {
+ type: "boolean"
+ },
+
+ // Allow/Disallow `export { default } from "mod"; export { default as default } from "mod";` declarations
+ defaultFrom: {
+ type: "boolean"
+ },
+
+ // Allow/Disallow `export { foo as default } from "mod";` declarations
+ namedFrom: {
+ type: "boolean"
+ },
+
+ // Allow/Disallow `export * as default from "mod"`; declarations
+ namespaceFrom: {
+ type: "boolean"
+ }
+ },
+ additionalProperties: false
+ }
+ },
+ additionalProperties: false
}
- },
- additionalProperties: false
+ ]
}],
messages: {
- restrictedNamed: "'{{name}}' is restricted from being used as an exported name."
+ restrictedNamed: "'{{name}}' is restricted from being used as an exported name.",
+ restrictedDefault: "Exporting 'default' is restricted."
}
},
create(context) {
const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports);
+ const restrictDefaultExports = context.options[0] && context.options[0].restrictDefaultExports;
+ const sourceCode = context.sourceCode;
/**
* Checks and reports given exported name.
messageId: "restrictedNamed",
data: { name }
});
+ return;
+ }
+
+ if (name === "default") {
+ if (node.parent.type === "ExportAllDeclaration") {
+ if (restrictDefaultExports && restrictDefaultExports.namespaceFrom) {
+ context.report({
+ node,
+ messageId: "restrictedDefault"
+ });
+ }
+
+ } else { // ExportSpecifier
+ const isSourceSpecified = !!node.parent.parent.source;
+ const specifierLocalName = astUtils.getModuleExportName(node.parent.local);
+
+ if (!isSourceSpecified && restrictDefaultExports && restrictDefaultExports.named) {
+ context.report({
+ node,
+ messageId: "restrictedDefault"
+ });
+ return;
+ }
+
+ if (isSourceSpecified && restrictDefaultExports) {
+ if (
+ (specifierLocalName === "default" && restrictDefaultExports.defaultFrom) ||
+ (specifierLocalName !== "default" && restrictDefaultExports.namedFrom)
+ ) {
+ context.report({
+ node,
+ messageId: "restrictedDefault"
+ });
+ }
+ }
+ }
}
}
}
},
+ ExportDefaultDeclaration(node) {
+ if (restrictDefaultExports && restrictDefaultExports.direct) {
+ context.report({
+ node,
+ messageId: "restrictedDefault"
+ });
+ }
+ },
+
ExportNamedDeclaration(node) {
const declaration = node.declaration;
if (declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") {
checkExportedName(declaration.id);
} else if (declaration.type === "VariableDeclaration") {
- context.getDeclaredVariables(declaration)
+ sourceCode.getDeclaredVariables(declaration)
.map(v => v.defs.find(d => d.parent === declaration))
.map(d => d.name) // Identifier nodes
.forEach(checkExportedName);
docs: {
description: "Disallow specified global variables",
recommended: false,
- url: "https://eslint.org/docs/rules/no-restricted-globals"
+ url: "https://eslint.org/docs/latest/rules/no-restricted-globals"
},
schema: {
create(context) {
+ const sourceCode = context.sourceCode;
+
// If no globals are restricted, we don't need to do anything
if (context.options.length === 0) {
return {};
}
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
// Report variables declared elsewhere (ex: variables defined as "global" by eslint)
scope.variables.forEach(variable => {
docs: {
description: "Disallow specified modules when loaded by `import`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-restricted-imports"
+ url: "https://eslint.org/docs/latest/rules/no-restricted-imports"
},
messages: {
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const options = Array.isArray(context.options) ? context.options : [];
const isPathAndPatternsObject =
typeof options[0] === "object" &&
docs: {
description: "Disallow specified modules when loaded by `require`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-restricted-modules"
+ url: "https://eslint.org/docs/latest/rules/no-restricted-modules"
},
schema: {
docs: {
description: "Disallow certain properties on certain objects",
recommended: false,
- url: "https://eslint.org/docs/rules/no-restricted-properties"
+ url: "https://eslint.org/docs/latest/rules/no-restricted-properties"
},
schema: {
docs: {
description: "Disallow specified syntax",
recommended: false,
- url: "https://eslint.org/docs/rules/no-restricted-syntax"
+ url: "https://eslint.org/docs/latest/rules/no-restricted-syntax"
},
schema: {
docs: {
description: "Disallow assignment operators in `return` statements",
recommended: false,
- url: "https://eslint.org/docs/rules/no-return-assign"
+ url: "https://eslint.org/docs/latest/rules/no-return-assign"
},
schema: [
create(context) {
const always = (context.options[0] || "except-parens") !== "except-parens";
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
AssignmentExpression(node) {
/** @type {import('../shared/types').Rule} */
module.exports = {
meta: {
+ hasSuggestions: true,
type: "suggestion",
docs: {
recommended: false,
- url: "https://eslint.org/docs/rules/no-return-await"
+ url: "https://eslint.org/docs/latest/rules/no-return-await"
},
fixable: null,
],
messages: {
+ removeAwait: "Remove redundant `await`.",
redundantUseOfAwait: "Redundant use of `await` on a return value."
}
},
*/
function reportUnnecessaryAwait(node) {
context.report({
- node: context.getSourceCode().getFirstToken(node),
+ node: context.sourceCode.getFirstToken(node),
loc: node.loc,
- messageId: "redundantUseOfAwait"
+ messageId: "redundantUseOfAwait",
+ suggest: [
+ {
+ messageId: "removeAwait",
+ fix(fixer) {
+ const sourceCode = context.sourceCode;
+ const [awaitToken, tokenAfterAwait] = sourceCode.getFirstTokens(node, 2);
+
+ const areAwaitAndAwaitedExpressionOnTheSameLine = awaitToken.loc.start.line === tokenAfterAwait.loc.start.line;
+
+ if (!areAwaitAndAwaitedExpressionOnTheSameLine) {
+ return null;
+ }
+
+ const [startOfAwait, endOfAwait] = awaitToken.range;
+
+ const characterAfterAwait = sourceCode.text[endOfAwait];
+ const trimLength = characterAfterAwait === " " ? 1 : 0;
+
+ const range = [startOfAwait, endOfAwait + trimLength];
+
+ return fixer.removeRange(range);
+ }
+ }
+ ]
+
});
}
docs: {
description: "Disallow `javascript:` urls",
recommended: false,
- url: "https://eslint.org/docs/rules/no-script-url"
+ url: "https://eslint.org/docs/latest/rules/no-script-url"
},
schema: [],
docs: {
description: "Disallow assignments where both sides are exactly the same",
recommended: true,
- url: "https://eslint.org/docs/rules/no-self-assign"
+ url: "https://eslint.org/docs/latest/rules/no-self-assign"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const [{ props = true } = {}] = context.options;
/**
docs: {
description: "Disallow comparisons where both sides are exactly the same",
recommended: false,
- url: "https://eslint.org/docs/rules/no-self-compare"
+ url: "https://eslint.org/docs/latest/rules/no-self-compare"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Determines whether two nodes are composed of the same tokens.
docs: {
description: "Disallow comma operators",
recommended: false,
- url: "https://eslint.org/docs/rules/no-sequences"
+ url: "https://eslint.org/docs/latest/rules/no-sequences"
},
schema: [{
create(context) {
const options = Object.assign({}, DEFAULT_OPTIONS, context.options[0]);
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Parts of the grammar that are required to have parens.
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const { findVariable } = require("eslint-utils");
+const { findVariable } = require("@eslint-community/eslint-utils");
//------------------------------------------------------------------------------
// Helpers
docs: {
description: "Disallow returning values from setters",
recommended: true,
- url: "https://eslint.org/docs/rules/no-setter-return"
+ url: "https://eslint.org/docs/latest/rules/no-setter-return"
},
schema: [],
create(context) {
let funcInfo = null;
+ const sourceCode = context.sourceCode;
/**
* Creates and pushes to the stack a function info object for the given function node.
* @returns {void}
*/
function enterFunction(node) {
- const outerScope = getOuterScope(context.getScope());
+ const outerScope = getOuterScope(sourceCode.getScope(node));
funcInfo = {
upper: funcInfo,
docs: {
description: "Disallow identifiers from shadowing restricted names",
recommended: true,
- url: "https://eslint.org/docs/rules/no-shadow-restricted-names"
+ url: "https://eslint.org/docs/latest/rules/no-shadow-restricted-names"
},
schema: [],
const RESTRICTED = new Set(["undefined", "NaN", "Infinity", "arguments", "eval"]);
+ const sourceCode = context.sourceCode;
return {
"VariableDeclaration, :function, CatchClause"(node) {
- for (const variable of context.getDeclaredVariables(node)) {
+ for (const variable of sourceCode.getDeclaredVariables(node)) {
if (variable.defs.length > 0 && RESTRICTED.has(variable.name) && !safelyShadowsUndefined(variable)) {
context.report({
node: variable.defs[0].name,
docs: {
description: "Disallow variable declarations from shadowing variables declared in the outer scope",
recommended: false,
- url: "https://eslint.org/docs/rules/no-shadow"
+ url: "https://eslint.org/docs/latest/rules/no-shadow"
},
schema: [
allow: (context.options[0] && context.options[0].allow) || [],
ignoreOnInitialization: context.options[0] && context.options[0].ignoreOnInitialization
};
+ const sourceCode = context.sourceCode;
/**
* Checks whether or not a given location is inside of the range of a given node.
}
return {
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
const stack = globalScope.childScopes.slice();
while (stack.length) {
docs: {
description: "Disallow spacing between function identifiers and their applications (deprecated)",
recommended: false,
- url: "https://eslint.org/docs/rules/no-spaced-func"
+ url: "https://eslint.org/docs/latest/rules/no-spaced-func"
},
deprecated: true,
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Check if open space is present in a function name
docs: {
description: "Disallow sparse arrays",
recommended: true,
- url: "https://eslint.org/docs/rules/no-sparse-arrays"
+ url: "https://eslint.org/docs/latest/rules/no-sparse-arrays"
},
schema: [],
docs: {
description: "Disallow synchronous methods",
recommended: false,
- url: "https://eslint.org/docs/rules/no-sync"
+ url: "https://eslint.org/docs/latest/rules/no-sync"
},
schema: [
docs: {
description: "Disallow all tabs",
recommended: false,
- url: "https://eslint.org/docs/rules/no-tabs"
+ url: "https://eslint.org/docs/latest/rules/no-tabs"
},
schema: [{
type: "object",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const allowIndentationTabs = context.options && context.options[0] && context.options[0].allowIndentationTabs;
return {
docs: {
description: "Disallow template literal placeholder syntax in regular strings",
recommended: false,
- url: "https://eslint.org/docs/rules/no-template-curly-in-string"
+ url: "https://eslint.org/docs/latest/rules/no-template-curly-in-string"
},
schema: [],
docs: {
description: "Disallow ternary operators",
recommended: false,
- url: "https://eslint.org/docs/rules/no-ternary"
+ url: "https://eslint.org/docs/latest/rules/no-ternary"
},
schema: [],
docs: {
description: "Disallow `this`/`super` before calling `super()` in constructors",
recommended: true,
- url: "https://eslint.org/docs/rules/no-this-before-super"
+ url: "https://eslint.org/docs/latest/rules/no-this-before-super"
},
schema: [],
docs: {
description: "Disallow throwing literals as exceptions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-throw-literal"
+ url: "https://eslint.org/docs/latest/rules/no-throw-literal"
},
schema: [],
docs: {
description: "Disallow trailing whitespace at the end of lines",
recommended: false,
- url: "https://eslint.org/docs/rules/no-trailing-spaces"
+ url: "https://eslint.org/docs/latest/rules/no-trailing-spaces"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const BLANK_CLASS = "[ \t\u00a0\u2000-\u200b\u3000]",
SKIP_BLANK = `^${BLANK_CLASS}*$`,
docs: {
description: "Disallow initializing variables to `undefined`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-undef-init"
+ url: "https://eslint.org/docs/latest/rules/no-undef-init"
},
schema: [],
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
VariableDeclarator(node) {
const name = sourceCode.getText(node.id),
init = node.init && node.init.name,
- scope = context.getScope(),
+ scope = sourceCode.getScope(node),
undefinedVar = astUtils.getVariableByName(scope, "undefined"),
shadowed = undefinedVar && undefinedVar.defs.length > 0,
lastToken = sourceCode.getLastToken(node);
docs: {
description: "Disallow the use of undeclared variables unless mentioned in `/*global */` comments",
recommended: true,
- url: "https://eslint.org/docs/rules/no-undef"
+ url: "https://eslint.org/docs/latest/rules/no-undef"
},
schema: [
create(context) {
const options = context.options[0];
const considerTypeOf = options && options.typeof === true || false;
+ const sourceCode = context.sourceCode;
return {
- "Program:exit"(/* node */) {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
globalScope.through.forEach(ref => {
const identifier = ref.identifier;
docs: {
description: "Disallow the use of `undefined` as an identifier",
recommended: false,
- url: "https://eslint.org/docs/rules/no-undefined"
+ url: "https://eslint.org/docs/latest/rules/no-undefined"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Report an invalid "undefined" identifier node.
* @param {ASTNode} node The node to report.
}
return {
- "Program:exit"() {
- const globalScope = context.getScope();
+ "Program:exit"(node) {
+ const globalScope = sourceCode.getScope(node);
const stack = [globalScope];
docs: {
description: "Disallow dangling underscores in identifiers",
recommended: false,
- url: "https://eslint.org/docs/rules/no-underscore-dangle"
+ url: "https://eslint.org/docs/latest/rules/no-underscore-dangle"
},
schema: [
enforceInClassFields: {
type: "boolean",
default: false
+ },
+ allowInArrayDestructuring: {
+ type: "boolean",
+ default: true
+ },
+ allowInObjectDestructuring: {
+ type: "boolean",
+ default: true
}
},
additionalProperties: false
const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
const enforceInClassFields = typeof options.enforceInClassFields !== "undefined" ? options.enforceInClassFields : false;
const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
+ const allowInArrayDestructuring = typeof options.allowInArrayDestructuring !== "undefined" ? options.allowInArrayDestructuring : true;
+ const allowInObjectDestructuring = typeof options.allowInObjectDestructuring !== "undefined" ? options.allowInObjectDestructuring : true;
+ const sourceCode = context.sourceCode;
//-------------------------------------------------------------------------
// Helpers
checkForDanglingUnderscoreInFunctionParameters(node);
}
+
/**
* Check if variable expression has a dangling underscore
* @param {ASTNode} node node to evaluate
* @private
*/
function checkForDanglingUnderscoreInVariableExpression(node) {
- const identifier = node.id.name;
+ sourceCode.getDeclaredVariables(node).forEach(variable => {
+ const definition = variable.defs.find(def => def.node === node);
+ const identifierNode = definition.name;
+ const identifier = identifierNode.name;
+ let parent = identifierNode.parent;
+
+ while (!["VariableDeclarator", "ArrayPattern", "ObjectPattern"].includes(parent.type)) {
+ parent = parent.parent;
+ }
- if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
- !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
- context.report({
- node,
- messageId: "unexpectedUnderscore",
- data: {
- identifier
- }
- });
- }
+ if (
+ hasDanglingUnderscore(identifier) &&
+ !isSpecialCaseIdentifierInVariableExpression(identifier) &&
+ !isAllowed(identifier) &&
+ !(allowInArrayDestructuring && parent.type === "ArrayPattern") &&
+ !(allowInObjectDestructuring && parent.type === "ObjectPattern")
+ ) {
+ context.report({
+ node,
+ messageId: "unexpectedUnderscore",
+ data: {
+ identifier
+ }
+ });
+ }
+ });
}
/**
docs: {
description: "Disallow confusing multiline expressions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unexpected-multiline"
+ url: "https://eslint.org/docs/latest/rules/no-unexpected-multiline"
},
schema: [],
const REGEX_FLAG_MATCHER = /^[gimsuy]+$/u;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Check to see if there is a newline between the node and the following open bracket
docs: {
description: "Disallow unmodified loop conditions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-unmodified-loop-condition"
+ url: "https://eslint.org/docs/latest/rules/no-unmodified-loop-condition"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let groupMap = null;
/**
}
return {
- "Program:exit"() {
- const queue = [context.getScope()];
+ "Program:exit"(node) {
+ const queue = [sourceCode.getScope(node)];
groupMap = new Map();
docs: {
description: "Disallow ternary operators when simpler alternatives exist",
recommended: false,
- url: "https://eslint.org/docs/rules/no-unneeded-ternary"
+ url: "https://eslint.org/docs/latest/rules/no-unneeded-ternary"
},
schema: [
create(context) {
const options = context.options[0] || {};
const defaultAssignment = options.defaultAssignment !== false;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Test if the node is a boolean literal
context.report({
node,
messageId: "unnecessaryConditionalAssignment",
- fix: fixer => {
+ fix(fixer) {
const shouldParenthesizeAlternate =
(
astUtils.getPrecedence(node.alternate) < OR_PRECEDENCE ||
docs: {
description: "Disallow loops with a body that allows only one iteration",
recommended: false,
- url: "https://eslint.org/docs/rules/no-unreachable-loop"
+ url: "https://eslint.org/docs/latest/rules/no-unreachable-loop"
},
schema: [{
docs: {
description: "Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unreachable"
+ url: "https://eslint.org/docs/latest/rules/no-unreachable"
},
schema: [],
let constructorInfo = null;
/** @type {ConsecutiveRange} */
- const range = new ConsecutiveRange(context.getSourceCode());
+ const range = new ConsecutiveRange(context.sourceCode);
/**
* Reports a given node if it's unreachable.
docs: {
description: "Disallow control flow statements in `finally` blocks",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unsafe-finally"
+ url: "https://eslint.org/docs/latest/rules/no-unsafe-finally"
},
schema: [],
docs: {
description: "Disallow negating the left operand of relational operators",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unsafe-negation"
+ url: "https://eslint.org/docs/latest/rules/no-unsafe-negation"
},
hasSuggestions: true,
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const options = context.options[0] || {};
const enforceForOrderingRelations = options.enforceForOrderingRelations === true;
docs: {
description: "Disallow use of optional chaining in contexts where the `undefined` value is not allowed",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unsafe-optional-chaining"
+ url: "https://eslint.org/docs/latest/rules/no-unsafe-optional-chaining"
},
schema: [{
type: "object",
docs: {
description: "Disallow unused expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/no-unused-expressions"
+ url: "https://eslint.org/docs/latest/rules/no-unused-expressions"
},
schema: [
/**
* Detect if a Node is a directive.
* @param {ASTNode} node any node
- * @param {ASTNode[]} ancestors the given node's ancestors
* @returns {boolean} whether the given node is considered a directive in its current position
*/
- function isDirective(node, ancestors) {
- const parent = ancestors[ancestors.length - 1],
- grandparent = ancestors[ancestors.length - 2];
+ function isDirective(node) {
+ const parent = node.parent,
+ grandparent = parent.parent;
/**
* https://tc39.es/ecma262/#directive-prologue
return {
ExpressionStatement(node) {
- if (Checker.isDisallowed(node.expression) && !isDirective(node, context.getAncestors())) {
+ if (Checker.isDisallowed(node.expression) && !isDirective(node)) {
context.report({ node, messageId: "unusedExpression" });
}
}
docs: {
description: "Disallow unused labels",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unused-labels"
+ url: "https://eslint.org/docs/latest/rules/no-unused-labels"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let scopeInfo = null;
/**
docs: {
description: "Disallow unused private class members",
recommended: false,
- url: "https://eslint.org/docs/rules/no-unused-private-class-members"
+ url: "https://eslint.org/docs/latest/rules/no-unused-private-class-members"
},
schema: [],
docs: {
description: "Disallow unused variables",
recommended: true,
- url: "https://eslint.org/docs/rules/no-unused-vars"
+ url: "https://eslint.org/docs/latest/rules/no-unused-vars"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const REST_PROPERTY_TYPE = /^(?:RestElement|(?:Experimental)?RestProperty)$/u;
*/
function isAfterLastUsedArg(variable) {
const def = variable.defs[0];
- const params = context.getDeclaredVariables(def.node);
+ const params = sourceCode.getDeclaredVariables(def.node);
const posteriorParams = params.slice(params.indexOf(variable) + 1);
// If any used parameters occur after this parameter, do not report.
return {
"Program:exit"(programNode) {
- const unusedVars = collectUnusedVariables(context.getScope(), []);
+ const unusedVars = collectUnusedVariables(sourceCode.getScope(programNode), []);
for (let i = 0, l = unusedVars.length; i < l; ++i) {
const unusedVar = unusedVars[i];
}
/**
- * Checks whether a given scope is the scope of a a class static initializer.
+ * Checks whether a given scope is the scope of a class static initializer.
* Static initializers are static blocks and initializers of static fields.
* @param {eslint-scope.Scope} scope A scope to check.
* @returns {boolean} `true` if the scope is a class static initializer scope.
docs: {
description: "Disallow the use of variables before they are defined",
recommended: false,
- url: "https://eslint.org/docs/rules/no-use-before-define"
+ url: "https://eslint.org/docs/latest/rules/no-use-before-define"
},
schema: [
create(context) {
const options = parseOptions(context.options[0]);
+ const sourceCode = context.sourceCode;
/**
* Determines whether a given reference should be checked.
}
return {
- Program() {
- checkReferencesInScope(context.getScope());
+ Program(node) {
+ checkReferencesInScope(sourceCode.getScope(node));
}
};
}
// Requirements
//------------------------------------------------------------------------------
-const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("eslint-utils");
-const { RegExpParser, visitRegExpAST } = require("regexpp");
+const { CALL, CONSTRUCT, ReferenceTracker, getStringIfConstant } = require("@eslint-community/eslint-utils");
+const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
//------------------------------------------------------------------------------
// Helpers
docs: {
description: "Disallow useless backreferences in regular expressions",
recommended: true,
- url: "https://eslint.org/docs/rules/no-useless-backreference"
+ url: "https://eslint.org/docs/latest/rules/no-useless-backreference"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Checks and reports useless backreferences in the given regular expression.
* @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call.
checkRegex(node, pattern, flags);
},
- Program() {
- const scope = context.getScope(),
+ Program(node) {
+ const scope = sourceCode.getScope(node),
tracker = new ReferenceTracker(scope),
traceMap = {
RegExp: {
}
};
- for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
- const [patternNode, flagsNode] = node.arguments,
+ for (const { node: refNode } of tracker.iterateGlobalReferences(traceMap)) {
+ const [patternNode, flagsNode] = refNode.arguments,
pattern = getStringIfConstant(patternNode, scope),
flags = getStringIfConstant(flagsNode, scope);
if (typeof pattern === "string") {
- checkRegex(node, pattern, flags || "");
+ checkRegex(refNode, pattern, flags || "");
}
}
}
docs: {
description: "Disallow unnecessary calls to `.call()` and `.apply()`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-useless-call"
+ url: "https://eslint.org/docs/latest/rules/no-useless-call"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
CallExpression(node) {
docs: {
description: "Disallow unnecessary `catch` clauses",
recommended: true,
- url: "https://eslint.org/docs/rules/no-useless-catch"
+ url: "https://eslint.org/docs/latest/rules/no-useless-catch"
},
schema: [],
docs: {
description: "Disallow unnecessary computed property keys in objects and classes",
recommended: false,
- url: "https://eslint.org/docs/rules/no-useless-computed-key"
+ url: "https://eslint.org/docs/latest/rules/no-useless-computed-key"
},
schema: [{
}
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const enforceForClassMembers = context.options[0] && context.options[0].enforceForClassMembers;
/**
docs: {
description: "Disallow unnecessary concatenation of literals or template literals",
recommended: false,
- url: "https://eslint.org/docs/rules/no-useless-concat"
+ url: "https://eslint.org/docs/latest/rules/no-useless-concat"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
BinaryExpression(node) {
docs: {
description: "Disallow unnecessary constructors",
recommended: false,
- url: "https://eslint.org/docs/rules/no-useless-constructor"
+ url: "https://eslint.org/docs/latest/rules/no-useless-constructor"
},
schema: [],
docs: {
description: "Disallow unnecessary escape characters",
recommended: true,
- url: "https://eslint.org/docs/rules/no-useless-escape"
+ url: "https://eslint.org/docs/latest/rules/no-useless-escape"
},
hasSuggestions: true,
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports a node
docs: {
description: "Disallow renaming import, export, and destructured assignments to the same name",
recommended: false,
- url: "https://eslint.org/docs/rules/no-useless-rename"
+ url: "https://eslint.org/docs/latest/rules/no-useless-rename"
},
fixable: "code",
},
create(context) {
- const sourceCode = context.getSourceCode(),
+ const sourceCode = context.sourceCode,
options = context.options[0] || {},
ignoreDestructuring = options.ignoreDestructuring === true,
ignoreImport = options.ignoreImport === true,
docs: {
description: "Disallow redundant return statements",
recommended: false,
- url: "https://eslint.org/docs/rules/no-useless-return"
+ url: "https://eslint.org/docs/latest/rules/no-useless-return"
},
fixable: "code",
create(context) {
const segmentInfoMap = new WeakMap();
const usedUnreachableSegments = new WeakSet();
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let scopeInfo = null;
/**
return {
- // Makes and pushs a new scope information.
+ // Makes and pushes a new scope information.
onCodePathStart(codePath) {
scopeInfo = {
upper: scopeInfo,
return !reference.init && (
start < idStart ||
(defaultValue !== null && start >= defaultStart && end <= defaultEnd) ||
- (start >= initStart && end <= initEnd)
+ (!astUtils.isFunction(node) && start >= initStart && end <= initEnd)
);
});
};
docs: {
description: "Require `let` or `const` instead of `var`",
recommended: false,
- url: "https://eslint.org/docs/rules/no-var"
+ url: "https://eslint.org/docs/latest/rules/no-var"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Checks whether the variables which are defined by the given declarator node have their references in TDZ.
if (!declarator.init) {
return false;
}
- const variables = context.getDeclaredVariables(declarator);
+ const variables = sourceCode.getDeclaredVariables(declarator);
return variables.some(hasReferenceInTDZ(declarator.init));
}
* @returns {boolean} `true` if it can fix the node.
*/
function canFix(node) {
- const variables = context.getDeclaredVariables(node);
+ const variables = sourceCode.getDeclaredVariables(node);
const scopeNode = getScopeNode(node);
if (node.parent.type === "SwitchCase" ||
docs: {
description: "Disallow `void` operators",
recommended: false,
- url: "https://eslint.org/docs/rules/no-void"
+ url: "https://eslint.org/docs/latest/rules/no-void"
},
messages: {
docs: {
description: "Disallow specified warning terms in comments",
recommended: false,
- url: "https://eslint.org/docs/rules/no-warning-comments"
+ url: "https://eslint.org/docs/latest/rules/no-warning-comments"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode(),
+ const sourceCode = context.sourceCode,
configuration = context.options[0] || {},
warningTerms = configuration.terms || ["todo", "fixme", "xxx"],
location = configuration.location || "start",
docs: {
description: "Disallow whitespace before properties",
recommended: false,
- url: "https://eslint.org/docs/rules/no-whitespace-before-property"
+ url: "https://eslint.org/docs/latest/rules/no-whitespace-before-property"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Disallow `with` statements",
recommended: true,
- url: "https://eslint.org/docs/rules/no-with"
+ url: "https://eslint.org/docs/latest/rules/no-with"
},
schema: [],
docs: {
description: "Enforce the location of single-line statements",
recommended: false,
- url: "https://eslint.org/docs/rules/nonblock-statement-body-position"
+ url: "https://eslint.org/docs/latest/rules/nonblock-statement-body-position"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//----------------------------------------------------------------------
// Helpers
docs: {
description: "Enforce consistent line breaks after opening and before closing braces",
recommended: false,
- url: "https://eslint.org/docs/rules/object-curly-newline"
+ url: "https://eslint.org/docs/latest/rules/object-curly-newline"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const normalizedOptions = normalizeOptions(context.options[0]);
/**
docs: {
description: "Enforce consistent spacing inside braces",
recommended: false,
- url: "https://eslint.org/docs/rules/object-curly-spacing"
+ url: "https://eslint.org/docs/latest/rules/object-curly-spacing"
},
fixable: "whitespace",
create(context) {
const spaced = context.options[0] === "always",
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
/**
* Determines whether an option is set, relative to the spacing option.
* @returns {void}
*/
function reportNoBeginningSpace(node, token) {
- const nextToken = context.getSourceCode().getTokenAfter(token, { includeComments: true });
+ const nextToken = context.sourceCode.getTokenAfter(token, { includeComments: true });
context.report({
node,
* @returns {void}
*/
function reportNoEndingSpace(node, token) {
- const previousToken = context.getSourceCode().getTokenBefore(token, { includeComments: true });
+ const previousToken = context.sourceCode.getTokenBefore(token, { includeComments: true });
context.report({
node,
docs: {
description: "Enforce placing object properties on separate lines",
recommended: false,
- url: "https://eslint.org/docs/rules/object-property-newline"
+ url: "https://eslint.org/docs/latest/rules/object-property-newline"
},
schema: [
? "propertiesOnNewlineAll"
: "propertiesOnNewline";
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
ObjectExpression(node) {
docs: {
description: "Require or disallow method and property shorthand syntax for object literals",
recommended: false,
- url: "https://eslint.org/docs/rules/object-shorthand"
+ url: "https://eslint.org/docs/latest/rules/object-shorthand"
},
fixable: "code",
: null;
const AVOID_QUOTES = PARAMS.avoidQuotes;
const AVOID_EXPLICIT_RETURN_ARROWS = !!PARAMS.avoidExplicitReturnArrows;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
/**
* Enters a function. This creates a new lexical identifier scope, so a new Set of arrow functions is pushed onto the stack.
* Also, this marks all `arguments` identifiers so that they can be detected later.
+ * @param {ASTNode} node The node representing the function.
* @returns {void}
*/
- function enterFunction() {
+ function enterFunction(node) {
lexicalScopeStack.unshift(new Set());
- context.getScope().variables.filter(variable => variable.name === "arguments").forEach(variable => {
+ sourceCode.getScope(node).variables.filter(variable => variable.name === "arguments").forEach(variable => {
variable.references.map(ref => ref.identifier).forEach(identifier => argumentsIdentifiers.add(identifier));
});
}
docs: {
description: "Require or disallow newlines around variable declarations",
recommended: false,
- url: "https://eslint.org/docs/rules/one-var-declaration-per-line"
+ url: "https://eslint.org/docs/latest/rules/one-var-declaration-per-line"
},
schema: [
docs: {
description: "Enforce variables to be declared either together or separately in functions",
recommended: false,
- url: "https://eslint.org/docs/rules/one-var"
+ url: "https://eslint.org/docs/latest/rules/one-var"
},
fixable: "code",
}
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Require or disallow assignment operator shorthand where possible",
recommended: false,
- url: "https://eslint.org/docs/rules/operator-assignment"
+ url: "https://eslint.org/docs/latest/rules/operator-assignment"
},
schema: [
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Returns the operator token of an AssignmentExpression or BinaryExpression
docs: {
description: "Enforce consistent linebreak style for operators",
recommended: false,
- url: "https://eslint.org/docs/rules/operator-linebreak"
+ url: "https://eslint.org/docs/latest/rules/operator-linebreak"
},
schema: [
styleOverrides[":"] = "before";
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Require or disallow padding within blocks",
recommended: false,
- url: "https://eslint.org/docs/rules/padded-blocks"
+ url: "https://eslint.org/docs/latest/rules/padded-blocks"
},
fixable: "whitespace",
options.allowSingleLineBlocks = exceptOptions.allowSingleLineBlocks === true;
}
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Gets the open brace token from a given node.
const nextToken = paddingLines[0][1];
const start = prevToken.range[1];
const end = nextToken.range[0];
- const text = context.getSourceCode().text
+ const text = context.sourceCode.text
.slice(start, end)
.replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
node: nextNode,
messageId: "expectedBlankLine",
fix(fixer) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let prevToken = getActualLastToken(sourceCode, prevNode);
const nextToken = sourceCode.getFirstTokenBetween(
prevToken,
docs: {
description: "Require or disallow padding lines between statements",
recommended: false,
- url: "https://eslint.org/docs/rules/padding-line-between-statements"
+ url: "https://eslint.org/docs/latest/rules/padding-line-between-statements"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const configureList = context.options || [];
let scopeInfo = null;
docs: {
description: "Require using arrow functions for callbacks",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-arrow-callback"
+ url: "https://eslint.org/docs/latest/rules/prefer-arrow-callback"
},
schema: [
const allowUnboundThis = options.allowUnboundThis !== false; // default to true
const allowNamedFunctions = options.allowNamedFunctions;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/*
* {Array<{this: boolean, super: boolean, meta: boolean}>}
}
// Skip recursive functions.
- const nameVar = context.getDeclaredVariables(node)[0];
+ const nameVar = sourceCode.getDeclaredVariables(node)[0];
if (isFunctionName(nameVar) && nameVar.references.length > 0) {
return;
}
// Skip if it's using arguments.
- const variable = getVariableOfArguments(context.getScope());
+ const variable = getVariableOfArguments(sourceCode.getScope(node));
if (variable && variable.references.length > 0) {
return;
// Convert the function expression to an arrow function.
const functionToken = sourceCode.getFirstToken(node, node.async ? 1 : 0);
const leftParenToken = sourceCode.getTokenAfter(functionToken, astUtils.isOpeningParenToken);
+ const tokenBeforeBody = sourceCode.getTokenBefore(node.body);
if (sourceCode.commentsExistBetween(functionToken, leftParenToken)) {
// Remove extra tokens and spaces.
yield fixer.removeRange([functionToken.range[0], leftParenToken.range[0]]);
}
- yield fixer.insertTextBefore(node.body, "=> ");
+ yield fixer.insertTextAfter(tokenBeforeBody, " =>");
// Get the node that will become the new arrow function.
let replacedNode = callbackInfo.isLexicalThis ? node.parent.parent : node;
docs: {
description: "Require `const` declarations for variables that are never reassigned after declared",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-const"
+ url: "https://eslint.org/docs/latest/rules/prefer-const"
},
fixable: "code",
create(context) {
const options = context.options[0] || {};
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const shouldMatchAnyDestructuredVariable = options.destructuring !== "all";
const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true;
const variables = [];
VariableDeclaration(node) {
if (node.kind === "let" && !isInitOfForStatement(node)) {
- variables.push(...context.getDeclaredVariables(node));
+ variables.push(...sourceCode.getDeclaredVariables(node));
}
}
};
docs: {
description: "Require destructuring from arrays and/or objects",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-destructuring"
+ url: "https://eslint.org/docs/latest/rules/prefer-destructuring"
},
fixable: "code",
*/
function fixIntoObjectDestructuring(fixer, node) {
const rightNode = node.init;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
// Don't fix if that would remove any comments. Only comments inside `rightNode.object` can be preserved.
if (sourceCode.getCommentsInside(node).length > sourceCode.getCommentsInside(rightNode.object).length) {
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const { CALL, ReferenceTracker } = require("eslint-utils");
+const { CALL, ReferenceTracker } = require("@eslint-community/eslint-utils");
//------------------------------------------------------------------------------
// Helpers
docs: {
description: "Disallow the use of `Math.pow` in favor of the `**` operator",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-exponentiation-operator"
+ url: "https://eslint.org/docs/latest/rules/prefer-exponentiation-operator"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Reports the given node.
}
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
const trackMap = {
Math: {
}
};
- for (const { node } of tracker.iterateGlobalReferences(trackMap)) {
- report(node);
+ for (const { node: refNode } of tracker.iterateGlobalReferences(trackMap)) {
+ report(refNode);
}
}
};
CONSTRUCT,
ReferenceTracker,
getStringIfConstant
-} = require("eslint-utils");
-const regexpp = require("regexpp");
+} = require("@eslint-community/eslint-utils");
+const regexpp = require("@eslint-community/regexpp");
//------------------------------------------------------------------------------
// Helpers
const parser = new regexpp.RegExpParser();
+/**
+ * Creates fixer suggestions for the regex, if statically determinable.
+ * @param {number} groupStart Starting index of the regex group.
+ * @param {string} pattern The regular expression pattern to be checked.
+ * @param {string} rawText Source text of the regexNode.
+ * @param {ASTNode} regexNode AST node which contains the regular expression.
+ * @returns {Array<SuggestionResult>} Fixer suggestions for the regex, if statically determinable.
+ */
+function suggestIfPossible(groupStart, pattern, rawText, regexNode) {
+ switch (regexNode.type) {
+ case "Literal":
+ if (typeof regexNode.value === "string" && rawText.includes("\\")) {
+ return null;
+ }
+ break;
+ case "TemplateLiteral":
+ if (regexNode.expressions.length || rawText.slice(1, -1) !== pattern) {
+ return null;
+ }
+ break;
+ default:
+ return null;
+ }
+
+ const start = regexNode.range[0] + groupStart + 2;
+
+ return [
+ {
+ fix(fixer) {
+ const existingTemps = pattern.match(/temp\d+/gu) || [];
+ const highestTempCount = existingTemps.reduce(
+ (previous, next) =>
+ Math.max(previous, Number(next.slice("temp".length))),
+ 0
+ );
+
+ return fixer.insertTextBeforeRange(
+ [start, start],
+ `?<temp${highestTempCount + 1}>`
+ );
+ },
+ messageId: "addGroupName"
+ },
+ {
+ fix(fixer) {
+ return fixer.insertTextBeforeRange(
+ [start, start],
+ "?:"
+ );
+ },
+ messageId: "addNonCapture"
+ }
+ ];
+}
+
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
docs: {
description: "Enforce using named capture group in regular expression",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-named-capture-group"
+ url: "https://eslint.org/docs/latest/rules/prefer-named-capture-group"
},
+ hasSuggestions: true,
+
schema: [],
messages: {
+ addGroupName: "Add name to capture group.",
+ addNonCapture: "Convert group to non-capturing.",
required: "Capture group '{{group}}' should be converted to a named or non-capturing group."
}
},
create(context) {
+ const sourceCode = context.sourceCode;
/**
* Function to check regular expression.
- * @param {string} pattern The regular expression pattern to be check.
- * @param {ASTNode} node AST node which contains regular expression.
+ * @param {string} pattern The regular expression pattern to be checked.
+ * @param {ASTNode} node AST node which contains the regular expression or a call/new expression.
+ * @param {ASTNode} regexNode AST node which contains the regular expression.
* @param {boolean} uFlag Flag indicates whether unicode mode is enabled or not.
* @returns {void}
*/
- function checkRegex(pattern, node, uFlag) {
+ function checkRegex(pattern, node, regexNode, uFlag) {
let ast;
try {
regexpp.visitRegExpAST(ast, {
onCapturingGroupEnter(group) {
if (!group.name) {
+ const rawText = sourceCode.getText(regexNode);
+ const suggest = suggestIfPossible(group.start, pattern, rawText, regexNode);
+
context.report({
node,
messageId: "required",
data: {
group: group.raw
- }
+ },
+ suggest
});
}
}
return {
Literal(node) {
if (node.regex) {
- checkRegex(node.regex.pattern, node, node.regex.flags.includes("u"));
+ checkRegex(node.regex.pattern, node, node, node.regex.flags.includes("u"));
}
},
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
const traceMap = {
RegExp: {
}
};
- for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
- const regex = getStringIfConstant(node.arguments[0]);
- const flags = getStringIfConstant(node.arguments[1]);
+ for (const { node: refNode } of tracker.iterateGlobalReferences(traceMap)) {
+ const regex = getStringIfConstant(refNode.arguments[0]);
+ const flags = getStringIfConstant(refNode.arguments[1]);
if (regex) {
- checkRegex(regex, node, flags && flags.includes("u"));
+ checkRegex(regex, refNode, refNode.arguments[0], flags && flags.includes("u"));
}
}
}
docs: {
description: "Disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-numeric-literals"
+ url: "https://eslint.org/docs/latest/rules/prefer-numeric-literals"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//----------------------------------------------------------------------
// Public
description:
"Disallow use of `Object.prototype.hasOwnProperty.call()` and prefer use of `Object.hasOwn()`",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-object-has-own"
+ url: "https://eslint.org/docs/latest/rules/prefer-object-has-own"
},
schema: [],
messages: {
fixable: "code"
},
create(context) {
+
+ const sourceCode = context.sourceCode;
+
return {
CallExpression(node) {
if (!(node.callee.type === "MemberExpression" && node.callee.object.type === "MemberExpression")) {
const isObject = hasLeftHandObject(node.callee.object);
// check `Object` scope
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
const variable = astUtils.getVariableByName(scope, "Object");
if (
node,
messageId: "useHasOwn",
fix(fixer) {
- const sourceCode = context.getSourceCode();
if (sourceCode.getCommentsInside(node.callee).length > 0) {
return null;
/**
* @fileoverview Prefers object spread property over Object.assign
* @author Sharmila Jesupaul
- * See LICENSE file in root directory for full license.
*/
"use strict";
-const { CALL, ReferenceTracker } = require("eslint-utils");
+const { CALL, ReferenceTracker } = require("@eslint-community/eslint-utils");
const {
isCommaToken,
isOpeningParenToken,
docs: {
description:
- "Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead.",
+ "Disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-object-spread"
+ url: "https://eslint.org/docs/latest/rules/prefer-object-spread"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
const trackMap = {
Object: {
};
// Iterate all calls of `Object.assign` (only of the global variable `Object`).
- for (const { node } of tracker.iterateGlobalReferences(trackMap)) {
+ for (const { node: refNode } of tracker.iterateGlobalReferences(trackMap)) {
if (
- node.arguments.length >= 1 &&
- node.arguments[0].type === "ObjectExpression" &&
- !hasArraySpread(node) &&
+ refNode.arguments.length >= 1 &&
+ refNode.arguments[0].type === "ObjectExpression" &&
+ !hasArraySpread(refNode) &&
!(
- node.arguments.length > 1 &&
- hasArgumentsWithAccessors(node)
+ refNode.arguments.length > 1 &&
+ hasArgumentsWithAccessors(refNode)
)
) {
- const messageId = node.arguments.length === 1
+ const messageId = refNode.arguments.length === 1
? "useLiteralMessage"
: "useSpreadMessage";
- const fix = defineFixer(node, sourceCode);
+ const fix = defineFixer(refNode, sourceCode);
- context.report({ node, messageId, fix });
+ context.report({ node: refNode, messageId, fix });
}
}
}
docs: {
description: "Require using Error objects as Promise rejection reasons",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-promise-reject-errors"
+ url: "https://eslint.org/docs/latest/rules/prefer-promise-reject-errors"
},
fixable: null,
create(context) {
const ALLOW_EMPTY_REJECT = context.options.length && context.options[0].allowEmptyReject;
+ const sourceCode = context.sourceCode;
//----------------------------------------------------------------------
// Helpers
node.arguments.length && astUtils.isFunction(node.arguments[0]) &&
node.arguments[0].params.length > 1 && node.arguments[0].params[1].type === "Identifier"
) {
- context.getDeclaredVariables(node.arguments[0])
+ sourceCode.getDeclaredVariables(node.arguments[0])
/*
* Find the first variable that matches the second parameter's name.
docs: {
description: "Require `Reflect` methods where applicable",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-reflect"
+ url: "https://eslint.org/docs/latest/rules/prefer-reflect"
},
deprecated: true,
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const { CALL, CONSTRUCT, ReferenceTracker, findVariable } = require("eslint-utils");
-const { RegExpValidator, visitRegExpAST, RegExpParser } = require("regexpp");
+const { CALL, CONSTRUCT, ReferenceTracker, findVariable } = require("@eslint-community/eslint-utils");
+const { RegExpValidator, visitRegExpAST, RegExpParser } = require("@eslint-community/regexpp");
const { canTokensBeAdjacent } = require("./utils/ast-utils");
+const { REGEXPP_LATEST_ECMA_VERSION } = require("./utils/regular-expressions");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
-const REGEXPP_LATEST_ECMA_VERSION = 2022;
-
/**
* Determines whether the given node is a string literal.
* @param {ASTNode} node Node to check.
docs: {
description: "Disallow use of the `RegExp` constructor in favor of regular expression literals",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-regex-literals"
+ url: "https://eslint.org/docs/latest/rules/prefer-regex-literals"
},
hasSuggestions: true,
messages: {
unexpectedRegExp: "Use a regular expression literal instead of the 'RegExp' constructor.",
replaceWithLiteral: "Replace with an equivalent regular expression literal.",
+ replaceWithLiteralAndFlags: "Replace with an equivalent regular expression literal with flags '{{ flags }}'.",
+ replaceWithIntendedLiteralAndFlags: "Replace with a regular expression literal with flags '{{ flags }}'.",
unexpectedRedundantRegExp: "Regular expression literal is unnecessarily wrapped within a 'RegExp' constructor.",
unexpectedRedundantRegExpWithFlags: "Use regular expression literal with flags instead of the 'RegExp' constructor."
}
create(context) {
const [{ disallowRedundantWrapping = false } = {}] = context.options;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Determines whether the given identifier node is a reference to a global variable.
* @returns {boolean} True if the identifier is a reference to a global variable.
*/
function isGlobalReference(node) {
- const scope = context.getScope();
+ const scope = sourceCode.getScope(node);
const variable = findVariable(scope, node);
return variable !== null && variable.scope.type === "global" && variable.defs.length === 0;
/**
* Returns a ecmaVersion compatible for regexpp.
- * @param {any} ecmaVersion The ecmaVersion to convert.
+ * @param {number} ecmaVersion The ecmaVersion to convert.
* @returns {import("regexpp/ecma-versions").EcmaVersion} The resulting ecmaVersion compatible for regexpp.
*/
function getRegexppEcmaVersion(ecmaVersion) {
- if (typeof ecmaVersion !== "number" || ecmaVersion <= 5) {
+ if (ecmaVersion <= 5) {
return 5;
}
- return Math.min(ecmaVersion + 2009, REGEXPP_LATEST_ECMA_VERSION);
+ return Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION);
}
+ const regexppEcmaVersion = getRegexppEcmaVersion(context.languageOptions.ecmaVersion);
+
/**
* Makes a character escaped or else returns null.
* @param {string} character The character to escape.
}
}
+ /**
+ * Checks whether the given regex and flags are valid for the ecma version or not.
+ * @param {string} pattern The regex pattern to check.
+ * @param {string | undefined} flags The regex flags to check.
+ * @returns {boolean} True if the given regex pattern and flags are valid for the ecma version.
+ */
+ function isValidRegexForEcmaVersion(pattern, flags) {
+ const validator = new RegExpValidator({ ecmaVersion: regexppEcmaVersion });
+
+ try {
+ validator.validatePattern(pattern, 0, pattern.length, flags ? flags.includes("u") : false);
+ if (flags) {
+ validator.validateFlags(flags);
+ }
+ return true;
+ } catch {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether two given regex flags contain the same flags or not.
+ * @param {string} flagsA The regex flags.
+ * @param {string} flagsB The regex flags.
+ * @returns {boolean} True if two regex flags contain same flags.
+ */
+ function areFlagsEqual(flagsA, flagsB) {
+ return [...flagsA].sort().join("") === [...flagsB].sort().join("");
+ }
+
+
+ /**
+ * Merges two regex flags.
+ * @param {string} flagsA The regex flags.
+ * @param {string} flagsB The regex flags.
+ * @returns {string} The merged regex flags.
+ */
+ function mergeRegexFlags(flagsA, flagsB) {
+ const flagsSet = new Set([
+ ...flagsA,
+ ...flagsB
+ ]);
+
+ return [...flagsSet].join("");
+ }
+
+ /**
+ * Checks whether a give node can be fixed to the given regex pattern and flags.
+ * @param {ASTNode} node The node to check.
+ * @param {string} pattern The regex pattern to check.
+ * @param {string} flags The regex flags
+ * @returns {boolean} True if a node can be fixed to the given regex pattern and flags.
+ */
+ function canFixTo(node, pattern, flags) {
+ const tokenBefore = sourceCode.getTokenBefore(node);
+
+ return sourceCode.getCommentsInside(node).length === 0 &&
+ (!tokenBefore || validPrecedingTokens.has(tokenBefore.value)) &&
+ isValidRegexForEcmaVersion(pattern, flags);
+ }
+
+ /**
+ * Returns a safe output code considering the before and after tokens.
+ * @param {ASTNode} node The regex node.
+ * @param {string} newRegExpValue The new regex expression value.
+ * @returns {string} The output code.
+ */
+ function getSafeOutput(node, newRegExpValue) {
+ const tokenBefore = sourceCode.getTokenBefore(node);
+ const tokenAfter = sourceCode.getTokenAfter(node);
+
+ return (tokenBefore && !canTokensBeAdjacent(tokenBefore, newRegExpValue) && tokenBefore.range[1] === node.range[0] ? " " : "") +
+ newRegExpValue +
+ (tokenAfter && !canTokensBeAdjacent(newRegExpValue, tokenAfter) && node.range[1] === tokenAfter.range[0] ? " " : "");
+
+ }
+
return {
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
const traceMap = {
RegExp: {
}
};
- for (const { node } of tracker.iterateGlobalReferences(traceMap)) {
- if (disallowRedundantWrapping && isUnnecessarilyWrappedRegexLiteral(node)) {
- if (node.arguments.length === 2) {
- context.report({ node, messageId: "unexpectedRedundantRegExpWithFlags" });
- } else {
- context.report({ node, messageId: "unexpectedRedundantRegExp" });
- }
- } else if (hasOnlyStaticStringArguments(node)) {
- let regexContent = getStringValue(node.arguments[0]);
- let noFix = false;
- let flags;
+ for (const { node: refNode } of tracker.iterateGlobalReferences(traceMap)) {
+ if (disallowRedundantWrapping && isUnnecessarilyWrappedRegexLiteral(refNode)) {
+ const regexNode = refNode.arguments[0];
- if (node.arguments[1]) {
- flags = getStringValue(node.arguments[1]);
- }
+ if (refNode.arguments.length === 2) {
+ const suggests = [];
- const regexppEcmaVersion = getRegexppEcmaVersion(context.parserOptions.ecmaVersion);
- const RegExpValidatorInstance = new RegExpValidator({ ecmaVersion: regexppEcmaVersion });
+ const argFlags = getStringValue(refNode.arguments[1]) || "";
- try {
- RegExpValidatorInstance.validatePattern(regexContent, 0, regexContent.length, flags ? flags.includes("u") : false);
- if (flags) {
- RegExpValidatorInstance.validateFlags(flags);
+ if (canFixTo(refNode, regexNode.regex.pattern, argFlags)) {
+ suggests.push({
+ messageId: "replaceWithLiteralAndFlags",
+ pattern: regexNode.regex.pattern,
+ flags: argFlags
+ });
}
- } catch {
- noFix = true;
- }
- const tokenBefore = sourceCode.getTokenBefore(node);
+ const literalFlags = regexNode.regex.flags || "";
+ const mergedFlags = mergeRegexFlags(literalFlags, argFlags);
+
+ if (
+ !areFlagsEqual(mergedFlags, argFlags) &&
+ canFixTo(refNode, regexNode.regex.pattern, mergedFlags)
+ ) {
+ suggests.push({
+ messageId: "replaceWithIntendedLiteralAndFlags",
+ pattern: regexNode.regex.pattern,
+ flags: mergedFlags
+ });
+ }
- if (tokenBefore && !validPrecedingTokens.has(tokenBefore.value)) {
- noFix = true;
+ context.report({
+ node: refNode,
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ suggest: suggests.map(({ flags, pattern, messageId }) => ({
+ messageId,
+ data: {
+ flags
+ },
+ fix(fixer) {
+ return fixer.replaceText(refNode, getSafeOutput(refNode, `/${pattern}/${flags}`));
+ }
+ }))
+ });
+ } else {
+ const outputs = [];
+
+ if (canFixTo(refNode, regexNode.regex.pattern, regexNode.regex.flags)) {
+ outputs.push(sourceCode.getText(regexNode));
+ }
+
+
+ context.report({
+ node: refNode,
+ messageId: "unexpectedRedundantRegExp",
+ suggest: outputs.map(output => ({
+ messageId: "replaceWithLiteral",
+ fix(fixer) {
+ return fixer.replaceText(
+ refNode,
+ getSafeOutput(refNode, output)
+ );
+ }
+ }))
+ });
}
+ } else if (hasOnlyStaticStringArguments(refNode)) {
+ let regexContent = getStringValue(refNode.arguments[0]);
+ let noFix = false;
+ let flags;
- if (!/^[-a-zA-Z0-9\\[\](){} \t\r\n\v\f!@#$%^&*+^_=/~`.><?,'"|:;]*$/u.test(regexContent)) {
+ if (refNode.arguments[1]) {
+ flags = getStringValue(refNode.arguments[1]);
+ }
+
+ if (!canFixTo(refNode, regexContent, flags)) {
noFix = true;
}
- if (sourceCode.getCommentsInside(node).length > 0) {
+ if (!/^[-a-zA-Z0-9\\[\](){} \t\r\n\v\f!@#$%^&*+^_=/~`.><?,'"|:;]*$/u.test(regexContent)) {
noFix = true;
}
const newRegExpValue = `/${regexContent || "(?:)"}/${flags || ""}`;
context.report({
- node,
+ node: refNode,
messageId: "unexpectedRegExp",
suggest: noFix ? [] : [{
messageId: "replaceWithLiteral",
fix(fixer) {
- const tokenAfter = sourceCode.getTokenAfter(node);
-
- return fixer.replaceText(
- node,
- (tokenBefore && !canTokensBeAdjacent(tokenBefore, newRegExpValue) && tokenBefore.range[1] === node.range[0] ? " " : "") +
- newRegExpValue +
- (tokenAfter && !canTokensBeAdjacent(newRegExpValue, tokenAfter) && node.range[1] === tokenAfter.range[0] ? " " : "")
- );
+ return fixer.replaceText(refNode, getSafeOutput(refNode, newRegExpValue));
}
}]
});
docs: {
description: "Require rest parameters instead of `arguments`",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-rest-params"
+ url: "https://eslint.org/docs/latest/rules/prefer-rest-params"
},
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Reports a given reference.
* @param {eslint-scope.Reference} reference A reference to report.
/**
* Reports references of the implicit `arguments` variable if exist.
+ * @param {ASTNode} node The node representing the function.
* @returns {void}
*/
- function checkForArguments() {
- const argumentsVar = getVariableOfArguments(context.getScope());
+ function checkForArguments(node) {
+ const argumentsVar = getVariableOfArguments(sourceCode.getScope(node));
if (argumentsVar) {
argumentsVar
docs: {
description: "Require spread operators instead of `.apply()`",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-spread"
+ url: "https://eslint.org/docs/latest/rules/prefer-spread"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
CallExpression(node) {
docs: {
description: "Require template literals instead of string concatenation",
recommended: false,
- url: "https://eslint.org/docs/rules/prefer-template"
+ url: "https://eslint.org/docs/latest/rules/prefer-template"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let done = Object.create(null);
/**
docs: {
description: "Require quotes around object literal property names",
recommended: false,
- url: "https://eslint.org/docs/rules/quote-props"
+ url: "https://eslint.org/docs/latest/rules/quote-props"
},
schema: {
CHECK_UNNECESSARY = !context.options[1] || context.options[1].unnecessary !== false,
NUMBERS = context.options[1] && context.options[1].numbers,
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
/**
docs: {
description: "Enforce the consistent use of either backticks, double, or single quotes",
recommended: false,
- url: "https://eslint.org/docs/rules/quotes"
+ url: "https://eslint.org/docs/latest/rules/quotes"
},
fixable: "code",
settings = QUOTE_SETTINGS[quoteOption || "double"],
options = context.options[1],
allowTemplateLiterals = options && options.allowTemplateLiterals === true,
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
let avoidEscape = options && options.avoidEscape === true;
// deprecated
docs: {
description: "Enforce the consistent use of the radix argument when using `parseInt()`",
recommended: false,
- url: "https://eslint.org/docs/rules/radix"
+ url: "https://eslint.org/docs/latest/rules/radix"
},
hasSuggestions: true,
create(context) {
const mode = context.options[0] || MODE_ALWAYS;
+ const sourceCode = context.sourceCode;
/**
* Checks the arguments of a given CallExpression node and reports it if it
{
messageId: "addRadixParameter10",
fix(fixer) {
- const sourceCode = context.getSourceCode();
const tokens = sourceCode.getTokens(node);
const lastToken = tokens[tokens.length - 1]; // Parenthesis.
const secondToLastToken = tokens[tokens.length - 2]; // May or may not be a comma.
}
return {
- "Program:exit"() {
- const scope = context.getScope();
+ "Program:exit"(node) {
+ const scope = sourceCode.getScope(node);
let variable;
// Check `parseInt()`
variable = astUtils.getVariableByName(scope, "parseInt");
if (variable && !isShadowed(variable)) {
variable.references.forEach(reference => {
- const node = reference.identifier;
+ const idNode = reference.identifier;
- if (astUtils.isCallee(node)) {
- checkArguments(node.parent);
+ if (astUtils.isCallee(idNode)) {
+ checkArguments(idNode.parent);
}
});
}
variable = astUtils.getVariableByName(scope, "Number");
if (variable && !isShadowed(variable)) {
variable.references.forEach(reference => {
- const node = reference.identifier.parent;
- const maybeCallee = node.parent.type === "ChainExpression"
- ? node.parent
- : node;
+ const parentNode = reference.identifier.parent;
+ const maybeCallee = parentNode.parent.type === "ChainExpression"
+ ? parentNode.parent
+ : parentNode;
- if (isParseIntMethod(node) && astUtils.isCallee(maybeCallee)) {
+ if (isParseIntMethod(parentNode) && astUtils.isCallee(maybeCallee)) {
checkArguments(maybeCallee.parent);
}
});
docs: {
description: "Disallow assignments that can lead to race conditions due to usage of `await` or `yield`",
recommended: false,
- url: "https://eslint.org/docs/rules/require-atomic-updates"
+ url: "https://eslint.org/docs/latest/rules/require-atomic-updates"
},
fixable: null,
create(context) {
const allowProperties = !!context.options[0] && context.options[0].allowProperties;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const assignmentReferences = new Map();
const segmentInfo = new SegmentInfo();
let stack = null;
return {
- onCodePathStart(codePath) {
- const scope = context.getScope();
+ onCodePathStart(codePath, node) {
+ const scope = sourceCode.getScope(node);
const shouldVerify =
scope.type === "function" &&
(scope.block.async || scope.block.generator);
docs: {
description: "Disallow async functions which have no `await` expression",
recommended: false,
- url: "https://eslint.org/docs/rules/require-await"
+ url: "https://eslint.org/docs/latest/rules/require-await"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
let scopeInfo = null;
/**
docs: {
description: "Require JSDoc comments",
recommended: false,
- url: "https://eslint.org/docs/rules/require-jsdoc"
+ url: "https://eslint.org/docs/latest/rules/require-jsdoc"
},
schema: [
},
create(context) {
- const source = context.getSourceCode();
+ const source = context.sourceCode;
const DEFAULT_OPTIONS = {
FunctionDeclaration: true,
MethodDefinition: false,
CONSTRUCT,
ReferenceTracker,
getStringIfConstant
-} = require("eslint-utils");
+} = require("@eslint-community/eslint-utils");
+const astUtils = require("./utils/ast-utils.js");
+const { isValidWithUnicodeFlag } = require("./utils/regular-expressions");
//------------------------------------------------------------------------------
// Rule Definition
docs: {
description: "Enforce the use of `u` flag on RegExp",
recommended: false,
- url: "https://eslint.org/docs/rules/require-unicode-regexp"
+ url: "https://eslint.org/docs/latest/rules/require-unicode-regexp"
},
+ hasSuggestions: true,
+
messages: {
+ addUFlag: "Add the 'u' flag.",
requireUFlag: "Use the 'u' flag."
},
},
create(context) {
+
+ const sourceCode = context.sourceCode;
+
return {
"Literal[regex]"(node) {
const flags = node.regex.flags || "";
if (!flags.includes("u")) {
- context.report({ node, messageId: "requireUFlag" });
+ context.report({
+ messageId: "requireUFlag",
+ node,
+ suggest: isValidWithUnicodeFlag(context.languageOptions.ecmaVersion, node.regex.pattern)
+ ? [
+ {
+ fix(fixer) {
+ return fixer.insertTextAfter(node, "u");
+ },
+ messageId: "addUFlag"
+ }
+ ]
+ : null
+ });
}
},
- Program() {
- const scope = context.getScope();
+ Program(node) {
+ const scope = sourceCode.getScope(node);
const tracker = new ReferenceTracker(scope);
const trackMap = {
RegExp: { [CALL]: true, [CONSTRUCT]: true }
};
- for (const { node } of tracker.iterateGlobalReferences(trackMap)) {
- const flagsNode = node.arguments[1];
+ for (const { node: refNode } of tracker.iterateGlobalReferences(trackMap)) {
+ const [patternNode, flagsNode] = refNode.arguments;
+
+ if (patternNode && patternNode.type === "SpreadElement") {
+ continue;
+ }
+ const pattern = getStringIfConstant(patternNode, scope);
const flags = getStringIfConstant(flagsNode, scope);
if (!flagsNode || (typeof flags === "string" && !flags.includes("u"))) {
- context.report({ node, messageId: "requireUFlag" });
+ context.report({
+ messageId: "requireUFlag",
+ node: refNode,
+ suggest: typeof pattern === "string" && isValidWithUnicodeFlag(context.languageOptions.ecmaVersion, pattern)
+ ? [
+ {
+ fix(fixer) {
+ if (flagsNode) {
+ if ((flagsNode.type === "Literal" && typeof flagsNode.value === "string") || flagsNode.type === "TemplateLiteral") {
+ const flagsNodeText = sourceCode.getText(flagsNode);
+
+ return fixer.replaceText(flagsNode, [
+ flagsNodeText.slice(0, flagsNodeText.length - 1),
+ flagsNodeText.slice(flagsNodeText.length - 1)
+ ].join("u"));
+ }
+
+ // We intentionally don't suggest concatenating + "u" to non-literals
+ return null;
+ }
+
+ const penultimateToken = sourceCode.getLastToken(refNode, { skip: 1 }); // skip closing parenthesis
+
+ return fixer.insertTextAfter(
+ penultimateToken,
+ astUtils.isCommaToken(penultimateToken)
+ ? ' "u",'
+ : ', "u"'
+ );
+ },
+ messageId: "addUFlag"
+ }
+ ]
+ : null
+ });
}
}
}
docs: {
description: "Require generator functions to contain `yield`",
recommended: true,
- url: "https://eslint.org/docs/rules/require-yield"
+ url: "https://eslint.org/docs/latest/rules/require-yield"
},
schema: [],
docs: {
description: "Enforce spacing between rest and spread operators and their expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/rest-spread-spacing"
+ url: "https://eslint.org/docs/latest/rules/rest-spread-spacing"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode(),
+ const sourceCode = context.sourceCode,
alwaysSpace = context.options[0] === "always";
//--------------------------------------------------------------------------
docs: {
description: "Enforce consistent spacing before and after semicolons",
recommended: false,
- url: "https://eslint.org/docs/rules/semi-spacing"
+ url: "https://eslint.org/docs/latest/rules/semi-spacing"
},
fixable: "whitespace",
create(context) {
const config = context.options[0],
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
let requireSpaceBefore = false,
requireSpaceAfter = true;
docs: {
description: "Enforce location of semicolons",
recommended: false,
- url: "https://eslint.org/docs/rules/semi-style"
+ url: "https://eslint.org/docs/latest/rules/semi-style"
},
schema: [{ enum: ["last", "first"] }],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const option = context.options[0] || "last";
/**
docs: {
description: "Require or disallow semicolons instead of ASI",
recommended: false,
- url: "https://eslint.org/docs/rules/semi"
+ url: "https://eslint.org/docs/latest/rules/semi"
},
fixable: "code",
{
type: "object",
properties: {
- omitLastInOneLineBlock: { type: "boolean" }
+ omitLastInOneLineBlock: { type: "boolean" },
+ omitLastInOneLineClassBody: { type: "boolean" }
},
additionalProperties: false
}
const options = context.options[1];
const never = context.options[0] === "never";
const exceptOneLine = Boolean(options && options.omitLastInOneLineBlock);
+ const exceptOneLineClassBody = Boolean(options && options.omitLastInOneLineClassBody);
const beforeStatementContinuationChars = options && options.beforeStatementContinuationChars || "any";
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
return false;
}
+ /**
+ * Checks a node to see if it's the last item in a one-liner `ClassBody` node.
+ * ClassBody is a one-liner if its braces (and consequently everything between them) are on the same line.
+ * @param {ASTNode} node The node to check.
+ * @returns {boolean} whether the node is the last item in a one-liner ClassBody.
+ */
+ function isLastInOneLinerClassBody(node) {
+ const parent = node.parent;
+ const nextToken = sourceCode.getTokenAfter(node);
+
+ if (!nextToken || nextToken.value !== "}") {
+ return false;
+ }
+
+ if (parent.type === "ClassBody") {
+ return parent.loc.start.line === parent.loc.end.line;
+ }
+
+ return false;
+ }
+
/**
* Checks a node to see if it's followed by a semicolon.
* @param {ASTNode} node The node to check.
}
} else {
const oneLinerBlock = (exceptOneLine && isLastInOneLinerBlock(node));
+ const oneLinerClassBody = (exceptOneLineClassBody && isLastInOneLinerClassBody(node));
+ const oneLinerBlockOrClassBody = oneLinerBlock || oneLinerClassBody;
- if (isSemi && oneLinerBlock) {
+ if (isSemi && oneLinerBlockOrClassBody) {
report(node, true);
- } else if (!isSemi && !oneLinerBlock) {
+ } else if (!isSemi && !oneLinerBlockOrClassBody) {
report(node);
}
}
docs: {
description: "Enforce sorted import declarations within modules",
recommended: false,
- url: "https://eslint.org/docs/rules/sort-imports"
+ url: "https://eslint.org/docs/latest/rules/sort-imports"
},
schema: [
ignoreMemberSort = configuration.ignoreMemberSort || false,
memberSyntaxSortOrder = configuration.memberSyntaxSortOrder || ["none", "all", "multiple", "single"],
allowSeparatedGroups = configuration.allowSeparatedGroups || false,
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
let previousDeclaration = null;
/**
docs: {
description: "Require object keys to be sorted",
recommended: false,
- url: "https://eslint.org/docs/rules/sort-keys"
+ url: "https://eslint.org/docs/latest/rules/sort-keys"
},
schema: [
// The stack to save the previous property's name for each object literals.
let stack = null;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
ObjectExpression(node) {
docs: {
description: "Require variables within the same declaration block to be sorted",
recommended: false,
- url: "https://eslint.org/docs/rules/sort-vars"
+ url: "https://eslint.org/docs/latest/rules/sort-vars"
},
schema: [
const configuration = context.options[0] || {},
ignoreCase = configuration.ignoreCase || false,
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
return {
VariableDeclaration(node) {
docs: {
description: "Enforce consistent spacing before blocks",
recommended: false,
- url: "https://eslint.org/docs/rules/space-before-blocks"
+ url: "https://eslint.org/docs/latest/rules/space-before-blocks"
},
fixable: "whitespace",
create(context) {
const config = context.options[0],
- sourceCode = context.getSourceCode();
+ sourceCode = context.sourceCode;
let alwaysFunctions = true,
alwaysKeywords = true,
alwaysClasses = true,
docs: {
description: "Enforce consistent spacing before `function` definition opening parenthesis",
recommended: false,
- url: "https://eslint.org/docs/rules/space-before-function-paren"
+ url: "https://eslint.org/docs/latest/rules/space-before-function-paren"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const baseConfig = typeof context.options[0] === "string" ? context.options[0] : "always";
const overrideConfig = typeof context.options[0] === "object" ? context.options[0] : {};
docs: {
description: "Enforce consistent spacing inside parentheses",
recommended: false,
- url: "https://eslint.org/docs/rules/space-in-parens"
+ url: "https://eslint.org/docs/latest/rules/space-in-parens"
},
fixable: "whitespace",
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Determines if a token is one of the exceptions for the opener paren
docs: {
description: "Require spacing around infix operators",
recommended: false,
- url: "https://eslint.org/docs/rules/space-infix-ops"
+ url: "https://eslint.org/docs/latest/rules/space-infix-ops"
},
fixable: "whitespace",
create(context) {
const int32Hint = context.options[0] ? context.options[0].int32Hint === true : false;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Returns the first token which violates the rule
docs: {
description: "Enforce consistent spacing before or after unary operators",
recommended: false,
- url: "https://eslint.org/docs/rules/space-unary-ops"
+ url: "https://eslint.org/docs/latest/rules/space-unary-ops"
},
fixable: "whitespace",
create(context) {
const options = context.options[0] || { words: true, nonwords: false };
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
//--------------------------------------------------------------------------
// Helpers
docs: {
description: "Enforce consistent spacing after the `//` or `/*` in a comment",
recommended: false,
- url: "https://eslint.org/docs/rules/spaced-comment"
+ url: "https://eslint.org/docs/latest/rules/spaced-comment"
},
fixable: "whitespace",
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
// Unless the first option is never, require a space
const requireSpace = context.options[0] !== "never";
docs: {
description: "Require or disallow strict mode directives",
recommended: false,
- url: "https://eslint.org/docs/rules/strict"
+ url: "https://eslint.org/docs/latest/rules/strict"
},
schema: [
if (ecmaFeatures.impliedStrict) {
mode = "implied";
} else if (mode === "safe") {
- mode = ecmaFeatures.globalReturn ? "global" : "function";
+ mode = ecmaFeatures.globalReturn || context.languageOptions.sourceType === "commonjs" ? "global" : "function";
}
/**
docs: {
description: "Enforce spacing around colons of switch statements",
recommended: false,
- url: "https://eslint.org/docs/rules/switch-colon-spacing"
+ url: "https://eslint.org/docs/latest/rules/switch-colon-spacing"
},
schema: [
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const options = context.options[0] || {};
const beforeSpacing = options.before === true; // false by default
const afterSpacing = options.after !== false; // true by default
docs: {
description: "Require symbol descriptions",
recommended: false,
- url: "https://eslint.org/docs/rules/symbol-description"
+ url: "https://eslint.org/docs/latest/rules/symbol-description"
},
fixable: null,
schema: [],
create(context) {
+ const sourceCode = context.sourceCode;
+
/**
* Reports if node does not conform the rule in case rule is set to
* report missing description
}
return {
- "Program:exit"() {
- const scope = context.getScope();
+ "Program:exit"(node) {
+ const scope = sourceCode.getScope(node);
const variable = astUtils.getVariableByName(scope, "Symbol");
if (variable && variable.defs.length === 0) {
variable.references.forEach(reference => {
- const node = reference.identifier;
+ const idNode = reference.identifier;
- if (astUtils.isCallee(node)) {
- checkArgument(node.parent);
+ if (astUtils.isCallee(idNode)) {
+ checkArgument(idNode.parent);
}
});
}
docs: {
description: "Require or disallow spacing around embedded expressions of template strings",
recommended: false,
- url: "https://eslint.org/docs/rules/template-curly-spacing"
+ url: "https://eslint.org/docs/latest/rules/template-curly-spacing"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const always = context.options[0] === "always";
/**
docs: {
description: "Require or disallow spacing between template tags and their literals",
recommended: false,
- url: "https://eslint.org/docs/rules/template-tag-spacing"
+ url: "https://eslint.org/docs/latest/rules/template-tag-spacing"
},
fixable: "whitespace",
create(context) {
const never = context.options[0] !== "always";
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Check if a space is present between a template tag and its literal
docs: {
description: "Require or disallow Unicode byte order mark (BOM)",
recommended: false,
- url: "https://eslint.org/docs/rules/unicode-bom"
+ url: "https://eslint.org/docs/latest/rules/unicode-bom"
},
fixable: "whitespace",
Program: function checkUnicodeBOM(node) {
- const sourceCode = context.getSourceCode(),
+ const sourceCode = context.sourceCode,
location = { column: 0, line: 1 },
requireBOM = context.options[0] || "never";
docs: {
description: "Require calls to `isNaN()` when checking for `NaN`",
recommended: true,
- url: "https://eslint.org/docs/rules/use-isnan"
+ url: "https://eslint.org/docs/latest/rules/use-isnan"
},
schema: [
--- /dev/null
+/**
+ * @fileoverview Common utils for regular expressions.
+ * @author Josh Goldberg
+ * @author Toru Nagashima
+ */
+
+"use strict";
+
+const { RegExpValidator } = require("@eslint-community/regexpp");
+
+const REGEXPP_LATEST_ECMA_VERSION = 2022;
+
+/**
+ * Checks if the given regular expression pattern would be valid with the `u` flag.
+ * @param {number} ecmaVersion ECMAScript version to parse in.
+ * @param {string} pattern The regular expression pattern to verify.
+ * @returns {boolean} `true` if the pattern would be valid with the `u` flag.
+ * `false` if the pattern would be invalid with the `u` flag or the configured
+ * ecmaVersion doesn't support the `u` flag.
+ */
+function isValidWithUnicodeFlag(ecmaVersion, pattern) {
+ if (ecmaVersion <= 5) { // ecmaVersion <= 5 doesn't support the 'u' flag
+ return false;
+ }
+
+ const validator = new RegExpValidator({
+ ecmaVersion: Math.min(ecmaVersion, REGEXPP_LATEST_ECMA_VERSION)
+ });
+
+ try {
+ validator.validatePattern(pattern, void 0, void 0, /* uFlag = */ true);
+ } catch {
+ return false;
+ }
+
+ return true;
+}
+
+module.exports = {
+ isValidWithUnicodeFlag,
+ REGEXPP_LATEST_ECMA_VERSION
+};
docs: {
description: "Enforce valid JSDoc comments",
recommended: false,
- url: "https://eslint.org/docs/rules/valid-jsdoc"
+ url: "https://eslint.org/docs/latest/rules/valid-jsdoc"
},
schema: [
const options = context.options[0] || {},
prefer = options.prefer || {},
- sourceCode = context.getSourceCode(),
+ sourceCode = context.sourceCode,
// these both default to true, so you have to explicitly make them false
requireReturn = options.requireReturn !== false,
docs: {
description: "Enforce comparing `typeof` expressions against valid strings",
recommended: true,
- url: "https://eslint.org/docs/rules/valid-typeof"
+ url: "https://eslint.org/docs/latest/rules/valid-typeof"
},
hasSuggestions: true,
const VALID_TYPES = new Set(["symbol", "undefined", "object", "boolean", "number", "string", "function", "bigint"]),
OPERATORS = new Set(["==", "===", "!=", "!=="]);
-
+ const sourceCode = context.sourceCode;
const requireStringLiterals = context.options[0] && context.options[0].requireStringLiterals;
let globalScope;
return {
- Program() {
- globalScope = context.getScope();
+ Program(node) {
+ globalScope = sourceCode.getScope(node);
},
UnaryExpression(node) {
if (isTypeofExpression(node)) {
- const parent = context.getAncestors().pop();
+ const { parent } = node;
if (parent.type === "BinaryExpression" && OPERATORS.has(parent.operator)) {
const sibling = parent.left === node ? parent.right : parent.left;
docs: {
description: "Require `var` declarations be placed at the top of their containing scope",
recommended: false,
- url: "https://eslint.org/docs/rules/vars-on-top"
+ url: "https://eslint.org/docs/latest/rules/vars-on-top"
},
schema: [],
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
-const eslintUtils = require("eslint-utils");
+const eslintUtils = require("@eslint-community/eslint-utils");
//----------------------------------------------------------------------
// Helpers
docs: {
description: "Require parentheses around immediate `function` invocations",
recommended: false,
- url: "https://eslint.org/docs/rules/wrap-iife"
+ url: "https://eslint.org/docs/latest/rules/wrap-iife"
},
schema: [
const style = context.options[0] || "outside";
const includeFunctionPrototypeMethods = context.options[1] && context.options[1].functionPrototypeMethods;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Check if the node is wrapped in any (). All parens count: grouping parens and parens for constructs such as if()
docs: {
description: "Require parenthesis around regex literals",
recommended: false,
- url: "https://eslint.org/docs/rules/wrap-regex"
+ url: "https://eslint.org/docs/latest/rules/wrap-regex"
},
schema: [],
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
if (nodeType === "RegularExpression") {
const beforeToken = sourceCode.getTokenBefore(node);
const afterToken = sourceCode.getTokenAfter(node);
- const ancestors = context.getAncestors();
- const grandparent = ancestors[ancestors.length - 1];
+ const { parent } = node;
- if (grandparent.type === "MemberExpression" && grandparent.object === node &&
+ if (parent.type === "MemberExpression" && parent.object === node &&
!(beforeToken && beforeToken.value === "(" && afterToken && afterToken.value === ")")) {
context.report({
node,
docs: {
description: "Require or disallow spacing around the `*` in `yield*` expressions",
recommended: false,
- url: "https://eslint.org/docs/rules/yield-star-spacing"
+ url: "https://eslint.org/docs/latest/rules/yield-star-spacing"
},
fixable: "whitespace",
},
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const mode = (function(option) {
if (!option || typeof option === "string") {
docs: {
description: 'Require or disallow "Yoda" conditions',
recommended: false,
- url: "https://eslint.org/docs/rules/yoda"
+ url: "https://eslint.org/docs/latest/rules/yoda"
},
schema: [
const onlyEquality =
context.options[1] && context.options[1].onlyEquality;
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
/**
* Determines whether node represents a range test.
) &&
!(!isEqualityOperator(node.operator) && onlyEquality) &&
isComparisonOperator(node.operator) &&
- !(exceptRange && isRangeTest(context.getAncestors().pop()))
+ !(exceptRange && isRangeTest(node.parent))
) {
context.report({
node,
--- /dev/null
+/**
+ * @fileoverview Common utils for directives.
+ *
+ * This file contains only shared items for directives.
+ * If you make a utility for rules, please see `../rules/utils/ast-utils.js`.
+ *
+ * @author gfyoung <https://github.com/gfyoung>
+ */
+"use strict";
+
+const directivesPattern = /^(eslint(?:-env|-enable|-disable(?:(?:-next)?-line)?)?|exported|globals?)(?:\s|$)/u;
+
+module.exports = {
+ directivesPattern
+};
*/
function getNpmPackageVersion(pkg, { global = false } = {}) {
const npmBinArgs = ["bin", "-g"];
- const npmLsArgs = ["ls", "--depth=0", "--json", "eslint"];
+ const npmLsArgs = ["ls", "--depth=0", "--json", pkg];
if (global) {
npmLsArgs.push("-g");
"use strict";
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const Graphemer = require("graphemer").default;
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+// eslint-disable-next-line no-control-regex -- intentionally including control characters
+const ASCII_REGEX = /^[\u0000-\u007f]*$/u;
+
+/** @type {Graphemer | undefined} */
+let splitter;
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
/**
* Converts the first letter of a string to uppercase.
* @param {string} string The string to operate on
return string[0].toUpperCase() + string.slice(1);
}
+/**
+ * Counts graphemes in a given string.
+ * @param {string} value A string to count graphemes.
+ * @returns {number} The number of graphemes in `value`.
+ */
+function getGraphemeCount(value) {
+ if (ASCII_REGEX.test(value)) {
+ return value.length;
+ }
+
+ if (!splitter) {
+ splitter = new Graphemer();
+ }
+
+ return splitter.countGraphemes(value);
+}
+
module.exports = {
- upperCaseFirst
+ upperCaseFirst,
+ getGraphemeCount
};
}
/**
- * Gives a a copy of the ancestor nodes.
+ * Gives a copy of the ancestor nodes.
* @returns {ASTNode[]} The ancestor nodes.
*/
parents() {
* @property {number|undefined} column The 1-based column number.
* @property {number} [endColumn] The 1-based column number of the end location.
* @property {number} [endLine] The 1-based line number of the end location.
- * @property {boolean} fatal If `true` then this is a fatal error.
+ * @property {boolean} [fatal] If `true` then this is a fatal error.
* @property {{range:[number,number], text:string}} [fix] Information for autofix.
* @property {number|undefined} line The 1-based line number.
* @property {string} message The error message.
+ * @property {string} [messageId] The ID of the message in the rule's meta.
+ * @property {(string|null)} nodeType Type of node
* @property {string|null} ruleId The ID of the rule which makes this message.
* @property {0|1|2} severity The severity of this message.
* @property {Array<{desc?: string, messageId?: string, fix: {range: [number, number], text: string}}>} [suggestions] Information for suggestions.
* @property {number|undefined} column The 1-based column number.
* @property {number} [endColumn] The 1-based column number of the end location.
* @property {number} [endLine] The 1-based line number of the end location.
- * @property {boolean} fatal If `true` then this is a fatal error.
+ * @property {boolean} [fatal] If `true` then this is a fatal error.
* @property {{range:[number,number], text:string}} [fix] Information for autofix.
* @property {number|undefined} line The 1-based line number.
* @property {string} message The error message.
+ * @property {string} [messageId] The ID of the message in the rule's meta.
+ * @property {(string|null)} nodeType Type of node
* @property {string|null} ruleId The ID of the rule which makes this message.
* @property {0|1|2} severity The severity of this message.
* @property {Array<{kind: string, justification: string}>} suppressions The suppression info.
* @property {DeprecatedRuleInfo[]} usedDeprecatedRules The list of used deprecated rules.
*/
+/**
+ * Information provided when the maximum warning threshold is exceeded.
+ * @typedef {Object} MaxWarningsExceeded
+ * @property {number} maxWarnings Number of warnings to trigger nonzero exit code.
+ * @property {number} foundWarnings Number of warnings found while linting.
+ */
+
+/**
+ * Metadata about results for formatters.
+ * @typedef {Object} ResultsMeta
+ * @property {MaxWarningsExceeded} [maxWarningsExceeded] Present if the maxWarnings threshold was exceeded.
+ */
+
/**
* A formatter function.
* @callback FormatterFunction
* @param {LintResult[]} results The list of linting results.
- * @param {{cwd: string, rulesMeta: Record<string, RuleMeta>}} [context] A context object.
+ * @param {{cwd: string, maxWarningsExceeded?: MaxWarningsExceeded, rulesMeta: Record<string, RuleMeta>}} [context] A context object.
* @returns {string | Promise<string>} Formatted text.
*/
//------------------------------------------------------------------------------
const
- { isCommentToken } = require("eslint-utils"),
+ { isCommentToken } = require("@eslint-community/eslint-utils"),
TokenStore = require("./token-store"),
astUtils = require("../shared/ast-utils"),
Traverser = require("../shared/traverser");
+//------------------------------------------------------------------------------
+// Type Definitions
+//------------------------------------------------------------------------------
+
+/** @typedef {import("eslint-scope").Variable} Variable */
+
//------------------------------------------------------------------------------
// Private
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
+const caches = Symbol("caches");
+
/**
* Represents parsed source code.
*/
validate(ast);
super(ast.tokens, ast.comments);
+ /**
+ * General purpose caching for the class.
+ */
+ this[caches] = new Map([
+ ["scopes", new WeakMap()]
+ ]);
+
/**
* The flag to indicate that the source code has Unicode BOM.
* @type {boolean}
return positionIndex;
}
+
+ /**
+ * Gets the scope for the given node
+ * @param {ASTNode} currentNode The node to get the scope of
+ * @returns {eslint-scope.Scope} The scope information for this node
+ * @throws {TypeError} If the `currentNode` argument is missing.
+ */
+ getScope(currentNode) {
+
+ if (!currentNode) {
+ throw new TypeError("Missing required argument: node.");
+ }
+
+ // check cache first
+ const cache = this[caches].get("scopes");
+ const cachedScope = cache.get(currentNode);
+
+ if (cachedScope) {
+ return cachedScope;
+ }
+
+ // On Program node, get the outermost scope to avoid return Node.js special function scope or ES modules scope.
+ const inner = currentNode.type !== "Program";
+
+ for (let node = currentNode; node; node = node.parent) {
+ const scope = this.scopeManager.acquire(node, inner);
+
+ if (scope) {
+ if (scope.type === "function-expression-name") {
+ cache.set(currentNode, scope.childScopes[0]);
+ return scope.childScopes[0];
+ }
+
+ cache.set(currentNode, scope);
+ return scope;
+ }
+ }
+
+ cache.set(currentNode, this.scopeManager.scopes[0]);
+ return this.scopeManager.scopes[0];
+ }
+
+ /**
+ * Get the variables that `node` defines.
+ * This is a convenience method that passes through
+ * to the same method on the `scopeManager`.
+ * @param {ASTNode} node The node for which the variables are obtained.
+ * @returns {Array<Variable>} An array of variable nodes representing
+ * the variables that `node` defines.
+ */
+ getDeclaredVariables(node) {
+ return this.scopeManager.getDeclaredVariables(node);
+ }
+
+ /* eslint-disable class-methods-use-this -- node is owned by SourceCode */
+ /**
+ * Gets all the ancestors of a given node
+ * @param {ASTNode} node The node
+ * @returns {Array<ASTNode>} All the ancestor nodes in the AST, not including the provided node, starting
+ * from the root node at index 0 and going inwards to the parent node.
+ * @throws {TypeError} When `node` is missing.
+ */
+ getAncestors(node) {
+
+ if (!node) {
+ throw new TypeError("Missing required argument: node.");
+ }
+
+ const ancestorsStartingAtParent = [];
+
+ for (let ancestor = node.parent; ancestor; ancestor = ancestor.parent) {
+ ancestorsStartingAtParent.push(ancestor);
+ }
+
+ return ancestorsStartingAtParent.reverse();
+ }
+ /* eslint-enable class-methods-use-this -- node is owned by SourceCode */
+
+ /**
+ * Marks a variable as used in the current scope
+ * @param {string} name The name of the variable to mark as used.
+ * @param {ASTNode} [refNode] The closest node to the variable reference.
+ * @returns {boolean} True if the variable was found and marked as used, false if not.
+ */
+ markVariableAsUsed(name, refNode = this.ast) {
+
+ const currentScope = this.getScope(refNode);
+ let initialScope = currentScope;
+
+ /*
+ * When we are in an ESM or CommonJS module, we need to start searching
+ * from the top-level scope, not the global scope. For ESM the top-level
+ * scope is the module scope; for CommonJS the top-level scope is the
+ * outer function scope.
+ *
+ * Without this check, we might miss a variable declared with `var` at
+ * the top-level because it won't exist in the global scope.
+ */
+ if (
+ currentScope.type === "global" &&
+ currentScope.childScopes.length > 0 &&
+
+ // top-level scopes refer to a `Program` node
+ currentScope.childScopes[0].block === this.ast
+ ) {
+ initialScope = currentScope.childScopes[0];
+ }
+
+ for (let scope = initialScope; scope; scope = scope.upper) {
+ const variable = scope.variables.find(scopeVar => scopeVar.name === name);
+
+ if (variable) {
+ variable.eslintUsed = true;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
}
module.exports = SourceCode;
//------------------------------------------------------------------------------
const assert = require("assert");
-const { isCommentToken } = require("eslint-utils");
+const { isCommentToken } = require("@eslint-community/eslint-utils");
const cursors = require("./cursors");
const ForwardTokenCursor = require("./forward-token-cursor");
const PaddedTokenCursor = require("./padded-token-cursor");
*/
"use strict";
-//------------------------------------------------------------------------------
-// Helpers
-//------------------------------------------------------------------------------
-
-/**
- * Gets `token.range[0]` from the given token.
- * @param {Node|Token|Comment} token The token to get.
- * @returns {number} The start location.
- * @private
- */
-function getStartLocation(token) {
- return token.range[0];
-}
-
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
* @returns {number} The found index or `tokens.length`.
*/
exports.search = function search(tokens, location) {
- const index = tokens.findIndex(el => location <= getStartLocation(el));
+ for (let minIndex = 0, maxIndex = tokens.length - 1; minIndex <= maxIndex;) {
- return index === -1 ? tokens.length : index;
+ /*
+ * Calculate the index in the middle between minIndex and maxIndex.
+ * `| 0` is used to round a fractional value down to the nearest integer: this is similar to
+ * using `Math.trunc()` or `Math.floor()`, but performance tests have shown this method to
+ * be faster.
+ */
+ const index = (minIndex + maxIndex) / 2 | 0;
+ const token = tokens[index];
+ const tokenStartLocation = token.range[0];
+
+ if (location <= tokenStartLocation) {
+ if (index === minIndex) {
+ return index;
+ }
+ maxIndex = index;
+ } else {
+ minIndex = index + 1;
+ }
+ }
+ return tokens.length;
};
/**
}
if ((startLoc - 1) in indexMap) {
const index = indexMap[startLoc - 1];
- const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
+ const token = tokens[index];
+
+ // If the mapped index is out of bounds, the returned cursor index will point after the end of the tokens array.
+ if (!token) {
+ return tokens.length;
+ }
/*
* For the map of "comment's location -> token's index", it points the next token of a comment.
* In that case, +1 is unnecessary.
*/
- if (token && token.range[0] >= startLoc) {
+ if (token.range[0] >= startLoc) {
return index;
}
return index + 1;
}
if ((endLoc - 1) in indexMap) {
const index = indexMap[endLoc - 1];
- const token = (index >= 0 && index < tokens.length) ? tokens[index] : null;
+ const token = tokens[index];
+
+ // If the mapped index is out of bounds, the returned cursor index will point before the end of the tokens array.
+ if (!token) {
+ return tokens.length - 1;
+ }
/*
* For the map of "comment's location -> token's index", it points the next token of a comment.
* In that case, -1 is necessary.
*/
- if (token && token.range[1] > endLoc) {
+ if (token.range[1] > endLoc) {
return index - 1;
}
return index;
//-----------------------------------------------------------------------------
const { FileEnumerator } = require("./cli-engine/file-enumerator");
-const { FlatESLint } = require("./eslint/flat-eslint");
+const { FlatESLint, shouldUseFlatConfig } = require("./eslint/flat-eslint");
const FlatRuleTester = require("./rule-tester/flat-rule-tester");
//-----------------------------------------------------------------------------
module.exports = {
builtinRules: require("./rules"),
FlatESLint,
+ shouldUseFlatConfig,
FlatRuleTester,
FileEnumerator
};
--- /dev/null
+"use strict";
+
+const { stringifyValueForError } = require("./shared");
+
+module.exports = function({ ruleId, value }) {
+ return `
+Configuration for rule "${ruleId}" is invalid. Each rule must have a severity ("off", 0, "warn", 1, "error", or 2) and may be followed by additional options for the rule.
+
+You passed '${stringifyValueForError(value, 4)}', which doesn't contain a valid severity.
+
+If you're attempting to configure rule options, perhaps you meant:
+
+ "${ruleId}": ["error", ${stringifyValueForError(value, 8)}]
+
+See https://eslint.org/docs/latest/use/configure/rules#using-configuration-files for configuring rules.
+`.trimStart();
+};
--- /dev/null
+"use strict";
+
+const { stringifyValueForError } = require("./shared");
+
+module.exports = function({ ruleId, value }) {
+ return `
+Configuration for rule "${ruleId}" is invalid. Expected severity of "off", 0, "warn", 1, "error", or 2.
+
+You passed '${stringifyValueForError(value, 4)}'.
+
+See https://eslint.org/docs/latest/use/configure/rules#using-configuration-files for configuring rules.
+`.trimStart();
+};
ESLint looked for configuration files in ${directoryPath} and its ancestors. If it found none, it then looked in your home directory.
-If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat/help
+If you think you already have a configuration file or if you need more help, please stop by the ESLint Discord server: https://eslint.org/chat
`.trimStart();
};
module.exports = function() {
return `
The '--print-config' CLI option requires a path to a source code file rather than a directory.
-See also: https://eslint.org/docs/user-guide/command-line-interface#--print-config
+See also: https://eslint.org/docs/latest/use/command-line-interface#--print-config
`.trimStart();
};
--- /dev/null
+/**
+ * @fileoverview Shared utilities for error messages.
+ * @author Josh Goldberg
+ */
+
+"use strict";
+
+/**
+ * Converts a value to a string that may be printed in errors.
+ * @param {any} value The invalid value.
+ * @param {number} indentation How many spaces to indent
+ * @returns {string} The value, stringified.
+ */
+function stringifyValueForError(value, indentation) {
+ return value ? JSON.stringify(value, null, 4).replace(/\n/gu, `\n${" ".repeat(indentation)}`) : `${value}`;
+}
+
+module.exports = { stringifyValueForError };
{
"name": "eslint",
- "version": "8.23.1",
+ "version": "8.41.0",
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
"description": "An AST-based pattern checker for JavaScript.",
"bin": {
"./use-at-your-own-risk": "./lib/unsupported-api.js"
},
"scripts": {
+ "build:docs:update-links": "node tools/fetch-docs-links.js",
+ "build:site": "node Makefile.js gensite",
+ "build:webpack": "node Makefile.js webpack",
+ "build:readme": "node tools/update-readme.js",
+ "lint": "node Makefile.js lint",
+ "lint:docs:js": "node Makefile.js lintDocsJS",
+ "lint:fix": "node Makefile.js lint -- fix",
+ "lint:fix:docs:js": "node Makefile.js lintDocsJS -- fix",
+ "release:generate:alpha": "node Makefile.js generatePrerelease -- alpha",
+ "release:generate:beta": "node Makefile.js generatePrerelease -- beta",
+ "release:generate:latest": "node Makefile.js generateRelease",
+ "release:generate:rc": "node Makefile.js generatePrerelease -- rc",
+ "release:publish": "node Makefile.js publishRelease",
"test": "node Makefile.js test",
"test:cli": "mocha",
- "lint": "node Makefile.js lint",
- "lint:docsjs": "node Makefile.js lintDocsJS",
- "fix": "node Makefile.js lint -- fix",
- "fix:docsjs": "node Makefile.js lintDocsJS -- fix",
- "fuzz": "node Makefile.js fuzz",
- "generate-release": "node Makefile.js generateRelease",
- "generate-alpharelease": "node Makefile.js generatePrerelease -- alpha",
- "generate-betarelease": "node Makefile.js generatePrerelease -- beta",
- "generate-rcrelease": "node Makefile.js generatePrerelease -- rc",
- "publish-release": "node Makefile.js publishRelease",
- "gensite": "node Makefile.js gensite",
- "webpack": "node Makefile.js webpack",
- "perf": "node Makefile.js perf",
- "docs:update-links": "node tools/fetch-docs-links.js"
+ "test:fuzz": "node Makefile.js fuzz",
+ "test:performance": "node Makefile.js perf"
},
"gitHooks": {
"pre-commit": "lint-staged"
"lint-staged": {
"*.js": "eslint --fix",
"*.md": "markdownlint --fix",
+ "lib/rules/*.js": [
+ "node tools/update-eslint-all.js",
+ "git add packages/js/src/configs/eslint-all.js"
+ ],
"docs/src/rules/*.md": [
"node tools/fetch-docs-links.js",
"git add docs/src/_data/further_reading_links.json"
"homepage": "https://eslint.org",
"bugs": "https://github.com/eslint/eslint/issues/",
"dependencies": {
- "@eslint/eslintrc": "^1.3.2",
- "@humanwhocodes/config-array": "^0.10.4",
- "@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.4.0",
+ "@eslint/eslintrc": "^2.0.3",
+ "@eslint/js": "8.41.0",
+ "@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.1.1",
- "eslint-utils": "^3.0.0",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.4.0",
- "esquery": "^1.4.0",
+ "eslint-scope": "^7.2.0",
+ "eslint-visitor-keys": "^3.4.1",
+ "espree": "^9.5.2",
+ "esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^6.0.1",
"find-up": "^5.0.0",
- "glob-parent": "^6.0.1",
- "globals": "^13.15.0",
- "globby": "^11.1.0",
- "grapheme-splitter": "^1.0.4",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "js-sdsl": "^4.1.4",
+ "is-path-inside": "^3.0.3",
"js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.1",
- "regexpp": "^3.2.0",
"strip-ansi": "^6.0.1",
"strip-json-comments": "^3.1.0",
"text-table": "^0.2.0"
"glob": "^7.1.6",
"got": "^11.8.3",
"gray-matter": "^4.0.3",
- "jsdoc": "^3.5.5",
"karma": "^6.1.1",
"karma-chrome-launcher": "^3.1.0",
"karma-mocha": "^2.0.1",
--- /dev/null
+Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+[![npm version](https://img.shields.io/npm/v/@eslint/js.svg)](https://www.npmjs.com/package/@eslint/js)
+
+# ESLint JavaScript Plugin
+
+[Website](https://eslint.org) | [Configure ESLint](https://eslint.org/docs/latest/use/configure) | [Rules](https://eslint.org/docs/rules/) | [Contributing](https://eslint.org/docs/latest/contribute) | [Twitter](https://twitter.com/geteslint) | [Chatroom](https://eslint.org/chat)
+
+The beginnings of separating out JavaScript-specific functionality from ESLint.
+
+Right now, this plugin contains two configurations:
+
+* `recommended` - enables the rules recommended by the ESLint team (the replacement for `"eslint:recommended"`)
+* `all` - enables all ESLint rules (the replacement for `"eslint:all"`)
+
+## Installation
+
+```shell
+npm install @eslint/js -D
+```
+
+## Usage
+
+Use in your `eslint.config.js` file anytime you want to extend one of the configs:
+
+```js
+import js from "@eslint/js";
+
+export default [
+
+ // apply recommended rules to JS files
+ {
+ files: ["**/*.js"],
+ rules: js.configs.recommended.rules
+ },
+
+ // apply recommended rules to JS files with an override
+ {
+ files: ["**/*.js"],
+ rules: {
+ ...js.configs.recommended.rules,
+ "no-unused-vars": "warn"
+ }
+ },
+
+ // apply all rules to JS files
+ {
+ files: ["**/*.js"],
+ rules: {
+ ...js.configs.all.rules,
+ "no-unused-vars": "warn"
+ }
+ }
+]
+```
+
+## License
+
+MIT
--- /dev/null
+{
+ "name": "@eslint/js",
+ "version": "8.41.0",
+ "description": "ESLint JavaScript language implementation",
+ "main": "./src/index.js",
+ "scripts": {},
+ "files": [
+ "LICENSE",
+ "README.md",
+ "src"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/eslint/eslint.git",
+ "directory": "packages/js"
+ },
+ "homepage": "https://eslint.org",
+ "bugs": "https://github.com/eslint/eslint/issues/",
+ "keywords": [
+ "javascript",
+ "eslint-plugin",
+ "eslint"
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+}
--- /dev/null
+/**
+ * @fileoverview Main package entrypoint.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Public Interface
+//------------------------------------------------------------------------------
+
+module.exports = {
+ configs: {
+ all: require("./configs/eslint-all"),
+ recommended: require("./configs/eslint-recommended")
+ }
+};
### Migration Guide
-As there are a lot of changes, we've created a [migration guide](/docs/<%- prereleaseMajorVersion %>/user-guide/migrating-to-<%- prereleaseMajorVersion %>) describing the changes in great detail along with the steps you should take to address them. We expect that most users should be able to upgrade without any build changes, but the migration guide should be a useful resource if you encounter problems.
+As there are a lot of changes, we've created a [migration guide](/docs/<%- prereleaseMajorVersion %>/use/migrating-to-<%- prereleaseMajorVersion %>) describing the changes in great detail along with the steps you should take to address them. We expect that most users should be able to upgrade without any build changes, but the migration guide should be a useful resource if you encounter problems.
<% } %>
-**Tell us about your environment:**
-
-* **ESLint Version:**
-* **Node Version:**
-* **npm Version:**
-
-**What parser (default, `@babel/eslint-parser`, `@typescript-eslint/parser`, etc.) are you using?**
+**Tell us about your environment (`npx eslint --env-info`):**
+
+* **Node version:**
+* **npm version:**
+* **Local ESLint version:**
+* **Global ESLint version:**
+* **Operating System:**
+
+**What parser are you using (place an "X" next to just one item)?**
+
+[ ] `Default (Espree)`
+[ ] `@typescript-eslint/parser`
+[ ] `@babel/eslint-parser`
+[ ] `vue-eslint-parser`
+[ ] `@angular-eslint/template-parser`
+[ ] `Other`
**Please show your full configuration:**
---
-title: Formatters
-layout: doc
+title: Formatters Reference
eleventyNavigation:
key: formatters
- parent: user guide
- title: Formatters
- order: 5
+ parent: use eslint
+ title: Formatters Reference
+ order: 6
edit_link: https://github.com/eslint/eslint/edit/main/templates/formatter-examples.md.ejs
---
ESLint comes with several built-in formatters to control the appearance of the linting results, and supports third-party formatters as well.
-You can specify a formatter using the `--format` or `-f` flag on the command line. For example, `--format json` uses the `json` formatter.
+You can specify a formatter using the `--format` or `-f` flag in the CLI. For example, `--format json` uses the `json` formatter.
The built-in formatter options are:
## Example Source
-Examples of each formatter were created from linting `fullOfProblems.js` using the `.eslintrc` configuration shown below.
+Examples of each formatter were created from linting `fullOfProblems.js` using the `.eslintrc.json` configuration shown below.
-### `fullOfProblems.js`
+`fullOfProblems.js`:
```js
function addOne(i) {
};
```
-### `.eslintrc`:
+`.eslintrc.json`:
```json
{
}
```
-## Output Examples
+Tests the formatters with the CLI:
+
+```shell
+npx eslint --format <Add formatter here> fullOfProblems.js
+```
+
+## Built-In Formatter Options
<% Object.keys(formatterResults).forEach(function(formatterName) { -%>
### <%= formatterName %>
-<% if (formatterName !== "html") { -%>
+<%= formatterResults[formatterName].description %>
+
+Example output:
+
+<% if (formatterName !== "html") { -%>
```text
-<%= formatterResults[formatterName].result %>
+<%- formatterResults[formatterName].result %>
```
<% } else {-%>
-
<iframe src="html-formatter-example.html" width="100%" height="460px"></iframe>
<% } -%>
<% }) -%>
**What rule do you want to change?**
-**Does this change cause the rule to produce more or fewer warnings?**
+**What change do you want to make (place an "X" next to just one item)?**
-**How will the change be implemented? (New option, new default behavior, etc.)?**
+[ ] Generate more warnings
+[ ] Generate fewer warnings
+[ ] Implement autofix
+[ ] Implement suggestions
+
+**How will the change be implemented (place an "X" next to just one item)?**
+
+[ ] A new option
+[ ] A new default behavior
+[ ] Other
**Please provide some example code that this change will affect:**
-**Please describe what the rule should do:**
+**What should the new rule do?**
+
+**What new ECMAScript feature does this rule relate to? Note that we only accept new core rules related to new ECMAScript features.**
**What category of rule is this (place an "X" next to just one item)?**
-[ ] Enforces code style
-[ ] Warns about a potential error
+[ ] Warns about a potential problem
[ ] Suggests an alternate way of doing something
-[ ] Other (please specify:)
+[ ] Enforces a formatting/stylistic preference
-**Provide 2-3 code examples that this rule will warn about:**
+**Please provide some example JavaScript code that this rule will warn about:**
```js
<!-- put your code examples here -->
/**
- * Echos the value of a value. Trys to print the value out
+ * Echos the value of a value. Tries to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
/*!
* JSHint, by JSHint Community.
*
- * This file (and this file only) is licensed under the same slightly modified
- * MIT license that JSLint is. It stops evil-doers everywhere:
+ * This file (and this file only) was licensed under the same slightly modified
+ * MIT license that JSLint is. After a relicensing in 2020 this is now MIT License (Expat).
+ * Relicensing: https://jshint.com/relicensing-2020/
+ * License-Url: https://github.com/jshint/jshint/blob/main/LICENSE
*
- * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
+ * Copyright 2012 Anton Kovalyov (http://jshint.com)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
- * The Software shall be used for Good, not Evil.
- *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--- /dev/null
+module.exports = [{
+ ignores: ["**/fixtures/**"]
+}];
--- /dev/null
+module.exports = {
+ root: true
+};
--- /dev/null
+module.exports = [];
--- /dev/null
+console.log("Running");
--- /dev/null
+console.log("Running");
--- /dev/null
+console.log("Running");
--- /dev/null
+module.exports = [
+ {
+ files: ["*.js"]
+ },
+ {
+ ignores: ["eslint.config.js"]
+ }
+];
--- /dev/null
+console.log("Running");
--- /dev/null
+module.exports = [
+ {
+ files: ["a..b.js"]
+ },
+ {
+ ignores: ["eslint.config.js"]
+ }
+];
--- /dev/null
+const eslintConfig = require("./eslint.config.js");
+
+module.exports = [
+ eslintConfig,
+ {
+ ignores: ["**/*.json", "**/*.js"]
+ }
+];
--- /dev/null
+const eslintConfig = require("./eslint.config.js");
+
+module.exports = [
+ eslintConfig,
+ {
+ ignores: ["**/undef.js", "undef2.js", "**/undef3.js"]
+ }
+];
--- /dev/null
+module.exports = [{
+ rules: {
+ quotes: ["error", "single"]
+ }
+}];
--- /dev/null
+console.log("Running");
--- /dev/null
+module.exports = [];
--- /dev/null
+module.exports = {};
--- /dev/null
+module.exports = [{
+ files: ["subdir*/**/*.js"]
+}];
--- /dev/null
+module.exports = {
+ ignores: ["subdir/subsubdir"]
+};
--- /dev/null
+module.exports = [
+ {
+ ignores: ["a.js"]
+ }
+];
--- /dev/null
+module.exports = {
+ ignores: ["**/ignores-self/**"]
+};
--- /dev/null
+module.exports = {
+ ignores: ["subdir"]
+};
--- /dev/null
+// Similar to the default parser, but considers leading and trailing comments to be part of the root node.
+// Some custom parsers like @typescript-eslint/parser behave in this way.
+
+const espree = require("espree");
+exports.parse = function(code, options) {
+ const ast = espree.parse(code, options);
+
+ if (ast.range && ast.comments && ast.comments.length > 0) {
+ const firstComment = ast.comments[0];
+ const lastComment = ast.comments[ast.comments.length - 1];
+
+ if (ast.range[0] > firstComment.range[0]) {
+ ast.range[0] = firstComment.range[0];
+ ast.start = firstComment.start;
+ if (ast.loc) {
+ ast.loc.start = firstComment.loc.start;
+ }
+ }
+ if (ast.range[1] < lastComment.range[1]) {
+ ast.range[1] = lastComment.range[1];
+ ast.end = lastComment.end;
+ if (ast.loc) {
+ ast.loc.end = lastComment.loc.end;
+ }
+ }
+ }
+ return ast;
+};
-module.exports = function(context) {
+module.exports = {
+ meta: {
+ schema: []
+ },
+ create(context) {
- "use strict";
+ "use strict";
- return {
- "Identifier": function(node) {
- if (node.name === "foo") {
- context.report(node, "Identifier cannot be named 'foo'.");
+ return {
+ "Identifier": function(node) {
+ if (node.name === "foo") {
+ context.report(node, "Identifier cannot be named 'foo'.");
+ }
}
- }
- };
-
+ };
+ }
};
-
-module.exports.schema = [];
create(context) {
return {
"Program": function(node) {
- if (context.getFilename() === '<input>') {
+ if (context.filename === '<input>') {
context.report(node, "Filename test was not defined.");
}
}
schema: [],
},
create(context) {
+
+ const sourceCode = context.sourceCode;
+
return {
- "Program": function(node) {
- var globals = context.getScope().variables.map(function (variable) {
+ "Program"(node) {
+ var globals = sourceCode.getScope(node).variables.map(function (variable) {
return variable.name;
});
schema: []
},
create(context) {
- var sourceCode = context.getSourceCode();
+ var sourceCode = context.sourceCode;
return {
"VariableDeclaration": function(node) {
--- /dev/null
+module.exports = { rules: { "no-console": "off" } };
--- /dev/null
+console.log("one");
--- /dev/null
+module.exports = { rules: { "no-console": "warn" } };
--- /dev/null
+console.log("two");
severity: 2,
message: "Parsing error: Unexpected token is",
line: 1,
- column: 19
+ column: 19,
+ nodeType: null
}
],
suppressedMessages: [],
severity: 2,
message: "Parsing error: Unexpected token",
line: 1,
- column: 10
+ column: 10,
+ nodeType: null
}
],
suppressedMessages: [],
severity: 2,
message: "Parsing error: Unexpected token is",
line: 1,
- column: 19
+ column: 19,
+ nodeType: null
}
],
suppressedMessages: [],
const cwd = getFixturePath("ignored-paths", "configurations");
const engine = new CLIEngine({ cwd });
- // a .eslintignore in parent directories includes `*.js`, but don't load it.
+ // an .eslintignore in parent directories includes `*.js`, but don't load it.
assert(!engine.isPathIgnored("foo.js"));
assert(engine.isPathIgnored("node_modules/foo.js"));
});
const cwd = getFixturePath("ignored-paths", "no-ignore-file");
const engine = new CLIEngine({ ignorePath: false, cwd });
- // a .eslintignore in parent directories includes `*.js`, but don't load it.
+ // an .eslintignore in parent directories includes `*.js`, but don't load it.
assert(!engine.isPathIgnored("foo.js"));
assert(engine.isPathIgnored("node_modules/foo.js"));
});
it("should call fs.writeFileSync() for each result with output", () => {
const fakeFS = {
- writeFileSync: () => {}
+ writeFileSync() {}
},
localCLIEngine = proxyquire("../../../lib/cli-engine/cli-engine", {
fs: fakeFS
it("should call fs.writeFileSync() for each result with output and not at all for a result without output", () => {
const fakeFS = {
- writeFileSync: () => {}
+ writeFileSync() {}
},
localCLIEngine = proxyquire("../../../lib/cli-engine/cli-engine", {
fs: fakeFS
const os = require("os");
const { assert } = require("chai");
const sh = require("shelljs");
+const sinon = require("sinon");
const {
Legacy: {
CascadingConfigArrayFactory
});
});
+ // https://github.com/eslint/eslint/issues/14742
+ describe("with 5 directories ('{lib}', '{lib}/client', '{lib}/client/src', '{lib}/server', '{lib}/server/src') that contains two files '{lib}/client/src/one.js' and '{lib}/server/src/two.js'", () => {
+ const root = path.join(os.tmpdir(), "eslint/file-enumerator");
+ const files = {
+ "{lib}/client/src/one.js": "console.log('one.js');",
+ "{lib}/server/src/two.js": "console.log('two.js');",
+ "{lib}/client/.eslintrc.json": JSON.stringify({
+ rules: {
+ "no-console": "error"
+ },
+ env: {
+ mocha: true
+ }
+ }),
+ "{lib}/server/.eslintrc.json": JSON.stringify({
+ rules: {
+ "no-console": "off"
+ },
+ env: {
+ mocha: true
+ }
+ })
+ };
+ const { prepare, cleanup, getPath } = createCustomTeardown({
+ cwd: root,
+ files
+ });
+
+ /** @type {FileEnumerator} */
+ let enumerator;
+
+ beforeEach(async () => {
+ await prepare();
+ enumerator = new FileEnumerator({
+ cwd: path.resolve(getPath("{lib}/server"))
+ });
+ });
+
+ afterEach(cleanup);
+
+ describe("when running eslint in the server directory", () => {
+ it("should use the config '{lib}/server/.eslintrc.json' for '{lib}/server/src/two.js'.", () => {
+ const spy = sinon.spy(fs, "readdirSync");
+
+ const list = [
+ ...enumerator.iterateFiles(["src/**/*.{js,json}"])
+ ];
+
+ // should enter the directory '{lib}/server/src' directly
+ assert.strictEqual(spy.getCall(0).firstArg, path.join(root, "{lib}/server/src"));
+ assert.strictEqual(list.length, 1);
+ assert.strictEqual(list[0].config.length, 2);
+ assert.strictEqual(list[0].config[0].name, "DefaultIgnorePattern");
+ assert.strictEqual(list[0].config[1].filePath, getPath("{lib}/server/.eslintrc.json"));
+ assert.deepStrictEqual(
+ list.map(entry => entry.filePath),
+ [
+ path.join(root, "{lib}/server/src/two.js")
+ ]
+ );
+
+ // destroy the spy
+ sinon.restore();
+ });
+ });
+ });
+
// This group moved from 'tests/lib/util/glob-utils.js' when refactoring to keep the cumulated test cases.
describe("with 'tests/fixtures/glob-utils' files", () => {
let fixtureDir;
const localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./flat-eslint": { FlatESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./flat-eslint": { FlatESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
});
+ describe("flat config", () => {
+ const originalEnv = process.env;
+ const originalCwd = process.cwd;
+
+ beforeEach(() => {
+ process.env = { ...originalEnv };
+ });
+
+ afterEach(() => {
+ process.env = originalEnv;
+ process.cwd = originalCwd;
+ });
+
+ it(`should use it when an eslint.config.js is present and useFlatConfig is true:${configType}`, async () => {
+ process.cwd = getFixturePath;
+
+ const exitCode = await cli.execute(`--no-ignore --ext .js ${getFixturePath("files")}`, null, useFlatConfig);
+
+ // When flat config is used, we get an exit code of 2 because the --ext option is unrecognized.
+ assert.strictEqual(exitCode, useFlatConfig ? 2 : 0);
+ });
+
+ it(`should not use it when ESLINT_USE_FLAT_CONFIG=false even if an eslint.config.js is present:${configType}`, async () => {
+ process.env.ESLINT_USE_FLAT_CONFIG = "false";
+ process.cwd = getFixturePath;
+
+ const exitCode = await cli.execute(`--no-ignore --ext .js ${getFixturePath("files")}`, null, useFlatConfig);
+
+ assert.strictEqual(exitCode, 0);
+ });
+
+ it(`should use it when ESLINT_USE_FLAT_CONFIG=true and useFlatConfig is true even if an eslint.config.js is not present:${configType}`, async () => {
+ process.env.ESLINT_USE_FLAT_CONFIG = "true";
+
+ // Set the CWD to outside the fixtures/ directory so that no eslint.config.js is found
+ process.cwd = () => getFixturePath("..");
+
+ const exitCode = await cli.execute(`--no-ignore --ext .js ${getFixturePath("files")}`, null, useFlatConfig);
+
+ // When flat config is used, we get an exit code of 2 because the --ext option is unrecognized.
+ assert.strictEqual(exitCode, useFlatConfig ? 2 : 0);
+ });
+ });
+
describe("when given a config with rules with options and severity level set to error", () => {
const originalCwd = process.cwd;
});
});
- describe("when given a config file and a directory of files", () => {
- it(`should load and execute without error with configType:${configType}`, async () => {
- const configPath = getFixturePath("configurations", "semi-error.js");
- const filePath = getFixturePath("formatters");
- const code = `--config ${configPath} ${filePath}`;
- const exitStatus = await cli.execute(code, null, useFlatConfig);
-
- assert.strictEqual(exitStatus, 0);
- });
- });
-
describe("when there is a local config file", () => {
it(`should load the local config file with configType:${configType}`, async () => {
});
});
+ describe("when the --max-warnings option is passed", () => {
+ const flag = useFlatConfig ? "--no-config-lookup" : "--no-eslintrc";
+
+ describe("and there are too many warnings", () => {
+ it(`should provide \`maxWarningsExceeded\` metadata to the formatter with configType:${configType}`, async () => {
+ const exit = await cli.execute(
+ `--no-ignore -f json-with-metadata --max-warnings 1 --rule 'quotes: warn' ${flag}`,
+ "'hello' + 'world';",
+ useFlatConfig
+ );
+
+ assert.strictEqual(exit, 1);
+
+ const { metadata } = JSON.parse(log.info.args[0][0]);
+
+ assert.deepStrictEqual(
+ metadata.maxWarningsExceeded,
+ { maxWarnings: 1, foundWarnings: 2 }
+ );
+ });
+ });
+
+ describe("and warnings do not exceed the limit", () => {
+ it(`should omit \`maxWarningsExceeded\` metadata from the formatter with configType:${configType}`, async () => {
+ const exit = await cli.execute(
+ `--no-ignore -f json-with-metadata --max-warnings 1 --rule 'quotes: warn' ${flag}`,
+ "'hello world';",
+ useFlatConfig
+ );
+
+ assert.strictEqual(exit, 0);
+
+ const { metadata } = JSON.parse(log.info.args[0][0]);
+
+ assert.notProperty(metadata, "maxWarningsExceeded");
+ });
+ });
+ });
+
describe("when given an invalid built-in formatter name", () => {
it(`should execute with error: with configType:${configType}`, async () => {
const filePath = getFixturePath("passing.js");
process.cwd = originalCwd;
});
+ describe("when given a config file and a directory of files", () => {
+ it(`should load and execute without error with configType:${configType}`, async () => {
+ const configPath = getFixturePath("configurations", "semi-error.js");
+ const filePath = getFixturePath("formatters");
+ const code = `--no-ignore --config ${configPath} ${filePath}`;
+ const exitStatus = await cli.execute(code, null, useFlatConfig);
+
+ assert.strictEqual(exitStatus, 0);
+ });
+ });
+
describe("when executing with global flag", () => {
it(`should default defined variables to read-only with configType:${configType}`, async () => {
describe("when given a directory with eslint excluded files in the directory", () => {
it(`should throw an error and not process any files with configType:${configType}`, async () => {
- const ignorePath = getFixturePath(".eslintignore");
+ const options = useFlatConfig
+ ? `--config ${getFixturePath("eslint.config_with_ignores.js")}`
+ : `--ignore-path ${getFixturePath(".eslintignore")}`;
const filePath = getFixturePath("cli");
const expectedMessage = useFlatConfig
- ? `All files matched by '${filePath.replace(/\\/gu, "/")}/**/*.js' are ignored.`
+ ? `All files matched by '${filePath.replace(/\\/gu, "/")}' are ignored.`
: `All files matched by '${filePath}' are ignored.`;
await stdAssert.rejects(async () => {
- await cli.execute(`--ignore-path ${ignorePath} ${filePath}`, null, useFlatConfig);
+ await cli.execute(`${options} ${filePath}`, null, useFlatConfig);
}, new Error(expectedMessage));
});
});
describe("when given a file in excluded files list", () => {
it(`should not process the file with configType:${configType}`, async () => {
- const ignorePath = getFixturePath(".eslintignore");
+ const options = useFlatConfig
+ ? `--config ${getFixturePath("eslint.config_with_ignores.js")}`
+ : `--ignore-path ${getFixturePath(".eslintignore")}`;
const filePath = getFixturePath("passing.js");
- const exit = await cli.execute(`--ignore-path ${ignorePath} ${filePath}`, null, useFlatConfig);
+ const exit = await cli.execute(`${options} ${filePath}`, null, useFlatConfig);
// a warning about the ignored file
assert.isTrue(log.info.called);
});
it(`should process the file when forced with configType:${configType}`, async () => {
- const ignorePath = getFixturePath(".eslintignore");
+ const options = useFlatConfig
+ ? `--config ${getFixturePath("eslint.config_with_ignores.js")}`
+ : `--ignore-path ${getFixturePath(".eslintignore")}`;
const filePath = getFixturePath("passing.js");
- const exit = await cli.execute(`--ignore-path ${ignorePath} --no-ignore ${filePath}`, null, useFlatConfig);
+ const exit = await cli.execute(`${options} --no-ignore ${filePath}`, null, useFlatConfig);
// no warnings
assert.isFalse(log.info.called);
describe("when given a pattern to ignore", () => {
it(`should not process any files with configType:${configType}`, async () => {
const ignoredFile = getFixturePath("cli/syntax-error.js");
+ const ignorePathOption = useFlatConfig
+ ? ""
+ : "--ignore-path .eslintignore_empty";
const filePath = getFixturePath("cli/passing.js");
- const exit = await cli.execute(`--ignore-pattern cli/ ${ignoredFile} ${filePath}`, null, useFlatConfig);
+ const ignorePattern = useFlatConfig ? "cli/**" : "cli/";
+ const exit = await cli.execute(
+ `--ignore-pattern ${ignorePattern} ${ignorePathOption} ${ignoredFile} ${filePath}`, null, useFlatConfig
+ );
// warnings about the ignored files
assert.isTrue(log.info.called);
assert.strictEqual(exit, 0);
});
+
+ it(`should interpret pattern that contains a slash as relative to cwd with configType:${configType}`, async () => {
+ process.cwd = () => getFixturePath("cli/ignore-pattern-relative/subdir");
+
+ /*
+ * The config file is in `cli/ignore-pattern-relative`, so this would fail
+ * if `subdir/**` ignore pattern is interpreted as relative to the config base path.
+ */
+ const exit = await cli.execute("**/*.js --ignore-pattern subdir/**", null, useFlatConfig);
+
+ assert.strictEqual(exit, 0);
+
+ await stdAssert.rejects(
+ async () => await cli.execute("**/*.js --ignore-pattern subsubdir/*.js", null, useFlatConfig),
+ /All files matched by '\*\*\/\*\.js' are ignored/u
+ );
+ });
+
+ it(`should interpret pattern that doesn't contain a slash as relative to cwd with configType:${configType}`, async () => {
+ process.cwd = () => getFixturePath("cli/ignore-pattern-relative/subdir/subsubdir");
+
+ await stdAssert.rejects(
+ async () => await cli.execute("**/*.js --ignore-pattern *.js", null, useFlatConfig),
+ /All files matched by '\*\*\/\*\.js' are ignored/u
+ );
+ });
+
+ if (useFlatConfig) {
+ it("should ignore files if the pattern is a path to a directory (with trailing slash)", async () => {
+ const filePath = getFixturePath("cli/syntax-error.js");
+ const exit = await cli.execute(`--ignore-pattern cli/ ${filePath}`, null, true);
+
+ // parsing error causes exit code 1
+ assert.isTrue(log.info.called);
+ assert.strictEqual(exit, 0);
+ });
+
+ it("should ignore files if the pattern is a path to a directory (without trailing slash)", async () => {
+ const filePath = getFixturePath("cli/syntax-error.js");
+ const exit = await cli.execute(`--ignore-pattern cli ${filePath}`, null, true);
+
+ // parsing error causes exit code 1
+ assert.isTrue(log.info.called);
+ assert.strictEqual(exit, 0);
+ });
+ }
});
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
localCLI = proxyquire("../../lib/cli", {
"./eslint": { ESLint: fakeESLint },
- "./eslint/flat-eslint": { ESLint: fakeESLint, findFlatConfigFile: () => null },
+ "./eslint/flat-eslint": { ESLint: fakeESLint, shouldUseFlatConfig: () => Promise.resolve(false) },
"./shared/logging": log
});
getFixturePath("globals-node.js")
];
- await cli.execute(`--no-eslintrc --config ./conf/eslint-recommended.js --no-ignore ${files.join(" ")}`);
+ await cli.execute(`--no-eslintrc --config ./packages/js/src/configs/eslint-recommended.js --no-ignore ${files.join(" ")}`);
assert.strictEqual(log.info.args[0][0].split("\n").length, 10);
});
const { FlatConfigArray } = require("../../../lib/config/flat-config-array");
const assert = require("chai").assert;
-const allConfig = require("../../../conf/eslint-all");
-const recommendedConfig = require("../../../conf/eslint-recommended");
+const {
+ all: allConfig,
+ recommended: recommendedConfig
+} = require("@eslint/js").configs;
const stringify = require("json-stable-stringify-without-jsonify");
+const espree = require("espree");
//-----------------------------------------------------------------------------
// Helpers
"@": {
rules: {
foo: {
- schema: {
- type: "array",
- items: [
- {
- enum: ["always", "never"]
- }
- ],
- minItems: 0,
- maxItems: 1
+ meta: {
+ schema: {
+ type: "array",
+ items: [
+ {
+ enum: ["always", "never"]
+ }
+ ],
+ minItems: 0,
+ maxItems: 1
+ }
}
},
boom() {},
foo2: {
- schema: {
- type: "array",
- items: {
- type: "string"
- },
- uniqueItems: true,
- minItems: 1
+ meta: {
+ schema: {
+ type: "array",
+ items: {
+ type: "string"
+ },
+ uniqueItems: true,
+ minItems: 1
+ }
}
}
}
});
describe("Serialization of configs", () => {
+
it("should convert config into normalized JSON object", () => {
const configs = new FlatConfigArray([{
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
- parser: "@/espree",
+ parser: `espree@${espree.version}`,
+ parserOptions: {}
+ },
+ processor: void 0
+ };
+ const actual = config.toJSON();
+
+ assert.deepStrictEqual(actual, expected);
+
+ assert.strictEqual(stringify(actual), stringify(expected));
+ });
+
+ it("should convert config with plugin name/version into normalized JSON object", () => {
+
+ const configs = new FlatConfigArray([{
+ plugins: {
+ a: {},
+ b: {
+ name: "b-plugin",
+ version: "2.3.1"
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+ const expected = {
+ plugins: ["@", "a", "b:b-plugin@2.3.1"],
+ languageOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ parser: `espree@${espree.version}`,
parserOptions: {}
},
processor: void 0
assert.strictEqual(stringify(actual), stringify(expected));
});
- it("should throw an error when config with parser object is normalized", () => {
+ it("should convert config with plugin meta into normalized JSON object", () => {
+
+ const configs = new FlatConfigArray([{
+ plugins: {
+ a: {},
+ b: {
+ meta: {
+ name: "b-plugin",
+ version: "2.3.1"
+ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+ const expected = {
+ plugins: ["@", "a", "b:b-plugin@2.3.1"],
+ languageOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ parser: `espree@${espree.version}`,
+ parserOptions: {}
+ },
+ processor: void 0
+ };
+ const actual = config.toJSON();
+
+ assert.deepStrictEqual(actual, expected);
+
+ assert.strictEqual(stringify(actual), stringify(expected));
+ });
+
+ it("should throw an error when config with unnamed parser object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ languageOptions: {
+ parser: {
+ parse() { /* empty */ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.throws(() => {
+ config.toJSON();
+ }, /Could not serialize parser/u);
+
+ });
+
+ it("should throw an error when config with unnamed parser object with empty meta object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ languageOptions: {
+ parser: {
+ meta: {},
+ parse() { /* empty */ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.throws(() => {
+ config.toJSON();
+ }, /Could not serialize parser/u);
+
+ });
+
+ it("should throw an error when config with unnamed parser object with only meta version is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ languageOptions: {
+ parser: {
+ meta: {
+ version: "0.1.1"
+ },
+ parse() { /* empty */ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.throws(() => {
+ config.toJSON();
+ }, /Could not serialize parser/u);
+
+ });
+
+ it("should not throw an error when config with named parser object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ languageOptions: {
+ parser: {
+ meta: {
+ name: "custom-parser"
+ },
+ parse() { /* empty */ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: "custom-parser",
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: void 0
+ });
+
+ });
+
+ it("should not throw an error when config with named and versioned parser object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ languageOptions: {
+ parser: {
+ meta: {
+ name: "custom-parser",
+ version: "0.1.0"
+ },
+ parse() { /* empty */ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: "custom-parser@0.1.0",
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: void 0
+ });
+
+ });
+
+ it("should not throw an error when config with meta-named and versioned parser object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ languageOptions: {
+ parser: {
+ meta: {
+ name: "custom-parser"
+ },
+ version: "0.1.0",
+ parse() { /* empty */ }
+ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: "custom-parser@0.1.0",
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: void 0
+ });
+
+ });
+
+ it("should not throw an error when config with named and versioned parser object outside of meta object is normalized", () => {
const configs = new FlatConfigArray([{
languageOptions: {
parser: {
+ name: "custom-parser",
+ version: "0.1.0",
parse() { /* empty */ }
}
}
const config = configs.getConfig("foo.js");
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: "custom-parser@0.1.0",
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: void 0
+ });
+
+ });
+
+ it("should throw an error when config with unnamed processor object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ processor: {
+ preprocess() { /* empty */ },
+ postprocess() { /* empty */ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
assert.throws(() => {
config.toJSON();
- }, /Caching is not supported/u);
+ }, /Could not serialize processor/u);
});
- it("should throw an error when config with processor object is normalized", () => {
+ it("should throw an error when config with processor object with empty meta object is normalized", () => {
const configs = new FlatConfigArray([{
processor: {
+ meta: {},
preprocess() { /* empty */ },
postprocess() { /* empty */ }
}
assert.throws(() => {
config.toJSON();
- }, /Caching is not supported/u);
+ }, /Could not serialize processor/u);
+
+ });
+
+
+ it("should not throw an error when config with named processor object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ processor: {
+ meta: {
+ name: "custom-processor"
+ },
+ preprocess() { /* empty */ },
+ postprocess() { /* empty */ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: `espree@${espree.version}`,
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: "custom-processor"
+ });
+
+ });
+
+ it("should not throw an error when config with named processor object without meta is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ processor: {
+ name: "custom-processor",
+ preprocess() { /* empty */ },
+ postprocess() { /* empty */ }
+ }
+ }]);
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: `espree@${espree.version}`,
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: "custom-processor"
+ });
+
+ });
+
+ it("should not throw an error when config with named and versioned processor object is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ processor: {
+ meta: {
+ name: "custom-processor",
+ version: "1.2.3"
+ },
+ preprocess() { /* empty */ },
+ postprocess() { /* empty */ }
+ }
+ }]);
+
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: `espree@${espree.version}`,
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: "custom-processor@1.2.3"
+ });
});
+ it("should not throw an error when config with named and versioned processor object without meta is normalized", () => {
+
+ const configs = new FlatConfigArray([{
+ processor: {
+ name: "custom-processor",
+ version: "1.2.3",
+ preprocess() { /* empty */ },
+ postprocess() { /* empty */ }
+ }
+ }]);
+
+
+ configs.normalizeSync();
+
+ const config = configs.getConfig("foo.js");
+
+ assert.deepStrictEqual(config.toJSON(), {
+ languageOptions: {
+ ecmaVersion: "latest",
+ parser: `espree@${espree.version}`,
+ parserOptions: {},
+ sourceType: "module"
+ },
+ plugins: ["@"],
+ processor: "custom-processor@1.2.3"
+ });
+
+ });
});
parser: true
}
}
- ], "Expected an object or string.");
+ ], "Key \"languageOptions\": Key \"parser\": Expected object with parse() or parseForESLint() method.");
});
- it("should error when an unexpected value is found", async () => {
+ it("should error when a null is found", async () => {
await assertInvalidConfig([
{
languageOptions: {
- parser: "true"
+ parser: null
}
}
- ], /Expected string in the form "pluginName\/objectName"/u);
+ ], "Key \"languageOptions\": Key \"parser\": Expected object with parse() or parseForESLint() method.");
});
- it("should error when a plugin parser can't be found", async () => {
+ it("should error when a parser is a string", async () => {
await assertInvalidConfig([
{
parser: "foo/bar"
}
}
- ], "Key \"parser\": Could not find \"bar\" in plugin \"foo\".");
+ ], "Key \"languageOptions\": Key \"parser\": Expected object with parse() or parseForESLint() method.");
});
it("should error when a value doesn't have a parse() method", async () => {
parser: {}
}
}
- ], "Expected object to have a parse() or parseForESLint() method.");
+ ], "Key \"languageOptions\": Key \"parser\": Expected object with parse() or parseForESLint() method.");
});
it("should merge two objects when second object has overrides", () => {
}
},
{
- plugins: {
- "@foo/baz": {
- parsers: {
- bar: stubParser
- }
- }
- },
languageOptions: {
- parser: "@foo/baz/bar"
+ parser: stubParser
}
}
], {
plugins: {
- "@foo/baz": {
- parsers: {
- bar: stubParser
- }
- },
...baseConfig.plugins
},
languageOptions: {
return assertMergedResult([
{
- plugins: {
- foo: {
- parsers: {
- bar: stubParser
- }
- }
- },
-
languageOptions: {
- parser: "foo/bar"
+ parser: stubParser
}
},
{
}
], {
plugins: {
- foo: {
- parsers: {
- bar: stubParser
- }
- },
...baseConfig.plugins
},
{
},
{
- plugins: {
- foo: {
- parsers: {
- bar: stubParser
- }
- }
- },
-
languageOptions: {
- parser: "foo/bar"
+ parser: stubParser
}
}
], {
plugins: {
- foo: {
- parsers: {
- bar: stubParser
- }
- },
...baseConfig.plugins
},
foo: true
}
}
- ], "Key \"rules\": Key \"foo\": Expected a string, number, or array.");
+ ], "Key \"rules\": Key \"foo\": Expected severity of \"off\", 0, \"warn\", 1, \"error\", or 2.");
});
it("should error when an invalid rule severity of the right type is set", async () => {
{
rules: {
foo: 1,
- bar: "error"
+ foo2: "error"
}
},
{
rules: {
foo: ["error", "never"],
- bar: ["warn", "foo"]
+ foo2: ["warn", "foo"]
}
}
], {
plugins: baseConfig.plugins,
rules: {
foo: [2, "never"],
- bar: [1, "foo"]
+ foo2: [1, "foo"]
}
}));
severity: 2,
message: "Parsing error: Unexpected token is",
line: 1,
- column: 19
+ column: 19,
+ nodeType: null
}
],
suppressedMessages: [],
severity: 2,
message: "Parsing error: Unexpected token",
line: 1,
- column: 10
+ column: 10,
+ nodeType: null
}
],
suppressedMessages: [],
severity: 2,
message: "Parsing error: Unexpected token is",
line: 1,
- column: 19
+ column: 19,
+ nodeType: null
}
],
suppressedMessages: [],
const cwd = getFixturePath("ignored-paths", "configurations");
const engine = new ESLint({ cwd });
- // a .eslintignore in parent directories includes `*.js`, but don't load it.
+ // an .eslintignore in parent directories includes `*.js`, but don't load it.
assert(!await engine.isPathIgnored("foo.js"));
assert(await engine.isPathIgnored("node_modules/foo.js"));
});
const rulesMeta = engine.getRulesMetaForResults([]);
- assert.strictEqual(Object.keys(rulesMeta).length, 0);
+ assert.deepStrictEqual(rulesMeta, {});
});
it("should return one rule meta when there is a linting error", async () => {
const results = await engine.lintText("a");
const rulesMeta = engine.getRulesMetaForResults(results);
+ assert.strictEqual(Object.keys(rulesMeta).length, 1);
assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
});
const results = await engine.lintText("a // eslint-disable-line semi");
const rulesMeta = engine.getRulesMetaForResults(results);
+ assert.strictEqual(Object.keys(rulesMeta).length, 1);
assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
});
nodePlugin.rules["no-new-require"].meta
);
});
+
+ it("should ignore messages not related to a rule", async () => {
+ const engine = new ESLint({
+ useEslintrc: false,
+ overrideConfig: {
+ ignorePatterns: "ignored.js",
+ rules: {
+ "no-var": "warn"
+ }
+ },
+ reportUnusedDisableDirectives: "warn"
+ });
+
+ {
+ const results = await engine.lintText("syntax error");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ }
+ {
+ const results = await engine.lintText("// eslint-disable-line no-var");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ }
+ {
+ const results = await engine.lintText("", { filePath: "ignored.js", warnIgnored: true });
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ }
+ });
+
+ it("should return a non-empty value if some of the messages are related to a rule", async () => {
+ const engine = new ESLint({
+ useEslintrc: false,
+ overrideConfig: { rules: { "no-var": "warn" } },
+ reportUnusedDisableDirectives: "warn"
+ });
+
+ const results = await engine.lintText("// eslint-disable-line no-var\nvar foo;");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, { "no-var": coreRules.get("no-var").meta });
+ });
});
describe("outputFixes()", () => {
//------------------------------------------------------------------------------
const assert = require("assert");
+const util = require("util");
const fs = require("fs");
const fsp = fs.promises;
const os = require("os");
const shell = require("shelljs");
const hash = require("../../../lib/cli-engine/hash");
const { unIndent, createCustomTeardown } = require("../../_utils");
+const { shouldUseFlatConfig } = require("../../../lib/eslint/flat-eslint");
const coreRules = require("../../../lib/rules");
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Creates a directory if it doesn't already exist.
+ * @param {string} dirPath The path to the directory that should exist.
+ * @returns {void}
+ */
+function ensureDirectoryExists(dirPath) {
+ try {
+ fs.statSync(dirPath);
+ } catch {
+ fs.mkdirSync(dirPath);
+ }
+}
+
+/**
+ * Does nothing for a given time.
+ * @param {number} time Time in ms.
+ * @returns {void}
+ */
+async function sleep(time) {
+ await util.promisify(setTimeout)(time);
+}
+
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
configFile: "",
envs: [],
globals: [],
+ ignorePath: ".gitignore",
ignorePattern: [],
parser: "",
parserOptions: {},
}),
new RegExp(escapeStringRegExp([
"Invalid Options:",
- "- Unknown options: cacheFile, configFile, envs, globals, ignorePattern, parser, parserOptions, rules"
+ "- Unknown options: cacheFile, configFile, envs, globals, ignorePath, ignorePattern, parser, parserOptions, rules"
].join("\n")), "u")
);
});
fixTypes: ["xyz"],
globInputPaths: "",
ignore: "",
- ignorePath: "",
+ ignorePatterns: "",
overrideConfig: "",
overrideConfigFile: "",
plugins: "",
"- 'fixTypes' must be an array of any of \"directive\", \"problem\", \"suggestion\", and \"layout\".",
"- 'globInputPaths' must be a boolean.",
"- 'ignore' must be a boolean.",
- "- 'ignorePath' must be a non-empty string or null.",
+ "- 'ignorePatterns' must be an array of non-empty strings or null.",
"- 'overrideConfig' must be an object or null.",
"- 'overrideConfigFile' must be a non-empty string, null, or true.",
"- 'plugins' must be an object or null.",
);
});
+ it("should throw readable messages if 'ignorePatterns' is not an array of non-empty strings.", () => {
+ const invalidIgnorePatterns = [
+ () => {},
+ false,
+ {},
+ "",
+ "foo",
+ [[]],
+ [() => {}],
+ [false],
+ [{}],
+ [""],
+ ["foo", ""],
+ ["foo", "", "bar"],
+ ["foo", false, "bar"]
+ ];
+
+ invalidIgnorePatterns.forEach(ignorePatterns => {
+ assert.throws(
+ () => new FlatESLint({ ignorePatterns }),
+ new RegExp(escapeStringRegExp([
+ "Invalid Options:",
+ "- 'ignorePatterns' must be an array of non-empty strings or null."
+ ].join("\n")), "u")
+ );
+ });
+ });
+
it("should throw readable messages if 'plugins' option contains empty key", () => {
assert.throws(
() => new FlatESLint({
it("should return a warning when given a filename by --stdin-filename in excluded files list if warnIgnored is true", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore"),
cwd: getFixturePath(".."),
- overrideConfigFile: "fixtures/eslint.config.js"
+ overrideConfigFile: "fixtures/eslint.config_with_ignores.js"
});
const options = { filePath: "fixtures/passing.js", warnIgnored: true };
it("should not return a warning when given a filename by --stdin-filename in excluded files list if warnIgnored is false", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore"),
cwd: getFixturePath(".."),
- overrideConfigFile: "fixtures/eslint.config.js"
+ overrideConfigFile: "fixtures/eslint.config_with_ignores.js"
});
const options = {
filePath: "fixtures/passing.js",
it("should suppress excluded file warnings by default", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore"),
cwd: getFixturePath(".."),
- overrideConfigFile: "fixtures/eslint.config.js"
+ overrideConfigFile: "fixtures/eslint.config_with_ignores.js"
});
const options = { filePath: "fixtures/passing.js" };
const results = await eslint.lintText("var bar = foo;", options);
it("should return a message when given a filename by --stdin-filename in excluded files list and ignore is off", async () => {
eslint = new FlatESLint({
- ignorePath: "fixtures/.eslintignore",
cwd: getFixturePath(".."),
ignore: false,
- overrideConfigFile: true,
+ overrideConfigFile: "fixtures/eslint.config_with_ignores.js",
overrideConfig: {
rules: {
"no-undef": 2
severity: 2,
message: "Parsing error: Unexpected token is",
line: 1,
- column: 19
+ column: 19,
+ nodeType: null
}
],
suppressedMessages: [],
severity: 2,
message: "Parsing error: Unexpected token",
line: 1,
- column: 10
+ column: 10,
+ nodeType: null
}
],
suppressedMessages: [],
severity: 2,
message: "Parsing error: Unexpected token is",
line: 1,
- column: 19
+ column: 19,
+ nodeType: null
}
],
suppressedMessages: [],
ignore: false
});
const results = await eslint.lintText("var bar = foo;", { filePath: "node_modules/passing.js", warnIgnored: true });
- const expectedMsg = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.";
+ const expectedMsg = "File ignored by default because it is located under the node_modules directory. Use ignore pattern \"!**/node_modules/\" to override.";
assert.strictEqual(results.length, 1);
assert.strictEqual(results[0].filePath, getFixturePath("node_modules/passing.js"));
overrideConfigFile: true
});
- await assert.rejects(async () => await eslint.lintFiles(["lib/cli.js"]), /Expected string in the form "pluginName\/objectName" but found "test11"/u);
+ await assert.rejects(async () => await eslint.lintFiles(["lib/cli.js"]), /Expected object with parse\(\) or parseForESLint\(\) method/u);
});
it("should report zero messages when given a directory with a .js2 file", async () => {
});
const results = await eslint.lintFiles(["fixtures/files/"]);
+ assert.strictEqual(results.length, 3);
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[1].messages.length, 0);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
+ // https://github.com/eslint/eslint/issues/16413
+ it("should find files and report zero messages when given a parent directory with a .js", async () => {
+ eslint = new FlatESLint({
+ ignore: false,
+ cwd: getFixturePath("example-app/subdir")
+ });
+ const results = await eslint.lintFiles(["../*.js"]);
+
assert.strictEqual(results.length, 2);
assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
assert.strictEqual(results[1].messages.length, 0);
+ assert.strictEqual(results[1].suppressedMessages.length, 0);
+ });
+
+ // https://github.com/eslint/eslint/issues/16038
+ it("should allow files patterns with '..' inside", async () => {
+ eslint = new FlatESLint({
+ ignore: false,
+ cwd: getFixturePath("dots-in-files")
+ });
+ const results = await eslint.lintFiles(["."]);
+
+ assert.strictEqual(results.length, 2);
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].filePath, getFixturePath("dots-in-files/a..b.js"));
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
+
+ // https://github.com/eslint/eslint/issues/16299
+ it("should only find files in the subdir1 directory when given a directory name", async () => {
+ eslint = new FlatESLint({
+ ignore: false,
+ cwd: getFixturePath("example-app2")
+ });
+ const results = await eslint.lintFiles(["subdir1"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].filePath, getFixturePath("example-app2/subdir1/a.js"));
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
+ // https://github.com/eslint/eslint/issues/14742
+ it("should run", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("{curly-path}", "server")
+ });
+ const results = await eslint.lintFiles(["src/**/*.{js,json}"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].messages.length, 1);
+ assert.strictEqual(results[0].messages[0].ruleId, "no-console");
+ assert.strictEqual(
+ results[0].filePath,
+ getFixturePath("{curly-path}/server/src/two.js")
+ );
assert.strictEqual(results[0].suppressedMessages.length, 0);
});
+ // https://github.com/eslint/eslint/issues/16265
+ describe("Dot files in searches", () => {
+
+ it("should find dot files in current directory when a . pattern is used", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("dot-files")
+ });
+ const results = await eslint.lintFiles(["."]);
+
+ assert.strictEqual(results.length, 3);
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].filePath, getFixturePath("dot-files/.a.js"));
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ assert.strictEqual(results[1].messages.length, 0);
+ assert.strictEqual(results[1].filePath, getFixturePath("dot-files/.c.js"));
+ assert.strictEqual(results[1].suppressedMessages.length, 0);
+ assert.strictEqual(results[2].messages.length, 0);
+ assert.strictEqual(results[2].filePath, getFixturePath("dot-files/b.js"));
+ assert.strictEqual(results[2].suppressedMessages.length, 0);
+ });
+
+ it("should find dot files in current directory when a *.js pattern is used", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("dot-files")
+ });
+ const results = await eslint.lintFiles(["*.js"]);
+
+ assert.strictEqual(results.length, 3);
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].filePath, getFixturePath("dot-files/.a.js"));
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ assert.strictEqual(results[1].messages.length, 0);
+ assert.strictEqual(results[1].filePath, getFixturePath("dot-files/.c.js"));
+ assert.strictEqual(results[1].suppressedMessages.length, 0);
+ assert.strictEqual(results[2].messages.length, 0);
+ assert.strictEqual(results[2].filePath, getFixturePath("dot-files/b.js"));
+ assert.strictEqual(results[2].suppressedMessages.length, 0);
+ });
+
+ it("should find dot files in current directory when a .a.js pattern is used", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("dot-files")
+ });
+ const results = await eslint.lintFiles([".a.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].messages.length, 0);
+ assert.strictEqual(results[0].filePath, getFixturePath("dot-files/.a.js"));
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+ });
+
+ // https://github.com/eslint/eslint/issues/16275
+ describe("Glob patterns without matches", () => {
+
+ it("should throw an error for a missing pattern when combined with a found pattern", async () => {
+ eslint = new FlatESLint({
+ ignore: false,
+ cwd: getFixturePath("example-app2")
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir1", "doesnotexist/*.js"]);
+ }, /No files matching 'doesnotexist\/\*\.js' were found/u);
+ });
+
+ it("should throw an error for an ignored directory pattern when combined with a found pattern", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("example-app2"),
+ overrideConfig: {
+ ignores: ["subdir2"]
+ }
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir1/*.js", "subdir2/*.js"]);
+ }, /All files matched by 'subdir2\/\*\.js' are ignored/u);
+ });
+
+ it("should throw an error for an ignored file pattern when combined with a found pattern", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("example-app2"),
+ overrideConfig: {
+ ignores: ["subdir2/*.js"]
+ }
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir1/*.js", "subdir2/*.js"]);
+ }, /All files matched by 'subdir2\/\*\.js' are ignored/u);
+ });
+
+ it("should always throw an error for the first unmatched file pattern", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("example-app2"),
+ overrideConfig: {
+ ignores: ["subdir1/*.js", "subdir2/*.js"]
+ }
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["doesnotexist1/*.js", "doesnotexist2/*.js"]);
+ }, /No files matching 'doesnotexist1\/\*\.js' were found/u);
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["doesnotexist1/*.js", "subdir1/*.js"]);
+ }, /No files matching 'doesnotexist1\/\*\.js' were found/u);
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir1/*.js", "doesnotexist1/*.js"]);
+ }, /All files matched by 'subdir1\/\*\.js' are ignored/u);
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir1/*.js", "subdir2/*.js"]);
+ }, /All files matched by 'subdir1\/\*\.js' are ignored/u);
+ });
+
+ it("should not throw an error for an ignored file pattern when errorOnUnmatchedPattern is false", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("example-app2"),
+ overrideConfig: {
+ ignores: ["subdir2/*.js"]
+ },
+ errorOnUnmatchedPattern: false
+ });
+
+ const results = await eslint.lintFiles(["subdir2/*.js"]);
+
+ assert.strictEqual(results.length, 0);
+ });
+
+ it("should not throw an error for a non-existing file pattern when errorOnUnmatchedPattern is false", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("example-app2"),
+ errorOnUnmatchedPattern: false
+ });
+
+ const results = await eslint.lintFiles(["doesexist/*.js"]);
+
+ assert.strictEqual(results.length, 0);
+ });
+ });
+
// https://github.com/eslint/eslint/issues/16260
describe("Globbing based on configs", () => {
it("should report zero messages when given a directory with a .js and config file specifying a subdirectory", async () => {
assert.strictEqual(results.length, 2);
assert.strictEqual(results[0].messages.length, 1);
+ assert.strictEqual(results[0].filePath, getFixturePath("shallow-glob/subdir/subsubdir/broken.js"));
assert(results[0].messages[0].fatal, "Fatal error expected.");
assert.strictEqual(results[0].suppressedMessages.length, 0);
+ assert.strictEqual(results[1].filePath, getFixturePath("shallow-glob/subdir/subsubdir/plain.jsx"));
assert.strictEqual(results[1].messages.length, 0);
assert.strictEqual(results[1].suppressedMessages.length, 0);
});
});
const results = await eslint.lintFiles(["fixtures/files/*"]);
- assert.strictEqual(results.length, 2);
+ 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[0].suppressedMessages.length, 0);
assert.strictEqual(results[1].suppressedMessages.length, 0);
+ assert.strictEqual(results[2].suppressedMessages.length, 0);
});
it("should resolve globs when 'globInputPaths' option is true", async () => {
});
const results = await eslint.lintFiles(["fixtures/files/*"]);
- assert.strictEqual(results.length, 2);
+ 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[0].suppressedMessages.length, 0);
assert.strictEqual(results[1].suppressedMessages.length, 0);
+ assert.strictEqual(results[2].suppressedMessages.length, 0);
});
// only works on a Windows machine
});
const results = await eslint.lintFiles(["fixtures\\files\\*"]);
- assert.strictEqual(results.length, 2);
+ 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[0].suppressedMessages.length, 0);
assert.strictEqual(results[1].suppressedMessages.length, 0);
+ assert.strictEqual(results[2].suppressedMessages.length, 0);
});
}
cwd: getFixturePath("cli-engine")
});
const results = await eslint.lintFiles(["node_modules/foo.js"]);
- const expectedMsg = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.";
+ const expectedMsg = "File ignored by default because it is located under the node_modules directory. Use ignore pattern \"!**/node_modules/\" to override.";
assert.strictEqual(results.length, 1);
assert.strictEqual(results[0].errorCount, 0);
await assert.rejects(async () => {
await eslint.lintFiles(["node_modules"]);
- }, /All files matched by 'node_modules\/\*\*\/\*.js' are ignored\./u);
+ }, /All files matched by 'node_modules' are ignored\./u);
});
// https://github.com/eslint/eslint/issues/5547
await assert.rejects(async () => {
await eslint.lintFiles(["node_modules"]);
- }, /All files matched by 'node_modules\/\*\*\/\*\.js' are ignored\./u);
- });
-
- it("should throw an error when given a directory with all eslint excluded files in the directory", async () => {
- eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore")
- });
-
- await assert.rejects(async () => {
- await eslint.lintFiles([getFixturePath("./cli-engine/")]);
- }, /All files matched by '.*?cli-engine[\\/]\*\*[\\/]\*\.js' are ignored/u);
+ }, /All files matched by 'node_modules' are ignored\./u);
});
it("should throw an error when all given files are ignored", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore")
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores.js")
});
await assert.rejects(async () => {
await eslint.lintFiles(["tests/fixtures/cli-engine/"]);
- }, /All files matched by 'tests\/fixtures\/cli-engine\/\*\*\/\*\.js' are ignored\./u);
+ }, /All files matched by 'tests\/fixtures\/cli-engine\/' are ignored\./u);
});
it("should throw an error when all given files are ignored even with a `./` prefix", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore")
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores.js")
});
await assert.rejects(async () => {
await eslint.lintFiles(["./tests/fixtures/cli-engine/"]);
- }, /All files matched by 'tests\/fixtures\/cli-engine\/\*\*\/\*\.js' are ignored\./u);
+ }, /All files matched by '\.\/tests\/fixtures\/cli-engine\/' are ignored\./u);
});
// https://github.com/eslint/eslint/issues/3788
- it("should ignore one-level down node_modules when ignore file has 'node_modules/' in it", async () => {
+ it("should ignore one-level down node_modules by default", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath("cli-engine", "nested_node_modules", ".eslintignore"),
overrideConfigFile: true,
overrideConfig: {
rules: {
});
// https://github.com/eslint/eslint/issues/3812
- it("should ignore all files and throw an error when fixtures/ is in ignore file", async () => {
+ it("should ignore all files and throw an error when **/fixtures/** is in `ignores` in the config file", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath("cli-engine/.eslintignore2"),
- overrideConfigFile: true,
+ overrideConfigFile: getFixturePath("cli-engine/eslint.config_with_ignores2.js"),
overrideConfig: {
rules: {
quotes: [2, "double"]
await assert.rejects(async () => {
await eslint.lintFiles(["./tests/fixtures/cli-engine/"]);
- }, /All files matched by 'tests\/fixtures\/cli-engine\/\*\*\/\*\.js' are ignored\./u);
+ }, /All files matched by '\.\/tests\/fixtures\/cli-engine\/' are ignored\./u);
});
it("should throw an error when all given files are ignored via ignore-pattern", async () => {
it("should return a warning when an explicitly given file is ignored", async () => {
eslint = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore"),
+ overrideConfigFile: "eslint.config_with_ignores.js",
cwd: getFixturePath()
});
const filePath = getFixturePath("passing.js");
assert.strictEqual(results[0].suppressedMessages.length, 0);
});
+ it("should return a warning about matching ignore patterns when an explicitly given dotfile is ignored", async () => {
+ eslint = new FlatESLint({
+ overrideConfigFile: "eslint.config_with_ignores.js",
+ cwd: getFixturePath()
+ });
+ const filePath = getFixturePath("dot-files/.a.js");
+ const results = await eslint.lintFiles([filePath]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, filePath);
+ assert.strictEqual(results[0].messages[0].severity, 1);
+ assert.strictEqual(results[0].messages[0].message, "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override.");
+ assert.strictEqual(results[0].errorCount, 0);
+ assert.strictEqual(results[0].warningCount, 1);
+ assert.strictEqual(results[0].fatalErrorCount, 0);
+ assert.strictEqual(results[0].fixableErrorCount, 0);
+ assert.strictEqual(results[0].fixableWarningCount, 0);
+ assert.strictEqual(results[0].suppressedMessages.length, 0);
+ });
+
it("should return two messages when given a file in excluded files list while ignore is off", async () => {
eslint = new FlatESLint({
cwd: getFixturePath(),
- ignorePath: getFixturePath(".eslintignore"),
ignore: false,
- overrideConfigFile: true,
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores.js"),
overrideConfig: {
rules: {
"no-undef": 2
assert.strictEqual(results[0].messages[1].severity, 2);
assert.strictEqual(results[0].suppressedMessages.length, 0);
});
+
+ // https://github.com/eslint/eslint/issues/16300
+ it("should process ignore patterns relative to basePath not cwd", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-relative/subdir")
+ });
+ const results = await eslint.lintFiles(["**/*.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, getFixturePath("ignores-relative/subdir/a.js"));
+ });
+
+ // https://github.com/eslint/eslint/issues/16354
+ it("should skip subdirectory files when ignore pattern matches deep subdirectory", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-directory")
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir/**"]);
+ }, /All files matched by 'subdir\/\*\*' are ignored\./u);
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir/subsubdir/**"]);
+ }, /All files matched by 'subdir\/subsubdir\/\*\*' are ignored\./u);
+
+ const results = await eslint.lintFiles(["subdir/subsubdir/a.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, getFixturePath("ignores-directory/subdir/subsubdir/a.js"));
+ assert.strictEqual(results[0].warningCount, 1);
+ assert(results[0].messages[0].message.startsWith("File ignored"), "Should contain file ignored warning");
+
+ });
+
+ // https://github.com/eslint/eslint/issues/16414
+ it("should skip subdirectory files when ignore pattern matches subdirectory", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-subdirectory")
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subdir/**/*.js"]);
+ }, /All files matched by 'subdir\/\*\*\/\*\.js' are ignored\./u);
+
+ const results = await eslint.lintFiles(["subdir/subsubdir/a.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, getFixturePath("ignores-subdirectory/subdir/subsubdir/a.js"));
+ assert.strictEqual(results[0].warningCount, 1);
+ assert(results[0].messages[0].message.startsWith("File ignored"), "Should contain file ignored warning");
+
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-subdirectory/subdir")
+ });
+
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["subsubdir/**/*.js"]);
+ }, /All files matched by 'subsubdir\/\*\*\/\*\.js' are ignored\./u);
+
+
+ });
+
+ // https://github.com/eslint/eslint/issues/16340
+ it("should lint files even when cwd directory name matches ignores pattern", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-self")
+ });
+
+ const results = await eslint.lintFiles(["*.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].filePath, getFixturePath("ignores-self/eslint.config.js"));
+ assert.strictEqual(results[0].errorCount, 0);
+ assert.strictEqual(results[0].warningCount, 0);
+
+ });
+
+ // https://github.com/eslint/eslint/issues/16416
+ it("should allow reignoring of previously ignored files", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-relative"),
+ overrideConfigFile: true,
+ overrideConfig: {
+ ignores: [
+ "*.js",
+ "!a*.js",
+ "a.js"
+ ]
+ }
+ });
+ const results = await eslint.lintFiles(["a.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].errorCount, 0);
+ assert.strictEqual(results[0].warningCount, 1);
+ assert.strictEqual(results[0].filePath, getFixturePath("ignores-relative/a.js"));
+ });
+
+ // https://github.com/eslint/eslint/issues/16415
+ it("should allow directories to be unignored", async () => {
+ eslint = new FlatESLint({
+ cwd: getFixturePath("ignores-directory"),
+ overrideConfigFile: true,
+ overrideConfig: {
+ ignores: [
+ "subdir/*",
+ "!subdir/subsubdir"
+ ]
+ }
+ });
+ const results = await eslint.lintFiles(["subdir/**/*.js"]);
+
+ assert.strictEqual(results.length, 1);
+ assert.strictEqual(results[0].errorCount, 0);
+ assert.strictEqual(results[0].warningCount, 0);
+ assert.strictEqual(results[0].filePath, getFixturePath("ignores-directory/subdir/subsubdir/a.js"));
+ });
+
+
});
});
const results = await eslint.lintFiles(["fixtures/files/*.?s*"]);
- assert.strictEqual(results.length, 2);
+ assert.strictEqual(results.length, 3);
assert.strictEqual(results[0].messages.length, 0);
assert.strictEqual(results[0].suppressedMessages.length, 0);
assert.strictEqual(results[1].messages.length, 0);
assert.strictEqual(results[1].suppressedMessages.length, 0);
+ assert.strictEqual(results[2].messages.length, 0);
+ assert.strictEqual(results[2].suppressedMessages.length, 0);
});
it("should return one error message when given a config with rules with options and severity level set to error", async () => {
});
it("should throw if the directory exists and is empty", async () => {
+ ensureDirectoryExists(getFixturePath("cli-engine/empty"));
await assert.rejects(async () => {
await eslint.lintFiles(["empty"]);
- }, /No files matching 'empty\/\*\*\/\*\.js' were found\./u);
+ }, /No files matching 'empty' were found\./u);
});
it("one glob pattern", async () => {
await eslint.lintFiles(["console.js", "non-exist.js"]);
}, /No files matching 'non-exist\.js' were found\./u);
});
+
+ // https://github.com/eslint/eslint/issues/16275
+ it("a mix of an existing glob pattern and a non-existing glob pattern", async () => {
+ await assert.rejects(async () => {
+ await eslint.lintFiles(["*.js", "non-exist/*.js"]);
+ }, /No files matching 'non-exist\/\*\.js' were found\./u);
+ });
});
describe("multiple processors", () => {
let id;
beforeEach(() => (id = Date.now().toString()));
- afterEach(async () => fsp.rmdir(root, { recursive: true, force: true }));
- it("should lint only JavaScript blocks.", async () => {
+ /*
+ * `fs.rmdir(path, { recursive: true })` is deprecated and will be removed.
+ * Use `fs.rm(path, { recursive: true })` instead.
+ * When supporting Node.js 14.14.0+, the compatibility condition can be removed for `fs.rmdir`.
+ */
+ if (typeof fsp.rm === "function") {
+ afterEach(async () => fsp.rm(root, { recursive: true, force: true }));
+ } else {
+ afterEach(async () => fsp.rmdir(root, { recursive: true, force: true }));
+ }
+
+ it("should lint only JavaScript blocks.", async () => {
const teardown = createCustomTeardown({
cwd: path.join(root, id),
files: {
describe("isPathIgnored", () => {
it("should check if the given path is ignored", async () => {
const engine = new FlatESLint({
- ignorePath: getFixturePath(".eslintignore2"),
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores2.js"),
cwd: getFixturePath()
});
it("should return false if ignoring is disabled", async () => {
const engine = new FlatESLint({
ignore: false,
- ignorePath: getFixturePath(".eslintignore2"),
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores2.js"),
cwd: getFixturePath()
});
assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/node_modules/package/file.js")));
});
- it("should allow subfolders of defaultPatterns to be unignored by ignorePattern", async () => {
+ it("should allow subfolders of defaultPatterns to be unignored by ignorePattern constructor option", async () => {
const cwd = getFixturePath("ignored-paths");
const engine = new FlatESLint({
cwd,
overrideConfigFile: true,
- ignorePatterns: "!/node_modules/package"
+ ignorePatterns: ["!node_modules/", "node_modules/*", "!node_modules/package/"]
});
const result = await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules", "package", "file.js"));
assert(!result, "File should not be ignored");
});
- it("should allow subfolders of defaultPatterns to be unignored by ignorePath", async () => {
+ it("should allow subfolders of defaultPatterns to be unignored by ignores in overrideConfig", async () => {
const cwd = getFixturePath("ignored-paths");
const engine = new FlatESLint({
cwd,
overrideConfigFile: true,
- ignorePath: getFixturePath("ignored-paths", ".eslintignoreWithUnignoredDefaults")
+ overrideConfig: {
+ ignores: ["!node_modules/", "node_modules/*", "!node_modules/package/"]
+ }
});
assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules", "package", "file.js")));
assert(!await engine.isPathIgnored(`${getFixturePath("ignored-paths", "foo")}/../unignored.js`));
});
- it("should ignore /node_modules/ relative to .eslintignore when loaded", async () => {
- const cwd = getFixturePath("ignored-paths");
- const engine = new FlatESLint({ ignorePath: getFixturePath("ignored-paths", ".eslintignore"), cwd });
-
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules", "existing.js")));
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo", "node_modules", "existing.js")));
- });
-
- it("should ignore /node_modules/ relative to cwd without an .eslintignore", async () => {
+ it("should ignore /node_modules/ relative to cwd without any configured ignore patterns", async () => {
const cwd = getFixturePath("ignored-paths", "no-ignore-file");
const engine = new FlatESLint({ cwd });
assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "no-ignore-file", "node_modules", "existing.js")));
assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "no-ignore-file", "foo", "node_modules", "existing.js")));
});
- });
-
- describe("with no .eslintignore file", () => {
- it("should not travel to parent directories to find .eslintignore when it's missing and cwd is provided", async () => {
- const cwd = getFixturePath("ignored-paths", "configurations");
- const engine = new FlatESLint({ cwd });
-
- // a .eslintignore in parent directories includes `*.js`, but don't load it.
- assert(!await engine.isPathIgnored("foo.js"));
- assert(await engine.isPathIgnored("node_modules/foo.js"));
- });
-
- it("should return false for files outside of the cwd (with no ignore file provided)", async () => {
- // Default ignore patterns should not inadvertently ignore files in parent directories
+ it("should not inadvertently ignore all files in parent directories", async () => {
const engine = new FlatESLint({ cwd: getFixturePath("ignored-paths", "no-ignore-file") });
assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
});
});
- describe("with .eslintignore file or package.json file", () => {
- it("should load .eslintignore from cwd when explicitly passed", async () => {
- const cwd = getFixturePath("ignored-paths");
- const engine = new FlatESLint({ cwd });
-
- // `${cwd}/.eslintignore` includes `sampleignorepattern`.
- assert(await engine.isPathIgnored("sampleignorepattern"));
- });
-
- });
-
describe("with ignorePatterns option", () => {
it("should accept a string for options.ignorePatterns", async () => {
const cwd = getFixturePath("ignored-paths", "ignore-pattern");
it("should return true for file matching an ignore pattern exactly", async () => {
const cwd = getFixturePath("ignored-paths");
- const engine = new FlatESLint({ ignorePatterns: ["undef.js"], cwd });
+ const engine = new FlatESLint({
+ ignorePatterns: ["undef.js"],
+ cwd,
+ overrideConfigFile: true
+ });
assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
});
- it("should return false for file in subfolder of cwd matching an ignore pattern with leading '/'", async () => {
+ it("should return false for file in subfolder of cwd matching an ignore pattern with a base filename", async () => {
const cwd = getFixturePath("ignored-paths");
const filePath = getFixturePath("ignored-paths", "subdir", "undef.js");
const engine = new FlatESLint({
- ignorePatterns: ["/undef.js"],
+ ignorePatterns: ["undef.js"],
overrideConfigFile: true,
cwd
});
assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "ignore-pattern", "ignore-me.txt")));
});
- it("should return true for file matching a grandchild of an ignore pattern", async () => {
+ it("should return true for file matching a grandchild of a directory when the pattern is directory/**", async () => {
const cwd = getFixturePath("ignored-paths");
- const engine = new FlatESLint({ ignorePatterns: ["ignore-pattern"], cwd });
+ const engine = new FlatESLint({ ignorePatterns: ["ignore-pattern/**"], cwd });
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "ignore-pattern", "subdir", "ignore-me.txt")));
+ assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "ignore-pattern", "subdir", "ignore-me.js")));
});
it("should return false for file not matching any ignore pattern", async () => {
});
});
- describe("with ignorePath option", () => {
- it("initialization with ignorePath should work when cwd is a parent directory", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored("custom-name/foo.js"));
- });
-
- it("initialization with ignorePath should work when the file is in the cwd", async () => {
- const cwd = getFixturePath("ignored-paths", "custom-name");
- const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored("foo.js"));
- });
-
- it("initialization with ignorePath should work when cwd is a subdirectory", async () => {
- const cwd = getFixturePath("ignored-paths", "custom-name", "subdirectory");
- const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored("../custom-name/foo.js"));
- });
-
- it("missing ignore file should throw error", done => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "not-a-directory", ".foobaz");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- engine.isPathIgnored("foo.js").then(() => {
- assert.fail("missing file should not succeed");
- }).catch(error => {
- assert(/Cannot read ignore file/u.test(error));
- done();
- });
- });
-
- it("should return false for files outside of ignorePath's directory", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
- });
-
- it("should resolve relative paths from CWD", async () => {
- const cwd = getFixturePath("ignored-paths", "subdir");
-
- // /undef.js in ignore file
- const ignorePath = getFixturePath("ignored-paths", ".eslintignoreForDifferentCwd");
- const engine = new FlatESLint({ ignorePath, cwd, overrideConfigFile: true });
-
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/undef.js")), "subdir/undef.js should be ignored");
- assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/subdir/undef.js")), "subdir/subdir/undef.js should not be ignored");
- });
-
- it("should resolve relative paths from CWD when it's in a child directory", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "subdir/.eslintignoreInChildDir");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/undef.js")));
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo.js")));
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/foo.js")));
-
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules/bar.js")));
- });
-
- it("should resolve relative paths from CWD when it contains negated globs", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "subdir/.eslintignoreInChildDir");
- const engine = new FlatESLint({
- ignorePath,
- cwd,
- overrideConfig: {
- files: ["**/*.txt"]
- }
- });
-
- assert(await engine.isPathIgnored("subdir/blah.txt"), "subdir/blah.txt should be ignore");
- assert(await engine.isPathIgnored("blah.txt"), "blah.txt should be ignored");
- assert(await engine.isPathIgnored("subdir/bar.txt"), "subdir/bar.txt should be ignored");
- assert(!await engine.isPathIgnored("bar.txt"), "bar.txt should not be ignored");
- assert(!await engine.isPathIgnored("baz.txt"), "baz.txt should not be ignored");
- assert(!await engine.isPathIgnored("subdir/baz.txt"), "subdir/baz.txt should not be ignored");
- });
-
- it("should resolve default ignore patterns from the CWD even when the ignorePath is in a subdirectory", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "subdir/.eslintignoreInChildDir");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored("node_modules/blah.js"));
- });
-
- it("should resolve default ignore patterns from the CWD even when the ignorePath is in a parent directory", async () => {
- const cwd = getFixturePath("ignored-paths", "subdir");
- const ignorePath = getFixturePath("ignored-paths", ".eslintignoreForDifferentCwd");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored("node_modules/blah.js"));
- });
-
- it("should handle .eslintignore which contains CRLF correctly.", async () => {
- const ignoreFileContent = fs.readFileSync(getFixturePath("ignored-paths", "crlf/.eslintignore"), "utf8");
-
- assert(ignoreFileContent.includes("\r"), "crlf/.eslintignore should contains CR.", "Ignore file must have CRLF for test to pass.");
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", "crlf/.eslintignore");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "crlf/hide1/a.js")));
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "crlf/hide2/a.js")));
- assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "crlf/hide3/a.js")));
- });
-
- it("should ignore a non-negated pattern", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", ".eslintignoreWithNegation");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "negation", "ignore.js")));
- });
-
- it("should not ignore a negated pattern", async () => {
- const cwd = getFixturePath("ignored-paths");
- const ignorePath = getFixturePath("ignored-paths", ".eslintignoreWithNegation");
- const engine = new FlatESLint({ ignorePath, cwd });
-
- assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "negation", "unignore.js")));
- });
- });
-
- describe("with ignorePath option and ignorePatterns option", () => {
+ describe("with config ignores ignorePatterns option", () => {
it("should return false for ignored file when unignored with ignore pattern", async () => {
const cwd = getFixturePath("ignored-paths");
const engine = new FlatESLint({
- ignorePath: getFixturePath("ignored-paths", ".eslintignoreForNegationTest"),
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores2.js"),
ignorePatterns: ["!undef.js"],
cwd
});
it("should return 0 error or warning messages even when the file has warnings", async () => {
const engine = new FlatESLint({
- overrideConfigFile: true,
- ignorePath: path.join(fixtureDir, ".eslintignore"),
+ overrideConfigFile: getFixturePath("eslint.config_with_ignores.js"),
cwd: path.join(fixtureDir, "..")
});
const options = {
});
});
+ describe("findConfigFile()", () => {
+
+ it("should return undefined when overrideConfigFile is true", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true
+ });
+
+ assert.strictEqual(await engine.findConfigFile(), void 0);
+ });
+
+ it("should return undefined when a config file isn't found", async () => {
+ const engine = new FlatESLint({
+ cwd: path.resolve(__dirname, "../../../../")
+ });
+
+ assert.strictEqual(await engine.findConfigFile(), void 0);
+ });
+
+ it("should return custom config file path when overrideConfigFile is a nonempty string", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: "my-config.js"
+ });
+ const configFilePath = path.resolve(__dirname, "../../../my-config.js");
+
+ assert.strictEqual(await engine.findConfigFile(), configFilePath);
+ });
+
+ it("should return root level eslint.config.js when overrideConfigFile is null", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: null
+ });
+ const configFilePath = path.resolve(__dirname, "../../../eslint.config.js");
+
+ assert.strictEqual(await engine.findConfigFile(), configFilePath);
+ });
+
+ it("should return root level eslint.config.js when overrideConfigFile is not specified", async () => {
+ const engine = new FlatESLint();
+ const configFilePath = path.resolve(__dirname, "../../../eslint.config.js");
+
+ assert.strictEqual(await engine.findConfigFile(), configFilePath);
+ });
+
+ });
+
describe("getRulesMetaForResults()", () => {
- it("should throw an error when results were not created from this instance", async () => {
+ it("should throw an error when this instance did not lint any files", async () => {
const engine = new FlatESLint({
overrideConfigFile: true
});
"var err = doStuff();\nif (err) console.log('failed tests: ' + err);\nprocess.exit(1);\n"
}
]);
- }, /Results object was not created from this ESLint instance/u);
+ }, {
+ constructor: TypeError,
+ message: "Results object was not created from this ESLint instance."
+ });
+ });
+
+ it("should throw an error when results were created from a different instance", async () => {
+ const engine1 = new FlatESLint({
+ overrideConfigFile: true,
+ cwd: path.join(fixtureDir, "foo"),
+ overrideConfig: {
+ rules: {
+ semi: 2
+ }
+ }
+ });
+ const engine2 = new FlatESLint({
+ overrideConfigFile: true,
+ cwd: path.join(fixtureDir, "bar"),
+ overrideConfig: {
+ rules: {
+ semi: 2
+ }
+ }
+ });
+
+ const results1 = await engine1.lintText("1", { filePath: "file.js" });
+ const results2 = await engine2.lintText("2", { filePath: "file.js" });
+
+ engine1.getRulesMetaForResults(results1); // should not throw an error
+ assert.throws(() => {
+ engine1.getRulesMetaForResults(results2);
+ }, {
+ constructor: TypeError,
+ message: "Results object was not created from this ESLint instance."
+ });
+ });
+
+ it("should treat a result without `filePath` as if the file was located in `cwd`", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true,
+ cwd: path.join(fixtureDir, "foo", "bar"),
+ ignorePatterns: ["*/**"], // ignore all subdirectories of `cwd`
+ overrideConfig: {
+ rules: {
+ eqeqeq: "warn"
+ }
+ }
+ });
+
+ const results = await engine.lintText("a==b");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta.eqeqeq, coreRules.get("eqeqeq").meta);
+ });
+
+ it("should not throw an error if a result without `filePath` contains an ignored file warning", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true,
+ cwd: path.join(fixtureDir, "foo", "bar"),
+ ignorePatterns: ["**"]
+ });
+
+ const results = await engine.lintText("", { warnIgnored: true });
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ });
+
+ it("should not throw an error if results contain linted files and one ignored file", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true,
+ cwd: getFixturePath(),
+ ignorePatterns: ["passing*"],
+ overrideConfig: {
+ rules: {
+ "no-undef": 2,
+ semi: 1
+ }
+ }
+ });
+
+ const results = await engine.lintFiles(["missing-semicolon.js", "passing.js", "undef.js"]);
+
+ assert(
+ results.some(({ messages }) => messages.some(({ message, ruleId }) => !ruleId && message.startsWith("File ignored"))),
+ "At least one file should be ignored but none is."
+ );
+
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta["no-undef"], coreRules.get("no-undef").meta);
+ assert.deepStrictEqual(rulesMeta.semi, coreRules.get("semi").meta);
});
it("should return empty object when there are no linting errors", async () => {
const rulesMeta = engine.getRulesMetaForResults([]);
- assert.strictEqual(Object.keys(rulesMeta).length, 0);
+ assert.deepStrictEqual(rulesMeta, {});
});
it("should return one rule meta when there is a linting error", async () => {
const results = await engine.lintText("a", { filePath: "foo.js" });
const rulesMeta = engine.getRulesMetaForResults(results);
+ assert.strictEqual(Object.keys(rulesMeta).length, 1);
+ assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
+ });
+
+ it("should return one rule meta when there is a suppressed linting error", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: {
+ rules: {
+ semi: 2
+ }
+ }
+ });
+
+ const results = await engine.lintText("a // eslint-disable-line semi");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.strictEqual(Object.keys(rulesMeta).length, 1);
assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
});
nodePlugin.rules["no-new-require"].meta
);
});
+
+ it("should ignore messages not related to a rule", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true,
+ ignorePatterns: ["ignored.js"],
+ overrideConfig: {
+ rules: {
+ "no-var": "warn"
+ }
+ },
+ reportUnusedDisableDirectives: "warn"
+ });
+
+ {
+ const results = await engine.lintText("syntax error");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ }
+ {
+ const results = await engine.lintText("// eslint-disable-line no-var");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ }
+ {
+ const results = await engine.lintText("", { filePath: "ignored.js", warnIgnored: true });
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, {});
+ }
+ });
+
+ it("should return a non-empty value if some of the messages are related to a rule", async () => {
+ const engine = new FlatESLint({
+ overrideConfigFile: true,
+ overrideConfig: { rules: { "no-var": "warn" } },
+ reportUnusedDisableDirectives: "warn"
+ });
+
+ const results = await engine.lintText("// eslint-disable-line no-var\nvar foo;");
+ const rulesMeta = engine.getRulesMetaForResults(results);
+
+ assert.deepStrictEqual(rulesMeta, { "no-var": coreRules.get("no-var").meta });
+ });
});
describe("outputFixes()", () => {
});
- /*
- * These tests fail due to a bug in fast-flob that doesn't allow
- * negated patterns inside of ignores. These tests won't work until
- * this bug is fixed:
- * https://github.com/mrmlnc/fast-glob/issues/356
- */
- xdescribe("ignorePatterns can unignore '/node_modules/foo'.", () => {
+ describe("ignores can unignore '/node_modules/foo' with patterns ['!node_modules/', 'node_modules/*', '!node_modules/foo/'].", () => {
const { prepare, cleanup, getPath } = createCustomTeardown({
- cwd: root,
+ cwd: `${root}-unignores`,
files: {
"eslint.config.js": `module.exports = {
- ignores: ["!**/node_modules/foo/**"]
+ ignores: ["!node_modules/", "node_modules/*", "!node_modules/foo/"]
};`,
"node_modules/foo/index.js": "",
"node_modules/foo/.dot.js": "",
.sort();
assert.deepStrictEqual(filePaths, [
- path.join(root, "eslint.config.js"),
- path.join(root, "foo.js"),
- path.join(root, "node_modules/foo/index.js")
+ path.join(getPath(), "eslint.config.js"),
+ path.join(getPath(), "foo.js"),
+ path.join(getPath(), "node_modules/foo/.dot.js"),
+ path.join(getPath(), "node_modules/foo/index.js")
]);
});
});
- xdescribe(".eslintignore can re-ignore files that are unignored by ignorePatterns.", () => {
+ describe("ignores can unignore '/node_modules/foo' with patterns ['!node_modules/', 'node_modules/*', '!node_modules/foo/**'].", () => {
+
const { prepare, cleanup, getPath } = createCustomTeardown({
- cwd: root,
+ cwd: `${root}-unignores`,
+ files: {
+ "eslint.config.js": `module.exports = {
+ ignores: ["!node_modules/", "node_modules/*", "!node_modules/foo/**"]
+ };`,
+ "node_modules/foo/index.js": "",
+ "node_modules/foo/.dot.js": "",
+ "node_modules/bar/index.js": "",
+ "foo.js": ""
+ }
+ });
+
+ beforeEach(prepare);
+ afterEach(cleanup);
+
+ it("'isPathIgnored()' should return 'false' for 'node_modules/foo/index.js'.", async () => {
+ const engine = new FlatESLint({ cwd: getPath() });
+
+ assert.strictEqual(await engine.isPathIgnored("node_modules/foo/index.js"), false);
+ });
+
+ it("'isPathIgnored()' should return 'false' for 'node_modules/foo/.dot.js'.", async () => {
+ const engine = new FlatESLint({ cwd: getPath() });
+
+ assert.strictEqual(await engine.isPathIgnored("node_modules/foo/.dot.js"), false);
+ });
+
+ it("'isPathIgnored()' should return 'true' for 'node_modules/bar/index.js'.", async () => {
+ const engine = new FlatESLint({ cwd: getPath() });
+
+ assert.strictEqual(await engine.isPathIgnored("node_modules/bar/index.js"), true);
+ });
+
+ it("'lintFiles()' should verify 'node_modules/foo/index.js'.", async () => {
+ const engine = new FlatESLint({ cwd: getPath() });
+ const result = (await engine.lintFiles("**/*.js"));
+
+ const filePaths = result
+ .map(r => r.filePath)
+ .sort();
+
+ assert.deepStrictEqual(filePaths, [
+ path.join(getPath(), "eslint.config.js"),
+ path.join(getPath(), "foo.js"),
+ path.join(getPath(), "node_modules/foo/.dot.js"),
+ path.join(getPath(), "node_modules/foo/index.js")
+ ]);
+ });
+ });
+
+ describe("ignore pattern can re-ignore files that are unignored by a previous pattern.", () => {
+ const { prepare, cleanup, getPath } = createCustomTeardown({
+ cwd: `${root}-reignore`,
files: {
"eslint.config.js": `module.exports = ${JSON.stringify({
- ignores: ["!.*"]
+ ignores: ["!.*", ".foo*"]
})}`,
- ".eslintignore": ".foo*",
".foo.js": "",
".bar.js": ""
}
.sort();
assert.deepStrictEqual(filePaths, [
- path.join(root, ".bar.js"),
- path.join(root, "eslint.config.js")
+ path.join(getPath(), ".bar.js"),
+ path.join(getPath(), "eslint.config.js")
]);
});
});
- xdescribe(".eslintignore can unignore files that are ignored by ignorePatterns.", () => {
+ describe("ignore pattern can unignore files that are ignored by a previous pattern.", () => {
const { prepare, cleanup, getPath } = createCustomTeardown({
- cwd: root,
+ cwd: `${root}-dignore`,
files: {
"eslint.config.js": `module.exports = ${JSON.stringify({
- ignores: ["**/*.js"]
+ ignores: ["**/*.js", "!foo.js"]
})}`,
- ".eslintignore": "!foo.js",
"foo.js": "",
"bar.js": ""
}
.sort();
assert.deepStrictEqual(filePaths, [
- path.join(root, "foo.js")
+ path.join(getPath(), "foo.js")
]);
});
});
fixableWarningCount: 0,
messages: [
{
+ ruleId: null,
fatal: false,
- message: "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.",
- severity: 1
+ message: "File ignored by default because it is located under the node_modules directory. Use ignore pattern \"!**/node_modules/\" to override.",
+ severity: 1,
+ nodeType: null
}
],
usedDeprecatedRules: [],
});
});
- // dependent on https://github.com/mrmlnc/fast-glob/issues/86
- xdescribe("if { ignores: 'foo/*.js', ... } is present by '--config node_modules/myconf/eslint.config.js',", () => {
+ describe("if { ignores: 'foo/*.js', ... } is present by '--config node_modules/myconf/eslint.config.js',", () => {
const { prepare, cleanup, getPath } = createCustomTeardown({
cwd: `${root}a3`,
files: {
- "node_modules/myconf/eslint.config.js": `module.exports = {
- ignores: ["**/eslint.config.js", "!node_modules/myconf", "foo/*.js"],
+ "node_modules/myconf/eslint.config.js": `module.exports = [{
+ ignores: ["!node_modules", "node_modules/*", "!node_modules/myconf", "foo/*.js"],
+ }, {
rules: {
eqeqeq: "error"
}
- }`,
+ }]`,
"node_modules/myconf/foo/test.js": "a == b",
"foo/test.js": "a == b"
}
beforeEach(prepare);
afterEach(cleanup);
- it("'lintFiles()' with '**/*.js' should iterate 'node_modules/myconf/foo/test.js' but not 'foo/test.js'.", async () => {
+ it("'lintFiles()' with '**/*.js' should lint 'node_modules/myconf/foo/test.js' but not 'foo/test.js'.", async () => {
const engine = new FlatESLint({
overrideConfigFile: "node_modules/myconf/eslint.config.js",
cwd: getPath()
.sort();
assert.deepStrictEqual(files, [
+ path.join(getPath(), "node_modules/myconf/eslint.config.js"),
path.join(getPath(), "node_modules/myconf/foo/test.js")
]);
});
});
});
+ describe("baseConfig", () => {
+ it("can be an object", async () => {
+ const eslint = new FlatESLint({
+ overrideConfigFile: true,
+ baseConfig: {
+ rules: {
+ semi: 2
+ }
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText("foo");
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ });
+
+ it("can be an array", async () => {
+ const eslint = new FlatESLint({
+ overrideConfigFile: true,
+ baseConfig: [
+ {
+ rules: {
+ "no-var": 2
+ }
+ },
+ {
+ rules: {
+ semi: 2
+ }
+ }
+ ]
+ });
+
+ const [{ messages }] = await eslint.lintText("var foo");
+
+ assert.strictEqual(messages.length, 2);
+ assert.strictEqual(messages[0].ruleId, "no-var");
+ assert.strictEqual(messages[1].ruleId, "semi");
+ });
+
+ it("should be inserted after default configs", async () => {
+ const eslint = new FlatESLint({
+ overrideConfigFile: true,
+ baseConfig: {
+ languageOptions: {
+ ecmaVersion: 5,
+ sourceType: "script"
+ }
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText("let x");
+
+ /*
+ * if baseConfig was inserted before default configs,
+ * `ecmaVersion: "latest"` from default configs would overwrite
+ * `ecmaVersion: 5` from baseConfig, so this wouldn't be a parsing error.
+ */
+
+ assert.strictEqual(messages.length, 1);
+ assert(messages[0].fatal, "Fatal error expected.");
+ });
+
+ it("should be inserted before configs from the config file", async () => {
+ const eslint = new FlatESLint({
+ cwd: getFixturePath(),
+ baseConfig: {
+ rules: {
+ strict: ["error", "global"]
+ },
+ languageOptions: {
+ sourceType: "script"
+ }
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText("foo");
+
+ /*
+ * if baseConfig was inserted after configs from the config file,
+ * `strict: 0` from eslint.config.js wouldn't overwrite `strict: ["error", "global"]`
+ * from baseConfig, so there would be an error message from the `strict` rule.
+ */
+
+ assert.strictEqual(messages.length, 0);
+ });
+
+ it("should be inserted before overrideConfig", async () => {
+ const eslint = new FlatESLint({
+ overrideConfigFile: true,
+ baseConfig: {
+ rules: {
+ semi: 2
+ }
+ },
+ overrideConfig: {
+ rules: {
+ semi: 1
+ }
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText("foo");
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ assert.strictEqual(messages[0].severity, 1);
+ });
+
+ it("should be inserted before configs from the config file and overrideConfig", async () => {
+ const eslint = new FlatESLint({
+ overrideConfigFile: getFixturePath("eslint.config_with_rules.js"),
+ baseConfig: {
+ rules: {
+ quotes: ["error", "double"],
+ semi: "error"
+ }
+ },
+ overrideConfig: {
+ rules: {
+ quotes: "warn"
+ }
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText('const foo = "bar"');
+
+ /*
+ * baseConfig: { quotes: ["error", "double"], semi: "error" }
+ * eslint.config_with_rules.js: { quotes: ["error", "single"] }
+ * overrideConfig: { quotes: "warn" }
+ *
+ * Merged config: { quotes: ["warn", "single"], semi: "error" }
+ */
+
+ assert.strictEqual(messages.length, 2);
+ assert.strictEqual(messages[0].ruleId, "quotes");
+ assert.strictEqual(messages[0].severity, 1);
+ assert.strictEqual(messages[1].ruleId, "semi");
+ assert.strictEqual(messages[1].severity, 2);
+ });
+
+ it("when it has 'files' they should be interpreted as relative to the config file", async () => {
+
+ /*
+ * `fixtures/plugins` directory does not have a config file.
+ * It's parent directory `fixtures` does have a config file, so
+ * the base path will be `fixtures`, cwd will be `fixtures/plugins`
+ */
+ const eslint = new FlatESLint({
+ cwd: getFixturePath("plugins"),
+ baseConfig: {
+ files: ["plugins/a.js"],
+ rules: {
+ semi: 2
+ }
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText("foo", { filePath: getFixturePath("plugins/a.js") });
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ });
+
+ it("when it has 'ignores' they should be interpreted as relative to the config file", async () => {
+
+ /*
+ * `fixtures/plugins` directory does not have a config file.
+ * It's parent directory `fixtures` does have a config file, so
+ * the base path will be `fixtures`, cwd will be `fixtures/plugins`
+ */
+ const eslint = new FlatESLint({
+ cwd: getFixturePath("plugins"),
+ baseConfig: {
+ ignores: ["plugins/a.js"]
+ }
+ });
+
+ const [{ messages }] = await eslint.lintText("foo", { filePath: getFixturePath("plugins/a.js"), warnIgnored: true });
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].severity, 1);
+ assert.match(messages[0].message, /ignored/u);
+ });
+ });
+
+ describe("config file", () => {
+
+ it("new instance of FlatESLint should use the latest version of the config file (ESM)", async () => {
+ const cwd = path.join(getFixturePath(), `config_file_${Date.now()}`);
+ const configFileContent = "export default [{ rules: { semi: ['error', 'always'] } }];";
+ const teardown = createCustomTeardown({
+ cwd,
+ files: {
+ "package.json": '{ "type": "module" }',
+ "eslint.config.js": configFileContent,
+ "a.js": "foo\nbar;"
+ }
+ });
+
+ await teardown.prepare();
+
+ let eslint = new FlatESLint({ cwd });
+ let [{ messages }] = await eslint.lintFiles(["a.js"]);
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ assert.strictEqual(messages[0].messageId, "missingSemi");
+ assert.strictEqual(messages[0].line, 1);
+
+ await sleep(100);
+ await fsp.writeFile(path.join(cwd, "eslint.config.js"), configFileContent.replace("always", "never"));
+
+ eslint = new FlatESLint({ cwd });
+ [{ messages }] = await eslint.lintFiles(["a.js"]);
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ assert.strictEqual(messages[0].messageId, "extraSemi");
+ assert.strictEqual(messages[0].line, 2);
+ });
+
+ it("new instance of FlatESLint should use the latest version of the config file (CJS)", async () => {
+ const cwd = path.join(getFixturePath(), `config_file_${Date.now()}`);
+ const configFileContent = "module.exports = [{ rules: { semi: ['error', 'always'] } }];";
+ const teardown = createCustomTeardown({
+ cwd,
+ files: {
+ "eslint.config.js": configFileContent,
+ "a.js": "foo\nbar;"
+ }
+ });
+
+ await teardown.prepare();
+
+ let eslint = new FlatESLint({ cwd });
+ let [{ messages }] = await eslint.lintFiles(["a.js"]);
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ assert.strictEqual(messages[0].messageId, "missingSemi");
+ assert.strictEqual(messages[0].line, 1);
+
+ await sleep(100);
+ await fsp.writeFile(path.join(cwd, "eslint.config.js"), configFileContent.replace("always", "never"));
+
+ eslint = new FlatESLint({ cwd });
+ [{ messages }] = await eslint.lintFiles(["a.js"]);
+
+ assert.strictEqual(messages.length, 1);
+ assert.strictEqual(messages[0].ruleId, "semi");
+ assert.strictEqual(messages[0].messageId, "extraSemi");
+ assert.strictEqual(messages[0].line, 2);
+ });
+ });
+
+});
+
+describe("shouldUseFlatConfig", () => {
+
+ /**
+ * Check that `shouldUseFlatConfig` returns the expected value from a CWD
+ * with a flat config and one without a flat config.
+ * @param {boolean} expectedValueWithConfig the expected return value of
+ * `shouldUseFlatConfig` when in a directory with a flat config present
+ * @param {boolean} expectedValueWithoutConfig the expected return value of
+ * `shouldUseFlatConfig` when in a directory without any flat config present
+ * @returns {void}
+ */
+ function testShouldUseFlatConfig(expectedValueWithConfig, expectedValueWithoutConfig) {
+ describe("when there is a flat config file present", () => {
+ const originalDir = process.cwd();
+
+ beforeEach(() => {
+ process.chdir(__dirname);
+ });
+
+ afterEach(() => {
+ process.chdir(originalDir);
+ });
+
+ it(`is \`${expectedValueWithConfig}\``, async () => {
+ assert.strictEqual(await shouldUseFlatConfig(), expectedValueWithConfig);
+ });
+ });
+
+ describe("when there is no flat config file present", () => {
+ const originalDir = process.cwd();
+
+ beforeEach(() => {
+ process.chdir(os.tmpdir());
+ });
+
+ afterEach(() => {
+ process.chdir(originalDir);
+ });
+
+ it(`is \`${expectedValueWithoutConfig}\``, async () => {
+ assert.strictEqual(await shouldUseFlatConfig(), expectedValueWithoutConfig);
+ });
+ });
+ }
+
+ describe("when the env variable `ESLINT_USE_FLAT_CONFIG` is `'true'`", () => {
+ beforeEach(() => {
+ process.env.ESLINT_USE_FLAT_CONFIG = true;
+ });
+
+ afterEach(() => {
+ delete process.env.ESLINT_USE_FLAT_CONFIG;
+ });
+
+ testShouldUseFlatConfig(true, true);
+ });
+
+ describe("when the env variable `ESLINT_USE_FLAT_CONFIG` is `'false'`", () => {
+ beforeEach(() => {
+ process.env.ESLINT_USE_FLAT_CONFIG = false;
+ });
+
+ afterEach(() => {
+ delete process.env.ESLINT_USE_FLAT_CONFIG;
+ });
+
+ testShouldUseFlatConfig(false, false);
+ });
+
+ describe("when the env variable `ESLINT_USE_FLAT_CONFIG` is unset", () => {
+ testShouldUseFlatConfig(true, false);
+ });
});
beforeEach(() => {
actual = [];
- linter.defineRule("test", () => ({
- onCodePathStart(codePath) {
- actual.push(codePath);
- }
- }));
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathStart(codePath) {
+ actual.push(codePath);
+ }
+ })
+ });
linter.verify(
"function foo(a) { if (a) return 0; else throw new Error(); }",
{ rules: { test: 2 } }
assert(actual[1].currentSegments.length === 0);
// there is the current segment in progress.
- linter.defineRule("test", () => {
- let codePath = null;
-
- return {
- onCodePathStart(cp) {
- codePath = cp;
- },
- ReturnStatement() {
- assert(codePath.currentSegments.length === 1);
- assert(codePath.currentSegments[0] instanceof CodePathSegment);
- },
- ThrowStatement() {
- assert(codePath.currentSegments.length === 1);
- assert(codePath.currentSegments[0] instanceof CodePathSegment);
- }
- };
+ linter.defineRule("test", {
+ create() {
+ let codePath = null;
+
+ return {
+ onCodePathStart(cp) {
+ codePath = cp;
+ },
+ ReturnStatement() {
+ assert(codePath.currentSegments.length === 1);
+ assert(codePath.currentSegments[0] instanceof CodePathSegment);
+ },
+ ThrowStatement() {
+ assert(codePath.currentSegments.length === 1);
+ assert(codePath.currentSegments[0] instanceof CodePathSegment);
+ }
+ };
+ }
});
linter.verify(
"function foo(a) { if (a) return 0; else throw new Error(); }",
beforeEach(() => {
actual = [];
- linter.defineRule("test", () => ({
- onCodePathSegmentStart(segment) {
- actual.push(segment);
- }
- }));
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentStart(segment) {
+ actual.push(segment);
+ }
+ })
+ });
linter.verify(
"function foo(a) { if (a) return 0; else throw new Error(); }",
{ rules: { test: 2 } }
let count = 0;
let lastCodePathNodeType = null;
- linter.defineRule("test", () => ({
- onCodePathStart(cp, node) {
- count += 1;
- lastCodePathNodeType = node.type;
-
- assert(cp instanceof CodePath);
- if (count === 1) {
- assert(node.type === "Program");
- } else if (count === 2) {
- assert(node.type === "FunctionDeclaration");
- } else if (count === 3) {
- assert(node.type === "FunctionExpression");
- } else if (count === 4) {
- assert(node.type === "ArrowFunctionExpression");
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathStart(cp, node) {
+ count += 1;
+ lastCodePathNodeType = node.type;
+
+ assert(cp instanceof CodePath);
+ if (count === 1) {
+ assert(node.type === "Program");
+ } else if (count === 2) {
+ assert(node.type === "FunctionDeclaration");
+ } else if (count === 3) {
+ assert(node.type === "FunctionExpression");
+ } else if (count === 4) {
+ assert(node.type === "ArrowFunctionExpression");
+ }
+ },
+ Program() {
+ assert(lastCodePathNodeType === "Program");
+ },
+ FunctionDeclaration() {
+ assert(lastCodePathNodeType === "FunctionDeclaration");
+ },
+ FunctionExpression() {
+ assert(lastCodePathNodeType === "FunctionExpression");
+ },
+ ArrowFunctionExpression() {
+ assert(lastCodePathNodeType === "ArrowFunctionExpression");
}
- },
- Program() {
- assert(lastCodePathNodeType === "Program");
- },
- FunctionDeclaration() {
- assert(lastCodePathNodeType === "FunctionDeclaration");
- },
- FunctionExpression() {
- assert(lastCodePathNodeType === "FunctionExpression");
- },
- ArrowFunctionExpression() {
- assert(lastCodePathNodeType === "ArrowFunctionExpression");
- }
- }));
+ })
+ });
linter.verify(
"foo(); function foo() {} var foo = function() {}; var foo = () => {};",
{ rules: { test: 2 }, env: { es6: true } }
let count = 0;
let lastNodeType = null;
- linter.defineRule("test", () => ({
- onCodePathEnd(cp, node) {
- count += 1;
-
- assert(cp instanceof CodePath);
- if (count === 4) {
- assert(node.type === "Program");
- } else if (count === 1) {
- assert(node.type === "FunctionDeclaration");
- } else if (count === 2) {
- assert(node.type === "FunctionExpression");
- } else if (count === 3) {
- assert(node.type === "ArrowFunctionExpression");
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathEnd(cp, node) {
+ count += 1;
+
+ assert(cp instanceof CodePath);
+ if (count === 4) {
+ assert(node.type === "Program");
+ } else if (count === 1) {
+ assert(node.type === "FunctionDeclaration");
+ } else if (count === 2) {
+ assert(node.type === "FunctionExpression");
+ } else if (count === 3) {
+ assert(node.type === "ArrowFunctionExpression");
+ }
+ assert(node.type === lastNodeType);
+ },
+ "Program:exit"() {
+ lastNodeType = "Program";
+ },
+ "FunctionDeclaration:exit"() {
+ lastNodeType = "FunctionDeclaration";
+ },
+ "FunctionExpression:exit"() {
+ lastNodeType = "FunctionExpression";
+ },
+ "ArrowFunctionExpression:exit"() {
+ lastNodeType = "ArrowFunctionExpression";
}
- assert(node.type === lastNodeType);
- },
- "Program:exit"() {
- lastNodeType = "Program";
- },
- "FunctionDeclaration:exit"() {
- lastNodeType = "FunctionDeclaration";
- },
- "FunctionExpression:exit"() {
- lastNodeType = "FunctionExpression";
- },
- "ArrowFunctionExpression:exit"() {
- lastNodeType = "ArrowFunctionExpression";
- }
- }));
+ })
+ });
linter.verify(
"foo(); function foo() {} var foo = function() {}; var foo = () => {};",
{ rules: { test: 2 }, env: { es6: true } }
let count = 0;
let lastCodePathNodeType = null;
- linter.defineRule("test", () => ({
- onCodePathSegmentStart(segment, node) {
- count += 1;
- lastCodePathNodeType = node.type;
-
- assert(segment instanceof CodePathSegment);
- if (count === 1) {
- assert(node.type === "Program");
- } else if (count === 2) {
- assert(node.type === "FunctionDeclaration");
- } else if (count === 3) {
- assert(node.type === "FunctionExpression");
- } else if (count === 4) {
- assert(node.type === "ArrowFunctionExpression");
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentStart(segment, node) {
+ count += 1;
+ lastCodePathNodeType = node.type;
+
+ assert(segment instanceof CodePathSegment);
+ if (count === 1) {
+ assert(node.type === "Program");
+ } else if (count === 2) {
+ assert(node.type === "FunctionDeclaration");
+ } else if (count === 3) {
+ assert(node.type === "FunctionExpression");
+ } else if (count === 4) {
+ assert(node.type === "ArrowFunctionExpression");
+ }
+ },
+ Program() {
+ assert(lastCodePathNodeType === "Program");
+ },
+ FunctionDeclaration() {
+ assert(lastCodePathNodeType === "FunctionDeclaration");
+ },
+ FunctionExpression() {
+ assert(lastCodePathNodeType === "FunctionExpression");
+ },
+ ArrowFunctionExpression() {
+ assert(lastCodePathNodeType === "ArrowFunctionExpression");
}
- },
- Program() {
- assert(lastCodePathNodeType === "Program");
- },
- FunctionDeclaration() {
- assert(lastCodePathNodeType === "FunctionDeclaration");
- },
- FunctionExpression() {
- assert(lastCodePathNodeType === "FunctionExpression");
- },
- ArrowFunctionExpression() {
- assert(lastCodePathNodeType === "ArrowFunctionExpression");
- }
- }));
+ })
+ });
linter.verify(
"foo(); function foo() {} var foo = function() {}; var foo = () => {};",
{ rules: { test: 2 }, env: { es6: true } }
let count = 0;
let lastNodeType = null;
- linter.defineRule("test", () => ({
- onCodePathSegmentEnd(cp, node) {
- count += 1;
-
- assert(cp instanceof CodePathSegment);
- if (count === 4) {
- assert(node.type === "Program");
- } else if (count === 1) {
- assert(node.type === "FunctionDeclaration");
- } else if (count === 2) {
- assert(node.type === "FunctionExpression");
- } else if (count === 3) {
- assert(node.type === "ArrowFunctionExpression");
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentEnd(cp, node) {
+ count += 1;
+
+ assert(cp instanceof CodePathSegment);
+ if (count === 4) {
+ assert(node.type === "Program");
+ } else if (count === 1) {
+ assert(node.type === "FunctionDeclaration");
+ } else if (count === 2) {
+ assert(node.type === "FunctionExpression");
+ } else if (count === 3) {
+ assert(node.type === "ArrowFunctionExpression");
+ }
+ assert(node.type === lastNodeType);
+ },
+ "Program:exit"() {
+ lastNodeType = "Program";
+ },
+ "FunctionDeclaration:exit"() {
+ lastNodeType = "FunctionDeclaration";
+ },
+ "FunctionExpression:exit"() {
+ lastNodeType = "FunctionExpression";
+ },
+ "ArrowFunctionExpression:exit"() {
+ lastNodeType = "ArrowFunctionExpression";
}
- assert(node.type === lastNodeType);
- },
- "Program:exit"() {
- lastNodeType = "Program";
- },
- "FunctionDeclaration:exit"() {
- lastNodeType = "FunctionDeclaration";
- },
- "FunctionExpression:exit"() {
- lastNodeType = "FunctionExpression";
- },
- "ArrowFunctionExpression:exit"() {
- lastNodeType = "ArrowFunctionExpression";
- }
- }));
+ })
+ });
linter.verify(
"foo(); function foo() {} var foo = function() {}; var foo = () => {};",
{ rules: { test: 2 }, env: { es6: true } }
it("should be fired in `while` loops", () => {
let count = 0;
- linter.defineRule("test", () => ({
- onCodePathSegmentLoop(fromSegment, toSegment, node) {
- count += 1;
- assert(fromSegment instanceof CodePathSegment);
- assert(toSegment instanceof CodePathSegment);
- assert(node.type === "WhileStatement");
- }
- }));
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentLoop(fromSegment, toSegment, node) {
+ count += 1;
+ assert(fromSegment instanceof CodePathSegment);
+ assert(toSegment instanceof CodePathSegment);
+ assert(node.type === "WhileStatement");
+ }
+ })
+ });
linter.verify(
"while (a) { foo(); }",
{ rules: { test: 2 } }
it("should be fired in `do-while` loops", () => {
let count = 0;
- linter.defineRule("test", () => ({
- onCodePathSegmentLoop(fromSegment, toSegment, node) {
- count += 1;
- assert(fromSegment instanceof CodePathSegment);
- assert(toSegment instanceof CodePathSegment);
- assert(node.type === "DoWhileStatement");
- }
- }));
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentLoop(fromSegment, toSegment, node) {
+ count += 1;
+ assert(fromSegment instanceof CodePathSegment);
+ assert(toSegment instanceof CodePathSegment);
+ assert(node.type === "DoWhileStatement");
+ }
+ })
+ });
linter.verify(
"do { foo(); } while (a);",
{ rules: { test: 2 } }
it("should be fired in `for` loops", () => {
let count = 0;
- linter.defineRule("test", () => ({
- onCodePathSegmentLoop(fromSegment, toSegment, node) {
- count += 1;
- assert(fromSegment instanceof CodePathSegment);
- assert(toSegment instanceof CodePathSegment);
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentLoop(fromSegment, toSegment, node) {
+ count += 1;
+ assert(fromSegment instanceof CodePathSegment);
+ assert(toSegment instanceof CodePathSegment);
- if (count === 1) {
+ if (count === 1) {
- // connect path: "update" -> "test"
- assert(node.parent.type === "ForStatement");
- } else if (count === 2) {
- assert(node.type === "ForStatement");
+ // connect path: "update" -> "test"
+ assert(node.parent.type === "ForStatement");
+ } else if (count === 2) {
+ assert(node.type === "ForStatement");
+ }
}
- }
- }));
+ })
+ });
linter.verify(
"for (var i = 0; i < 10; ++i) { foo(); }",
{ rules: { test: 2 } }
it("should be fired in `for-in` loops", () => {
let count = 0;
- linter.defineRule("test", () => ({
- onCodePathSegmentLoop(fromSegment, toSegment, node) {
- count += 1;
- assert(fromSegment instanceof CodePathSegment);
- assert(toSegment instanceof CodePathSegment);
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentLoop(fromSegment, toSegment, node) {
+ count += 1;
+ assert(fromSegment instanceof CodePathSegment);
+ assert(toSegment instanceof CodePathSegment);
- if (count === 1) {
+ if (count === 1) {
- // connect path: "right" -> "left"
- assert(node.parent.type === "ForInStatement");
- } else if (count === 2) {
- assert(node.type === "ForInStatement");
+ // connect path: "right" -> "left"
+ assert(node.parent.type === "ForInStatement");
+ } else if (count === 2) {
+ assert(node.type === "ForInStatement");
+ }
}
- }
- }));
+ })
+ });
linter.verify(
"for (var k in obj) { foo(); }",
{ rules: { test: 2 } }
it("should be fired in `for-of` loops", () => {
let count = 0;
- linter.defineRule("test", () => ({
- onCodePathSegmentLoop(fromSegment, toSegment, node) {
- count += 1;
- assert(fromSegment instanceof CodePathSegment);
- assert(toSegment instanceof CodePathSegment);
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathSegmentLoop(fromSegment, toSegment, node) {
+ count += 1;
+ assert(fromSegment instanceof CodePathSegment);
+ assert(toSegment instanceof CodePathSegment);
- if (count === 1) {
+ if (count === 1) {
- // connect path: "right" -> "left"
- assert(node.parent.type === "ForOfStatement");
- } else if (count === 2) {
- assert(node.type === "ForOfStatement");
+ // connect path: "right" -> "left"
+ assert(node.parent.type === "ForOfStatement");
+ } else if (count === 2) {
+ assert(node.type === "ForOfStatement");
+ }
}
- }
- }));
+ })
+ });
linter.verify(
"for (var x of xs) { foo(); }",
{ rules: { test: 2 }, env: { es6: true } }
assert(expected.length > 0, "/*expected */ comments not found.");
- linter.defineRule("test", () => ({
- onCodePathEnd(codePath) {
- actual.push(debug.makeDotArrows(codePath));
- }
- }));
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathEnd(codePath) {
+ actual.push(debug.makeDotArrows(codePath));
+ }
+ })
+ });
const messages = linter.verify(source, {
parserOptions: { ecmaVersion: 2022 },
rules: { test: 2 }
function parseCodePaths(code) {
const retv = [];
- linter.defineRule("test", () => ({
- onCodePathStart(codePath) {
- retv.push(codePath);
- }
- }));
+ linter.defineRule("test", {
+ create: () => ({
+ onCodePathStart(codePath) {
+ retv.push(codePath);
+ }
+ })
+ });
linter.verify(code, {
rules: { test: 2 },
it("an error should be thrown when an error occurs inside of an event handler", () => {
const config = { rules: { checker: "error" } };
- linter.defineRule("checker", () => ({
- Program() {
- throw new Error("Intentional error.");
- }
- }));
+ linter.defineRule("checker", {
+ create: () => ({
+ Program() {
+ throw new Error("Intentional error.");
+ }
+ })
+ });
assert.throws(() => {
linter.verify(code, config, filename);
it("does not call rule listeners with a `this` value", () => {
const spy = sinon.spy();
- linter.defineRule("checker", () => ({ Program: spy }));
+ linter.defineRule("checker", {
+ create: () => ({ Program: spy })
+ });
linter.verify("foo", { rules: { checker: "error" } });
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", () => {
const spy = sinon.spy();
- linter.defineRule("checker", () => ({ newListener: spy }));
+ linter.defineRule("checker", {
+ create: () => ({ newListener: spy })
+ });
linter.verify("foo", { rules: { checker: "error", "no-undef": "error" } });
assert(spy.notCalled);
});
it("has all the `parent` properties on nodes when the rule listeners are created", () => {
const spy = sinon.spy(context => {
- const ast = context.getSourceCode().ast;
+ assert.strictEqual(context.getSourceCode(), context.sourceCode);
+ const ast = context.sourceCode.ast;
assert.strictEqual(ast.body[0].parent, ast);
assert.strictEqual(ast.body[0].expression.parent, ast.body[0]);
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify("foo + bar", { rules: { checker: "error" } });
assert(spy.calledOnce);
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, { rules: { checker: "error" } });
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, { rules: { checker: "error" } });
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, { rules: { checker: "error" } });
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, { rules: { checker: "error" } });
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, { rules: { checker: "error" } });
assert(spy.calledOnce);
});
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getSource(), TEST_CODE);
- });
- return { Program: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getSource(), TEST_CODE);
+ });
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node), TEST_CODE);
- });
- return { Program: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node), TEST_CODE);
+ });
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
- });
- return { Program: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
+ });
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node), "6 * 7");
- });
- return { BinaryExpression: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node), "6 * 7");
+ });
+ return { BinaryExpression: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
- });
- return { BinaryExpression: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
+ });
+ return { BinaryExpression: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
- });
- return { BinaryExpression: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
+ });
+ return { BinaryExpression: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
- });
- return { BinaryExpression: spy };
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
+ });
+ return { BinaryExpression: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const ancestors = context.getAncestors();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const ancestors = context.getAncestors();
- assert.strictEqual(ancestors.length, 3);
- });
- return { BinaryExpression: spy };
+ assert.strictEqual(ancestors.length, 3);
+ });
+ return { BinaryExpression: spy };
+ }
});
linter.verify(code, config, filename, true);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const ancestors = context.getAncestors();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const ancestors = context.getAncestors();
- assert.strictEqual(ancestors.length, 0);
- });
+ assert.strictEqual(ancestors.length, 0);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "global");
- });
- return { Program: spy };
+ assert.strictEqual(scope.type, "global");
+ });
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- });
- return { FunctionDeclaration: spy };
+ assert.strictEqual(scope.type, "function");
+ });
+ return { FunctionDeclaration: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.id.name, "foo");
- });
- return { LabeledStatement: spy };
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.id.name, "foo");
+ });
+ return { LabeledStatement: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
- });
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
+ });
- return { ReturnStatement: spy };
+ return { ReturnStatement: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "switch");
- assert.strictEqual(scope.block.type, "SwitchStatement");
- });
+ assert.strictEqual(scope.type, "switch");
+ assert.strictEqual(scope.block.type, "SwitchStatement");
+ });
- return { SwitchStatement: spy };
+ return { SwitchStatement: spy };
+ }
});
linter.verify("switch(foo){ case 'a': var b = 'foo'; }", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "block");
- assert.strictEqual(scope.block.type, "BlockStatement");
- });
+ assert.strictEqual(scope.type, "block");
+ assert.strictEqual(scope.block.type, "BlockStatement");
+ });
- return { BlockStatement: spy };
+ return { BlockStatement: spy };
+ }
});
linter.verify("var x; {let y = 1}", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "block");
- assert.strictEqual(scope.block.type, "BlockStatement");
- });
+ assert.strictEqual(scope.type, "block");
+ assert.strictEqual(scope.block.type, "BlockStatement");
+ });
- return { BlockStatement: spy };
+ return { BlockStatement: spy };
+ }
});
linter.verify("if (true) { let x = 1 }", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.type, "FunctionDeclaration");
- });
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.type, "FunctionDeclaration");
+ });
- return { FunctionDeclaration: spy };
+ return { FunctionDeclaration: spy };
+ }
});
linter.verify("function foo() {}", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.type, "FunctionExpression");
- });
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.type, "FunctionExpression");
+ });
- return { FunctionExpression: spy };
+ return { FunctionExpression: spy };
+ }
});
linter.verify("(function foo() {})();", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "catch");
- assert.strictEqual(scope.block.type, "CatchClause");
- });
+ assert.strictEqual(scope.type, "catch");
+ assert.strictEqual(scope.block.type, "CatchClause");
+ });
- return { CatchClause: spy };
+ return { CatchClause: spy };
+ }
});
linter.verify("try {} catch (err) {}", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "module");
- });
+ assert.strictEqual(scope.type, "module");
+ });
- return { AssignmentExpression: spy };
+ return { AssignmentExpression: spy };
+ }
});
linter.verify("var foo = {}; foo.bar = 1;", config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, ecmaFeatures: { globalReturn: true } } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- });
+ assert.strictEqual(scope.type, "function");
+ });
- return { AssignmentExpression: spy };
+ return { AssignmentExpression: spy };
+ }
});
linter.verify("var foo = {}; foo.bar = 1;", config);
const code = "var a = 1, b = 2;";
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- assert.isTrue(context.markVariableAsUsed("a"));
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.isTrue(context.markVariableAsUsed("a"));
- const scope = context.getScope();
+ const scope = context.getScope();
- assert.isTrue(getVariable(scope, "a").eslintUsed);
- assert.notOk(getVariable(scope, "b").eslintUsed);
- });
+ assert.isTrue(getVariable(scope, "a").eslintUsed);
+ assert.notOk(getVariable(scope, "b").eslintUsed);
+ });
- return { "Program:exit": spy };
+ return { "Program:exit": spy };
+ }
});
linter.verify(code, { rules: { checker: "error" } });
const code = "function abc(a, b) { return 1; }";
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- assert.isTrue(context.markVariableAsUsed("a"));
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.isTrue(context.markVariableAsUsed("a"));
- const scope = context.getScope();
+ const scope = context.getScope();
- assert.isTrue(getVariable(scope, "a").eslintUsed);
- assert.notOk(getVariable(scope, "b").eslintUsed);
- });
+ assert.isTrue(getVariable(scope, "a").eslintUsed);
+ assert.notOk(getVariable(scope, "b").eslintUsed);
+ });
- return { ReturnStatement: spy };
+ return { ReturnStatement: spy };
+ }
});
linter.verify(code, { rules: { checker: "error" } });
const code = "var a, b; function abc() { return 1; }";
let returnSpy, exitSpy;
- linter.defineRule("checker", context => {
- returnSpy = sinon.spy(() => {
- assert.isTrue(context.markVariableAsUsed("a"));
- });
- exitSpy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(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);
- });
+ assert.isTrue(getVariable(scope, "a").eslintUsed);
+ assert.notOk(getVariable(scope, "b").eslintUsed);
+ });
- return { ReturnStatement: returnSpy, "Program:exit": exitSpy };
+ return { ReturnStatement: returnSpy, "Program:exit": exitSpy };
+ }
});
linter.verify(code, { rules: { checker: "error" } });
const code = "var a = 1, b = 2;";
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const globalScope = context.getScope(),
- childScope = globalScope.childScopes[0];
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const globalScope = context.getScope(),
+ childScope = globalScope.childScopes[0];
- assert.isTrue(context.markVariableAsUsed("a"));
+ assert.isTrue(context.markVariableAsUsed("a"));
- assert.isTrue(getVariable(childScope, "a").eslintUsed);
- assert.isUndefined(getVariable(childScope, "b").eslintUsed);
- });
+ assert.isTrue(getVariable(childScope, "a").eslintUsed);
+ assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+ });
- return { "Program:exit": spy };
+ return { "Program:exit": spy };
+ }
});
linter.verify(code, { rules: { checker: "error" }, env: { node: true } });
const code = "var a = 1, b = 2;";
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const globalScope = context.getScope(),
- childScope = globalScope.childScopes[0];
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const globalScope = context.getScope(),
+ childScope = globalScope.childScopes[0];
- assert.isTrue(context.markVariableAsUsed("a"));
+ assert.isTrue(context.markVariableAsUsed("a"));
- assert.isTrue(getVariable(childScope, "a").eslintUsed);
- assert.isUndefined(getVariable(childScope, "b").eslintUsed);
- });
+ assert.isTrue(getVariable(childScope, "a").eslintUsed);
+ assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+ });
- return { "Program:exit": spy };
+ return { "Program:exit": spy };
+ }
});
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } }, filename, true);
const code = "var a = 1, b = 2;";
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- assert.isFalse(context.markVariableAsUsed("c"));
- });
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.isFalse(context.markVariableAsUsed("c"));
+ });
- return { "Program:exit": spy };
+ return { "Program:exit": spy };
+ }
});
linter.verify(code, { rules: { checker: "error" } });
spyIdentifier = sinon.spy(),
spyBinaryExpression = sinon.spy();
- linter.defineRule("checker", () => ({
- Literal: spyLiteral,
- VariableDeclarator: spyVariableDeclarator,
- VariableDeclaration: spyVariableDeclaration,
- Identifier: spyIdentifier,
- BinaryExpression: spyBinaryExpression
- }));
+ linter.defineRule("checker", {
+ create: () => ({
+ Literal: spyLiteral,
+ VariableDeclarator: spyVariableDeclarator,
+ VariableDeclaration: spyVariableDeclaration,
+ Identifier: spyIdentifier,
+ BinaryExpression: spyBinaryExpression
+ })
+ });
const messages = linter.verify(code, config, filename, true);
const suppressedMessages = linter.getSuppressedMessages();
});
it("should throw an error if a rule reports a problem without a message", () => {
- linter.defineRule("invalid-report", context => ({
- Program(node) {
- context.report({ node });
- }
- }));
+ linter.defineRule("invalid-report", {
+ create: context => ({
+ Program(node) {
+ context.report({ node });
+ }
+ })
+ });
assert.throws(
() => linter.verify("foo", { rules: { "invalid-report": "error" } }),
const code = "test-rule";
it("should pass settings to all rules", () => {
- linter.defineRule(code, context => ({
- Literal(node) {
- context.report(node, context.settings.info);
- }
- }));
+ linter.defineRule(code, {
+ create: context => ({
+ Literal(node) {
+ context.report(node, context.settings.info);
+ }
+ })
+ });
const config = { rules: {}, settings: { info: "Hello" } };
});
it("should not have any settings if they were not passed in", () => {
- linter.defineRule(code, context => ({
- Literal(node) {
- if (Object.getOwnPropertyNames(context.settings).length !== 0) {
- context.report(node, "Settings should be empty");
+ linter.defineRule(code, {
+ create: context => ({
+ Literal(node) {
+ if (Object.getOwnPropertyNames(context.settings).length !== 0) {
+ context.report(node, "Settings should be empty");
+ }
}
- }
- }));
+ })
+ });
const config = { rules: {} };
}
};
- linter.defineRule("test-rule", sinon.mock().withArgs(
- sinon.match({ parserOptions })
- ).returns({}));
+ linter.defineRule("test-rule", {
+ create: sinon.mock().withArgs(
+ sinon.match({ parserOptions })
+ ).returns({})
+ });
const config = { rules: { "test-rule": 2 }, parserOptions };
const parserOptions = {};
- linter.defineRule("test-rule", sinon.mock().withArgs(
- sinon.match({ parserOptions })
- ).returns({}));
+ linter.defineRule("test-rule", {
+ create: sinon.mock().withArgs(
+ sinon.match({ parserOptions })
+ ).returns({})
+ });
const config = { rules: { "test-rule": 2 } };
const alternateParser = "esprima";
linter.defineParser("esprima", esprima);
- linter.defineRule("test-rule", sinon.mock().withArgs(
- sinon.match({ parserPath: alternateParser })
- ).returns({}));
+ linter.defineRule("test-rule", {
+ create: sinon.mock().withArgs(
+ sinon.match({ parserPath: alternateParser })
+ ).returns({})
+ });
const config = { rules: { "test-rule": 2 }, parser: alternateParser };
it("should expose parser services when using parseForESLint() and services are specified", () => {
linter.defineParser("enhanced-parser", testParsers.enhancedParser);
- linter.defineRule("test-service-rule", context => ({
- Literal(node) {
- context.report({
- node,
- message: context.parserServices.test.getMessage()
- });
- }
- }));
+ linter.defineRule("test-service-rule", {
+ create: context => ({
+ Literal(node) {
+ context.report({
+ node,
+ message: context.parserServices.test.getMessage()
+ });
+ }
+ })
+ });
const config = { rules: { "test-service-rule": 2 }, parser: "enhanced-parser" };
const messages = linter.verify("0", config, filename);
it("should use the same parserServices if source code object is reused", () => {
linter.defineParser("enhanced-parser", testParsers.enhancedParser);
- linter.defineRule("test-service-rule", context => ({
- Literal(node) {
- context.report({
- node,
- message: context.parserServices.test.getMessage()
- });
- }
- }));
+ linter.defineRule("test-service-rule", {
+ create: context => ({
+ Literal(node) {
+ context.report({
+ node,
+ message: context.parserServices.test.getMessage()
+ });
+ }
+ })
+ });
const config = { rules: { "test-service-rule": 2 }, parser: "enhanced-parser" };
const messages = linter.verify("0", config, filename);
});
it("should pass parser as parserPath to all rules when default parser is used", () => {
- linter.defineRule("test-rule", sinon.mock().withArgs(
- sinon.match({ parserPath: "espree" })
- ).returns({}));
+ linter.defineRule("test-rule", {
+ create: sinon.mock().withArgs(
+ sinon.match({ parserPath: "espree" })
+ ).returns({})
+ });
const config = { rules: { "test-rule": 2 } };
`;
let spy;
- linter.defineRule("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 };
+ linter.defineRule("checker", {
+ create(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 };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- a = getVariable(scope, "a"),
- b = getVariable(scope, "b"),
- c = getVariable(scope, "c");
+ linter.defineRule("checker", {
+ create(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);
- });
+ 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 };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- exports = getVariable(scope, "exports"),
- window = getVariable(scope, "window");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ exports = getVariable(scope, "exports"),
+ window = getVariable(scope, "window");
- assert.strictEqual(exports.writeable, true);
- assert.strictEqual(window.writeable, false);
- });
+ assert.strictEqual(exports.writeable, true);
+ assert.strictEqual(window.writeable, false);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- exports = getVariable(scope, "exports"),
- window = getVariable(scope, "window");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ exports = getVariable(scope, "exports"),
+ window = getVariable(scope, "window");
- assert.strictEqual(exports.writeable, true);
- assert.strictEqual(window, null);
- });
+ assert.strictEqual(exports.writeable, true);
+ assert.strictEqual(window, null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse.eslintUsed, true);
- });
+ assert.strictEqual(horse.eslintUsed, true);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse, null);
- });
+ assert.strictEqual(horse, null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse.eslintUsed, true);
- });
+ assert.strictEqual(horse.eslintUsed, true);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse, null); // there is no global scope at all
- });
+ assert.strictEqual(horse, null); // there is no global scope at all
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, env: { node: true } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse, null); // there is no global scope at all
- });
+ assert.strictEqual(horse, null); // there is no global scope at all
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(getVariable(scope, "a"), null);
- });
+ assert.strictEqual(getVariable(scope, "a"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(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);
- });
+ 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 };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(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);
- });
+ assert.notStrictEqual(getVariable(scope, "Object"), null);
+ assert.notStrictEqual(getVariable(scope, "Array"), null);
+ assert.notStrictEqual(getVariable(scope, "undefined"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(getVariable(scope, "Promise"), null);
- assert.strictEqual(getVariable(scope, "Symbol"), null);
- assert.strictEqual(getVariable(scope, "WeakMap"), null);
- });
+ assert.strictEqual(getVariable(scope, "Promise"), null);
+ assert.strictEqual(getVariable(scope, "Symbol"), null);
+ assert.strictEqual(getVariable(scope, "WeakMap"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, env: { es6: true } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(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);
- });
+ assert.notStrictEqual(getVariable(scope, "Promise"), null);
+ assert.notStrictEqual(getVariable(scope, "Symbol"), null);
+ assert.notStrictEqual(getVariable(scope, "WeakMap"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const config = { rules: { checker: "error" }, globals: { Promise: "off", Symbol: "off", WeakMap: "off" }, env: { es6: true } };
let spy;
- linter.defineRule("checker", context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ linter.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(getVariable(scope, "Promise"), null);
- assert.strictEqual(getVariable(scope, "Symbol"), null);
- assert.strictEqual(getVariable(scope, "WeakMap"), null);
- });
+ assert.strictEqual(getVariable(scope, "Promise"), null);
+ assert.strictEqual(getVariable(scope, "Symbol"), null);
+ assert.strictEqual(getVariable(scope, "WeakMap"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
});
linter.verify(code, config);
const code = "new-rule";
it("can add a rule dynamically", () => {
- linter.defineRule(code, context => ({
- Literal(node) {
- context.report(node, "message");
- }
- }));
+ linter.defineRule(code, {
+ create: context => ({
+ Literal(node) {
+ context.report(node, "message");
+ }
+ })
+ });
const config = { rules: {} };
code.forEach(item => {
config.rules[item] = 1;
- newRules[item] = function(context) {
- return {
- Literal(node) {
- context.report(node, "message");
- }
- };
+ newRules[item] = {
+ create(context) {
+ return {
+ Literal(node) {
+ context.report(node, "message");
+ }
+ };
+ }
};
});
linter.defineRules(newRules);
const code = "filename-rule";
it("has access to the filename", () => {
- linter.defineRule(code, context => ({
- Literal(node) {
- context.report(node, context.getFilename());
- }
- }));
+ linter.defineRule(code, {
+ create: context => ({
+ Literal(node) {
+ assert.strictEqual(context.getFilename(), context.filename);
+ context.report(node, context.filename);
+ }
+ })
+ });
const config = { rules: {} };
});
it("has access to the physicalFilename", () => {
- linter.defineRule(code, context => ({
- Literal(node) {
- context.report(node, context.getPhysicalFilename());
- }
- }));
+ linter.defineRule(code, {
+ create: context => ({
+ Literal(node) {
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ context.report(node, context.physicalFilename);
+ }
+ })
+ });
const config = { rules: {} };
});
it("defaults filename to '<input>'", () => {
- linter.defineRule(code, context => ({
- Literal(node) {
- context.report(node, context.getFilename());
- }
- }));
-
- const config = { rules: {} };
+ linter.defineRule(code, {
+ create: context => ({
+ Literal(node) {
+ assert.strictEqual(context.getFilename(), context.filename);
+ context.report(node, context.filename);
+ }
+ })
+ });
+
+ const config = { rules: {} };
config.rules[code] = 1;
describe("when evaluating code with comments to disable and enable configurable rule as part of plugin", () => {
beforeEach(() => {
- linter.defineRule("test-plugin/test-rule", context => ({
- Literal(node) {
- if (node.value === "trigger violation") {
- context.report(node, "Reporting violation.");
- }
+ linter.defineRule("test-plugin/test-rule", {
+ create(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", () => {
it("should report a violation when the report is right before the comment", () => {
const code = " /* eslint-disable */ ";
- linter.defineRule("checker", context => ({
- Program() {
- context.report({ loc: { line: 1, column: 0 }, message: "foo" });
- }
- }));
+ linter.defineRule("checker", {
+ create: context => ({
+ Program() {
+ context.report({ loc: { line: 1, column: 0 }, message: "foo" });
+ }
+ })
+ });
const problems = linter.verify(code, { rules: { checker: "error" } });
const suppressedMessages = linter.getSuppressedMessages();
it("should not report a violation when the report is right at the start of the comment", () => {
const code = " /* eslint-disable */ ";
- linter.defineRule("checker", context => ({
- Program() {
- context.report({ loc: { line: 1, column: 1 }, message: "foo" });
- }
- }));
+ linter.defineRule("checker", {
+ create: context => ({
+ Program() {
+ context.report({ loc: { line: 1, column: 1 }, message: "foo" });
+ }
+ })
+ });
const problems = linter.verify(code, { rules: { checker: "error" } });
const suppressedMessages = linter.getSuppressedMessages();
return {};
});
- linter.defineRule("checker", spy);
+ linter.defineRule("checker", { create: spy });
linter.verify(code, config);
assert(spy.calledOnce);
});
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.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node), "'123';");
+ });
+ return { ExpressionStatement: spy };
+ }
});
linter.verify(code, config);
describe("when evaluating an empty string", () => {
it("runs rules", () => {
- linter.defineRule("no-programs", context => ({
- Program(node) {
- context.report({ node, message: "No programs allowed." });
- }
- }));
+ linter.defineRule("no-programs", {
+ create: context => ({
+ Program(node) {
+ context.report({ node, message: "No programs allowed." });
+ }
+ })
+ });
assert.strictEqual(
linter.verify("", { rules: { "no-programs": "error" } }).length,
let ok = false;
linter.defineRules({
- test(context) {
- return {
+ test: {
+ create: context => ({
Program() {
const scope = context.getScope();
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const comments = sourceCode.getAllComments();
+ assert.strictEqual(context.getSourceCode(), sourceCode);
assert.strictEqual(1, comments.length);
const foo = getVariable(scope, "foo");
ok = true;
}
- };
+ })
}
});
const linterWithOption = new Linter({ cwd });
let spy;
- linterWithOption.defineRule("checker", context => {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getCwd(), cwd);
- });
- return { Program: spy };
+ linterWithOption.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), context.cwd);
+ assert.strictEqual(context.cwd, cwd);
+ });
+ return { Program: spy };
+ }
});
linterWithOption.verify(code, config);
let spy;
const linterWithOption = new Linter({ });
- linterWithOption.defineRule("checker", context => {
+ linterWithOption.defineRule("checker", {
+ create(context) {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getCwd(), process.cwd());
- });
- return { Program: spy };
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), context.cwd);
+ assert.strictEqual(context.cwd, process.cwd());
+ });
+ return { Program: spy };
+ }
});
linterWithOption.verify(code, config);
it("should assign process.cwd() to it if the option is undefined", () => {
let spy;
- linter.defineRule("checker", context => {
+ linter.defineRule("checker", {
+ create(context) {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getCwd(), process.cwd());
- });
- return { Program: spy };
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), context.cwd);
+ assert.strictEqual(context.cwd, process.cwd());
+ });
+ return { Program: spy };
+ }
});
linter.verify(code, config);
assert.strictEqual(suppressedMessages[0].ruleId, "no-alert");
});
+ it("reports no problems for no-fallthrough despite comment pattern match", () => {
+ const code = "switch (foo) { case 0: a(); \n// eslint-disable-next-line no-fallthrough\n case 1: }";
+ const config = {
+ reportUnusedDisableDirectives: true,
+ rules: {
+ "no-fallthrough": 2
+ }
+ };
+
+ const messages = linter.verify(code, config, {
+ filename,
+ allowInlineConfig: true
+ });
+ const suppressedMessages = linter.getSuppressedMessages();
+
+ assert.strictEqual(messages.length, 0);
+
+ assert.strictEqual(suppressedMessages.length, 1);
+ assert.strictEqual(suppressedMessages[0].ruleId, "no-fallthrough");
+ });
+
describe("autofix", () => {
const alwaysReportsRule = {
create(context) {
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.defineRule("checker", {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node), "'123';");
+ });
+ return { ExpressionStatement: spy };
+ }
});
linter.verify(code, config);
describe("filenames", () => {
it("should allow filename to be passed on options object", () => {
const filenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getFilename(), "foo.js");
+ assert.strictEqual(context.filename, "foo.js");
return {};
});
- linter.defineRule("checker", filenameChecker);
+ linter.defineRule("checker", { create: filenameChecker });
linter.verify("foo;", { rules: { checker: "error" } }, { 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");
+ assert.strictEqual(context.filename, "bar.js");
return {};
});
- linter.defineRule("checker", filenameChecker);
+ linter.defineRule("checker", { create: filenameChecker });
linter.verify("foo;", { rules: { checker: "error" } }, "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>");
+ assert.strictEqual(context.filename, "<input>");
return {};
});
- linter.defineRule("checker", filenameChecker);
+ linter.defineRule("checker", { create: filenameChecker });
linter.verify("foo;", { rules: { checker: "error" } }, {});
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>");
+ assert.strictEqual(context.filename, "<input>");
return {};
});
- linter.defineRule("checker", filenameChecker);
+ linter.defineRule("checker", { create: filenameChecker });
linter.verify("foo;", { rules: { checker: "error" } });
assert(filenameChecker.calledOnce);
});
describe("physicalFilenames", () => {
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");
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ assert.strictEqual(context.physicalFilename, "foo.js");
return {};
});
- linter.defineRule("checker", physicalFilenameChecker);
+ linter.defineRule("checker", { create: physicalFilenameChecker });
linter.verify("foo;", { rules: { checker: "error" } }, { 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>");
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ assert.strictEqual(context.physicalFilename, "<input>");
return {};
});
- linter.defineRule("checker", physicalFilenameChecker);
+ linter.defineRule("checker", { create: physicalFilenameChecker });
linter.verify("foo;", { rules: { checker: "error" } }, {});
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>");
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ assert.strictEqual(context.physicalFilename, "<input>");
return {};
});
- linter.defineRule("checker", physicalFilenameChecker);
+ linter.defineRule("checker", { create: physicalFilenameChecker });
linter.verify("foo;", { rules: { checker: "error" } });
assert(physicalFilenameChecker.calledOnce);
});
let ecmaVersion = null;
const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };
- linter.defineRule("ecma-version", context => ({
- Program() {
- ecmaVersion = context.parserOptions.ecmaVersion;
- }
- }));
+ linter.defineRule("ecma-version", {
+ create: context => ({
+ Program() {
+ ecmaVersion = context.parserOptions.ecmaVersion;
+ }
+ })
+ });
linter.verify("", config);
assert.strictEqual(ecmaVersion, espree.latestEcmaVersion, "ecmaVersion should be 13");
});
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.defineRule("ecma-version", {
+ create: context => ({
+ Program() {
+ ecmaVersion = context.parserOptions.ecmaVersion;
+ }
+ })
+ });
linter.verify("", config);
assert.strictEqual(ecmaVersion, "latest", "ecmaVersion should be latest");
});
let ecmaVersion = null;
const config = { rules: { "ecma-version": 2 }, parserOptions: { ecmaVersion: "latest" } };
- linter.defineRule("ecma-version", context => ({
- Program() {
- ecmaVersion = context.languageOptions.ecmaVersion;
- }
- }));
+ linter.defineRule("ecma-version", {
+ create: context => ({
+ Program() {
+ ecmaVersion = context.languageOptions.ecmaVersion;
+ }
+ })
+ });
linter.verify("", config);
assert.strictEqual(ecmaVersion, espree.latestEcmaVersion + 2009, "ecmaVersion should be 2022");
});
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.defineRule("ecma-version", {
+ create: context => ({
+ Program() {
+ ecmaVersion = context.languageOptions.ecmaVersion;
+ }
+ })
+ });
linter.verify("", config);
assert.strictEqual(ecmaVersion, espree.latestEcmaVersion + 2009, "ecmaVersion should be 2022");
});
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.defineRule("ecma-version", {
+ create: 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", () => {
let blockScope = null;
- linter.defineRule("block-scope", context => ({
- BlockStatement() {
- blockScope = context.getScope();
- }
- }));
+ linter.defineRule("block-scope", {
+ create: context => ({
+ BlockStatement() {
+ blockScope = context.getScope();
+ }
+ })
+ });
linter.defineParser("custom-parser", {
parse: (...args) => espree.parse(...args)
});
let ok = false;
linter.defineRules({
- test(context) {
- return {
+ test: {
+ create: context => ({
Program() {
const scope = context.getScope();
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const comments = sourceCode.getAllComments();
+ assert.strictEqual(context.getSourceCode(), sourceCode);
assert.strictEqual(2, comments.length);
const foo = getVariable(scope, "foo");
ok = true;
}
- };
+ })
}
});
let ast1 = null,
ast2 = null;
- linter.defineRule("save-ast1", () => ({
- Program(node) {
- ast1 = node;
- }
- }));
- linter.defineRule("save-ast2", () => ({
- Program(node) {
- ast2 = node;
- }
- }));
+ linter.defineRule("save-ast1", {
+ create: () => ({
+ Program(node) {
+ ast1 = node;
+ }
+ })
+ });
+ linter.defineRule("save-ast2", {
+ create: () => ({
+ Program(node) {
+ ast2 = node;
+ }
+ })
+ });
linter.verify("function render() { return <div className='test'>{hello}</div> }", { parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } }, rules: { "save-ast1": 2 } });
linter.verify(linter.getSourceCode(), { parserOptions: { ecmaVersion: 6, ecmaFeatures: { jsx: true } }, rules: { "save-ast2": 2 } });
return {};
});
- linter.defineRule("foo-bar-baz", spy);
+ linter.defineRule("foo-bar-baz", { create: spy });
linter.verify("x", { rules: { "foo-bar-baz": "error" } });
assert(spy.calledOnce);
});
function getScope(code, astSelector, ecmaVersion = 5) {
let node, scope;
- linter.defineRule("get-scope", context => ({
- [astSelector](node0) {
- node = node0;
- scope = context.getScope();
- }
- }));
+ linter.defineRule("get-scope", {
+ create: context => ({
+ [astSelector](node0) {
+ node = node0;
+ scope = context.getScope();
+ }
+ })
+ });
linter.verify(
code,
{
let ok = false;
linter.defineRules({
- test(context) {
- return {
+ test: {
+ create: context => ({
Program() {
scope = context.getScope();
ok = true;
}
- };
+ })
}
});
linter.verify(code, { rules: { test: 2 }, globals: { e: true, f: false } });
*/
function verify(code, type, expectedNamesList) {
linter.defineRules({
- test(context) {
+ test: {
+ create(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
- };
+ /**
+ * 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);
+ 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;
+ 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;
+ }
}
});
linter.verify(code, {
});
it("loading rule in one doesn't change the other", () => {
- linter1.defineRule("mock-rule", () => ({}));
+ linter1.defineRule("mock-rule", {
+ create: () => ({})
+ });
assert.isTrue(linter1.getRules().has("mock-rule"), "mock rule is present");
assert.isFalse(linter2.getRules().has("mock-rule"), "mock rule is not present");
receivedPhysicalFilenames = [];
// A rule that always reports the AST with a message equal to the source text
- linter.defineRule("report-original-text", context => ({
- Program(ast) {
- receivedFilenames.push(context.getFilename());
- receivedPhysicalFilenames.push(context.getPhysicalFilename());
- context.report({ node: ast, message: context.getSourceCode().text });
- }
- }));
+ linter.defineRule("report-original-text", {
+ create: context => ({
+ Program(ast) {
+ assert.strictEqual(context.getFilename(), context.filename);
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+
+ receivedFilenames.push(context.filename);
+ receivedPhysicalFilenames.push(context.physicalFilename);
+
+ context.report({ node: ast, message: context.sourceCode.text });
+ }
+ })
+ });
});
describe("preprocessors", () => {
severity: 2,
message: "Preprocessing error: Invalid syntax",
line: 1,
- column: 1
+ column: 1,
+ nodeType: null
}
]);
});
});
it("should throw an error if fix is passed from a legacy-format rule", () => {
- linter.defineRule("test-rule", context => ({
- Program(node) {
- context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
- }
- }));
+ linter.defineRule("test-rule", {
+ create: context => ({
+ Program(node) {
+ context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
+ }
+ })
+ });
assert.throws(() => {
linter.verify("0", { rules: { "test-rule": "error" } });
* This test focuses on the instance of https://github.com/eslint/eslint/blob/v2.0.0-alpha-2/conf/environments.js#L26-L28
* This `verify()` takes the instance and runs https://github.com/eslint/eslint/blob/v2.0.0-alpha-2/lib/eslint.js#L416
*/
- linter.defineRule("test", () => ({}));
+ linter.defineRule("test", {
+ create: () => ({})
+ });
linter.verify("var a = 0;", {
env: { node: true },
parserOptions: { ecmaVersion: 6, sourceType: "module" },
// This `verify()` takes the instance and tests that the instance was not modified.
let ok = false;
- linter.defineRule("test", context => {
- assert(
- context.parserOptions.ecmaFeatures.globalReturn,
- "`ecmaFeatures.globalReturn` of the node environment should not be modified."
- );
- ok = true;
- return {};
+ linter.defineRule("test", {
+ create(context) {
+ assert(
+ context.parserOptions.ecmaFeatures.globalReturn,
+ "`ecmaFeatures.globalReturn` of the node environment should not be modified."
+ );
+ ok = true;
+ return {};
+ }
});
linter.verify("var a = 0;", {
env: { node: true },
it("should throw when rule's create() function does not return an object", () => {
const config = { rules: { checker: "error" } };
- linter.defineRule("checker", () => null); // returns null
+ linter.defineRule("checker", {
+ create: () => null
+ }); // returns null
assert.throws(() => {
linter.verify("abc", config, filename);
}, "The create() function for rule 'checker' did not return an object.");
- linter.defineRule("checker", () => {}); // returns undefined
+ linter.defineRule("checker", {
+ create() {}
+ }); // returns undefined
assert.throws(() => {
linter.verify("abc", config, filename);
const nodes = [];
- linter.defineRule("collect-node-types", () => ({
- "*"(node) {
- nodes.push(node.type);
- }
- }));
+ linter.defineRule("collect-node-types", {
+ create: () => ({
+ "*"(node) {
+ nodes.push(node.type);
+ }
+ })
+ });
linter.defineParser("non-js-parser", testParsers.nonJSParser);
beforeEach(() => {
types = [];
firstChildNodes = [];
- linter.defineRule("collect-node-types", () => ({
- "*"(node) {
- types.push(node.type);
- }
- }));
- linter.defineRule("save-scope-manager", context => {
- scopeManager = context.getSourceCode().scopeManager;
-
- return {};
+ linter.defineRule("collect-node-types", {
+ create: () => ({
+ "*"(node) {
+ types.push(node.type);
+ }
+ })
});
- linter.defineRule("esquery-option", () => ({
- ":first-child"(node) {
- firstChildNodes.push(node);
+ linter.defineRule("save-scope-manager", {
+ create(context) {
+ scopeManager = context.sourceCode.scopeManager;
+
+ return {};
}
- }));
+ });
+ linter.defineRule("esquery-option", {
+ create: () => ({
+ ":first-child"(node) {
+ firstChildNodes.push(node);
+ }
+ })
+ });
linter.defineParser("enhanced-parser2", testParsers.enhancedParser2);
linter.verify("@foo class A {}", {
parser: "enhanced-parser2",
it("should use the same visitorKeys if the source code object is reused", () => {
const types2 = [];
- linter.defineRule("collect-node-types", () => ({
- "*"(node) {
- types2.push(node.type);
- }
- }));
+ linter.defineRule("collect-node-types", {
+ create: () => ({
+ "*"(node) {
+ types2.push(node.type);
+ }
+ })
+ });
linter.verify(sourceCode, {
rules: {
"collect-node-types": "error"
beforeEach(() => {
linter.defineParser("enhanced-parser3", testParsers.enhancedParser3);
- linter.defineRule("save-scope1", context => ({
- Program() {
- scope = context.getScope();
- }
- }));
+ linter.defineRule("save-scope1", {
+ create: context => ({
+ Program() {
+ scope = context.getScope();
+ }
+ })
+ });
linter.verify("@foo class A {}", { parser: "enhanced-parser3", rules: { "save-scope1": 2 } });
sourceCode = linter.getSourceCode();
it("should use the same scope if the source code object is reused", () => {
let scope2 = null;
- linter.defineRule("save-scope2", context => ({
- Program() {
- scope2 = context.getScope();
- }
- }));
+ linter.defineRule("save-scope2", {
+ create: context => ({
+ Program() {
+ scope2 = context.getScope();
+ }
+ })
+ });
linter.verify(sourceCode, { rules: { "save-scope2": 2 } }, "test.js");
assert(scope2 !== null);
plugins: {
test: {
rules: {
- checker(context) {
- return {
+ checker: {
+ create: context => ({
Program() {
assert.strictEqual(context.languageOptions.ecmaVersion, 2015);
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker(context) {
- return {
+ checker: {
+ create: context => ({
Program() {
assert.strictEqual(context.languageOptions.ecmaVersion, espree.latestEcmaVersion + 2009);
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker(context) {
- return {
+ checker: {
+ create: context => ({
Program() {
assert.strictEqual(context.languageOptions.ecmaVersion, 5);
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker(context) {
- return {
+ checker: {
+ create: context => ({
Program() {
assert.strictEqual(context.languageOptions.ecmaVersion, espree.latestEcmaVersion + 2009);
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker(context) {
- return {
+ checker: {
+ create: context => ({
Program() {
assert.strictEqual(context.languageOptions.sourceType, "module");
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker(context) {
- return {
+ checker: {
+ create: context => ({
Program() {
assert.strictEqual(context.languageOptions.sourceType, "commonjs");
}
- };
+ })
}
}
}
};
const config = {
- plugins: {
- test: {
- parsers: {
- "test-parser": parser
- }
- }
- },
languageOptions: {
- parser: "test/test-parser"
+ parser
}
};
plugins: {
test: {
rules: {
- "test-rule": sinon.mock().withArgs(
- sinon.match({ languageOptions: { parser: esprima } })
- ).returns({})
+ "test-rule": {
+ create: sinon.mock().withArgs(
+ sinon.match({ languageOptions: { parser: esprima } })
+ ).returns({})
+ }
}
}
},
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"
+ parser: testParsers.enhancedParser
}
};
const config = {
plugins: {
test: {
- parsers: {
- "enhanced-parser": testParsers.enhancedParser
- },
rules: {
- "test-service-rule": context => ({
- Literal(node) {
- context.report({
- node,
- message: context.parserServices.test.getMessage()
- });
- }
- })
+ "test-service-rule": {
+ create: context => ({
+ Literal(node) {
+ context.report({
+ node,
+ message: context.parserServices.test.getMessage()
+ });
+ }
+ })
+ }
}
}
},
languageOptions: {
- parser: "test/enhanced-parser"
+ parser: testParsers.enhancedParser
},
rules: {
"test/test-service-rule": 2
const config = {
plugins: {
test: {
- parsers: {
- "enhanced-parser": testParsers.enhancedParser
- },
rules: {
- "test-service-rule": context => ({
- Literal(node) {
- context.report({
- node,
- message: context.parserServices.test.getMessage()
- });
- }
- })
+ "test-service-rule": {
+ create: context => ({
+ Literal(node) {
+ context.report({
+ node,
+ message: context.parserServices.test.getMessage()
+ });
+ }
+ })
+ }
}
}
},
languageOptions: {
- parser: "test/enhanced-parser"
+ parser: testParsers.enhancedParser
},
rules: {
"test/test-service-rule": 2
plugins: {
test: {
rules: {
- "test-rule": spy
+ "test-rule": { create: spy }
}
}
},
plugins: {
test: {
rules: {
- "collect-node-types": () => ({
- "*"(node) {
- nodes.push(node.type);
- }
- })
+ "collect-node-types": {
+ create: () => ({
+ "*"(node) {
+ nodes.push(node.type);
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- "collect-node-types": () => ({
- "*"(node) {
- types.push(node.type);
- }
- }),
- "save-scope-manager": context => {
- scopeManager = context.getSourceCode().scopeManager;
-
- return {};
+ "collect-node-types": {
+ create: () => ({
+ "*"(node) {
+ types.push(node.type);
+ }
+ })
},
- "esquery-option": () => ({
- ":first-child"(node) {
- firstChildNodes.push(node);
+ "save-scope-manager": {
+ create(context) {
+ scopeManager = context.sourceCode.scopeManager;
+
+ return {};
}
- })
- }
- }
+ },
+ "esquery-option": {
+ create: () => ({
+ ":first-child"(node) {
+ firstChildNodes.push(node);
+ }
+ })
+ }
+ }
+ }
},
languageOptions: {
parser: testParsers.enhancedParser2
plugins: {
test: {
rules: {
- "collect-node-types": () => ({
- "*"(node) {
- types2.push(node.type);
- }
- })
+ "collect-node-types": {
+ create: () => ({
+ "*"(node) {
+ types2.push(node.type);
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- "save-scope1": context => ({
- Program() {
- scope = context.getScope();
- }
- })
+ "save-scope1": {
+ create: context => ({
+ Program() {
+ scope = context.getScope();
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- "save-scope2": context => ({
- Program() {
- scope2 = context.getScope();
- }
- })
+ "save-scope2": {
+ create: context => ({
+ Program() {
+ scope2 = context.getScope();
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- "test-rule": sinon.mock().withArgs(
- sinon.match({ languageOptions: { parserOptions } })
- ).returns({})
+ "test-rule": {
+ create: sinon.mock().withArgs(
+ sinon.match({ languageOptions: { parserOptions } })
+ ).returns({})
+ }
}
}
},
plugins: {
test: {
rules: {
- "test-rule": sinon.mock().withArgs(
- sinon.match({
- languageOptions: {
- parserOptions: {
- ecmaFeatures: {
- globalReturn: false
+ "test-rule": {
+ create: sinon.mock().withArgs(
+ sinon.match({
+ languageOptions: {
+ parserOptions: {
+ ecmaFeatures: {
+ globalReturn: false
+ }
}
}
- }
- })
- ).returns({})
+ })
+ ).returns({})
+ }
}
}
},
const code = "var enum;";
const messages = linter.verify(code, {
languageOptions: {
- ...ecmaVersion ? { ecmaVersion } : {},
+ ...(ecmaVersion ? { ecmaVersion } : {}),
sourceType: "script"
}
}, filename);
const code = "obj.enum; obj.function; var obj = { enum: 1, function: 2 };";
const messages = linter.verify(code, {
languageOptions: {
- ...ecmaVersion ? { ecmaVersion } : {},
+ ...(ecmaVersion ? { ecmaVersion } : {}),
sourceType: "script"
}
}, filename);
const code = "";
const messages = linter.verify(code, {
languageOptions: {
- ...ecmaVersion ? { ecmaVersion } : {},
+ ...(ecmaVersion ? { ecmaVersion } : {}),
sourceType: "script",
parserOptions: {
allowReserved: true
plugins: {
test: {
rules: {
- [ruleId]: context => ({
- Literal(node) {
- context.report(node, context.settings.info);
- }
- })
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ context.report(node, context.settings.info);
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- [ruleId]: context => ({
- Literal(node) {
- if (Object.getOwnPropertyNames(context.settings).length !== 0) {
- context.report(node, "Settings should be empty");
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ if (Object.getOwnPropertyNames(context.settings).length !== 0) {
+ context.report(node, "Settings should be empty");
+ }
}
- }
- })
+ })
+ }
}
}
},
assert.throws(() => {
linter.verify(code, config, filename, true);
- }, /Key "rules": Key "semi"/u);
+ }, /Key "rules": Key "semi": Expected severity/u);
});
it("should process empty config", () => {
severity: 1,
message: "No matching configuration found for filename.ts.",
line: 0,
- column: 0
+ column: 0,
+ nodeType: null
});
});
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
}
plugins: {
test: {
rules: {
- checker: () => ({
- Program() {
- throw new Error("Intentional error.");
- }
- })
+ checker: {
+ create: () => ({
+ Program() {
+ throw new Error("Intentional error.");
+ }
+
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- checker: () => ({
- Program: spy
- })
+ checker: {
+ create: () => ({
+ Program: spy
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- checker: () => ({
- newListener: spy
- })
+ checker: {
+ create: () => ({
+ newListener: spy
+ })
+ }
}
}
},
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(context.getSourceCode(), context.sourceCode);
+ const ast = context.sourceCode.ast;
assert.strictEqual(ast.body[0].parent, ast);
assert.strictEqual(ast.body[0].expression.parent, ast.body[0]);
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker() {
- return {
- Literal: spyLiteral,
- VariableDeclarator: spyVariableDeclarator,
- VariableDeclaration: spyVariableDeclaration,
- Identifier: spyIdentifier,
- BinaryExpression: spyBinaryExpression
- };
+ checker: {
+ create() {
+ return {
+ Literal: spyLiteral,
+ VariableDeclarator: spyVariableDeclarator,
+ VariableDeclaration: spyVariableDeclaration,
+ Identifier: spyIdentifier,
+ BinaryExpression: spyBinaryExpression
+ };
+ }
}
}
}
plugins: {
test: {
rules: {
- "invalid-report"(context) {
- return {
+ "invalid-report": {
+ create: context => ({
Program(node) {
context.report({ node });
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- [ruleId]: context => ({
- Literal(node) {
- context.report(node, context.getFilename());
- }
- })
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ context.report(node, context.getFilename());
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- [ruleId]: context => ({
- Literal(node) {
- context.report(node, context.getFilename());
- }
- })
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ context.report(node, context.getFilename());
+ }
+ })
+ }
+ }
+ }
+ },
+ rules: {
+ [`test/${ruleId}`]: 1
+ }
+ };
+
+
+ const messages = linter.verify("0", config);
+ const suppressedMessages = linter.getSuppressedMessages();
+
+ assert.strictEqual(messages[0].message, "<input>");
+ assert.strictEqual(suppressedMessages.length, 0);
+ });
+ });
+
+ describe("context.filename", () => {
+ const ruleId = "filename-rule";
+
+ it("has access to the filename", () => {
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ assert.strictEqual(context.getFilename(), context.filename);
+ context.report(node, context.filename);
+ }
+ })
+ }
+ }
+ }
+ },
+ rules: {
+ [`test/${ruleId}`]: 1
+ }
+ };
+
+ const messages = linter.verify("0", config, filename);
+ const suppressedMessages = linter.getSuppressedMessages();
+
+ assert.strictEqual(messages[0].message, filename);
+ assert.strictEqual(suppressedMessages.length, 0);
+ });
+
+ it("defaults filename to '<input>'", () => {
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ assert.strictEqual(context.getFilename(), context.filename);
+ context.report(node, context.filename);
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- [ruleId]: context => ({
- Literal(node) {
- context.report(node, context.getPhysicalFilename());
- }
- })
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ context.report(node, context.getPhysicalFilename());
+ }
+ })
+ }
+ }
+ }
+ },
+ rules: {
+ [`test/${ruleId}`]: 1
+ }
+ };
+
+ const messages = linter.verify("0", config, filename);
+ const suppressedMessages = linter.getSuppressedMessages();
+
+ assert.strictEqual(messages[0].message, filename);
+ assert.strictEqual(suppressedMessages.length, 0);
+ });
+
+ });
+
+ describe("context.physicalFilename", () => {
+
+ const ruleId = "filename-rule";
+
+ it("has access to the physicalFilename", () => {
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ [ruleId]: {
+ create: context => ({
+ Literal(node) {
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ context.report(node, context.physicalFilename);
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getSource(), TEST_CODE);
- });
- return { Program: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getSource(), TEST_CODE);
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node), TEST_CODE);
- });
- return { Program: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node), TEST_CODE);
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
- });
- return { Program: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 2, 0), TEST_CODE);
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node), "6 * 7");
- });
- return { BinaryExpression: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node), "6 * 7");
+ });
+ return { BinaryExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
- });
- return { BinaryExpression: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 2), "= 6 * 7");
+ });
+ return { BinaryExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
- });
- return { BinaryExpression: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 0, 1), "6 * 7;");
+ });
+ return { BinaryExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(node => {
- assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
- });
- return { BinaryExpression: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ assert.strictEqual(context.getSource(node, 2, 1), "= 6 * 7;");
+ });
+ return { BinaryExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const ancestors = context.getAncestors();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const ancestors = context.getAncestors();
- assert.strictEqual(ancestors.length, 3);
- });
- return { BinaryExpression: spy };
+ assert.strictEqual(ancestors.length, 3);
+ });
+ return { BinaryExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const ancestors = context.getAncestors();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const ancestors = context.getAncestors();
- assert.strictEqual(ancestors.length, 0);
- });
+ assert.strictEqual(ancestors.length, 0);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "global");
- });
- return { Program: spy };
+ assert.strictEqual(scope.type, "global");
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- });
- return { FunctionDeclaration: spy };
+ assert.strictEqual(scope.type, "function");
+ });
+ return { FunctionDeclaration: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.id.name, "foo");
- });
- return { LabeledStatement: spy };
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.id.name, "foo");
+ });
+ return { LabeledStatement: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
- });
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.type, "ArrowFunctionExpression");
+ });
- return { ReturnStatement: spy };
+ return { ReturnStatement: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "switch");
- assert.strictEqual(scope.block.type, "SwitchStatement");
- });
+ assert.strictEqual(scope.type, "switch");
+ assert.strictEqual(scope.block.type, "SwitchStatement");
+ });
- return { SwitchStatement: spy };
+ return { SwitchStatement: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "block");
- assert.strictEqual(scope.block.type, "BlockStatement");
- });
+ assert.strictEqual(scope.type, "block");
+ assert.strictEqual(scope.block.type, "BlockStatement");
+ });
- return { BlockStatement: spy };
+ return { BlockStatement: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "block");
- assert.strictEqual(scope.block.type, "BlockStatement");
- });
+ assert.strictEqual(scope.type, "block");
+ assert.strictEqual(scope.block.type, "BlockStatement");
+ });
- return { BlockStatement: spy };
+ return { BlockStatement: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.type, "FunctionDeclaration");
- });
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.type, "FunctionDeclaration");
+ });
- return { FunctionDeclaration: spy };
+ return { FunctionDeclaration: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- assert.strictEqual(scope.block.type, "FunctionExpression");
- });
+ assert.strictEqual(scope.type, "function");
+ assert.strictEqual(scope.block.type, "FunctionExpression");
+ });
- return { FunctionExpression: spy };
+ return { FunctionExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "catch");
- assert.strictEqual(scope.block.type, "CatchClause");
- });
+ assert.strictEqual(scope.type, "catch");
+ assert.strictEqual(scope.block.type, "CatchClause");
+ });
- return { CatchClause: spy };
+ return { CatchClause: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "module");
- });
+ assert.strictEqual(scope.type, "module");
+ });
- return { AssignmentExpression: spy };
+ return { AssignmentExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(scope.type, "function");
- });
+ assert.strictEqual(scope.type, "function");
+ });
- return { AssignmentExpression: spy };
+ return { AssignmentExpression: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- "get-scope": context => ({
- [astSelector](node0) {
- node = node0;
- scope = context.getScope();
- }
- })
+ "get-scope": {
+ create: context => ({
+ [astSelector](node0) {
+ node = node0;
+ scope = context.getScope();
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- test(context) {
- return {
+ test: {
+ create: context => ({
Program() {
scope = context.getScope();
ok = true;
}
- };
+ })
}
}
}
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);
+ test: {
+ create(context) {
- 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);
+ /**
+ * 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);
}
- };
- return rule;
+ 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;
+ }
+
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- assert.isTrue(context.markVariableAsUsed("a"));
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.isTrue(context.markVariableAsUsed("a"));
- const scope = context.getScope();
+ const scope = context.getScope();
- assert.isTrue(getVariable(scope, "a").eslintUsed);
- assert.notOk(getVariable(scope, "b").eslintUsed);
- });
+ assert.isTrue(getVariable(scope, "a").eslintUsed);
+ assert.notOk(getVariable(scope, "b").eslintUsed);
+ });
- return { "Program:exit": spy };
+ return { "Program:exit": spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- assert.isTrue(context.markVariableAsUsed("a"));
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.isTrue(context.markVariableAsUsed("a"));
- const scope = context.getScope();
+ const scope = context.getScope();
- assert.isTrue(getVariable(scope, "a").eslintUsed);
- assert.notOk(getVariable(scope, "b").eslintUsed);
- });
+ 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: {
+ create(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: {
+ create(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: {
+ create(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 { ReturnStatement: spy };
+ return { "Program:exit": spy };
+ }
}
}
}
},
+ languageOptions: {
+ ecmaVersion: 6,
+ sourceType: "module"
+ },
rules: { "test/checker": "error" }
};
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;
+ 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 => {
- 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);
- });
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.isFalse(context.markVariableAsUsed("c"));
+ });
- return { ReturnStatement: returnSpy, "Program:exit": exitSpy };
+ return { "Program:exit": spy };
+ }
}
}
}
},
- languageOptions: {
- sourceType: "script"
- },
rules: { "test/checker": "error" }
};
linter.verify(code, config);
- assert(returnSpy && returnSpy.calledOnce);
- assert(exitSpy && exitSpy.calledOnce);
+ assert(spy && spy.calledOnce);
});
+ });
- it("should mark variables as used when sourceType is commonjs", () => {
- const code = "var a = 1, b = 2;";
- let spy;
+ 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(() => {
- 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 };
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), cwd);
+ });
+ return { Program: spy };
+ }
}
}
}
},
- languageOptions: {
- sourceType: "commonjs"
- },
- rules: { "test/checker": "error" }
+ ...baseConfig
};
- linter.verify(code, config);
- assert(spy && spy.calledOnce, "Spy wasn't called.");
+ linterWithOption.verify(code, config);
+ assert(spy && spy.calledOnce);
});
- it("should mark variables in modules as used", () => {
- const code = "var a = 1, b = 2;";
- let spy;
+ 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(() => {
- 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);
- });
+ checker: {
+ create(context) {
- return { "Program:exit": spy };
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), process.cwd());
+ });
+ return { Program: spy };
+ }
}
}
}
},
- languageOptions: {
- ecmaVersion: 6,
- sourceType: "module"
- },
- rules: { "test/checker": "error" }
+ ...baseConfig
};
- linter.verify(code, config);
+ linterWithOption.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;";
+ 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.isFalse(context.markVariableAsUsed("c"));
- });
+ checker: {
+ create(context) {
- return { "Program:exit": spy };
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), process.cwd());
+ });
+ return { Program: spy };
+ }
}
}
}
},
- rules: { "test/checker": "error" }
+ ...baseConfig
};
linter.verify(code, config);
});
});
- describe("context.getCwd()", () => {
+ describe("context.cwd", () => {
const code = "a;\nb;";
const baseConfig = { rules: { "test/checker": "error" } };
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getCwd(), cwd);
- });
- return { Program: spy };
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.cwd, cwd);
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
+ checker: {
+ create(context) {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getCwd(), process.cwd());
- });
- return { Program: spy };
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), context.cwd);
+ assert.strictEqual(context.cwd, process.cwd());
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
+ checker: {
+ create(context) {
- spy = sinon.spy(() => {
- assert.strictEqual(context.getCwd(), process.cwd());
- });
- return { Program: spy };
+ spy = sinon.spy(() => {
+ assert.strictEqual(context.getCwd(), context.cwd);
+ assert.strictEqual(context.cwd, process.cwd());
+ });
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: spy
+ checker: { create: spy }
}
}
},
describe("filename", () => {
it("should allow filename to be passed on options object", () => {
const filenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getFilename(), "foo.js");
+ assert.strictEqual(context.filename, "foo.js");
return {};
});
plugins: {
test: {
rules: {
- checker: filenameChecker
+ checker: { create: filenameChecker }
}
}
},
it("should allow filename to be passed as third argument", () => {
const filenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getFilename(), "bar.js");
+ assert.strictEqual(context.filename, "bar.js");
return {};
});
plugins: {
test: {
rules: {
- checker: filenameChecker
+ checker: { create: filenameChecker }
}
}
},
it("should default filename to <input> when options object doesn't have filename", () => {
const filenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getFilename(), "<input>");
+ assert.strictEqual(context.filename, "<input>");
return {};
});
plugins: {
test: {
rules: {
- checker: filenameChecker
+ checker: { create: filenameChecker }
}
}
},
it("should default filename to <input> when only two arguments are passed", () => {
const filenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getFilename(), "<input>");
+ assert.strictEqual(context.filename, "<input>");
return {};
});
plugins: {
test: {
rules: {
- checker: filenameChecker
+ checker: { create: filenameChecker }
}
}
},
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");
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ assert.strictEqual(context.physicalFilename, "foo.js");
return {};
});
plugins: {
test: {
rules: {
- checker: physicalFilenameChecker
+ checker: { create: physicalFilenameChecker }
}
}
},
it("should default physicalFilename to <input> when options object doesn't have filename", () => {
const physicalFilenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getPhysicalFilename(), "<input>");
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ assert.strictEqual(context.physicalFilename, "<input>");
return {};
});
plugins: {
test: {
rules: {
- checker: physicalFilenameChecker
+ checker: { create: physicalFilenameChecker }
}
}
},
it("should default physicalFilename to <input> when only two arguments are passed", () => {
const physicalFilenameChecker = sinon.spy(context => {
- assert.strictEqual(context.getPhysicalFilename(), "<input>");
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+ assert.strictEqual(context.physicalFilename, "<input>");
return {};
});
plugins: {
test: {
rules: {
- checker: physicalFilenameChecker
+ checker: { create: physicalFilenameChecker }
}
}
},
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 };
+ checker: {
+ create(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 };
+ }
}
}
}
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 };
+ checker: {
+ create(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 };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope();
- assert.strictEqual(getVariable(scope, "a"), null);
- });
+ assert.strictEqual(getVariable(scope, "a"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(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);
- });
+ 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 };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- test(context) {
- return {
+ test: {
+ create: context => ({
Program() {
const scope = context.getScope();
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const comments = sourceCode.getAllComments();
+ assert.strictEqual(context.getSourceCode(), sourceCode);
assert.strictEqual(2, comments.length);
const foo = getVariable(scope, "foo");
ok = true;
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse.eslintUsed, true);
- });
+ assert.strictEqual(horse.eslintUsed, true);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse, null);
- });
+ assert.strictEqual(horse, null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse.eslintUsed, true);
- });
+ assert.strictEqual(horse.eslintUsed, true);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse, null); // there is no global scope at all
- });
+ assert.strictEqual(horse, null); // there is no global scope at all
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope(),
- horse = getVariable(scope, "horse");
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const scope = context.getScope(),
+ horse = getVariable(scope, "horse");
- assert.strictEqual(horse, null); // there is no global scope at all
- });
+ assert.strictEqual(horse, null); // there is no global scope at all
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
"test-plugin": {
rules: {
- "test-rule"(context) {
- return {
+ "test-rule": {
+ create: context => ({
Literal(node) {
if (node.value === "trigger violation") {
context.report(node, "Reporting violation.");
}
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker: context => ({
- Program() {
- context.report({ loc: { line: 1, column: 0 }, message: "foo" });
- }
- })
+ checker: {
+ create: context => ({
+ Program() {
+ context.report({ loc: { line: 1, column: 0 }, message: "foo" });
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- checker: context => ({
- Program() {
- context.report({ loc: { line: 1, column: 1 }, message: "foo" });
- }
- })
+ checker: {
+ create: context => ({
+ Program() {
+ context.report({ loc: { line: 1, column: 1 }, message: "foo" });
+ }
+ })
+ }
}
}
},
plugins: {
test: {
rules: {
- test(context) {
- return {
+ test: {
+ create: context => ({
Program() {
const scope = context.getScope();
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const comments = sourceCode.getAllComments();
+ assert.strictEqual(context.getSourceCode(), sourceCode);
assert.strictEqual(1, comments.length);
const foo = getVariable(scope, "foo");
ok = true;
}
- };
+ })
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(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);
- });
+ assert.notStrictEqual(getVariable(scope, "Object"), null);
+ assert.notStrictEqual(getVariable(scope, "Array"), null);
+ assert.notStrictEqual(getVariable(scope, "undefined"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
plugins: {
test: {
rules: {
- checker: context => {
- spy = sinon.spy(() => {
- const scope = context.getScope();
+ checker: {
+ create(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);
- });
+ assert.notStrictEqual(getVariable(scope, "Promise"), null);
+ assert.notStrictEqual(getVariable(scope, "Symbol"), null);
+ assert.notStrictEqual(getVariable(scope, "WeakMap"), null);
+ });
- return { Program: spy };
+ return { Program: spy };
+ }
}
}
}
describe("defineRule()", () => {
it("should throw an error when called in flat config mode", () => {
assert.throws(() => {
- linter.defineRule("foo", () => {});
+ linter.defineRule("foo", {
+ create() {}
+ });
}, /This method cannot be used with flat config/u);
});
});
plugins: {
test: {
rules: {
- "test-rule": context => ({
- Program(node) {
- context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
- }
- })
+ "test-rule": {
+ create: context => ({
+ Program(node) {
+ context.report(node, "hello world", {}, () => ({ range: [1, 1], text: "" }));
+ }
+ })
+ }
}
}
},
});
it("loading rule in one doesn't change the other", () => {
- linter1.defineRule("mock-rule", () => ({}));
+ linter1.defineRule("mock-rule", {
+ create: () => ({})
+ });
assert.isTrue(linter1.getRules().has("mock-rule"), "mock rule is present");
assert.isFalse(linter2.getRules().has("mock-rule"), "mock rule is not present");
create(context) {
return {
Program(ast) {
- receivedFilenames.push(context.getFilename());
- receivedPhysicalFilenames.push(context.getPhysicalFilename());
- context.report({ node: ast, message: context.getSourceCode().text });
+ assert.strictEqual(context.getFilename(), context.filename);
+ assert.strictEqual(context.getPhysicalFilename(), context.physicalFilename);
+
+ receivedFilenames.push(context.filename);
+ receivedPhysicalFilenames.push(context.physicalFilename);
+
+ context.report({ node: ast, message: context.sourceCode.text });
}
};
}
severity: 2,
message: "Preprocessing error: Invalid syntax",
line: 1,
- column: 1
+ column: 1,
+ nodeType: null
}
]);
});
plugins: {
test: {
rules: {
- "save-ast1": () => ({
- Program(node) {
- ast1 = node;
- }
- }),
+ "save-ast1": {
+ create: () => ({
+ Program(node) {
+ ast1 = node;
+ }
+ })
+ },
- "save-ast2": () => ({
- Program(node) {
- ast2 = node;
- }
- })
+ "save-ast2": {
+ create: () => ({
+ Program(node) {
+ ast2 = node;
+ }
+ })
+ }
}
}
plugins: {
test: {
rules: {
- "foo-bar-baz": spy
+ "foo-bar-baz": { create: spy }
}
}
},
plugins: {
test: {
rules: {
- "no-programs": context => ({
- Program(node) {
- context.report({ node, message: "No programs allowed." });
+ "no-programs": {
+ create(context) {
+ return {
+ Program(node) {
+ context.report({ node, message: "No programs allowed." });
+ }
+ };
}
- })
+ }
}
}
},
});
});
- describe("--ignore-path", () => {
- it("should return a string for .ignorePath when passed", () => {
- const currentOptions = options.parse("--ignore-path .gitignore");
-
- assert.strictEqual(currentOptions.ignorePath, ".gitignore");
- });
- });
-
describe("--ignore-pattern", () => {
it("should return a string array for .ignorePattern when passed", () => {
const currentOptions = options.parse("--ignore-pattern *.js");
});
});
+ describe("--ignore-path", () => {
+ it("should return a string for .ignorePath when passed", () => {
+ const currentOptions = eslintrcOptions.parse("--ignore-path .gitignore");
+
+ assert.strictEqual(currentOptions.ignorePath, ".gitignore");
+ });
+ });
+
describe("--parser", () => {
it("should return a string for --parser when passed", () => {
const currentOptions = eslintrcOptions.parse("--parser test");
FlatRuleTester.setDefaultConfig(config);
};
}
- assert.throw(setConfig());
- assert.throw(setConfig(1));
- assert.throw(setConfig(3.14));
- assert.throw(setConfig("foo"));
- assert.throw(setConfig(null));
- assert.throw(setConfig(true));
+ const errorMessage = "FlatRuleTester.setDefaultConfig: config must be an object";
+
+ assert.throw(setConfig(), errorMessage);
+ assert.throw(setConfig(1), errorMessage);
+ assert.throw(setConfig(3.14), errorMessage);
+ assert.throw(setConfig("foo"), errorMessage);
+ assert.throw(setConfig(null), errorMessage);
+ assert.throw(setConfig(true), errorMessage);
});
it("should pass-through the globals config to the tester then to the to rule", () => {
const usesStartEndRule = {
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
CallExpression(node) {
const useGetCommentsRule = {
create: context => ({
Program(node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
sourceCode.getComments(node);
}
RuleTester.setDefaultConfig(config);
};
}
- assert.throw(setConfig());
- assert.throw(setConfig(1));
- assert.throw(setConfig(3.14));
- assert.throw(setConfig("foo"));
- assert.throw(setConfig(null));
- assert.throw(setConfig(true));
+ const errorMessage = "RuleTester.setDefaultConfig: config must be an object";
+
+ assert.throw(setConfig(), errorMessage);
+ assert.throw(setConfig(1), errorMessage);
+ assert.throw(setConfig(3.14), errorMessage);
+ assert.throw(setConfig("foo"), errorMessage);
+ assert.throw(setConfig(null), errorMessage);
+ assert.throw(setConfig(true), errorMessage);
});
it("should pass-through the globals config to the tester then to the to rule", () => {
const usesStartEndRule = {
create(context) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
return {
CallExpression(node) {
assert.deepStrictEqual(
processStub.getCall(0).args,
[
- "\"function-style-rule\" rule is using the deprecated function-style format and will stop working in ESLint v9. Please use object-style format: https://eslint.org/docs/developer-guide/working-with-rules",
+ "\"function-style-rule\" rule is using the deprecated function-style format and will stop working in ESLint v9. Please use object-style format: https://eslint.org/docs/latest/extend/custom-rules",
"DeprecationWarning"
]
);
assert.deepStrictEqual(
processStub.getCall(0).args,
[
- "\"rule-with-no-meta-1\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/developer-guide/working-with-rules#options-schemas",
+ "\"rule-with-no-meta-1\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas",
"DeprecationWarning"
]
);
assert.deepStrictEqual(
processStub.getCall(0).args,
[
- "\"rule-with-no-schema-1\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/developer-guide/working-with-rules#options-schemas",
+ "\"rule-with-no-schema-1\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas",
"DeprecationWarning"
]
);
const ruleWithUndefinedSchema = {
meta: {
type: "problem",
- // eslint-disable-next-line no-undefined -- intentioally added for test case
+ // eslint-disable-next-line no-undefined -- intentionally added for test case
schema: undefined
},
create(context) {
assert.deepStrictEqual(
processStub.getCall(0).args,
[
- "\"rule-with-undefined-schema\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/developer-guide/working-with-rules#options-schemas",
+ "\"rule-with-undefined-schema\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas",
"DeprecationWarning"
]
);
assert.deepStrictEqual(
processStub.getCall(0).args,
[
- "\"rule-with-null-schema\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/developer-guide/working-with-rules#options-schemas",
+ "\"rule-with-null-schema\" rule has options but is missing the \"meta.schema\" property and will stop working in ESLint v9. Please add a schema: https://eslint.org/docs/latest/extend/custom-rules#options-schemas",
"DeprecationWarning"
]
);
const useGetCommentsRule = {
create: context => ({
Program(node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
sourceCode.getComments(node);
}
"foo.filter(function() { return true; })",
"foo.find(function() { return true; })",
"foo.findIndex(function() { return true; })",
+ "foo.findLast(function() { return true; })",
+ "foo.findLastIndex(function() { return true; })",
"foo.flatMap(function() { return true; })",
"foo.forEach(function() { return; })",
"foo.map(function() { return true; })",
"foo.reduceRight(function() { return true; })",
"foo.some(function() { return true; })",
"foo.sort(function() { return 0; })",
+ "foo.toSorted(function() { return 0; })",
{ code: "foo.every(() => { return true; })", parserOptions: { ecmaVersion: 6 } },
"foo.every(function() { if (a) return true; else return false; })",
"foo.every(function() { switch (a) { case 0: bar(); default: return true; } })",
{ code: "foo.filter(function() { return; })", options: allowImplicitOptions },
{ code: "foo.find(function() { return; })", options: allowImplicitOptions },
{ code: "foo.findIndex(function() { return; })", options: allowImplicitOptions },
+ { code: "foo.findLast(function() { return; })", options: allowImplicitOptions },
+ { code: "foo.findLastIndex(function() { return; })", options: allowImplicitOptions },
{ code: "foo.flatMap(function() { return; })", options: allowImplicitOptions },
{ code: "foo.forEach(function() { return; })", options: allowImplicitOptions },
{ code: "foo.map(function() { return; })", options: allowImplicitOptions },
{ code: "foo.reduceRight(function() { return; })", options: allowImplicitOptions },
{ code: "foo.some(function() { return; })", options: allowImplicitOptions },
{ code: "foo.sort(function() { return; })", options: allowImplicitOptions },
+ { code: "foo.toSorted(function() { return; })", options: allowImplicitOptions },
{ code: "foo.every(() => { return; })", options: allowImplicitOptions, parserOptions: { ecmaVersion: 6 } },
{ code: "foo.every(function() { if (a) return; else return a; })", options: allowImplicitOptions },
{ code: "foo.every(function() { switch (a) { case 0: bar(); default: return; } })", options: allowImplicitOptions },
{ code: "foo.filter(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.filter" } }] },
{ code: "foo.find(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.find" } }] },
{ code: "foo.find(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.find" } }] },
+ { code: "foo.findLast(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.findLast" } }] },
+ { code: "foo.findLast(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.findLast" } }] },
{ code: "foo.findIndex(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.findIndex" } }] },
{ code: "foo.findIndex(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.findIndex" } }] },
+ { code: "foo.findLastIndex(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.findLastIndex" } }] },
+ { code: "foo.findLastIndex(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.findLastIndex" } }] },
{ code: "foo.flatMap(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.flatMap" } }] },
{ code: "foo.flatMap(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.flatMap" } }] },
{ code: "foo.map(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.map" } }] },
{ code: "foo.some(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.some" } }] },
{ code: "foo.sort(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.sort" } }] },
{ code: "foo.sort(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.sort" } }] },
+ { code: "foo.toSorted(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.toSorted" } }] },
+ { code: "foo.toSorted(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.toSorted" } }] },
{ code: "foo.bar.baz.every(function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.every" } }] },
{ code: "foo.bar.baz.every(function foo() {})", errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.every" } }] },
{ code: "foo[\"every\"](function() {})", errors: [{ messageId: "expectedInside", data: { name: "function", arrayMethodName: "Array.prototype.every" } }] },
{ code: "foo.bar.baz.every(function foo() {})", options: allowImplicitOptions, errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.every" } }] },
{ code: "foo.every(cb || function() {})", options: allowImplicitOptions, errors: ["Array.prototype.every() expects a return value from function."] },
{ code: "[\"foo\",\"bar\"].sort(function foo() {})", options: allowImplicitOptions, errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.sort" } }] },
+ { code: "[\"foo\",\"bar\"].toSorted(function foo() {})", options: allowImplicitOptions, errors: [{ messageId: "expectedInside", data: { name: "function 'foo'", arrayMethodName: "Array.prototype.toSorted" } }] },
{ code: "foo.forEach(x => x)", options: allowImplicitCheckForEach, parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "expectedNoReturnValue", data: { name: "arrow function", arrayMethodName: "Array.prototype.forEach" } }] },
{ code: "foo.forEach(function(x) { if (a == b) {return x;}})", options: allowImplicitCheckForEach, errors: [{ messageId: "expectedNoReturnValue", data: { name: "function", arrayMethodName: "Array.prototype.forEach" } }] },
{ code: "foo.forEach(function bar(x) { return x;})", options: allowImplicitCheckForEach, errors: [{ messageId: "expectedNoReturnValue", data: { name: "function 'bar'", arrayMethodName: "Array.prototype.forEach" } }] },
const path = require("path"),
{ unIndent } = require("../../_utils"),
rule = require("../../../lib/rules/comma-dangle"),
- { RuleTester } = require("../../../lib/rule-tester");
+ { RuleTester } = require("../../../lib/rule-tester"),
+ FlatRuleTester = require("../../../lib/rule-tester/flat-rule-tester");
//------------------------------------------------------------------------------
// Helpers
create(context) {
return {
ImportDeclaration(node) {
- const sourceCode = context.getSourceCode();
+ const sourceCode = context.sourceCode;
const closingBrace = sourceCode.getLastToken(node, token => token.value === "}");
const addComma = sourceCode.getTokenBefore(closingBrace).value !== ",";
code: "function foo(a,\nb) {}",
options: ["always-multiline"]
},
+ {
+ code: "foo(a,\nb\n)",
+ options: ["always-multiline"]
+ },
+ {
+ code: "function foo(a,\nb\n) {}",
+ options: ["always-multiline"]
+ },
{
code: "foo(a,\nb)",
options: ["always-multiline"]
options: ["always-multiline"],
parserOptions: { ecmaVersion: 7 }
},
+ {
+ code: "function foo(a,\nb\n) {}",
+ options: ["always-multiline"],
+ parserOptions: { ecmaVersion: 7 }
+ },
+ {
+ code: "foo(a,\nb\n)",
+ options: ["always-multiline"],
+ parserOptions: { ecmaVersion: 7 }
+ },
{
code: "function foo(a,\nb) {}",
options: ["only-multiline"],
}
]
});
+
+const flatRuleTester = new FlatRuleTester();
+
+// https://github.com/eslint/eslint/issues/16442
+flatRuleTester.run("comma-dangle", rule, {
+ valid: [
+ {
+ code: "function f(\n a,\n b\n) {}",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: 5,
+ sourceType: "script"
+ }
+ },
+ {
+ code: "f(\n a,\n b\n);",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: 5,
+ sourceType: "script"
+ }
+ },
+ {
+ code: "function f(\n a,\n b\n) {}",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: 2016
+ }
+ },
+ {
+ code: "f(\n a,\n b\n);",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: 2016
+ }
+ }
+ ],
+
+ invalid: [
+ {
+ code: "function f(\n a,\n b\n) {}",
+ output: "function f(\n a,\n b,\n) {}",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: 2017
+ },
+ errors: [{
+ messageId: "missing",
+ type: "Identifier",
+ line: 3,
+ column: 3
+ }]
+ },
+ {
+ code: "f(\n a,\n b\n);",
+ output: "f(\n a,\n b,\n);",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: 2017
+ },
+ errors: [{
+ messageId: "missing",
+ type: "Identifier",
+ line: 3,
+ column: 3
+ }]
+ },
+ {
+ code: "function f(\n a,\n b\n) {}",
+ output: "function f(\n a,\n b,\n) {}",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: "latest"
+ },
+ errors: [{
+ messageId: "missing",
+ type: "Identifier",
+ line: 3,
+ column: 3
+ }]
+ },
+ {
+ code: "f(\n a,\n b\n);",
+ output: "f(\n a,\n b,\n);",
+ options: ["always-multiline"],
+ languageOptions: {
+ ecmaVersion: "latest"
+ },
+ errors: [{
+ messageId: "missing",
+ type: "Identifier",
+ line: 3,
+ column: 3
+ }]
+ }
+ ]
+});
//------------------------------------------------------------------------------
const rule = require("../../../lib/rules/func-name-matching"),
- { RuleTester } = require("../../../lib/rule-tester");
+ { RuleTester } = require("../../../lib/rule-tester"),
+ FlatRuleTester = require("../../../lib/rule-tester/flat-rule-tester");
//------------------------------------------------------------------------------
// Tests
code: "class C { #x; foo() { a.b.#x = function y() {}; } }",
options: ["never"],
parserOptions: { ecmaVersion: 2022 }
- }
+ },
+ "var obj = { '\\u1885': function foo() {} };" // not a valid identifier in es5
],
invalid: [
{
errors: [
{ messageId: "notMatchProperty", data: { funcName: "x", name: "x" } }
]
+ },
+ {
+ code: "var obj = { '\\u1885': function foo() {} };", // valid identifier in es2015
+ parserOptions: { ecmaVersion: 6 },
+ errors: [
+ { messageId: "matchProperty", data: { funcName: "foo", name: "\u1885" } }
+ ]
+ }
+ ]
+});
+
+const flatRuleTester = new FlatRuleTester();
+
+flatRuleTester.run("func-name-matching", rule, {
+ valid: [
+ {
+ code: "var obj = { '\\u1885': function foo() {} };", // not a valid identifier in es5
+ languageOptions: {
+ ecmaVersion: 5,
+ sourceType: "script"
+ }
+ }
+ ],
+
+ invalid: [
+ {
+ code: "var obj = { '\\u1885': function foo() {} };", // valid identifier in es2015
+ languageOptions: {
+ ecmaVersion: 2015
+ },
+ errors: [
+ { messageId: "matchProperty", data: { funcName: "foo", name: "\u1885" } }
+ ]
}
]
});
"Object.defineProperties(foo, { bar: { get: function () {return true;}} });",
"Object.defineProperties(foo, { bar: { get: function () { ~function (){ return true; }(); return true;}} });",
+ /*
+ * test reflect.defineProperty(s)
+ * option: {allowImplicit: false}
+ */
+ "Reflect.defineProperty(foo, \"bar\", { get: function () {return true;}});",
+ "Reflect.defineProperty(foo, \"bar\", { get: function () { ~function (){ return true; }();return true;}});",
+
+ /*
+ * test object.create(s)
+ * option: {allowImplicit: false}
+ */
+ "Object.create(foo, { bar: { get() {return true;} } });",
+ "Object.create(foo, { bar: { get: function () {return true;} } });",
+ "Object.create(foo, { bar: { get: () => {return true;} } });",
+
// option: {allowImplicit: true}
{ code: "Object.defineProperty(foo, \"bar\", { get: function () {return true;}});", options },
{ code: "Object.defineProperty(foo, \"bar\", { get: function (){return;}});", options },
{ code: "Object.defineProperties(foo, { bar: { get: function () {return true;}} });", options },
{ code: "Object.defineProperties(foo, { bar: { get: function () {return;}} });", options },
+ { code: "Reflect.defineProperty(foo, \"bar\", { get: function () {return true;}});", options },
// not getter.
"var get = function(){};",
"var foo = { bar: function(){return true;} };",
"var foo = { get: function () {} }",
"var foo = { get: () => {}};",
- "class C { get; foo() {} }"
+ "class C { get; foo() {} }",
+ "foo.defineProperty(null, { get() {} });",
+ "foo.defineProperties(null, { bar: { get() {} } });",
+ "foo.create(null, { bar: { get() {} } });"
],
invalid: [
{ code: "Object.defineProperty(foo, \"bar\", { get: function (){if(bar) {return true;}}});", errors: [{ messageId: "expectedAlways" }] },
{ code: "Object.defineProperty(foo, \"bar\", { get: function (){ ~function () { return true; }()}});", errors: [{ messageId: "expected" }] },
+ /*
+ * test reflect.defineProperty(s)
+ * option: {allowImplicit: false}
+ */
+ {
+ code: "Reflect.defineProperty(foo, 'bar', { get: function (){}});",
+ errors: [{
+ messageId: "expected",
+ data: { name: "method 'get'" },
+ line: 1,
+ column: 38,
+ endLine: 1,
+ endColumn: 52
+ }]
+ },
+
+ /*
+ * test object.create(s)
+ * option: {allowImplicit: false}
+ */
+ {
+ code: "Object.create(foo, { bar: { get: function() {} } })",
+ errors: [{
+ messageId: "expected",
+ data: { name: "method 'get'" },
+ line: 1,
+ column: 29,
+ endLine: 1,
+ endColumn: 42
+ }]
+ },
+ {
+ code: "Object.create(foo, { bar: { get() {} } })",
+ errors: [{
+ messageId: "expected",
+ data: { name: "method 'get'" },
+ line: 1,
+ column: 29,
+ endLine: 1,
+ endColumn: 32
+ }]
+ },
+ {
+ code: "Object.create(foo, { bar: { get: () => {} } })",
+ errors: [{
+ messageId: "expected",
+ data: { name: "method 'get'" },
+ line: 1,
+ column: 29,
+ endLine: 1,
+ endColumn: 34
+ }]
+ },
+
// option: {allowImplicit: true}
{ code: "Object.defineProperties(foo, { bar: { get: function () {}} });", options, errors: [{ messageId: "expected" }] },
{ code: "Object.defineProperties(foo, { bar: { get: function (){if(bar) {return true;}}}});", options, errors: [{ messageId: "expectedAlways" }] },
{ code: "Object.defineProperties(foo, { bar: { get: function () {~function () { return true; }()}} });", options, errors: [{ messageId: "expected" }] },
{ code: "Object.defineProperty(foo, \"bar\", { get: function (){}});", options, errors: [{ messageId: "expected" }] },
+ { code: "Object.create(foo, { bar: { get: function (){} } });", options, errors: [{ messageId: "expected" }] },
+ { code: "Reflect.defineProperty(foo, \"bar\", { get: function (){}});", options, errors: [{ messageId: "expected" }] },
// Optional chaining
{
options,
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "expected", data: { name: "method 'get'" } }]
+ },
+ {
+ code: "(Object?.create)(foo, { bar: { get: function (){} } });",
+ options,
+ parserOptions: { ecmaVersion: 2020 },
+ errors: [{ messageId: "expected", data: { name: "method 'get'" } }]
}
]
});
code: "class Foo { #abc = 1 }",
options: [{ max: 3 }],
parserOptions: { ecmaVersion: 2022 }
+ },
+
+ // Identifier consisting of two code units
+ {
+ code: "var 𠮟 = 2",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: { ecmaVersion: 6 }
+ },
+ {
+ code: "var 葛󠄀 = 2", // 2 code points but only 1 grapheme
+ options: [{ min: 1, max: 1 }],
+ parserOptions: { ecmaVersion: 6 }
+ },
+ {
+ code: "var a = { 𐌘: 1 };",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "(𐌘) => { 𐌘 * 𐌘 };",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "class 𠮟 { }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "class F { 𐌘() {} }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "class F { #𐌘() {} }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 2022
+ }
+ },
+ {
+ code: "class F { 𐌘 = 1 }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 2022
+ }
+ },
+ {
+ code: "class F { #𐌘 = 1 }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 2022
+ }
+ },
+ {
+ code: "function f(...𐌘) { }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "function f([𐌘]) { }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "var [ 𐌘 ] = a;",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "var { p: [𐌘]} = {};",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "function f({𐌘}) { }",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "var { 𐌘 } = {};",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "var { p: 𐌘} = {};",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
+ },
+ {
+ code: "({ prop: o.𐌘 } = {});",
+ options: [{ min: 1, max: 1 }],
+ parserOptions: {
+ ecmaVersion: 6
+ }
}
],
invalid: [
errors: [
tooLongErrorPrivate
]
+ },
+
+ // Identifier consisting of two code units
+ {
+ code: "var 𠮟 = 2",
+ parserOptions: { ecmaVersion: 6 },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "var 葛󠄀 = 2", // 2 code points but only 1 grapheme
+ parserOptions: { ecmaVersion: 6 },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "var myObj = { 𐌘: 1 };",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "(𐌘) => { 𐌘 * 𐌘 };",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "class 𠮟 { }",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "class Foo { 𐌘() {} }",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "class Foo1 { #𐌘() {} }",
+ parserOptions: {
+ ecmaVersion: 2022
+ },
+ errors: [
+ tooShortErrorPrivate
+ ]
+ },
+ {
+ code: "class Foo2 { 𐌘 = 1 }",
+ parserOptions: {
+ ecmaVersion: 2022
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "class Foo3 { #𐌘 = 1 }",
+ parserOptions: {
+ ecmaVersion: 2022
+ },
+ errors: [
+ tooShortErrorPrivate
+ ]
+ },
+ {
+ code: "function foo1(...𐌘) { }",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "function foo([𐌘]) { }",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "var [ 𐌘 ] = arr;",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "var { prop: [𐌘]} = {};",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "function foo({𐌘}) { }",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "var { 𐌘 } = {};",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "var { prop: 𐌘} = {};",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
+ },
+ {
+ code: "({ prop: obj.𐌘 } = {});",
+ parserOptions: {
+ ecmaVersion: 6
+ },
+ errors: [
+ tooShortError
+ ]
}
]
});
" method() {",
" return 42;",
" },",
- " baz: 456",
+ " baz: 456,",
+ " 10: ",
+ " 10",
"};"
].join("\n"),
options: [{ align: "value" }],
" bat: function() {",
" return this.a;",
" },",
+ " barfoo:",
+ " [",
+ " 1",
+ " ],",
" baz: 42",
"};"
].join("\n"),
" internalGroup: {",
" internal : true,",
" ext : false",
+ " },",
+ " func3:",
+ " function () {",
+ " var test3 = true;",
" }",
"})"
].join("\n"),
}
}],
parserOptions: { ecmaVersion: 6 }
+ },
+
+ // https://github.com/eslint/eslint/issues/16490
+ {
+ code: `
+ var foo =
+ {
+ id: 1,
+ code: 2,
+ [n]: 3,
+ message:
+ "some value on the next line",
+ };
+ `,
+ options: [{
+ align: "value"
+ }],
+ parserOptions: { ecmaVersion: 6 }
+ },
+ {
+ code: `
+ var foo =
+ {
+ id : 1,
+ code : 2,
+ message :
+ "some value on the next line",
+ };
+ `,
+ options: [{
+ align: "colon",
+ beforeColon: true
+ }]
+ },
+ {
+ code: `
+ ({
+ a: 1,
+ // different group
+ bcd:
+ 2
+ })
+ `,
+ options: [{
+ align: "value"
+ }]
+ },
+ {
+ code: `
+ ({
+ foo : 1,
+ bar : 2,
+ foobar :
+ 3
+ })
+ `,
+ options: [{
+ align: "value",
+ beforeColon: true,
+ mode: "minimum"
+ }]
+ },
+ {
+ code: `
+ ({
+ oneLine: 1,
+ ["some key " +
+ "spanning multiple lines"]: 2
+ })
+ `,
+ options: [{
+ align: "value"
+ }],
+ parserOptions: { ecmaVersion: 6 }
+ },
+
+ // https://github.com/eslint/eslint/issues/16674
+ {
+ code: `
+ a = {
+ item : 123,
+ longerItem : (
+ 1 + 1
+ ),
+ };
+ `,
+ options: [{
+ align: {
+ beforeColon: true,
+ afterColon: true,
+ on: "colon"
+ }
+ }]
+ },
+ {
+ code: `
+ a = {
+ item: 123,
+ longerItem: // a comment - not a token
+ (1 + 1),
+ };
+ `,
+ options: [{ align: "value" }]
}],
invalid: [{
code: "var a ={'key' : value };",
" method() {",
" return 42;",
" },",
- " baz: 456",
+ " baz: 456,",
+ " 10: ",
+ " 10",
"};"
].join("\n"),
output: [
" method() {",
" return 42;",
" },",
- " baz: 456",
+ " baz: 456,",
+ " 10: ",
+ " 10",
"};"
].join("\n"),
options: [{ align: "value" }],
{ messageId: "extraValue", data: { computed: "", key: "🎁" }, line: 4, column: 21, type: "Literal" },
{ messageId: "extraValue", data: { computed: "", key: "🇮🇳" }, line: 5, column: 23, type: "Literal" }
]
- }
- ]
+ },
+
+ // https://github.com/eslint/eslint/issues/16490
+ {
+ code: `
+ var foo =
+ {
+ id: 1,
+ code: 2,
+ [n]: 3,
+ message:
+ "some value on the next line",
+ };
+ `,
+ output: `
+ var foo =
+ {
+ id: 1,
+ code: 2,
+ [n]: 3,
+ message:
+ "some value on the next line",
+ };
+ `,
+ options: [{
+ align: "value"
+ }],
+ parserOptions: { ecmaVersion: 6 },
+ errors: [
+ { messageId: "extraValue", data: { computed: "", key: "id" }, line: 4, column: 19, type: "Literal" },
+ { messageId: "extraValue", data: { computed: "", key: "code" }, line: 5, column: 21, type: "Literal" },
+ { messageId: "extraValue", data: { computed: "computed ", key: "n" }, line: 6, column: 20, type: "Literal" }
+ ]
+ },
+ {
+ code: `
+ var foo =
+ {
+ id : 1,
+ code : 2,
+ message :
+ "some value on the next line",
+ };
+ `,
+ output: `
+ var foo =
+ {
+ id : 1,
+ code : 2,
+ message :
+ "some value on the next line",
+ };
+ `,
+ options: [{
+ align: "colon",
+ beforeColon: true
+ }],
+ errors: [
+ { messageId: "extraKey", data: { computed: "", key: "id" }, line: 4, column: 19, type: "Identifier" },
+ { messageId: "extraKey", data: { computed: "", key: "code" }, line: 5, column: 21, type: "Identifier" }
+ ]
+ },
+ {
+ code: `
+ ({
+ a: 1,
+ // different group
+ bcd:
+ 2
+ })
+ `,
+ output: `
+ ({
+ a: 1,
+ // different group
+ bcd:
+ 2
+ })
+ `,
+ options: [{
+ align: "value"
+ }],
+ errors: [
+ { messageId: "extraValue", data: { computed: "", key: "a" }, line: 3, column: 18, type: "Literal" }
+ ]
+ },
+ {
+ code: [
+ "({",
+ " singleLine : 10,",
+ " newGroup :",
+ " function() {",
+ " var test3 = true;",
+ " }",
+ "})"
+ ].join("\n"),
+ output: [
+ "({",
+ " singleLine: 10,",
+ " newGroup:",
+ " function() {",
+ " var test3 = true;",
+ " }",
+ "})"
+ ].join("\n"),
+ options: [{
+ multiLine: {
+ beforeColon: false
+ },
+ align: {
+ on: "colon",
+ beforeColon: true
+ }
+ }],
+ errors: [
+ { messageId: "extraKey", data: { computed: "", key: "singleLine" }, line: 2, column: 15, type: "Identifier" },
+ { messageId: "extraKey", data: { computed: "", key: "newGroup" }, line: 3, column: 13, type: "Identifier" }
+ ]
+ },
+
+ // https://github.com/eslint/eslint/issues/16674
+ {
+ code:
+ `
+ c = {
+ item: 123,
+ longerItem: (
+ 1 + 1
+ ),
+ };
+ `,
+ output:
+ `
+ c = {
+ item : 123,
+ longerItem: (
+ 1 + 1
+ ),
+ };
+ `,
+ options: [{ align: "colon" }],
+ errors: [
+ { messageId: "missingKey", data: { computed: "", key: "item" }, line: 3, column: 13, type: "Identifier" }
+ ]
+ }]
});
{
code: "foo\n/* this is pragmatic */",
options: [{ applyDefaultIgnorePatterns: false, ignorePattern: "pragma" }]
+ },
+
+ // Hashbang comment
+ {
+ code: "#!comment\n\nvar a = 1;",
+ options: [{ afterHashbangComment: true }]
+ },
+ "#!comment\nvar a = 1;",
+ {
+ code: "#!comment\nvar a = 1;",
+ options: [{}]
+ },
+ {
+ code: "#!comment\nvar a = 1;",
+ options: [{ afterHashbangComment: false }]
+ },
+ {
+ code: "#!comment\nvar a = 1;",
+ options: [{ afterLineComment: true, afterBlockComment: true }]
}
],
afterLineComment: true
}],
errors: [{ messageId: "before", type: "Line" }]
+ },
+
+ // Hashbang comment
+ {
+ code: "#!foo\nvar a = 1;",
+ output: "#!foo\n\nvar a = 1;",
+ options: [{ afterHashbangComment: true }],
+ errors: [{ messageId: "after", type: "Shebang" }]
}
]
--- /dev/null
+/**
+ * @fileoverview Tests for logical-assignment-operators.
+ * @author Daniel Martens
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/logical-assignment-operators"),
+ { RuleTester } = require("../../../lib/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2021 } });
+
+ruleTester.run("logical-assignment-operators", rule, {
+ valid: [
+
+ // Unrelated
+ "a || b",
+ "a && b",
+ "a ?? b",
+ "a || a || b",
+ "var a = a || b",
+ "a === undefined ? a : b",
+ "while (a) a = b",
+
+ // Preferred
+ "a ||= b",
+ "a &&= b",
+ "a ??= b",
+
+ // > Operator
+ "a += a || b",
+ "a *= a || b",
+ "a ||= a || b",
+ "a &&= a || b",
+
+ // > Right
+ "a = a",
+ "a = b",
+ "a = a === b",
+ "a = a + b",
+ "a = a / b",
+ "a = fn(a) || b",
+
+ // > Reference
+ "a = false || c",
+ "a = f() || g()",
+ "a = b || c",
+ "a = b || a",
+ "object.a = object.b || c",
+ "[a] = a || b",
+ "({ a } = a || b)",
+
+ // Logical
+ "(a = b) || a",
+ "a + (a = b)",
+ "a || (b ||= c)",
+ "a || (b &&= c)",
+ "a || b === 0",
+ "a || fn()",
+ "a || (b && c)",
+ "a || (b ?? c)",
+
+ // > Reference
+ "a || (b = c)",
+ "a || (a ||= b)",
+ "fn() || (a = b)",
+ "a.b || (a = b)",
+ "a?.b || (a.b = b)",
+ {
+ code: "class Class { #prop; constructor() { this.#prop || (this.prop = value) } }",
+ parserOptions: { ecmaVersion: 2022 }
+ }, {
+ code: "class Class { #prop; constructor() { this.prop || (this.#prop = value) } }",
+ parserOptions: { ecmaVersion: 2022 }
+ },
+
+ // If
+ "if (a) a = b",
+ {
+ code: "if (a) a = b",
+ options: ["always", { enforceForIfStatements: false }]
+ }, {
+ code: "if (a) { a = b } else {}",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) { a = b } else if (a) {}",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (unrelated) {} else if (a) a = b; else {}",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (unrelated) {} else if (a) a = b; else if (unrelated) {}",
+ options: ["always", { enforceForIfStatements: true }]
+ },
+
+ // > Body
+ {
+ code: "if (a) {}",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) { before; a = b }",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) { a = b; after }",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) throw new Error()",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) a",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) a ||= b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) b = a",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) { a() }",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a) { a += a || b }",
+ options: ["always", { enforceForIfStatements: true }]
+ },
+
+ // > Test
+ {
+ code: "if (true) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (predicate(a)) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a?.b) a.b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (!a?.b) a.b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === b) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a != null) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null && a === undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === 0 || a === undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === 1) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a == null || a == undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === !0) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === +0) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === null) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === undefined || a === void 0) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === void void 0) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === void 'string') a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === void fn()) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ },
+
+ // > Test > Yoda
+ {
+ code: "if (a == a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a == b) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null == null) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (undefined == undefined) undefined = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null == x) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null == fn()) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null === a || a === 0) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (0 === a || null === a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (1 === a || a === undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (undefined === a || 1 === a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === b) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (b === undefined || a === null) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null === a || b === a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null === null || undefined === undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null === null || a === a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (undefined === undefined || a === a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (null === undefined || a === a) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ },
+
+ // > Test > Undefined
+ {
+ code: [
+ "{",
+ " const undefined = 0;",
+ " if (a == undefined) a = b",
+ "}"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: [
+ "(() => {",
+ " const undefined = 0;",
+ " if (condition) {",
+ " if (a == undefined) a = b",
+ " }",
+ "})()"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: [
+ "{",
+ " if (a == undefined) a = b",
+ "}",
+ "var undefined = 0;"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: [
+ "{",
+ " const undefined = 0;",
+ " if (undefined == null) undefined = b",
+ "}"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: [
+ "{",
+ " const undefined = 0;",
+ " if (a === undefined || a === null) a = b",
+ "}"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: [
+ "{",
+ " const undefined = 0;",
+ " if (undefined === a || null === a) a = b",
+ "}"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ },
+
+ // > Reference
+ {
+ code: "if (a) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (!a) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (!!a) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a == null) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || a === undefined) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || b === undefined) a = b",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (a === null || b === undefined) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: "if (Boolean(a)) b = c",
+ options: ["always", { enforceForIfStatements: true }]
+ }, {
+ code: [
+ "function fn(Boolean) {",
+ " if (Boolean(a)) a = b",
+ "}"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }]
+ },
+
+ // Never
+ {
+ code: "a = a || b",
+ options: ["never"]
+ }, {
+ code: "a = a && b",
+ options: ["never"]
+ }, {
+ code: "a = a ?? b",
+ options: ["never"]
+ }, {
+ code: "a = b",
+ options: ["never"]
+ }, {
+ code: "a += b",
+ options: ["never"]
+ }, {
+ code: "a -= b",
+ options: ["never"]
+ }, {
+ code: "a.b = a.b || c",
+ options: ["never"]
+ }
+ ],
+ invalid: [
+
+ // Assignment
+ {
+ code: "a = a || b",
+ output: "a ||= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a && b",
+ output: "a &&= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "&&=" }, suggestions: [] }]
+ }, {
+ code: "a = a ?? b",
+ output: "a ??= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "foo = foo || bar",
+ output: "foo ||= bar",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ },
+
+ // > Right
+ {
+ code: "a = a || fn()",
+ output: "a ||= fn()",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || b && c",
+ output: "a ||= b && c",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || (b || c)",
+ output: "a ||= (b || c)",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || (b ? c : d)",
+ output: "a ||= (b ? c : d)",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ },
+
+ // > Comments
+ {
+ code: "/* before */ a = a || b",
+ output: "/* before */ a ||= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || b // after",
+ output: "a ||= b // after",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a /* between */ = a || b",
+ output: null,
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = /** @type */ a || b",
+ output: null,
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || /* between */ b",
+ output: null,
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ },
+
+ // > Parenthesis
+ {
+ code: "(a) = a || b",
+ output: "(a) ||= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = (a) || b",
+ output: "a ||= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || (b)",
+ output: "a ||= (b)",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || ((b))",
+ output: "a ||= ((b))",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "(a = a || b)",
+ output: "(a ||= b)",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || (f(), b)",
+ output: "a ||= (f(), b)",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ },
+
+ // > Suggestions
+ {
+ code: "a.b = a.b ?? c",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "a.b ??= c"
+ }]
+ }]
+ }, {
+ code: "a.b.c = a.b.c ?? d",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "a.b.c ??= d"
+ }]
+ }]
+ }, {
+ code: "a[b] = a[b] ?? c",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "a[b] ??= c"
+ }]
+ }]
+ }, {
+ code: "a['b'] = a['b'] ?? c",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "a['b'] ??= c"
+ }]
+ }]
+ }, {
+ code: "a.b = a['b'] ?? c",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "a.b ??= c"
+ }]
+ }]
+ }, {
+ code: "a['b'] = a.b ?? c",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "a['b'] ??= c"
+ }]
+ }]
+ }, {
+ code: "this.prop = this.prop ?? {}",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "??=" },
+ output: "this.prop ??= {}"
+ }]
+ }]
+ },
+
+ // > With
+ {
+ code: "with (object) a = a || b",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "||=" },
+
+ output: "with (object) a ||= b"
+ }]
+ }]
+ }, {
+ code: "with (object) { a = a || b }",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "||=" },
+ output: "with (object) { a ||= b }"
+ }]
+ }]
+ }, {
+ code: "with (object) { if (condition) a = a || b }",
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "||=" },
+ output: "with (object) { if (condition) a ||= b }"
+ }]
+ }]
+ }, {
+ code: "with (a = a || b) {}",
+ output: "with (a ||= b) {}",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "with (object) {} a = a || b",
+ output: "with (object) {} a ||= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = a || b; with (object) {}",
+ output: "a ||= b; with (object) {}",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "if (condition) a = a || b",
+ output: "if (condition) a ||= b",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: [
+ "with (object) {",
+ ' "use strict";',
+ " a = a || b",
+ "}"
+ ].join("\n"),
+ output: null,
+ errors: [{
+ messageId: "assignment",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "useLogicalOperator",
+ data: { operator: "||=" },
+ output: [
+ "with (object) {",
+ ' "use strict";',
+ " a ||= b",
+ "}"
+ ].join("\n")
+ }]
+ }]
+ },
+
+ // > Context
+ {
+ code: "fn(a = a || b)",
+ output: "fn(a ||= b)",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "fn((a = a || b))",
+ output: "fn((a ||= b))",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "(a = a || b) ? c : d",
+ output: "(a ||= b) ? c : d",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ }, {
+ code: "a = b = b || c",
+ output: "a = b ||= c",
+ errors: [{ messageId: "assignment", type: "AssignmentExpression", data: { operator: "||=" }, suggestions: [] }]
+ },
+
+ // Logical
+ {
+ code: "a || (a = b)",
+ output: "a ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a && (a = b)",
+ output: "a &&= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "&&=" } }]
+ }, {
+ code: "a ?? (a = b)",
+ output: "a ??= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "??=" } }]
+ }, {
+ code: "foo ?? (foo = bar)",
+ output: "foo ??= bar",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "??=" } }]
+ },
+
+ // > Right
+ {
+ code: "a || (a = 0)",
+ output: "a ||= 0",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (a = fn())",
+ output: "a ||= fn()",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (a = (b || c))",
+ output: "a ||= (b || c)",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ },
+
+ // > Parenthesis
+ {
+ code: "(a) || (a = b)",
+ output: "a ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || ((a) = b)",
+ output: "(a) ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (a = (b))",
+ output: "a ||= (b)",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || ((a = b))",
+ output: "a ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (((a = b)))",
+ output: "a ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || ( ( a = b ) )",
+ output: "a ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ },
+
+ // > Comments
+ {
+ code: "/* before */ a || (a = b)",
+ output: "/* before */ a ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (a = b) // after",
+ output: "a ||= b // after",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a /* between */ || (a = b)",
+ output: null,
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || /* between */ (a = b)",
+ output: null,
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ },
+
+ // > Fix Condition
+ {
+ code: "a.b || (a.b = c)",
+ output: "a.b ||= c",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "class Class { #prop; constructor() { this.#prop || (this.#prop = value) } }",
+ output: "class Class { #prop; constructor() { this.#prop ||= value } }",
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a['b'] || (a['b'] = c)",
+ output: "a['b'] ||= c",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a[0] || (a[0] = b)",
+ output: "a[0] ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a[this] || (a[this] = b)",
+ output: "a[this] ||= b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "foo.bar || (foo.bar = baz)",
+ output: "foo.bar ||= baz",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a.b.c || (a.b.c = d)",
+ output: null,
+ errors: [{
+ messageId: "logical",
+ type: "LogicalExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "convertLogical",
+ data: { operator: "||=" },
+ output: "a.b.c ||= d"
+ }]
+ }]
+ }, {
+ code: "a[b.c] || (a[b.c] = d)",
+ output: null,
+ errors: [{
+ messageId: "logical",
+ type: "LogicalExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "convertLogical",
+ data: { operator: "||=" },
+ output: "a[b.c] ||= d"
+ }]
+ }]
+ }, {
+ code: "a[b?.c] || (a[b?.c] = d)",
+ output: null,
+ errors: [{
+ messageId: "logical",
+ type: "LogicalExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "convertLogical",
+ data: { operator: "||=" },
+ output: "a[b?.c] ||= d"
+ }]
+ }]
+ }, {
+ code: "with (object) a.b || (a.b = c)",
+ output: null,
+ errors: [{
+ messageId: "logical",
+ type: "LogicalExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "convertLogical",
+ data: { operator: "||=" },
+ output: "with (object) a.b ||= c"
+ }]
+ }]
+ },
+
+ // > Context
+ {
+ code: "a = a.b || (a.b = {})",
+ output: "a = a.b ||= {}",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" }, suggestions: [] }]
+ },
+ {
+ code: "a || (a = 0) || b",
+ output: "(a ||= 0) || b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "(a || (a = 0)) || b",
+ output: "(a ||= 0) || b",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (b || (b = 0))",
+ output: "a || (b ||= 0)",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a = b || (b = c)",
+ output: "a = b ||= c",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a || (a = 0) ? b : c",
+ output: "(a ||= 0) ? b : c",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ }, {
+ code: "fn(a || (a = 0))",
+ output: "fn(a ||= 0)",
+ errors: [{ messageId: "logical", type: "LogicalExpression", data: { operator: "||=" } }]
+ },
+
+ // If
+ {
+ code: "if (a) a = b",
+ output: "a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (Boolean(a)) a = b",
+ output: "a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (!!a) a = b",
+ output: "a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (!a) a = b",
+ output: "a ||= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "||=" } }]
+ }, {
+ code: "if (!Boolean(a)) a = b",
+ output: "a ||= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "||=" } }]
+ }, {
+ code: "if (a == undefined) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: "if (a == null) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: "if (a === null || a === undefined) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: "if (a === undefined || a === null) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: "if (a === null || a === void 0) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: "if (a === void 0 || a === null) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: "if (a) { a = b; }",
+ output: "a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: [
+ "{ const undefined = 0; }",
+ "if (a == undefined) a = b"
+ ].join("\n"),
+ output: [
+ "{ const undefined = 0; }",
+ "a ??= b"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ }, {
+ code: [
+ "if (a == undefined) a = b",
+ "{ const undefined = 0; }"
+ ].join("\n"),
+ output: [
+ "a ??= b",
+ "{ const undefined = 0; }"
+ ].join("\n"),
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" } }]
+ },
+
+ // > Yoda
+ {
+ code: "if (null == a) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (undefined == a) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (undefined === a || a === null) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (a === undefined || null === a) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (undefined === a || null === a) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (null === a || a === undefined) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (a === null || undefined === a) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ }, {
+ code: "if (null === a || undefined === a) a = b",
+ output: "a ??= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "??=" }, suggestions: [] }]
+ },
+
+ // > Parenthesis
+ {
+ code: "if ((a)) a = b",
+ output: "a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) (a) = b",
+ output: "(a) &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) a = (b)",
+ output: "a &&= (b)",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) (a = b)",
+ output: "(a &&= b)",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Previous statement
+ {
+ code: ";if (a) (a) = b",
+ output: ";(a) &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "{ if (a) (a) = b }",
+ output: "{ (a) &&= b }",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "fn();if (a) (a) = b",
+ output: "fn();(a) &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "fn()\nif (a) a = b",
+ output: "fn()\na &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "id\nif (a) (a) = b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "object.prop\nif (a) (a) = b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "object[computed]\nif (a) (a) = b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "fn()\nif (a) (a) = b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Adding semicolon
+ {
+ code: "if (a) a = b; fn();",
+ output: "a &&= b; fn();",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) { a = b }",
+ output: "a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) { a = b; }\nfn();",
+ output: "a &&= b;\nfn();",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) { a = b }\nfn();",
+ output: "a &&= b;\nfn();",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) { a = b } fn();",
+ output: "a &&= b; fn();",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) { a = b\n} fn();",
+ output: "a &&= b; fn();",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Spacing
+ {
+ code: "if (a) a = b",
+ output: "a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a)\n a = b",
+ output: "a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) {\n a = b; \n}",
+ output: "a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Comments
+ {
+ code: "/* before */ if (a) a = b",
+ output: "/* before */ a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) a = b /* after */",
+ output: "a &&= b /* after */",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) /* between */ a = b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) a = /* between */ b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Members > Single Property Access
+ {
+ code: "if (a.b) a.b = c",
+ output: "a.b &&= c",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" }, suggestions: [] }]
+ }, {
+ code: "if (a[b]) a[b] = c",
+ output: "a[b] &&= c",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" }, suggestions: [] }]
+ }, {
+ code: "if (a['b']) a['b'] = c",
+ output: "a['b'] &&= c",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" }, suggestions: [] }]
+ }, {
+ code: "if (this.prop) this.prop = value",
+ output: "this.prop &&= value",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", suggestions: [] }]
+ }, {
+ code: "(class extends SuperClass { method() { if (super.prop) super.prop = value } })",
+ output: "(class extends SuperClass { method() { super.prop &&= value } })",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" }, suggestions: [] }]
+ }, {
+ code: "with (object) if (a) a = b",
+ output: "with (object) a &&= b",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" }, suggestions: [] }]
+ },
+
+ // > Members > Possible Multiple Property Accesses
+ {
+ code: "if (a.b === undefined || a.b === null) a.b = c",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{
+ messageId: "if",
+ type: "IfStatement",
+ data: { operator: "??=" },
+ suggestions: [{
+ messageId: "convertIf",
+ data: { operator: "??=" },
+ output: "a.b ??= c"
+ }]
+ }]
+ }, {
+ code: "if (a.b.c) a.b.c = d",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{
+ messageId: "if",
+ type: "IfStatement",
+ data: { operator: "&&=" },
+ suggestions: [{
+ messageId: "convertIf",
+ data: { operator: "&&=" },
+ output: "a.b.c &&= d"
+ }]
+ }]
+ }, {
+ code: "if (a.b.c.d) a.b.c.d = e",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{
+ messageId: "if",
+ type: "IfStatement",
+ data: { operator: "&&=" },
+ suggestions: [{
+ messageId: "convertIf",
+ data: { operator: "&&=" },
+ output: "a.b.c.d &&= e"
+ }]
+ }]
+ }, {
+ code: "if (a[b].c) a[b].c = d",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{
+ messageId: "if",
+ type: "IfStatement",
+ data: { operator: "&&=" },
+ suggestions: [{
+ messageId: "convertIf",
+ data: { operator: "&&=" },
+ output: "a[b].c &&= d"
+ }]
+ }]
+ }, {
+ code: "with (object) if (a.b) a.b = c",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{
+ messageId: "if",
+ type: "IfStatement",
+ data: { operator: "&&=" },
+ suggestions: [{
+ messageId: "convertIf",
+ data: { operator: "&&=" },
+ output: "with (object) a.b &&= c"
+ }]
+ }]
+ },
+
+ // > Else if
+ {
+ code: "if (unrelated) {} else if (a) a = b;",
+ output: "if (unrelated) {} else a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (a) {} else if (b) {} else if (a) a = b;",
+ output: "if (a) {} else if (b) {} else a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) {} else\nif (a) a = b;",
+ output: "if (unrelated) {} else\na &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) {\n}\nelse if (a) {\na = b;\n}",
+ output: "if (unrelated) {\n}\nelse a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) statement; else if (a) a = b;",
+ output: "if (unrelated) statement; else a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) id\nelse if (a) (a) = b",
+ output: null,
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) {} else if (a) a = b; else if (c) c = d",
+ output: "if (unrelated) {} else if (a) a = b; else c &&= d",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Else if > Comments
+ {
+ code: "if (unrelated) { /* body */ } else if (a) a = b;",
+ output: "if (unrelated) { /* body */ } else a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) {} /* before else */ else if (a) a = b;",
+ output: "if (unrelated) {} /* before else */ else a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) {} else // Line\nif (a) a = b;",
+ output: "if (unrelated) {} else // Line\na &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ }, {
+ code: "if (unrelated) {} else /* Block */ if (a) a = b;",
+ output: "if (unrelated) {} else /* Block */ a &&= b;",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // > Patterns
+ {
+ code: "if (array) array = array.filter(predicate)",
+ output: "array &&= array.filter(predicate)",
+ options: ["always", { enforceForIfStatements: true }],
+ errors: [{ messageId: "if", type: "IfStatement", data: { operator: "&&=" } }]
+ },
+
+ // Never
+ {
+ code: "a ||= b",
+ output: "a = a || b",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a &&= b",
+ output: "a = a && b",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "&&=" } }]
+ }, {
+ code: "a ??= b",
+ output: "a = a ?? b",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }]
+ }, {
+ code: "foo ||= bar",
+ output: "foo = foo || bar",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ },
+
+ // > Suggestions
+ {
+ code: "a.b ||= c",
+ output: null,
+ options: ["never"],
+ errors: [{
+ messageId: "unexpected",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "separate",
+ output: "a.b = a.b || c"
+ }]
+ }]
+ }, {
+ code: "a[b] ||= c",
+ output: null,
+ options: ["never"],
+ errors: [{
+ messageId: "unexpected",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "separate",
+ output: "a[b] = a[b] || c"
+ }]
+ }]
+ }, {
+ code: "a['b'] ||= c",
+ output: null,
+ options: ["never"],
+ errors: [{
+ messageId: "unexpected",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "separate",
+ output: "a['b'] = a['b'] || c"
+ }]
+ }]
+ }, {
+ code: "this.prop ||= 0",
+ output: null,
+ options: ["never"],
+ errors: [{
+ messageId: "unexpected",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "separate",
+ output: "this.prop = this.prop || 0"
+ }]
+ }]
+ }, {
+ code: "with (object) a ||= b",
+ output: null,
+ options: ["never"],
+ errors: [{
+ messageId: "unexpected",
+ type: "AssignmentExpression",
+ data: { operator: "||=" },
+ suggestions: [{
+ messageId: "separate",
+ output: "with (object) a = a || b"
+ }]
+ }]
+ },
+
+ // > Parenthesis
+ {
+ code: "(a) ||= b",
+ output: "(a) = a || b",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a ||= (b)",
+ output: "a = a || (b)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "(a ||= b)",
+ output: "(a = a || b)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ },
+
+ // > Comments
+ {
+ code: "/* before */ a ||= b",
+ output: "/* before */ a = a || b",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a ||= b // after",
+ output: "a = a || b // after",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a /* before */ ||= b",
+ output: null,
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a ||= /* after */ b",
+ output: null,
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ },
+
+ // > Precedence
+ {
+ code: "a ||= b && c",
+ output: "a = a || b && c",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a &&= b || c",
+ output: "a = a && (b || c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "&&=" } }]
+ }, {
+ code: "a ||= b || c",
+ output: "a = a || (b || c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }]
+ }, {
+ code: "a &&= b && c",
+ output: "a = a && (b && c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "&&=" } }]
+ },
+
+ // > Mixed
+ {
+ code: "a ??= b || c",
+ output: "a = a ?? (b || c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }]
+ }, {
+ code: "a ??= b && c",
+ output: "a = a ?? (b && c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }]
+ }, {
+ code: "a ??= b ?? c",
+ output: "a = a ?? (b ?? c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }]
+ }, {
+ code: "a ??= (b || c)",
+ output: "a = a ?? (b || c)",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }]
+ }, {
+ code: "a ??= b + c",
+ output: "a = a ?? b + c",
+ options: ["never"],
+ errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }]
+ }]
+});
options: ["separate-lines"],
errors: [{ messageId: "expectedLines", line: 2 }]
},
+ {
+ code: `
+ /**
+ * JSDoc
+ * Comment
+ */
+ `,
+ output: `
+ // JSDoc
+ // Comment
+ `,
+ options: ["separate-lines", { checkJSDoc: true }],
+ errors: [{ messageId: "expectedLines", line: 2 }]
+ },
{
code: `
/* foo
"function foo(undefined) { undefined === true;}",
"[...arr, 1] == true",
"[,,,] == true",
- { code: "new Foo() === bar;", globals: { Foo: "writable" } }
+ { code: "new Foo() === bar;", globals: { Foo: "writable" } },
+ "(foo && true) ?? bar",
+ "foo ?? null ?? bar",
+ "a ?? (doSomething(), undefined) ?? b",
+ "a ?? (something = null) ?? b"
],
invalid: [
{ code: "x === /[a-z]/", errors: [{ messageId: "alwaysNew" }] },
// It's not obvious what this does, but it compares the old value of `x` to the new object.
- { code: "x === (x = {})", errors: [{ messageId: "alwaysNew" }] }
+ { code: "x === (x = {})", errors: [{ messageId: "alwaysNew" }] },
+
+ { code: "window.abc && false && anything", errors: [{ messageId: "constantShortCircuit" }] },
+ { code: "window.abc || true || anything", errors: [{ messageId: "constantShortCircuit" }] },
+ { code: "window.abc ?? 'non-nullish' ?? anything", errors: [{ messageId: "constantShortCircuit" }] }
]
});
--- /dev/null
+/**
+ * @fileoverview Tests for no-empty-static-block rule.
+ * @author Sosuke Suzuki
+ */
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/no-empty-static-block"),
+ { RuleTester } = require("../../../lib/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({
+ parserOptions: { ecmaVersion: 2022 }
+});
+
+ruleTester.run("no-empty-static-block", rule, {
+ valid: [
+ "class Foo { static { bar(); } }",
+ "class Foo { static { /* comments */ } }",
+ "class Foo { static {\n// comment\n} }",
+ "class Foo { static { bar(); } static { bar(); } }"
+ ],
+ invalid: [
+ {
+ code: "class Foo { static {} }",
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "class Foo { static { } }",
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "class Foo { static { \n\n } }",
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "class Foo { static { bar(); } static {} }",
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "class Foo { static // comment\n {} }",
+ errors: [{ messageId: "unexpected" }]
+ }
+ ]
+});
{ code: "try { foo(); } catch (ex) {} finally { bar(); }", options: [{ allowEmptyCatch: true }] }
],
invalid: [
- { code: "try {} catch (ex) {throw ex}", errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }] },
- { code: "try { foo() } catch (ex) {}", errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }] },
- { code: "try { foo() } catch (ex) {throw ex} finally {}", errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }] },
- { code: "if (foo) {}", errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }] },
- { code: "while (foo) {}", errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }] },
- { code: "for (;foo;) {}", errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }] },
- { code: "switch(foo) {}", errors: [{ messageId: "unexpected", data: { type: "switch" }, type: "SwitchStatement" }] },
+ {
+ code: "try {} catch (ex) {throw ex}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { /* empty */ } catch (ex) {throw ex}"
+ }]
+ }]
+ },
+ {
+ code: "try { foo() } catch (ex) {}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { foo() } catch (ex) { /* empty */ }"
+ }]
+ }]
+ },
+ {
+ code: "try { foo() } catch (ex) {throw ex} finally {}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { foo() } catch (ex) {throw ex} finally { /* empty */ }"
+ }]
+ }]
+ },
+ {
+ code: "if (foo) {}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "if (foo) { /* empty */ }"
+ }]
+ }]
+ },
+ {
+ code: "while (foo) {}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "while (foo) { /* empty */ }"
+ }]
+ }]
+ },
+ {
+ code: "for (;foo;) {}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "for (;foo;) { /* empty */ }"
+ }]
+ }]
+ },
+ {
+ code: "switch(foo) {}",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "switch" },
+ type: "SwitchStatement",
+ suggestions: null
+ }]
+ },
+ {
+ code: "switch (foo) { /* empty */ }",
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "switch" },
+ type: "SwitchStatement",
+ suggestions: null
+ }]
+ },
{
code: "try {} catch (ex) {}",
options: [{ allowEmptyCatch: true }],
- errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }]
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { /* empty */ } catch (ex) {}"
+ }]
+ }]
},
{
code: "try { foo(); } catch (ex) {} finally {}",
options: [{ allowEmptyCatch: true }],
- errors: [{ messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }]
+ errors: [{
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [{
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { foo(); } catch (ex) {} finally { /* empty */ }"
+ }]
+ }]
},
{
code: "try {} catch (ex) {} finally {}",
options: [{ allowEmptyCatch: true }],
errors: [
- { messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" },
- { messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }
+ {
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [
+ {
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { /* empty */ } catch (ex) {} finally {}"
+ }
+ ]
+ },
+ {
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [
+ {
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try {} catch (ex) {} finally { /* empty */ }"
+ }
+ ]
+ }
]
},
{
code: "try { foo(); } catch (ex) {} finally {}",
errors: [
- { messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" },
- { messageId: "unexpected", data: { type: "block" }, type: "BlockStatement" }
+ {
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [
+ {
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { foo(); } catch (ex) { /* empty */ } finally {}"
+ }
+ ]
+ },
+ {
+ messageId: "unexpected",
+ data: { type: "block" },
+ type: "BlockStatement",
+ suggestions: [
+ {
+ messageId: "suggestComment",
+ data: { type: "block" },
+ output: "try { foo(); } catch (ex) {} finally { /* empty */ }"
+ }
+ ]
+ }
]
}
]
code: "var foo = (function(){}?.call())",
options: ["all", { enforceForFunctionPrototypeMethods: false }],
parserOptions: { ecmaVersion: 2020 }
+ },
+ {
+ code: "(Object.prototype.toString.call())",
+ options: ["functions"]
+ },
+
+ // "allowParensAfterCommentPattern" option
+ {
+ code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
+ options: ["all", { allowParensAfterCommentPattern: "@type" }]
+ },
+ {
+ code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');",
+ options: ["all", { allowParensAfterCommentPattern: "@type" }]
+ },
+ {
+ code: `
+ validate(/** @type {Schema} */ (schema), options, {
+ name: "Dev Server",
+ baseDataPath: "options",
+ });
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "@type" }]
+ },
+ {
+ code: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ (options.server.options).requestCert = false;
+ }
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "@type" }]
+ },
+ {
+ code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
+ options: ["all", { allowParensAfterCommentPattern: "@type" }]
+ },
+
+ // https://github.com/eslint/eslint/issues/16850
+ "(a) = function () {};",
+ "(a) = () => {};",
+ "(a) = class {};",
+ "(a) ??= function () {};",
+ "(a) &&= class extends SuperClass {};",
+ "(a) ||= async () => {}",
+ {
+ code: "((a)) = function () {};",
+ options: ["functions"]
}
],
errors: [{ messageId: "unexpected" }]
},
+ // "allowParensAfterCommentPattern" option (off by default)
+ {
+ code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
+ output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;",
+ options: ["all"],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');",
+ output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');",
+ options: ["all"],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ validate(/** @type {Schema} */ (schema), options, {
+ name: "Dev Server",
+ baseDataPath: "options",
+ });
+ `,
+ output: `
+ validate(/** @type {Schema} */ schema, options, {
+ name: "Dev Server",
+ baseDataPath: "options",
+ });
+ `,
+ options: ["all"],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ (options.server.options).requestCert = false;
+ }
+ `,
+ output: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ options.server.options.requestCert = false;
+ }
+ `,
+ options: ["all"],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
+ output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);",
+ options: ["all"],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "const span = /**@type {HTMLSpanElement}*/(event.currentTarget);",
+ output: "const span = /**@type {HTMLSpanElement}*/event.currentTarget;",
+ options: ["all", { allowParensAfterCommentPattern: "invalid" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "if (/** @type {Compiler | MultiCompiler} */(options).hooks) console.log('good');",
+ output: "if (/** @type {Compiler | MultiCompiler} */options.hooks) console.log('good');",
+ options: ["all", { allowParensAfterCommentPattern: "invalid" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ validate(/** @type {Schema} */ (schema), options, {
+ name: "Dev Server",
+ baseDataPath: "options",
+ });
+ `,
+ output: `
+ validate(/** @type {Schema} */ schema, options, {
+ name: "Dev Server",
+ baseDataPath: "options",
+ });
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "invalid" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ (options.server.options).requestCert = false;
+ }
+ `,
+ output: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ options.server.options.requestCert = false;
+ }
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "invalid" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ /** extra comment */
+ (options.server.options).requestCert = false;
+ }
+ `,
+ output: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ /** extra comment */
+ options.server.options.requestCert = false;
+ }
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "@type" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ ((options.server.options)).requestCert = false;
+ }
+ `,
+ output: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ (options.server.options).requestCert = false;
+ }
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "@type" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ let foo = "bar";
+ (options.server.options).requestCert = false;
+ }
+ `,
+ output: `
+ if (condition) {
+ /** @type {ServerOptions} */
+ let foo = "bar";
+ options.server.options.requestCert = false;
+ }
+ `,
+ options: ["all", { allowParensAfterCommentPattern: "@type" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+ {
+ code: "const net = ipaddr.parseCIDR(/** @type {string} */ (cidr));",
+ output: "const net = ipaddr.parseCIDR(/** @type {string} */ cidr);",
+ options: ["all", { allowParensAfterCommentPattern: "invalid" }],
+ errors: [{ messageId: "unexpected" }]
+ },
+
// Optional chaining
{
code: "var v = (obj?.aaa)?.aaa",
options: ["all", { enforceForFunctionPrototypeMethods: true }],
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "unexpected" }]
- }
+ },
+ {
+ code: "(Object.prototype.toString.call())",
+ output: "Object.prototype.toString.call()",
+ options: ["all"],
+ parserOptions: { ecmaVersion: 2020 },
+ errors: [{ messageId: "unexpected" }]
+ },
+
+ // https://github.com/eslint/eslint/issues/16850
+ invalid("(a) = function foo() {};", "a = function foo() {};", "Identifier"),
+ invalid("(a) = class Bar {};", "a = class Bar {};", "Identifier"),
+ invalid("(a.b) = function () {};", "a.b = function () {};", "MemberExpression"),
+ {
+ code: "(newClass) = [(one)] = class { static * [Symbol.iterator]() { yield 1; } };",
+ output: "newClass = [one] = class { static * [Symbol.iterator]() { yield 1; } };",
+ errors: [
+ { messageId: "unexpected", type: "Identifier" },
+ { messageId: "unexpected", type: "Identifier" }
+ ]
+ },
+ invalid("((a)) = () => {};", "(a) = () => {};", "Identifier"),
+ invalid("(a) = (function () {})();", "a = (function () {})();", "Identifier"),
+ ...["**=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|="].map(
+ operator => invalid(
+ `(a) ${operator} function () {};`,
+ `a ${operator} function () {};`,
+ "Identifier"
+ )
+ )
]
});
"switch (foo) { case 0: try {} finally { break; } default: b(); }",
"switch (foo) { case 0: try { throw 0; } catch (err) { break; } default: b(); }",
"switch (foo) { case 0: do { throw 0; } while(a); default: b(); }",
+ "switch (foo) { case 0: a(); \n// eslint-disable-next-line no-fallthrough\n case 1: }",
{
code: "switch(foo) { case 0: a(); /* no break */ case 1: b(); }",
options: [{
column: 34
}
]
+ },
+ {
+ code: "switch (foo) { case 0: a(); \n// eslint-enable no-fallthrough\n case 1: }",
+ options: [{}],
+ errors: [
+ {
+ messageId: "case",
+ type: "SwitchCase",
+ line: 3,
+ column: 2
+ }
+ ]
}
]
});
{ code: "String(foo) + ``", parserOptions: { ecmaVersion: 6 } },
{ code: "`${'foo'}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } },
{ code: "`${`foo`}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } },
- { code: "`${String(foo)}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } }
+ { code: "`${String(foo)}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } },
+
+ // https://github.com/eslint/eslint/issues/16373
+ "console.log(Math.PI * 1/4)",
+ "a * 1 / 2",
+ "a * 1 / b"
],
invalid: [
{
data: { recommendation: "(foo?.indexOf)(1) !== -1" },
type: "UnaryExpression"
}]
+ },
+
+ // https://github.com/eslint/eslint/issues/16373 regression tests
+ {
+ code: "1 * a / 2",
+ output: "Number(a) / 2",
+ errors: [{
+ messageId: "useRecommendation",
+ data: { recommendation: "Number(a)" },
+ type: "BinaryExpression"
+ }]
+ },
+ {
+ code: "(a * 1) / 2",
+ output: "(Number(a)) / 2",
+ errors: [{
+ messageId: "useRecommendation",
+ data: { recommendation: "Number(a)" },
+ type: "BinaryExpression"
+ }]
+ },
+ {
+ code: "a * 1 / (b * 1)",
+ output: "a * 1 / (Number(b))",
+ errors: [{
+ messageId: "useRecommendation",
+ data: { recommendation: "Number(b)" },
+ type: "BinaryExpression"
+ }]
+ },
+ {
+ code: "a * 1 + 2",
+ output: "Number(a) + 2",
+ errors: [{
+ messageId: "useRecommendation",
+ data: { recommendation: "Number(a)" },
+ type: "BinaryExpression"
+ }]
}
]
});
// This rule doesn't disallow assignments to properties of readonly globals
"Array.from = 1;",
"Object['assign'] = 1;",
- "/*global foo:readonly*/ foo.bar = 1;"
+ "/*global foo:readonly*/ foo.bar = 1;",
+
+
+ //------------------------------------------------------------------------------
+ // exported
+ //------------------------------------------------------------------------------
+
+ // `var` and functions
+ "/* exported foo */ var foo = 'foo';",
+ "/* exported foo */ function foo() {}",
+ {
+ code: "/* exported foo */ function *foo() {}",
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported foo */ async function foo() {}",
+ parserOptions: { ecmaVersion: 2017 }
+ },
+ {
+ code: "/* exported foo */ async function *foo() {}",
+ parserOptions: { ecmaVersion: 2018 }
+ },
+ "/* exported foo */ var foo = function() {};",
+ "/* exported foo */ var foo = function foo() {};",
+ {
+ code: "/* exported foo */ var foo = function*() {};",
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported foo */ var foo = function *foo() {};",
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ "/* exported foo, bar */ var foo = 1, bar = 2;",
+
+
+ // `const`, `let` and `class`
+ {
+ code: "/* exported a */ const a = 1;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a */ let a;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a */ let a = 1;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported A */ class A {}",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a, b */ const a = 1; const b = 2;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a, b */ const a = 1, b = 2;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a, b */ let a, b = 1;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a, b, C */ const a = 1; let b; class C {}",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a, b, c */ const [a, b, ...c] = [];",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ },
+ {
+ code: "/* exported a, b, c */ let { a, foo: b, bar: { c } } = {};",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 }
+ }
],
invalid: [
type: "VariableDeclarator"
}
]
+ },
+
+ //------------------------------------------------------------------------------
+ // exported
+ //------------------------------------------------------------------------------
+
+ // `var` and `function`
+ {
+ code: "/* exported bar */ var foo = 'text';",
+ errors: [
+ {
+ message: varMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ function foo() {}",
+ errors: [
+ {
+ message: functionMessage,
+ type: "FunctionDeclaration"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ function *foo() {}",
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: functionMessage,
+ type: "FunctionDeclaration"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ async function foo() {}",
+ parserOptions: { ecmaVersion: 2017 },
+ errors: [
+ {
+ message: functionMessage,
+ type: "FunctionDeclaration"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ async function *foo() {}",
+ parserOptions: { ecmaVersion: 2018 },
+ errors: [
+ {
+ message: functionMessage,
+ type: "FunctionDeclaration"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ var foo = function() {};",
+ errors: [
+ {
+ message: varMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ var foo = function foo() {};",
+ errors: [
+ {
+ message: varMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ var foo = function*() {};",
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: varMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ var foo = function *foo() {};",
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: varMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported bar */ var foo = 1, bar = 2;",
+ errors: [
+ {
+ message: varMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+
+ // `let`, `const` and `class`
+ {
+ code: "/* exported b */ const a = 1;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: constMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported b */ let a;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: letMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported b */ let a = 1;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: letMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported B */ class A {}",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: classMessage,
+ type: "ClassDeclaration"
+ }
+ ]
+ },
+ {
+ code: "/* exported a */ const a = 1; const b = 2;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: constMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported a */ const a = 1, b = 2;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: constMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported a */ let a, b = 1;",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: letMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported a */ const a = 1; let b; class C {}",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: letMessage,
+ type: "VariableDeclarator"
+ },
+ {
+ message: classMessage,
+ type: "ClassDeclaration"
+ }
+ ]
+ },
+ {
+ code: "/* exported a */ const [a, b, ...c] = [];",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: constMessage,
+ type: "VariableDeclarator"
+ },
+ {
+ message: constMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+ {
+ code: "/* exported a */ let { a, foo: b, bar: { c } } = {};",
+ options: [{ lexicalBindings: true }],
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: letMessage,
+ type: "VariableDeclarator"
+ },
+ {
+ message: letMessage,
+ type: "VariableDeclarator"
+ }
+ ]
+ },
+
+ // Global variable leaks
+ {
+ code: "/* exported foo */ foo = 1",
+ errors: [
+ {
+ message: leakMessage,
+ type: "AssignmentExpression"
+ }
+ ]
+ },
+ {
+ code: "/* exported foo */ foo = function() {};",
+ errors: [
+ {
+ message: leakMessage,
+ type: "AssignmentExpression"
+ }
+ ]
+ },
+ {
+ code: "/* exported foo */ foo = function*() {};",
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: leakMessage,
+ type: "AssignmentExpression"
+ }
+ ]
+ },
+ {
+ code: "/* exported foo */ window.foo = function() { bar = 1; }",
+ errors: [
+ {
+ message: leakMessage,
+ type: "AssignmentExpression"
+ }
+ ]
+ },
+ {
+ code: "/* exported foo */ (function() {}(foo = 1));",
+ errors: [
+ {
+ message: leakMessage,
+ type: "AssignmentExpression"
+ }
+ ]
+ },
+ {
+ code: "/* exported foo */ for (foo in {});",
+ errors: [
+ {
+ message: leakMessage,
+ type: "ForInStatement"
+ }
+ ]
+ },
+ {
+ code: "/* exported foo */ for (foo of []);",
+ parserOptions: { ecmaVersion: 2015 },
+ errors: [
+ {
+ message: leakMessage,
+ type: "ForOfStatement"
+ }
+ ]
}
]
});
options: [{ allowConstructorFlags: ["a"] }]
},
+ // unknown pattern
+ "new RegExp(pattern, 'g')",
+ "new RegExp('.' + '', 'g')",
+ "new RegExp(pattern, '')",
+ "new RegExp(pattern)",
+
// ES2020
"new RegExp('(?<\\\\ud835\\\\udc9c>.)', 'g')",
"new RegExp('(?<\\\\u{1d49c}>.)', 'g')",
// ES2022
"new RegExp('a+(?<Z>z)?', 'd')",
+ "new RegExp('\\\\p{Script=Cpmn}', 'u')",
+ "new RegExp('\\\\p{Script=Cypro_Minoan}', 'u')",
+ "new RegExp('\\\\p{Script=Old_Uyghur}', 'u')",
+ "new RegExp('\\\\p{Script=Ougr}', 'u')",
+ "new RegExp('\\\\p{Script=Tangsa}', 'u')",
+ "new RegExp('\\\\p{Script=Tnsa}', 'u')",
+ "new RegExp('\\\\p{Script=Toto}', 'u')",
+ "new RegExp('\\\\p{Script=Vith}', 'u')",
+ "new RegExp('\\\\p{Script=Vithkuqi}', 'u')",
// allowConstructorFlags
{
code: "new RegExp('.', 'ga')",
options: [{ allowConstructorFlags: ["a"] }]
},
+ {
+ code: "new RegExp(pattern, 'ga')",
+ options: [{ allowConstructorFlags: ["a"] }]
+ },
+ {
+ code: "new RegExp('.' + '', 'ga')",
+ options: [{ allowConstructorFlags: ["a"] }]
+ },
{
code: "new RegExp('.', 'a')",
options: [{ allowConstructorFlags: ["a", "z"] }]
data: { message: "Invalid regular expression: /\\/: \\ at end of pattern" },
type: "NewExpression"
}]
+ },
+
+ // https://github.com/eslint/eslint/issues/16573
+ {
+ code: "RegExp(')' + '', 'a');",
+ errors: [{
+ messageId: "regexMessage",
+ data: { message: "Invalid flags supplied to RegExp constructor 'a'" },
+ type: "CallExpression"
+ }]
+ },
+ {
+ code: "new RegExp('.' + '', 'az');",
+ options: [{ allowConstructorFlags: ["z"] }],
+ errors: [{
+ messageId: "regexMessage",
+ data: { message: "Invalid flags supplied to RegExp constructor 'a'" },
+ type: "NewExpression"
+ }]
+ },
+ {
+ code: "new RegExp(pattern, 'az');",
+ options: [{ allowConstructorFlags: ["a"] }],
+ errors: [{
+ messageId: "regexMessage",
+ data: { message: "Invalid flags supplied to RegExp constructor 'z'" },
+ type: "NewExpression"
+ }]
}
]
});
code: "foo?.[777]",
options: [{ ignoreArrayIndexes: true }],
parserOptions: { ecmaVersion: 2020 }
+ },
+
+ // ignoreClassFieldInitialValues
+ {
+ code: "class C { foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C { foo = -2; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C { static foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C { #foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C { static #foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 }
}
],
invalid: [
{ messageId: "noMagic", data: { raw: "1" }, line: 1 },
{ messageId: "noMagic", data: { raw: "2" }, line: 1 }
]
+ },
+
+ // ignoreClassFieldInitialValues
+ {
+ code: "class C { foo = 2; }",
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 }
+ ]
+ },
+ {
+ code: "class C { foo = 2; }",
+ options: [{}],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 }
+ ]
+ },
+ {
+ code: "class C { foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 }
+ ]
+ },
+ {
+ code: "class C { foo = -2; }",
+ options: [{ ignoreClassFieldInitialValues: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "-2" }, line: 1, column: 17 }
+ ]
+ },
+ {
+ code: "class C { static foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 24 }
+ ]
+ },
+ {
+ code: "class C { #foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 18 }
+ ]
+ },
+ {
+ code: "class C { static #foo = 2; }",
+ options: [{ ignoreClassFieldInitialValues: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 25 }
+ ]
+ },
+ {
+ code: "class C { foo = 2 + 3; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 },
+ { messageId: "noMagic", data: { raw: "3" }, line: 1, column: 21 }
+ ]
+ },
+ {
+ code: "class C { 2; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 11 }
+ ]
+ },
+ {
+ code: "class C { [2]; }",
+ options: [{ ignoreClassFieldInitialValues: true }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "noMagic", data: { raw: "2" }, line: 1, column: 12 }
+ ]
}
]
});
//------------------------------------------------------------------------------
const rule = require("../../../lib/rules/no-misleading-character-class"),
- { RuleTester } = require("../../../lib/rule-tester");
+ { RuleTester } = require("../../../lib/rule-tester"),
+ FlatRuleTester = require("../../../lib/rule-tester/flat-rule-tester");
//------------------------------------------------------------------------------
// Tests
}
]
});
+
+const flatRuleTester = new FlatRuleTester();
+
+flatRuleTester.run("no-misleading-character-class", rule, {
+ valid: [],
+
+ invalid: [
+ {
+ code: "var r = /[👍]/",
+ languageOptions: {
+ ecmaVersion: 5,
+ sourceType: "script"
+ },
+ errors: [{
+ messageId: "surrogatePairWithoutUFlag",
+ suggestions: null // ecmaVersion doesn't support the 'u' flag
+ }]
+ },
+ {
+ code: "var r = /[👍]/",
+ languageOptions: {
+ ecmaVersion: 2015
+ },
+ errors: [{
+ messageId: "surrogatePairWithoutUFlag",
+ suggestions: [{ messageId: "suggestUnicodeFlag", output: "var r = /[👍]/u" }]
+ }]
+ }
+ ]
+});
--- /dev/null
+/**
+ * @fileoverview Tests for the no-new-native-nonconstructor rule
+ * @author Sosuke Suzuki
+ */
+
+"use strict";
+
+//------------------------------------------------------------------------------
+// Requirements
+//------------------------------------------------------------------------------
+
+const rule = require("../../../lib/rules/no-new-native-nonconstructor"),
+ { RuleTester } = require("../../../lib/rule-tester");
+
+//------------------------------------------------------------------------------
+// Tests
+//------------------------------------------------------------------------------
+
+const ruleTester = new RuleTester({ env: { es2022: true } });
+
+ruleTester.run("no-new-native-nonconstructor", rule, {
+ valid: [
+
+ // Symbol
+ "var foo = Symbol('foo');",
+ "function bar(Symbol) { var baz = new Symbol('baz');}",
+ "function Symbol() {} new Symbol();",
+ "new foo(Symbol);",
+ "new foo(bar, Symbol);",
+
+ // BigInt
+ "var foo = BigInt(9007199254740991);",
+ "function bar(BigInt) { var baz = new BigInt(9007199254740991);}",
+ "function BigInt() {} new BigInt();",
+ "new foo(BigInt);",
+ "new foo(bar, BigInt);"
+ ],
+ invalid: [
+
+ // Symbol
+ {
+ code: "var foo = new Symbol('foo');",
+ errors: [{
+ message: "`Symbol` cannot be called as a constructor."
+ }]
+ },
+ {
+ code: "function bar() { return function Symbol() {}; } var baz = new Symbol('baz');",
+ errors: [{
+ message: "`Symbol` cannot be called as a constructor."
+ }]
+ },
+
+ // BigInt
+ {
+ code: "var foo = new BigInt(9007199254740991);",
+ errors: [{
+ message: "`BigInt` cannot be called as a constructor."
+ }]
+ },
+ {
+ code: "function bar() { return function BigInt() {}; } var baz = new BigInt(9007199254740991);",
+ errors: [{
+ message: "`BigInt` cannot be called as a constructor."
+ }]
+ }
+ ]
+});
code: "new Atomics.foo()",
env: { es2017: true }
},
+ {
+ code: "new Intl.Segmenter()",
+ env: { browser: true }
+ },
+ {
+ code: "Intl.foo()",
+ env: { browser: true }
+ },
{ code: "globalThis.Math();", env: { es6: true } },
{ code: "var x = globalThis.Math();", env: { es6: true } },
{ code: "/*globals Reflect: true*/ globalThis.Reflect();", env: { es2017: true } },
{ code: "var x = globalThis.Atomics();", env: { es2017: true } },
{ code: "var x = globalThis.Atomics();", globals: { Atomics: false }, env: { es2017: true } },
+ { code: "var x = globalThis.Intl();", env: { browser: true } },
+ { code: "var x = globalThis.Intl();", globals: { Intl: false }, env: { browser: true } },
// non-existing variables
"/*globals Math: off*/ Math();",
code: "Atomics();",
env: { es6: true }
},
+ "Intl()",
+ "new Intl()",
// shadowed variables
"var Math; Math();",
{
code: "var construct = typeof Reflect !== \"undefined\" ? Reflect.construct : undefined; construct();",
globals: { Reflect: false }
+ },
+ {
+ code: "function foo(Intl) { Intl(); }",
+ env: { browser: true }
+ },
+ {
+ code: "if (foo) { const Intl = 1; Intl(); }",
+ parserOptions: { ecmaVersion: 2015 },
+ env: { browser: true }
+ },
+ {
+ code: "if (foo) { const Intl = 1; new Intl(); }",
+ parserOptions: { ecmaVersion: 2015 },
+ env: { browser: true }
}
],
invalid: [
globals: { Atomics: "writable" },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "NewExpression" }]
},
+ {
+ code: "var x = Intl();",
+ env: { browser: true },
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
+ },
+ {
+ code: "var x = new Intl();",
+ env: { browser: true },
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "NewExpression" }]
+ },
+ {
+ code: "/*globals Intl: true*/ Intl();",
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
+ },
+ {
+ code: "/*globals Intl: true*/ new Intl();",
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "NewExpression" }]
+ },
{
code: "var x = globalThis.Math();",
env: { es2020: true },
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
},
+ {
+ code: "var x = globalThis.Intl();",
+ env: { browser: true, es2020: true },
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
+ },
+ {
+ code: "var x = new globalThis.Intl;",
+ env: { browser: true, es2020: true },
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "NewExpression" }]
+ },
+ {
+ code: "/*globals Intl: true*/ Intl();",
+ env: { browser: true, es2020: true },
+ errors: [{ messageId: "unexpectedCall", data: { name: "Intl" }, type: "CallExpression" }]
+ },
{
code: "var foo = bar ? baz: JSON; foo();",
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "JSON" }, type: "CallExpression" }]
env: { es2020: true, browser: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Atomics" }, type: "NewExpression" }]
},
+ {
+ code: "var foo = window.Intl; foo();",
+ env: { es2020: true, browser: true },
+ errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Intl" }, type: "CallExpression" }]
+ },
+ {
+ code: "var foo = window.Intl; new foo;",
+ env: { es2020: true, browser: true },
+ errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Intl" }, type: "NewExpression" }]
+ },
// Optional chaining
{
{ code: "export default 1;", options: [{ restrictedNamedExports: ["default"] }] },
// "default" does not disallow re-exporting a renamed default export from another module
- { code: "export { default as a } from 'foo';", options: [{ restrictedNamedExports: ["default"] }] }
+ { code: "export { default as a } from 'foo';", options: [{ restrictedNamedExports: ["default"] }] },
+
+ // restrictDefaultExports.direct option
+ { code: "export default foo;", options: [{ restrictDefaultExports: { direct: false } }] },
+ { code: "export default 42;", options: [{ restrictDefaultExports: { direct: false } }] },
+ { code: "export default function foo() {}", options: [{ restrictDefaultExports: { direct: false } }] },
+
+ // restrictDefaultExports.named option
+ { code: "const foo = 123;\nexport { foo as default };", options: [{ restrictDefaultExports: { named: false } }] },
+
+ // restrictDefaultExports.defaultFrom option
+ { code: "export { default } from 'mod';", options: [{ restrictDefaultExports: { defaultFrom: false } }] },
+ { code: "export { default as default } from 'mod';", options: [{ restrictDefaultExports: { defaultFrom: false } }] },
+ { code: "export { foo as default } from 'mod';", options: [{ restrictDefaultExports: { defaultFrom: true } }] },
+ { code: "export { default } from 'mod';", options: [{ restrictDefaultExports: { named: true, defaultFrom: false } }] },
+ { code: "export { 'default' } from 'mod'; ", options: [{ restrictDefaultExports: { defaultFrom: false } }] },
+
+ // restrictDefaultExports.namedFrom option
+ { code: "export { foo as default } from 'mod';", options: [{ restrictDefaultExports: { namedFrom: false } }] },
+ { code: "export { default as default } from 'mod';", options: [{ restrictDefaultExports: { namedFrom: true } }] },
+ { code: "export { default as default } from 'mod';", options: [{ restrictDefaultExports: { namedFrom: false } }] },
+ { code: "export { 'default' } from 'mod'; ", options: [{ restrictDefaultExports: { defaultFrom: false, namedFrom: true } }] },
+
+ // restrictDefaultExports.namespaceFrom option
+ { code: "export * as default from 'mod';", options: [{ restrictDefaultExports: { namespaceFrom: false } }] }
],
invalid: [
code: "export { default } from 'foo';",
options: [{ restrictedNamedExports: ["default"] }],
errors: [{ messageId: "restrictedNamed", data: { name: "default" }, type: "Identifier", column: 10 }]
+ },
+
+ // restrictDefaultExports.direct option
+ {
+ code: "export default foo;",
+ options: [{ restrictDefaultExports: { direct: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }]
+ },
+ {
+ code: "export default 42;",
+ options: [{ restrictDefaultExports: { direct: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }]
+ },
+ {
+ code: "export default function foo() {}",
+ options: [{ restrictDefaultExports: { direct: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }]
+ },
+ {
+ code: "export default foo;",
+ options: [{ restrictedNamedExports: ["bar"], restrictDefaultExports: { direct: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "ExportDefaultDeclaration", column: 1 }]
+ },
+
+ // restrictDefaultExports.named option
+ {
+ code: "const foo = 123;\nexport { foo as default };",
+ options: [{ restrictDefaultExports: { named: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "Identifier", line: 2, column: 17 }]
+ },
+
+ // restrictDefaultExports.defaultFrom option
+ {
+ code: "export { default } from 'mod';",
+ options: [{ restrictDefaultExports: { defaultFrom: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "Identifier", line: 1, column: 10 }]
+ },
+ {
+ code: "export { default as default } from 'mod';",
+ options: [{ restrictDefaultExports: { defaultFrom: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "Identifier", line: 1, column: 21 }]
+ },
+ {
+ code: "export { 'default' } from 'mod';",
+ options: [{ restrictDefaultExports: { defaultFrom: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "Literal", line: 1, column: 10 }]
+ },
+
+ // restrictDefaultExports.namedFrom option
+ {
+ code: "export { foo as default } from 'mod';",
+ options: [{ restrictDefaultExports: { namedFrom: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "Identifier", line: 1, column: 17 }]
+ },
+
+ // restrictDefaultExports.namespaceFrom option
+ {
+ code: "export * as default from 'mod';",
+ options: [{ restrictDefaultExports: { namespaceFrom: true } }],
+ errors: [{ messageId: "restrictedDefault", type: "Identifier", line: 1, column: 13 }]
}
]
});
// Tests
//------------------------------------------------------------------------------
-// pending https://github.com/eslint/espree/issues/304, the type should be "Keyword"
-const errors = [{ messageId: "redundantUseOfAwait", type: "Identifier" }];
+/**
+ * Creates the list of errors that should be found by this rule
+ * @param {Object} options Options for creating errors
+ * @param {string} options.suggestionOutput The suggested output
+ * @returns {Array} the list of errors
+ */
+function createErrorList({ suggestionOutput: output } = {}) {
+
+ // pending https://github.com/eslint/espree/issues/304, the type should be "Keyword"
+ return [{
+ messageId: "redundantUseOfAwait",
+ type: "Identifier",
+ suggestions: output ? [{
+ messageId: "removeAwait", output
+ }] : []
+ }];
+}
+
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2017 } });
invalid: [
{
code: "\nasync function foo() {\n\treturn await bar();\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn bar();\n}\n" })
+ },
+ {
+ code: "\nasync function foo() {\n\treturn await(bar());\n}\n",
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a, await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a, b, await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, b, bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a && await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a && bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a && b && await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a && b && bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a || await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a || bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a, b, (c, d, await bar()));\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, b, (c, d, bar()));\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (a, b, (c && await bar()));\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (a, b, (c && bar()));\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (await baz(), b, await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (await baz(), b, bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (baz() ? await bar() : b);\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? bar() : b);\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (baz() ? a : await bar());\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? a : bar());\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (baz() ? (a, await bar()) : b);\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? (a, bar()) : b);\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (baz() ? a : (b, await bar()));\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? a : (b, bar()));\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (baz() ? (a && await bar()) : b);\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? (a && bar()) : b);\n}\n" })
},
{
code: "\nasync function foo() {\n\treturn (baz() ? a : (b && await bar()));\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\n\treturn (baz() ? a : (b && bar()));\n}\n" })
},
{
code: "\nasync () => { return await bar(); }\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => { return bar(); }\n" })
},
{
code: "\nasync () => await bar()\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => bar()\n" })
},
{
code: "\nasync () => (a, b, await bar())\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => (a, b, bar())\n" })
},
{
code: "\nasync () => (a && await bar())\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => (a && bar())\n" })
},
{
code: "\nasync () => (baz() ? await bar() : b)\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => (baz() ? bar() : b)\n" })
},
{
code: "\nasync () => (baz() ? a : (b, await bar()))\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => (baz() ? a : (b, bar()))\n" })
},
{
code: "\nasync () => (baz() ? a : (b && await bar()))\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => (baz() ? a : (b && bar()))\n" })
},
{
code: "\nasync function foo() {\nif (a) {\n\t\tif (b) {\n\t\t\treturn await bar();\n\t\t}\n\t}\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync function foo() {\nif (a) {\n\t\tif (b) {\n\t\t\treturn bar();\n\t\t}\n\t}\n}\n" })
},
{
code: "\nasync () => {\nif (a) {\n\t\tif (b) {\n\t\t\treturn await bar();\n\t\t}\n\t}\n}\n",
- errors
+ errors: createErrorList({ suggestionOutput: "\nasync () => {\nif (a) {\n\t\tif (b) {\n\t\t\treturn bar();\n\t\t}\n\t}\n}\n" })
},
{
code: `
}
}
`,
- errors
+ errors: createErrorList({
+ suggestionOutput: `
+ async function foo() {
+ try {}
+ finally {
+ return bar();
+ }
+ }
+ `
+ })
},
{
code: `
}
}
`,
- errors
+ errors: createErrorList({
+ suggestionOutput: `
+ async function foo() {
+ try {}
+ catch (e) {
+ return bar();
+ }
+ }
+ `
+ })
},
{
code: `
}
} catch (e) {}
`,
- errors
+ errors: createErrorList({
+ suggestionOutput: `
+ try {
+ async function foo() {
+ return bar();
+ }
+ } catch (e) {}
+ `
+ })
},
{
code: `
async () => await bar();
} catch (e) {}
`,
- errors
+ errors: createErrorList({
+ suggestionOutput: `
+ try {
+ async () => bar();
+ } catch (e) {}
+ `
+ })
},
{
code: `
}
}
`,
- errors
+ errors: createErrorList({
+ suggestionOutput: `
+ async function foo() {
+ try {}
+ catch (e) {
+ try {}
+ catch (e) {
+ return bar();
+ }
+ }
+ }
+ `
+ })
+ },
+ {
+ code: `
+ async function foo() {
+ return await new Promise(resolve => {
+ resolve(5);
+ });
+ }
+ `,
+ errors: createErrorList({
+ suggestionOutput: `
+ async function foo() {
+ return new Promise(resolve => {
+ resolve(5);
+ });
+ }
+ `
+ })
+ },
+ {
+ code: `
+ async () => {
+ return await (
+ foo()
+ )
+ };
+ `,
+ errors: createErrorList({
+ suggestionOutput: `
+ async () => {
+ return (
+ foo()
+ )
+ };
+ `
+ })
+ },
+ {
+ code: `
+ async function foo() {
+ return await // Test
+ 5;
+ }
+ `,
+ errors: createErrorList()
}
]
});
{ code: "function foo( { _bar }) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 } },
{ code: "function foo( { _bar = 0 } = {}) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 } },
{ code: "function foo(...[_bar]) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 2016 } },
+ { code: "const [_foo] = arr", parserOptions: { ecmaVersion: 6 } },
+ { code: "const [_foo] = arr", options: [{}], parserOptions: { ecmaVersion: 6 } },
+ { code: "const [_foo] = arr", options: [{ allowInArrayDestructuring: true }], parserOptions: { ecmaVersion: 6 } },
+ { code: "const [foo, ...rest] = [1, 2, 3]", options: [{ allowInArrayDestructuring: false }], parserOptions: { ecmaVersion: 2022 } },
+ { code: "const [foo, _bar] = [1, 2, 3]", options: [{ allowInArrayDestructuring: false, allow: ["_bar"] }], parserOptions: { ecmaVersion: 2022 } },
+ { code: "const { _foo } = obj", parserOptions: { ecmaVersion: 6 } },
+ { code: "const { _foo } = obj", options: [{}], parserOptions: { ecmaVersion: 6 } },
+ { code: "const { _foo } = obj", options: [{ allowInObjectDestructuring: true }], parserOptions: { ecmaVersion: 6 } },
+ { code: "const { foo, bar: _bar } = { foo: 1, bar: 2 }", options: [{ allowInObjectDestructuring: false, allow: ["_bar"] }], parserOptions: { ecmaVersion: 2022 } },
+ { code: "const { foo, _bar } = { foo: 1, _bar: 2 }", options: [{ allowInObjectDestructuring: false, allow: ["_bar"] }], parserOptions: { ecmaVersion: 2022 } },
+ { code: "const { foo, _bar: bar } = { foo: 1, _bar: 2 }", options: [{ allowInObjectDestructuring: false }], parserOptions: { ecmaVersion: 2022 } },
{ code: "class foo { _field; }", parserOptions: { ecmaVersion: 2022 } },
{ code: "class foo { _field; }", options: [{ enforceInClassFields: false }], parserOptions: { ecmaVersion: 2022 } },
{ code: "class foo { #_field; }", parserOptions: { ecmaVersion: 2022 } },
{ code: "const foo = { onClick(..._bar) { } }", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_bar" }, type: "RestElement" }] },
{ code: "const foo = (..._bar) => {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_bar" }, type: "RestElement" }] },
{
+ code: "const [foo, _bar] = [1, 2]",
+ options: [{ allowInArrayDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_bar" } }]
+ }, {
+ code: "const [_foo = 1] = arr",
+ options: [{ allowInArrayDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
+ }, {
+ code: "const [foo, ..._rest] = [1, 2, 3]",
+ options: [{ allowInArrayDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_rest" } }]
+ }, {
+ code: "const [foo, [bar_, baz]] = [1, [2, 3]]",
+ options: [{ allowInArrayDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "bar_" } }]
+ }, {
+ code: "const { _foo, bar } = { _foo: 1, bar: 2 }",
+ options: [{ allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
+ }, {
+ code: "const { _foo = 1 } = obj",
+ options: [{ allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
+ }, {
+ code: "const { bar: _foo = 1 } = obj",
+ options: [{ allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
+ }, {
+ code: "const { foo: _foo, bar } = { foo: 1, bar: 2 }",
+ options: [{ allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" } }]
+ }, {
+ code: "const { foo, ..._rest} = { foo: 1, bar: 2, baz: 3 }",
+ options: [{ allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_rest" } }]
+ }, {
+ code: "const { foo: [_bar, { a: _a, b } ] } = { foo: [1, { a: 'a', b: 'b' }] }",
+ options: [{ allowInArrayDestructuring: false, allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "unexpectedUnderscore", data: { identifier: "_bar" } },
+ { messageId: "unexpectedUnderscore", data: { identifier: "_a" } }
+ ]
+ }, {
+ code: "const { foo: [_bar, { a: _a, b } ] } = { foo: [1, { a: 'a', b: 'b' }] }",
+ options: [{ allowInArrayDestructuring: true, allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_a" } }]
+ }, {
+ code: "const [{ foo: [_bar, _, { bar: _baz }] }] = [{ foo: [1, 2, { bar: 'a' }] }]",
+ options: [{ allowInArrayDestructuring: false, allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [
+ { messageId: "unexpectedUnderscore", data: { identifier: "_bar" } },
+ { messageId: "unexpectedUnderscore", data: { identifier: "_baz" } }
+ ]
+ }, {
+ code: "const { foo, bar: { baz, _qux } } = { foo: 1, bar: { baz: 3, _qux: 4 } }",
+ options: [{ allowInObjectDestructuring: false }],
+ parserOptions: { ecmaVersion: 2022 },
+ errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_qux" } }]
+ }, {
code: "class foo { #_bar() {} }",
options: [{ enforceInMethodNames: true }],
parserOptions: { ecmaVersion: 2022 },
const ruleTester = new RuleTester();
-ruleTester.defineRule("use-every-a", context => {
-
- /**
- * Mark a variable as used
- * @returns {void}
- * @private
- */
- function useA() {
- context.markVariableAsUsed("a");
+ruleTester.defineRule("use-every-a", {
+ create(context) {
+
+ const sourceCode = context.sourceCode;
+
+ /**
+ * Mark a variable as used
+ * @param {ASTNode} node The node representing the scope to search
+ * @returns {void}
+ * @private
+ */
+ function useA(node) {
+ sourceCode.markVariableAsUsed("a", node);
+ }
+ return {
+ VariableDeclaration: useA,
+ ReturnStatement: useA
+ };
}
- return {
- VariableDeclaration: useA,
- ReturnStatement: useA
- };
});
/**
code: "function foo() { var { let } = {}; }",
output: null,
errors: [{ messageId: "unexpectedVar" }]
+ },
+
+ // https://github.com/eslint/eslint/issues/16610
+ {
+ code: "var fx = function (i = 0) { if (i < 5) { return fx(i + 1); } console.log(i); }; fx();",
+ output: "let fx = function (i = 0) { if (i < 5) { return fx(i + 1); } console.log(i); }; fx();",
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var foo = function () { foo() };",
+ output: "let foo = function () { foo() };",
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var foo = () => foo();",
+ output: "let foo = () => foo();",
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var foo = (function () { foo(); })();",
+ output: null,
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var foo = bar(function () { foo(); });",
+ output: null,
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var bar = foo, foo = function () { foo(); };",
+ output: null,
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var bar = foo; var foo = function () { foo(); };",
+ output: "let bar = foo; var foo = function () { foo(); };",
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [
+ { messageId: "unexpectedVar" },
+ { messageId: "unexpectedVar" }
+ ]
+ },
+ {
+ code: "var { foo = foo } = function () { foo(); };",
+ output: null,
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var { bar = foo, foo } = function () { foo(); };",
+ output: null,
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [{ messageId: "unexpectedVar" }]
+ },
+ {
+ code: "var bar = function () { foo(); }; var foo = function() {};",
+ output: "let bar = function () { foo(); }; var foo = function() {};",
+ parserOptions: { ecmaVersion: 6, sourceType: "module" },
+ errors: [
+ { messageId: "unexpectedVar" },
+ { messageId: "unexpectedVar" }
+ ]
}
]
});
code: "foo((function() { return this; }?.bind)(this));",
output: null,
errors
+ },
+
+ // https://github.com/eslint/eslint/issues/16718
+ {
+ code: `
+ test(
+ function ()
+ { }
+ );
+ `,
+ output: `
+ test(
+ () =>
+ { }
+ );
+ `,
+ errors
+ },
+ {
+ code: `
+ test(
+ function (
+ ...args
+ ) /* Lorem ipsum
+ dolor sit amet. */ {
+ return args;
+ }
+ );
+ `,
+ output: `
+ test(
+ (
+ ...args
+ ) => /* Lorem ipsum
+ dolor sit amet. */ {
+ return args;
+ }
+ );
+ `,
+ errors
}
]
});
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });
-ruleTester.defineRule("use-x", context => ({
- VariableDeclaration() {
- context.markVariableAsUsed("x");
+ruleTester.defineRule("use-x", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ return {
+ VariableDeclaration(node) {
+ sourceCode.markVariableAsUsed("x", node);
+ }
+ };
}
-}));
+});
ruleTester.run("prefer-const", rule, {
valid: [
data: { group: "([0-9]{4})" },
line: 1,
column: 1,
- endColumn: 13
+ endColumn: 13,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp1>[0-9]{4})/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?:[0-9]{4})/"
+ }
+ ]
}]
},
{
data: { group: "([0-9]{4})" },
line: 1,
column: 1,
- endColumn: 25
+ endColumn: 25,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "new RegExp('(?<temp1>[0-9]{4})')"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "new RegExp('(?:[0-9]{4})')"
+ }
+ ]
}]
},
{
data: { group: "([0-9]{4})" },
line: 1,
column: 1,
- endColumn: 21
+ endColumn: 21,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "RegExp('(?<temp1>[0-9]{4})')"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "RegExp('(?:[0-9]{4})')"
+ }
+ ]
}]
},
{
errors: [{
messageId: "required",
type: "NewExpression",
- data: { group: "(bc)" }
+ data: { group: "(bc)" },
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "new RegExp(`a(?<temp1>bc)d`)"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "new RegExp(`a(?:bc)d`)"
+ }
+ ]
+ }]
+ },
+ {
+ code: "new RegExp('\u1234\u5678(?:a)(b)');",
+ errors: [{
+ messageId: "required",
+ type: "NewExpression",
+ data: { group: "(b)" },
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "new RegExp('\u1234\u5678(?:a)(?<temp1>b)');"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "new RegExp('\u1234\u5678(?:a)(?:b)');"
+ }
+ ]
+ }]
+ },
+ {
+ code: "new RegExp('\\u1234\\u5678(?:a)(b)');",
+ errors: [{
+ messageId: "required",
+ type: "NewExpression",
+ data: { group: "(b)" },
+ suggestions: null
}]
},
{
data: { group: "([0-9]{4})" },
line: 1,
column: 1,
- endColumn: 21
+ endColumn: 21,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp1>[0-9]{4})-(\\w{5})/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?:[0-9]{4})-(\\w{5})/"
+ }
+ ]
},
{
messageId: "required",
data: { group: "(\\w{5})" },
line: 1,
column: 1,
- endColumn: 21
+ endColumn: 21,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/([0-9]{4})-(?<temp1>\\w{5})/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/([0-9]{4})-(?:\\w{5})/"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "/([0-9]{4})-(5)/",
+ errors: [
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "([0-9]{4})" },
+ line: 1,
+ column: 1,
+ endColumn: 17,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp1>[0-9]{4})-(5)/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?:[0-9]{4})-(5)/"
+ }
+ ]
+ },
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "(5)" },
+ line: 1,
+ column: 1,
+ endColumn: 17,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/([0-9]{4})-(?<temp1>5)/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/([0-9]{4})-(?:5)/"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "/(?<temp2>(a))/",
+ errors: [
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "(a)" },
+ line: 1,
+ column: 1,
+ endColumn: 16,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp2>(?<temp3>a))/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?<temp2>(?:a))/"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "/(?<temp2>(a)(?<temp5>b))/",
+ errors: [
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "(a)" },
+ line: 1,
+ column: 1,
+ endColumn: 27,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp2>(?<temp6>a)(?<temp5>b))/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?<temp2>(?:a)(?<temp5>b))/"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "/(?<temp1>[0-9]{4})-(\\w{5})/",
+ errors: [
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "(\\w{5})" },
+ line: 1,
+ column: 1,
+ endColumn: 29,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp1>[0-9]{4})-(?<temp2>\\w{5})/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?<temp1>[0-9]{4})-(?:\\w{5})/"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "/(?<temp1>[0-9]{4})-(5)/",
+ errors: [
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "(5)" },
+ line: 1,
+ column: 1,
+ endColumn: 25,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp1>[0-9]{4})-(?<temp2>5)/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?<temp1>[0-9]{4})-(?:5)/"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "/(?<temp1>a)(?<temp2>a)(a)(?<temp3>a)/",
+ errors: [
+ {
+ messageId: "required",
+ type: "Literal",
+ data: { group: "(a)" },
+ line: 1,
+ column: 1,
+ endColumn: 39,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "/(?<temp1>a)(?<temp2>a)(?<temp4>a)(?<temp3>a)/"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "/(?<temp1>a)(?<temp2>a)(?:a)(?<temp3>a)/"
+ }
+ ]
}
]
},
errors: [{
messageId: "required",
type: "NewExpression",
- data: { group: "(a)" }
+ data: { group: "(a)" },
+ suggestions: null
}]
},
{
errors: [{
messageId: "required",
type: "NewExpression",
- data: { group: "(bc)" }
+ data: { group: "(bc)" },
+ suggestions: null
+ }]
+ },
+ {
+ code: "new RegExp(\"foo\" + \"(a)\" + \"(b)\");",
+ errors: [
+ {
+ messageId: "required",
+ type: "NewExpression",
+ data: { group: "(a)" },
+ suggestions: null
+ },
+ {
+ messageId: "required",
+ type: "NewExpression",
+ data: { group: "(b)" },
+ suggestions: null
+ }
+ ]
+ },
+ {
+ code: "new RegExp(\"foo\" + \"(?:a)\" + \"(b)\");",
+ errors: [{
+ messageId: "required",
+ type: "NewExpression",
+ data: { group: "(b)" },
+ suggestions: null
}]
},
{
errors: [{
messageId: "required",
type: "CallExpression",
- data: { group: "(a)" }
+ data: { group: "(a)" },
+ suggestions: null
}]
},
{
errors: [{
messageId: "required",
type: "CallExpression",
- data: { group: "(ab)" }
+ data: { group: "(ab)" },
+ suggestions: null
}]
},
{
errors: [{
messageId: "required",
type: "NewExpression",
- data: { group: "(ab)" }
+ data: { group: "(ab)" },
+ suggestions: null
}]
},
{
line: 1,
column: 1,
endLine: 2,
- endColumn: 3
+ endColumn: 3,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "new RegExp(`(?<temp1>a)\n`)"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "new RegExp(`(?:a)\n`)"
+ }
+ ]
}]
},
{
errors: [{
messageId: "required",
type: "CallExpression",
- data: { group: "(b\nc)" }
+ data: { group: "(b\nc)" },
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "RegExp(`a(?<temp1>b\nc)d`)"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "RegExp(`a(?:b\nc)d`)"
+ }
+ ]
}]
},
{
errors: [{
messageId: "required",
type: "NewExpression",
- data: { group: "(b)" }
+ data: { group: "(b)" },
+ suggestions: null
}]
},
{
errors: [{
messageId: "required",
type: "CallExpression",
- data: { group: "(a)" }
+ data: { group: "(a)" },
+ suggestions: null
}]
},
{
errors: [{
messageId: "required",
type: "CallExpression",
- data: { group: "(b)" }
+ data: { group: "(b)" },
+ suggestions: null
}]
},
{
data: { group: "([0-9]{4})" },
line: 1,
column: 1,
- endColumn: 36
+ endColumn: 36,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "new globalThis.RegExp('(?<temp1>[0-9]{4})')"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "new globalThis.RegExp('(?:[0-9]{4})')"
+ }
+ ]
}]
},
{
data: { group: "([0-9]{4})" },
line: 1,
column: 1,
- endColumn: 32
+ endColumn: 32,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: "globalThis.RegExp('(?<temp1>[0-9]{4})')"
+ },
+ {
+ messageId: "addNonCapture",
+ output: "globalThis.RegExp('(?:[0-9]{4})')"
+ }
+ ]
}]
},
{
data: { group: "([0-9]{4})" },
line: 3,
column: 17,
- endColumn: 52
+ endColumn: 52,
+ suggestions: [
+ {
+ messageId: "addGroupName",
+ output: `
+ function foo() { var globalThis = bar; }
+ new globalThis.RegExp('(?<temp1>[0-9]{4})');
+ `
+ },
+ {
+ messageId: "addNonCapture",
+ output: `
+ function foo() { var globalThis = bar; }
+ new globalThis.RegExp('(?:[0-9]{4})');
+ `
+ }
+ ]
}]
}
]
/**
* @fileoverview Prefers object spread property over Object.assign
* @author Sharmila Jesupaul
- * See LICENSE file in root directory for full license.
*/
"use strict";
//------------------------------------------------------------------------------
const rule = require("../../../lib/rules/prefer-regex-literals");
-const { RuleTester } = require("../../../lib/rule-tester");
+const { RuleTester } = require("../../../lib/rule-tester"),
+ FlatRuleTester = require("../../../lib/rule-tester/flat-rule-tester");
//------------------------------------------------------------------------------
// Tests
messageId: "unexpectedRedundantRegExp",
type: "NewExpression",
line: 1,
- column: 1
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteral",
+ output: "/a/;"
+ }
+ ]
}
]
},
messageId: "unexpectedRedundantRegExpWithFlags",
type: "NewExpression",
line: 1,
- column: 1
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/u;",
+ data: {
+ flags: "u"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/g, '');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/;",
+ data: {
+ flags: ""
+ }
+ },
+ {
+ messageId: "replaceWithIntendedLiteralAndFlags",
+ output: "/a/g;",
+ data: {
+ flags: "g"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/g, 'g');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/g;",
+ data: {
+ flags: "g"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/ig, 'g');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/g;",
+ data: {
+ flags: "g"
+ }
+ },
+ {
+ messageId: "replaceWithIntendedLiteralAndFlags",
+ output: "/a/ig;",
+ data: {
+ flags: "ig"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/g, 'ig');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/ig;",
+ data: {
+ flags: "ig"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/i, 'g');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/g;",
+ data: {
+ flags: "g"
+ }
+ },
+ {
+ messageId: "replaceWithIntendedLiteralAndFlags",
+ output: "/a/ig;",
+ data: {
+ flags: "ig"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/i, 'i');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/i;",
+ data: {
+ flags: "i"
+ }
+ }
+ ]
}
]
},
messageId: "unexpectedRedundantRegExpWithFlags",
type: "NewExpression",
line: 1,
- column: 1
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/u;",
+ data: {
+ flags: "u"
+ }
+ }
+ ]
}
]
},
{
- code: "new RegExp(/a/, String.raw`u`);",
+ code: "new RegExp(/a/, `gi`);",
options: [
{
disallowRedundantWrapping: true
messageId: "unexpectedRedundantRegExpWithFlags",
type: "NewExpression",
line: 1,
- column: 1
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/gi;",
+ data: {
+ flags: "gi"
+ }
+ }
+ ]
}
]
},
}
]
},
+ {
+ code: "new RegExp(/a/, String.raw`u`);",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteralAndFlags",
+ output: "/a/u;",
+ data: {
+ flags: "u"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/ /* comment */);",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExp",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: null
+ }
+ ]
+ },
+ {
+ code: "new RegExp(/a/, 'd');",
+ options: [
+ {
+ disallowRedundantWrapping: true
+ }
+ ],
+ parserOptions: {
+ ecmaVersion: 2021
+ },
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 1,
+ column: 1,
+ suggestions: null
+ }
+ ]
+ },
+ {
+ code: "(a)\nnew RegExp(/b/);",
+ options: [{
+ disallowRedundantWrapping: true
+ }],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExp",
+ type: "NewExpression",
+ line: 2,
+ column: 1,
+ suggestions: null
+ }
+ ]
+ },
+ {
+ code: "(a)\nnew RegExp(/b/, 'g');",
+ options: [{
+ disallowRedundantWrapping: true
+ }],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExpWithFlags",
+ type: "NewExpression",
+ line: 2,
+ column: 1,
+ suggestions: null
+ }
+ ]
+ },
+ {
+ code: "a/RegExp(/foo/);",
+ options: [{
+ disallowRedundantWrapping: true
+ }],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExp",
+ type: "CallExpression",
+ line: 1,
+ column: 3,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteral",
+ output: "a/ /foo/;"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ code: "RegExp(/foo/)in a;",
+ options: [{
+ disallowRedundantWrapping: true
+ }],
+ errors: [
+ {
+ messageId: "unexpectedRedundantRegExp",
+ type: "CallExpression",
+ line: 1,
+ column: 1,
+ suggestions: [
+ {
+ messageId: "replaceWithLiteral",
+ output: "/foo/ in a;"
+ }
+ ]
+ }
+ ]
+ },
{
code: "new RegExp((String?.raw)`a`);",
errors: [
}
]
});
+
+const flatRuleTester = new FlatRuleTester();
+
+flatRuleTester.run("prefer-regex-literals", rule, {
+ valid: [],
+
+ invalid: [
+ {
+ code: "var regex = new RegExp('foo', 'u');",
+ languageOptions: {
+ ecmaVersion: 2015
+ },
+ errors: [{
+ messageId: "unexpectedRegExp",
+ suggestions: [
+ {
+ messageId: "replaceWithLiteral",
+ output: "var regex = /foo/u;"
+ }
+ ]
+ }]
+ }
+ ]
+});
"/foo/u",
"/foo/gimuy",
"RegExp('', 'u')",
+ "RegExp('', `u`)",
"new RegExp('', 'u')",
"RegExp('', 'gimuy')",
+ "RegExp('', `gimuy`)",
+ "RegExp(...patternAndFlags)",
"new RegExp('', 'gimuy')",
"const flags = 'u'; new RegExp('', flags)",
"const flags = 'g'; new RegExp('', flags + 'u')",
"new RegExp('', flags)",
"function f(flags) { return new RegExp('', flags) }",
"function f(RegExp) { return new RegExp('foo') }",
+ "function f(patternAndFlags) { return new RegExp(...patternAndFlags) }",
{ code: "new globalThis.RegExp('foo')", env: { es6: true } },
{ code: "new globalThis.RegExp('foo')", env: { es2017: true } },
{ code: "new globalThis.RegExp('foo', 'u')", env: { es2020: true } },
{ code: "class C { #RegExp; foo() { new globalThis.#RegExp('foo') } }", parserOptions: { ecmaVersion: 2022 }, env: { es2020: true } }
],
invalid: [
+ {
+ code: "/\\a/",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
+ },
{
code: "/foo/",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "/foo/u"
+ }
+ ]
+ }]
},
{
code: "/foo/gimy",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "/foo/gimyu"
+ }
+ ]
+ }]
+ },
+ {
+ code: "RegExp()",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
},
{
code: "RegExp('foo')",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "RegExp('foo', \"u\")"
+ }
+ ]
+ }]
+ },
+ {
+ code: "RegExp('\\\\a')",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
},
{
code: "RegExp('foo', '')",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "RegExp('foo', 'u')"
+ }
+ ]
+ }]
},
{
code: "RegExp('foo', 'gimy')",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "RegExp('foo', 'gimyu')"
+ }
+ ]
+ }]
+ },
+ {
+ code: "RegExp('foo', `gimy`)",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "RegExp('foo', `gimyu`)"
+ }
+ ]
+ }]
},
{
code: "new RegExp('foo')",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new RegExp('foo', \"u\")"
+ }
+ ]
+ }]
+ },
+ {
+ code: "new RegExp('foo', false)",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
+ },
+ {
+ code: "new RegExp('foo', 1)",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
},
{
code: "new RegExp('foo', '')",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new RegExp('foo', 'u')"
+ }
+ ]
+ }]
},
{
code: "new RegExp('foo', 'gimy')",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new RegExp('foo', 'gimyu')"
+ }
+ ]
+ }]
+ },
+ {
+ code: "new RegExp(('foo'))",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new RegExp(('foo'), \"u\")"
+ }
+ ]
+ }]
+ },
+ {
+ code: "new RegExp(('unrelated', 'foo'))",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new RegExp(('unrelated', 'foo'), \"u\")"
+ }
+ ]
+ }]
},
{
code: "const flags = 'gi'; new RegExp('foo', flags)",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
+ },
+ {
+ code: "const flags = 'gi'; new RegExp('foo', ('unrelated', flags))",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
+ },
+ {
+ code: "let flags; new RegExp('foo', flags = 'g')",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
+ },
+ {
+ code: "const flags = `gi`; new RegExp(`foo`, (`unrelated`, flags))",
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
},
{
code: "const flags = 'gimu'; new RegExp('foo', flags[0])",
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: null
+ }]
},
{
code: "new window.RegExp('foo')",
env: { browser: true },
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new window.RegExp('foo', \"u\")"
+ }
+ ]
+ }]
},
{
code: "new global.RegExp('foo')",
env: { node: true },
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new global.RegExp('foo', \"u\")"
+ }
+ ]
+ }]
},
{
code: "new globalThis.RegExp('foo')",
env: { es2020: true },
- errors: [{ messageId: "requireUFlag" }]
+ errors: [{
+ messageId: "requireUFlag",
+ suggestions: [
+ {
+ messageId: "addUFlag",
+ output: "new globalThis.RegExp('foo', \"u\")"
+ }
+ ]
+ }]
}
]
});
{ code: "class C {\n static {\n bar(); baz(); } \n}", options: ["always", { omitLastInOneLineBlock: true }], parserOptions: { ecmaVersion: 2022 } },
{ code: "class C {\n static { bar(); baz(); \n} \n}", options: ["always", { omitLastInOneLineBlock: true }], parserOptions: { ecmaVersion: 2022 } },
+ // omitLastInOneLineClassBody: true
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1}
+ export class Variant2 extends SomeClass{type=2}
+ export class Variant3 extends SomeClass{type=3}
+ export class Variant4 extends SomeClass{type=4}
+ export class Variant5 extends SomeClass{type=5}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" }
+ },
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ console.log(this.anotherType);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1; anotherType=2}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" }
+ },
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1;}
+ export class Variant2 extends SomeClass{type=2;}
+ export class Variant3 extends SomeClass{type=3;}
+ export class Variant4 extends SomeClass{type=4;}
+ export class Variant5 extends SomeClass{type=5;}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: false }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" }
+ },
+ {
+ code: "class C {\nfoo;}",
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C {foo;\n}",
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C {foo;\nbar;}",
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "{ foo; }",
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+ {
+ code: "class C\n{ foo }",
+ options: ["always", { omitLastInOneLineClassBody: true }],
+ parserOptions: { ecmaVersion: 2022 }
+ },
+
// method definitions and static blocks don't have a semicolon.
{ code: "class A { a() {} b() {} }", parserOptions: { ecmaVersion: 6 } },
{ code: "var A = class { a() {} b() {} };", parserOptions: { ecmaVersion: 6 } },
endLine: 1,
endColumn: 18
}]
+ },
+
+ // omitLastInOneLineClassBody
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1}
+ `,
+ output: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1;}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: false }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" },
+ errors: [
+ {
+ messageId: "missingSemi",
+ line: 8,
+ column: 63,
+ endLine: 8,
+ endColumn: 64
+ }
+ ]
+ },
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1}
+ `,
+ output: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1;}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: false, omitLastInOneLineBlock: true }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" },
+ errors: [
+ {
+ messageId: "missingSemi",
+ line: 8,
+ column: 63,
+ endLine: 8,
+ endColumn: 64
+ }
+ ]
+ },
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1;}
+ `,
+ output: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: true, omitLastInOneLineBlock: false }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" },
+ errors: [
+ {
+ messageId: "extraSemi",
+ line: 8,
+ column: 63,
+ endLine: 8,
+ endColumn: 64
+ }
+ ]
+ },
+ {
+ code: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ console.log(this.anotherType);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1; anotherType=2}
+ `,
+ output: `
+ export class SomeClass{
+ logType(){
+ console.log(this.type);
+ console.log(this.anotherType);
+ }
+ }
+
+ export class Variant1 extends SomeClass{type=1; anotherType=2;}
+ `,
+ options: ["always", { omitLastInOneLineClassBody: false, omitLastInOneLineBlock: true }],
+ parserOptions: { ecmaVersion: 2022, sourceType: "module" },
+ errors: [
+ {
+ messageId: "missingSemi",
+ line: 9,
+ column: 78,
+ endLine: 9,
+ endColumn: 79
+ }
+ ]
}
]
});
//------------------------------------------------------------------------------
const rule = require("../../../lib/rules/strict"),
- { RuleTester } = require("../../../lib/rule-tester");
+ { RuleTester } = require("../../../lib/rule-tester"),
+ FlatRuleTester = require("../../../lib/rule-tester/flat-rule-tester");
//------------------------------------------------------------------------------
// Tests
}
]
});
+
+const flatRuleTester = new FlatRuleTester();
+
+// TODO: merge these tests into `ruleTester.run` once we switch to FlatRuleTester (when FlatRuleTester becomes RuleTester).
+flatRuleTester.run("strict", rule, {
+ valid: [
+ {
+ code: "'use strict'; module.exports = function identity (value) { return value; }",
+ languageOptions: {
+ sourceType: "commonjs"
+ }
+ },
+ {
+ code: "'use strict'; module.exports = function identity (value) { return value; }",
+ options: ["safe"],
+ languageOptions: {
+ sourceType: "commonjs"
+ }
+ }
+ ],
+
+ invalid: [
+ {
+ code: "module.exports = function identity (value) { return value; }",
+ options: ["safe"],
+ languageOptions: {
+ sourceType: "commonjs"
+ },
+ errors: [
+ { messageId: "global", line: 1 }
+ ]
+ },
+ {
+ code: "module.exports = function identity (value) { return value; }",
+ languageOptions: {
+ sourceType: "commonjs"
+ },
+ errors: [
+ { messageId: "global", line: 1 }
+ ]
+ }
+ ]
+});
describe("isTokenOnSameLine", () => {
it("should return false if the tokens are not on the same line", () => {
- linter.defineRule("checker", mustCall(context => ({
- BlockStatement: mustCall(node => {
- assert.isFalse(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node));
- })
- })));
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ BlockStatement: mustCall(node => {
+ assert.isFalse(astUtils.isTokenOnSameLine(context.sourceCode.getTokenBefore(node), node));
+ })
+ }))
+ });
linter.verify("if(a)\n{}", { rules: { checker: "error" } });
});
it("should return true if the tokens are on the same line", () => {
- linter.defineRule("checker", mustCall(context => ({
- BlockStatement: mustCall(node => {
- assert.isTrue(astUtils.isTokenOnSameLine(context.getTokenBefore(node), node));
- })
- })));
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ BlockStatement: mustCall(node => {
+ assert.isTrue(astUtils.isTokenOnSameLine(context.sourceCode.getTokenBefore(node), node));
+ })
+ }))
+ });
linter.verify("if(a){}", { rules: { checker: "error" } });
});
// catch
it("should return true if reference is assigned for catch", () => {
- linter.defineRule("checker", mustCall(context => ({
- CatchClause: mustCall(node => {
- const variables = context.getDeclaredVariables(node);
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ CatchClause: mustCall(node => {
+ const variables = context.sourceCode.getDeclaredVariables(node);
- assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
- })
- })));
+ assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
+ })
+ }))
+ });
linter.verify("try { } catch (e) { e = 10; }", { rules: { checker: "error" } });
});
// const
it("should return true if reference is assigned for const", () => {
- linter.defineRule("checker", mustCall(context => ({
- VariableDeclaration: mustCall(node => {
- const variables = context.getDeclaredVariables(node);
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ VariableDeclaration: mustCall(node => {
+ const variables = context.sourceCode.getDeclaredVariables(node);
- assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
- })
- })));
+ assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
+ })
+ }))
+ });
linter.verify("const a = 1; a = 2;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
});
it("should return false if reference is not assigned for const", () => {
- linter.defineRule("checker", mustCall(context => ({
- VariableDeclaration: mustCall(node => {
- const variables = context.getDeclaredVariables(node);
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ VariableDeclaration: mustCall(node => {
+ const variables = context.sourceCode.getDeclaredVariables(node);
- assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0);
- })
- })));
+ assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0);
+ })
+ }))
+ });
linter.verify("const a = 1; c = 2;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
});
// class
it("should return true if reference is assigned for class", () => {
- linter.defineRule("checker", mustCall(context => ({
- ClassDeclaration: mustCall(node => {
- const variables = context.getDeclaredVariables(node);
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ ClassDeclaration: mustCall(node => {
+ const variables = context.sourceCode.getDeclaredVariables(node);
- assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
- assert.lengthOf(astUtils.getModifyingReferences(variables[1].references), 0);
- })
- })));
+ assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 1);
+ assert.lengthOf(astUtils.getModifyingReferences(variables[1].references), 0);
+ })
+ }))
+ });
linter.verify("class A { }\n A = 1;", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
});
it("should return false if reference is not assigned for class", () => {
- linter.defineRule("checker", mustCall(context => ({
- ClassDeclaration: mustCall(node => {
- const variables = context.getDeclaredVariables(node);
+ linter.defineRule("checker", {
+ create: mustCall(context => ({
+ ClassDeclaration: mustCall(node => {
+ const variables = context.sourceCode.getDeclaredVariables(node);
- assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0);
- })
- })));
+ assert.lengthOf(astUtils.getModifyingReferences(variables[0].references), 0);
+ })
+ }))
+ });
linter.verify("class A { } foo(A);", { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
});
function assertNodeTypeInLoop(code, nodeType, expectedInLoop) {
const results = [];
- linter.defineRule("checker", mustCall(() => ({
- [nodeType]: mustCall(node => {
- results.push(astUtils.isInLoop(node));
- })
- })));
+ linter.defineRule("checker", {
+ create: mustCall(() => ({
+ [nodeType]: mustCall(node => {
+ results.push(astUtils.isInLoop(node));
+ })
+ }))
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.lengthOf(results, 1);
Object.keys(expectedResults).forEach(key => {
it(`should return "${expectedResults[key]}" for "${key}".`, () => {
- linter.defineRule("checker", mustCall(() => ({
- ":function": mustCall(node => {
- assert.strictEqual(
- astUtils.getFunctionNameWithKind(node),
- expectedResults[key]
- );
- })
- })));
+ linter.defineRule("checker", {
+ create: mustCall(() => ({
+ ":function": mustCall(node => {
+ assert.strictEqual(
+ astUtils.getFunctionNameWithKind(node),
+ expectedResults[key]
+ );
+ })
+ }))
+ });
linter.verify(key, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 13 } });
});
};
it(`should return "${JSON.stringify(expectedLoc)}" for "${key}".`, () => {
- linter.defineRule("checker", mustCall(() => ({
- ":function": mustCall(node => {
- assert.deepStrictEqual(
- astUtils.getFunctionHeadLoc(node, linter.getSourceCode()),
- expectedLoc
- );
- })
- })));
+ linter.defineRule("checker", {
+ create: mustCall(() => ({
+ ":function": mustCall(node => {
+ assert.deepStrictEqual(
+ astUtils.getFunctionHeadLoc(node, linter.getSourceCode()),
+ expectedLoc
+ );
+ })
+ }))
+ });
linter.verify(key, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 13 } }, "test.js", true);
});
options: [{ requireReturn: false }]
},
- // https://github.com/eslint/eslint/issues/9412 - different orders for jsodc tags
+ // https://github.com/eslint/eslint/issues/9412 - different orders for jsdoc tags
{
code:
"/**\n" +
const linter = new Linter();
-/**
- * Fake a rule object
- * @param {Object} context context passed to the rules by eslint
- * @returns {Object} mocked rule listeners
- * @private
- */
-function mockRule(context) {
- return {
- Program(node) {
- context.report(node, "Expected a validation error.");
- }
- };
-}
-
-mockRule.schema = [
- {
- enum: ["first", "second"]
+const mockRule = {
+ meta: {
+ schema: [{
+ enum: ["first", "second"]
+ }]
+ },
+ create(context) {
+ return {
+ Program(node) {
+ context.report(node, "Expected a validation error.");
+ }
+ };
}
-];
-
-/**
- * Fake a rule object
- * @param {Object} context context passed to the rules by eslint
- * @returns {Object} mocked rule listeners
- * @private
- */
-function mockObjectRule(context) {
- return {
- Program(node) {
- context.report(node, "Expected a validation error.");
- }
- };
-}
-
-mockObjectRule.schema = {
- enum: ["first", "second"]
};
-/**
- * Fake a rule with no options
- * @param {Object} context context passed to the rules by eslint
- * @returns {Object} mocked rule listeners
- * @private
- */
-function mockNoOptionsRule(context) {
- return {
- Program(node) {
- context.report(node, "Expected a validation error.");
+const mockObjectRule = {
+ meta: {
+ schema: {
+ enum: ["first", "second"]
}
- };
-}
+ },
+ create(context) {
+ return {
+ Program(node) {
+ context.report(node, "Expected a validation error.");
+ }
+ };
+ }
+};
-mockNoOptionsRule.schema = [];
+const mockNoOptionsRule = {
+ meta: {
+ schema: []
+ },
+ create(context) {
+ return {
+ Program(node) {
+ context.report(node, "Expected a validation error.");
+ }
+ };
+ }
+};
const mockRequiredOptionsRule = {
meta: {
spawnSyncStubArgs[2] = "This is not JSON";
setupSpawnSyncStubReturnVals(spawnSyncStub, spawnSyncStubArgs);
- assert.throws(RuntimeInfo.environment, "Unexpected token T in JSON at position 0");
+ assert.throws(RuntimeInfo.environment, /^Unexpected token .*T.* JSON/u);
assert.strictEqual(logErrorStub.args[0][0], "Error finding eslint version running the command `npm ls --depth=0 --json eslint`");
});
spawnSyncStubArgs[4] = "This is not JSON";
setupSpawnSyncStubReturnVals(spawnSyncStub, spawnSyncStubArgs);
- assert.throws(RuntimeInfo.environment, "Unexpected token T in JSON at position 0");
+ assert.throws(RuntimeInfo.environment, /^Unexpected token .*T.* JSON/u);
assert.strictEqual(logErrorStub.args[0][0], "Error finding eslint version running the command `npm ls --depth=0 --json eslint -g`");
});
});
const assert = require("chai").assert;
-const { upperCaseFirst } = require("../../../lib/shared/string-utils");
+const { upperCaseFirst, getGraphemeCount } = require("../../../lib/shared/string-utils");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+/**
+ * Replaces raw control characters with the `\xXX` form.
+ * @param {string} text The text to process.
+ * @returns {string} `text` with escaped control characters.
+ */
+function escapeControlCharacters(text) {
+ return text.replace(
+ /[\u0000-\u001F\u007F-\u009F]/gu, // eslint-disable-line no-control-regex -- intentionally including control characters
+ c => `\\x${c.codePointAt(0).toString(16).padStart(2, "0")}`
+ );
+}
//------------------------------------------------------------------------------
// Tests
assert(upperCaseFirst("") === "");
});
});
+
+describe("getGraphemeCount", () => {
+ /* eslint-disable quote-props -- Make consistent here for readability */
+ const expectedResults = {
+ "": 0,
+ "a": 1,
+ "ab": 2,
+ "aa": 2,
+ "123": 3,
+ "cccc": 4,
+ [Array.from({ length: 128 }, (_, i) => String.fromCharCode(i)).join("")]: 128, // all ASCII characters
+ "👍": 1, // 1 grapheme, 1 code point, 2 code units
+ "👍👍": 2,
+ "👍9👍": 3,
+ "a👍b": 3,
+ "👶🏽": 1, // 1 grapheme, 2 code points, 4 code units
+ "👨👩👦": 1, // 1 grapheme, 5 code points, 8 code units
+ "👨👩👦👨👩👦": 2,
+ "👨👩👦a👨👩👦": 3,
+ "a👨👩👦b👨👩👦c": 5,
+ "👨👩👦👍": 2,
+ "👶🏽👨👩👦": 2,
+ "👩🦰👩👩👦👦🏳️🌈": 3 // 3 grapheme, 14 code points, 22 code units
+ };
+ /* eslint-enable quote-props -- Make consistent here for readability */
+
+ Object.entries(expectedResults).forEach(([key, value]) => {
+ it(`should return ${value} for ${escapeControlCharacters(key)}`, () => {
+ assert.strictEqual(getGraphemeCount(key), value);
+ });
+ });
+});
loc: true
};
const linter = new Linter();
+const flatLinter = new Linter({ configType: "flat" });
const AST = espree.parse("let foo = bar;", DEFAULT_CONFIG),
TEST_CODE = "var answer = 6 * 7;",
SHEBANG_TEST_CODE = `#!/usr/bin/env node\n${TEST_CODE}`;
+const filename = "foo.js";
+
+/**
+ * Get variables in the current scope
+ * @param {Object} scope current scope
+ * @param {string} name name of the variable to look for
+ * @returns {ASTNode|null} The variable object
+ * @private
+ */
+function getVariable(scope, name) {
+ return scope.variables.find(v => v.name === name) || null;
+}
+
//------------------------------------------------------------------------------
// Tests
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledTwice, "Event handler should be called twice.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ ArrowFunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ ArrowFunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledTwice, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledTwice, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" } });
assert.isTrue(spy.calledTwice, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ ClassExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ ClassExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ ClassDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ ClassDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionExpression: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionExpression: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
const spy = sinon.spy(assertJSDoc);
- linter.defineRule("checker", () => ({ FunctionDeclaration: spy }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ FunctionDeclaration: spy
+ });
+ }
+ });
linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6 } });
assert.isTrue(spy.calledOnce, "Event handler should be called.");
});
"/* Trailing comment for VariableDeclaration */"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(1, 1),
- VariableDeclarator: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- Literal: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(1, 1),
+ VariableDeclarator: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ Literal: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(0, 1),
- CallExpression: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(0, 1),
+ CallExpression: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"if (/* Leading comment for Identifier */ a) {}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- IfStatement: assertCommentCount(1, 0),
- Identifier: assertCommentCount(1, 0),
- BlockStatement: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ IfStatement: assertCommentCount(1, 0),
+ Identifier: assertCommentCount(1, 0),
+ BlockStatement: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(0, 0),
- VariableDeclarator: assertCommentCount(0, 0),
- ObjectExpression: assertCommentCount(0, 1),
- ReturnStatement: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(0, 0),
+ VariableDeclarator: assertCommentCount(0, 0),
+ ObjectExpression: assertCommentCount(0, 1),
+ ReturnStatement: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"var baz;"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(0, 0),
- VariableDeclarator: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- ObjectExpression: assertCommentCount(0, 0),
- Property: assertCommentCount(0, 1),
- Literal: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(0, 0),
+ VariableDeclarator: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ ObjectExpression: assertCommentCount(0, 0),
+ Property: assertCommentCount(0, 1),
+ Literal: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- ExportDefaultDeclaration: assertCommentCount(1, 0),
- ClassDeclaration: assertCommentCount(0, 0),
- ClassBody: assertCommentCount(0, 0),
- MethodDefinition: assertCommentCount(1, 0),
- Identifier: assertCommentCount(0, 0),
- FunctionExpression: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ ExportDefaultDeclaration: assertCommentCount(1, 0),
+ ClassDeclaration: assertCommentCount(0, 0),
+ ClassBody: assertCommentCount(0, 0),
+ MethodDefinition: assertCommentCount(1, 0),
+ Identifier: assertCommentCount(0, 0),
+ FunctionExpression: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
].join("\n");
let varDeclCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration(node) {
- if (varDeclCount === 0) {
- assertCommentCount(1, 1)(node);
- } else {
- assertCommentCount(1, 0)(node);
- }
- varDeclCount++;
- },
- VariableDeclarator: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+
+ VariableDeclaration(node) {
+ if (varDeclCount === 0) {
+ assertCommentCount(1, 1)(node);
+ } else {
+ assertCommentCount(1, 0)(node);
+ }
+ varDeclCount++;
+ },
+
+ VariableDeclarator: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
].join("\n");
let varDeclCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration(node) {
- if (varDeclCount === 0) {
- assertCommentCount(1, 1)(node);
- } else {
- assertCommentCount(1, 0)(node);
- }
- varDeclCount++;
- },
- Identifier: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+
+ VariableDeclaration(node) {
+ if (varDeclCount === 0) {
+ assertCommentCount(1, 1)(node);
+ } else {
+ assertCommentCount(1, 0)(node);
+ }
+ varDeclCount++;
+ },
+
+ Identifier: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
it("should include shebang comment when program only contains shebang", () => {
const code = "#!/usr/bin/env node";
- linter.defineRule("checker", () => ({ Program: assertCommentCount(1, 0) }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(1, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"// Trailing comment for VariableDeclaration"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(1, 1),
- VariableDeclarator: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 1),
- Literal: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(1, 1),
+ VariableDeclarator: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 1),
+ Literal: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(1, 1),
- CallExpression: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(1, 1),
+ CallExpression: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- DebuggerStatement: assertCommentCount(1, 1)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ DebuggerStatement: assertCommentCount(1, 1)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- ReturnStatement: assertCommentCount(1, 1)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ ReturnStatement: assertCommentCount(1, 1)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- ThrowStatement: assertCommentCount(1, 1)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ ThrowStatement: assertCommentCount(1, 1)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- WhileStatement: assertCommentCount(1, 1),
- Literal: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(1, 0),
- VariableDeclarator: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ WhileStatement: assertCommentCount(1, 1),
+ Literal: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(1, 0),
+ VariableDeclarator: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
].join("\n");
let switchCaseCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(0, 0),
- SwitchCase: node => {
- if (switchCaseCount === 0) {
- assertCommentCount(1, 1)(node);
- } else {
- assertCommentCount(1, 0)(node);
- }
- switchCaseCount++;
- },
- Literal: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(0, 0),
- CallExpression: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(0, 0),
+
+ SwitchCase(node) {
+ if (switchCaseCount === 0) {
+ assertCommentCount(1, 1)(node);
+ } else {
+ assertCommentCount(1, 0)(node);
+ }
+ switchCaseCount++;
+ },
+
+ Literal: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(0, 0),
+ CallExpression: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
].join("\n");
let switchCaseCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(0, 0),
- SwitchCase: node => {
- if (switchCaseCount === 0) {
- assertCommentCount(1, 1)(node);
- } else {
- assertCommentCount(1, 0)(node);
- }
- switchCaseCount++;
- },
- Literal: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(0, 0),
- CallExpression: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(0, 0),
+
+ SwitchCase(node) {
+ if (switchCaseCount === 0) {
+ assertCommentCount(1, 1)(node);
+ } else {
+ assertCommentCount(1, 0)(node);
+ }
+ switchCaseCount++;
+ },
+
+ Literal: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(0, 0),
+ CallExpression: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
].join("\n");
let breakStatementCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(0, 0),
- SwitchCase: node => {
- if (breakStatementCount === 0) {
- assertCommentCount(0, 0)(node);
- } else {
- assertCommentCount(0, 1)(node);
- }
- breakStatementCount++;
- },
- BreakStatement: assertCommentCount(0, 0),
- Literal: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(0, 0),
+
+ SwitchCase(node) {
+ if (breakStatementCount === 0) {
+ assertCommentCount(0, 0)(node);
+ } else {
+ assertCommentCount(0, 1)(node);
+ }
+ breakStatementCount++;
+ },
+
+ BreakStatement: assertCommentCount(0, 0),
+ Literal: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- SwitchCase: assertCommentCount(0, 1),
- BreakStatement: assertCommentCount(0, 0),
- Literal: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ SwitchCase: assertCommentCount(0, 1),
+ BreakStatement: assertCommentCount(0, 0),
+ Literal: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"};"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(0, 0),
- AssignmentExpression: assertCommentCount(0, 0),
- MemberExpression: assertCommentCount(0, 0),
- Identifier: assertCommentCount(0, 0),
- FunctionExpression: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(0, 0),
- SwitchCase: assertCommentCount(0, 1),
- ReturnStatement: assertCommentCount(0, 0),
- CallExpression: assertCommentCount(0, 0),
- BinaryExpression: assertCommentCount(0, 0),
- Literal: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(0, 0),
+ AssignmentExpression: assertCommentCount(0, 0),
+ MemberExpression: assertCommentCount(0, 0),
+ Identifier: assertCommentCount(0, 0),
+ FunctionExpression: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(0, 0),
+ SwitchCase: assertCommentCount(0, 1),
+ ReturnStatement: assertCommentCount(0, 0),
+ CallExpression: assertCommentCount(0, 0),
+ BinaryExpression: assertCommentCount(0, 0),
+ Literal: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"/*another comment*/"
].join("\n");
- linter.defineRule("checker", () => ({ Program: assertCommentCount(2, 0) }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(2, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- BlockStatement: assertCommentCount(0, 2)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ BlockStatement: assertCommentCount(0, 2)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- ClassDeclaration: assertCommentCount(0, 0),
- ClassBody: assertCommentCount(0, 2)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ ClassDeclaration: assertCommentCount(0, 0),
+ ClassBody: assertCommentCount(0, 2)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"})"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(0, 0),
- ObjectExpression: assertCommentCount(0, 2)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(0, 0),
+ ObjectExpression: assertCommentCount(0, 2)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"]"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- ExpressionStatement: assertCommentCount(0, 0),
- ArrayExpression: assertCommentCount(0, 2)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ ExpressionStatement: assertCommentCount(0, 0),
+ ArrayExpression: assertCommentCount(0, 2)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
"}"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(0, 2),
- Identifier: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(0, 2),
+ Identifier: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
].join("\n");
let varDeclCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(1, 2),
- VariableDeclarator: node => {
- if (varDeclCount === 0) {
- assertCommentCount(0, 0)(node);
- } else if (varDeclCount === 1) {
- assertCommentCount(1, 0)(node);
- } else {
- assertCommentCount(1, 0)(node);
- }
- varDeclCount++;
- },
- Identifier: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(1, 2),
+
+ VariableDeclarator(node) {
+ if (varDeclCount === 0) {
+ assertCommentCount(0, 0)(node);
+ } else if (varDeclCount === 1) {
+ assertCommentCount(1, 0)(node);
+ } else {
+ assertCommentCount(1, 0)(node);
+ }
+ varDeclCount++;
+ },
+
+ Identifier: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
" a;"
].join("\n");
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- VariableDeclaration: assertCommentCount(0, 0),
- VariableDeclarator: assertCommentCount(2, 0),
- Identifier: assertCommentCount(0, 0)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ VariableDeclaration: assertCommentCount(0, 0),
+ VariableDeclarator: assertCommentCount(2, 0),
+ Identifier: assertCommentCount(0, 0)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
it("should return attached comments between tokens to the correct nodes for empty function declarations", () => {
const code = "/* 1 */ function /* 2 */ foo(/* 3 */) /* 4 */ { /* 5 */ } /* 6 */";
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- FunctionDeclaration: assertCommentCount(1, 1),
- Identifier: assertCommentCount(1, 0),
- BlockStatement: assertCommentCount(1, 1)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ FunctionDeclaration: assertCommentCount(1, 1),
+ Identifier: assertCommentCount(1, 0),
+ BlockStatement: assertCommentCount(1, 1)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
const code = "/* 1 */ class /* 2 */ Foo /* 3 */ extends /* 4 */ Bar /* 5 */ { /* 6 */ } /* 7 */";
let idCount = 0;
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- ClassDeclaration: assertCommentCount(1, 1),
- Identifier: node => {
- if (idCount === 0) {
- assertCommentCount(1, 1)(node);
- } else {
- assertCommentCount(1, 1)(node);
- }
- idCount++;
- },
- ClassBody: assertCommentCount(1, 1)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ ClassDeclaration: assertCommentCount(1, 1),
+
+ Identifier(node) {
+ if (idCount === 0) {
+ assertCommentCount(1, 1)(node);
+ } else {
+ assertCommentCount(1, 1)(node);
+ }
+ idCount++;
+ },
+
+ ClassBody: assertCommentCount(1, 1)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
it("should return attached comments between tokens to the correct nodes for empty switch statements", () => {
const code = "/* 1 */ switch /* 2 */ (/* 3 */ foo /* 4 */) /* 5 */ { /* 6 */ } /* 7 */";
- linter.defineRule("checker", () => ({
- Program: assertCommentCount(0, 0),
- SwitchStatement: assertCommentCount(1, 6),
- Identifier: assertCommentCount(1, 1)
- }));
+ linter.defineRule("checker", {
+ create() {
+ return ({
+ Program: assertCommentCount(0, 0),
+ SwitchStatement: assertCommentCount(1, 6),
+ Identifier: assertCommentCount(1, 1)
+ });
+ }
+ });
assert.isEmpty(linter.verify(code, config));
});
});
-
describe("getNodeByRangeIndex()", () => {
let sourceCode;
assert.strictEqual(sourceCode.getIndexFromLoc({ line: 8, column: 0 }), CODE.length);
});
});
+
+ describe("getScope()", () => {
+
+ it("should throw an error when argument is missing", () => {
+
+ linter.defineRule("get-scope", {
+ create: context => ({
+ Program() {
+ context.sourceCode.getScope();
+ }
+ })
+ });
+
+ assert.throws(() => {
+ linter.verify(
+ "foo",
+ {
+ rules: { "get-scope": 2 }
+ }
+ );
+ }, /Missing required argument: node/u);
+
+ });
+
+ /**
+ * Get the scope on the node `astSelector` specified.
+ * @param {string} code 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(code, astSelector, ecmaVersion = 5) {
+ let node, scope;
+
+ linter.defineRule("get-scope", {
+ create: context => ({
+ [astSelector](node0) {
+ node = node0;
+ scope = context.sourceCode.getScope(node);
+ }
+ })
+ });
+ linter.verify(
+ code,
+ {
+ parserOptions: { ecmaVersion },
+ rules: { "get-scope": 2 }
+ }
+ );
+
+ 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("getAncestors()", () => {
+ const code = TEST_CODE;
+
+ it("should retrieve all ancestors when used", () => {
+
+ let spy;
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ const sourceCode = context.sourceCode;
+ const ancestors = sourceCode.getAncestors(node);
+
+ assert.strictEqual(ancestors.length, 3);
+ });
+ return { BinaryExpression: spy };
+ }
+ }
+ }
+ }
+ },
+ rules: { "test/checker": "error" }
+ };
+
+ flatLinter.verify(code, config, filename, true);
+ assert(spy && spy.calledOnce, "Spy was not called.");
+ });
+
+ it("should retrieve empty ancestors for root node", () => {
+ let spy;
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ checker: {
+ create(context) {
+ spy = sinon.spy(node => {
+ const sourceCode = context.sourceCode;
+ const ancestors = sourceCode.getAncestors(node);
+
+ assert.strictEqual(ancestors.length, 0);
+ });
+
+ return { Program: spy };
+ }
+ }
+ }
+ }
+ },
+ rules: { "test/checker": "error" }
+ };
+
+ flatLinter.verify(code, config);
+ assert(spy && spy.calledOnce, "Spy was not called.");
+ });
+
+ it("should throw an error when the argument is missing", () => {
+ let spy;
+
+ const config = {
+ plugins: {
+ test: {
+ rules: {
+ checker: {
+ create(context) {
+ spy = sinon.spy(() => {
+ const sourceCode = context.sourceCode;
+
+ assert.throws(() => {
+ sourceCode.getAncestors();
+ }, /Missing required argument: node/u);
+
+ });
+
+ return { Program: spy };
+ }
+ }
+ }
+ }
+ },
+ rules: { "test/checker": "error" }
+ };
+
+ flatLinter.verify(code, config);
+ assert(spy && spy.calledOnce, "Spy was not called.");
+ });
+ });
+
+
+ describe("getDeclaredVariables(node)", () => {
+
+ /**
+ * Assert `sourceCode.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) {
+ linter.defineRules({
+ test: {
+ create(context) {
+
+ const sourceCode = context.sourceCode;
+
+ /**
+ * Assert `sourceCode.getDeclaredVariables(node)` is empty.
+ * @param {ASTNode} node A node to check.
+ * @returns {void}
+ */
+ function checkEmpty(node) {
+ assert.strictEqual(0, sourceCode.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 = sourceCode.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;
+ }
+ }
+ });
+ linter.verify(code, {
+ rules: { test: 2 },
+ parserOptions: {
+ ecmaVersion: 6,
+ sourceType: "module"
+ }
+ });
+
+ // 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("markVariableAsUsed()", () => {
+
+ it("should mark variables in current scope as used", () => {
+ const code = "var a = 1, b = 2;";
+ let spy;
+
+ linter.defineRule("checker", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ spy = sinon.spy(() => {
+ assert.isTrue(sourceCode.markVariableAsUsed("a"));
+
+ const scope = context.getScope();
+
+ assert.isTrue(getVariable(scope, "a").eslintUsed);
+ assert.notOk(getVariable(scope, "b").eslintUsed);
+ });
+
+ return { "Program:exit": spy };
+ }
+ });
+
+ linter.verify(code, { rules: { checker: "error" } });
+ assert(spy && spy.calledOnce);
+ });
+
+ it("should mark variables in function args as used", () => {
+ const code = "function abc(a, b) { return 1; }";
+ let spy;
+
+ linter.defineRule("checker", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ spy = sinon.spy(node => {
+ assert.isTrue(sourceCode.markVariableAsUsed("a", node));
+
+ const scope = context.getScope();
+
+ assert.isTrue(getVariable(scope, "a").eslintUsed);
+ assert.notOk(getVariable(scope, "b").eslintUsed);
+ });
+
+ return { ReturnStatement: spy };
+ }
+ });
+
+ linter.verify(code, { rules: { checker: "error" } });
+ 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;
+
+ linter.defineRule("checker", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ returnSpy = sinon.spy(node => {
+ assert.isTrue(sourceCode.markVariableAsUsed("a", node));
+ });
+ 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 };
+ }
+ });
+
+ linter.verify(code, { rules: { checker: "error" } });
+ assert(returnSpy && returnSpy.calledOnce);
+ assert(exitSpy && exitSpy.calledOnce);
+ });
+
+ it("should mark variables in Node.js environment as used", () => {
+ const code = "var a = 1, b = 2;";
+ let spy;
+
+ linter.defineRule("checker", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ spy = sinon.spy(() => {
+ const globalScope = context.getScope(),
+ childScope = globalScope.childScopes[0];
+
+ assert.isTrue(sourceCode.markVariableAsUsed("a"));
+
+ assert.isTrue(getVariable(childScope, "a").eslintUsed);
+ assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+ });
+
+ return { "Program:exit": spy };
+ }
+ });
+
+ linter.verify(code, { rules: { checker: "error" }, env: { node: true } });
+ assert(spy && spy.calledOnce);
+ });
+
+ it("should mark variables in modules as used", () => {
+ const code = "var a = 1, b = 2;";
+ let spy;
+
+ linter.defineRule("checker", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ spy = sinon.spy(() => {
+ const globalScope = context.getScope(),
+ childScope = globalScope.childScopes[0];
+
+ assert.isTrue(sourceCode.markVariableAsUsed("a"));
+
+ assert.isTrue(getVariable(childScope, "a").eslintUsed);
+ assert.isUndefined(getVariable(childScope, "b").eslintUsed);
+ });
+
+ return { "Program:exit": spy };
+ }
+ });
+
+ linter.verify(code, { rules: { checker: "error" }, parserOptions: { ecmaVersion: 6, sourceType: "module" } }, filename, true);
+ assert(spy && spy.calledOnce);
+ });
+
+ it("should return false if the given variable is not found", () => {
+ const code = "var a = 1, b = 2;";
+ let spy;
+
+ linter.defineRule("checker", {
+ create(context) {
+ const sourceCode = context.sourceCode;
+
+ spy = sinon.spy(() => {
+ assert.isFalse(sourceCode.markVariableAsUsed("c"));
+ });
+
+ return { "Program:exit": spy };
+ }
+ });
+
+ linter.verify(code, { rules: { checker: "error" } });
+ assert(spy && spy.calledOnce);
+ });
+
+ });
});
const tokenStore = new TokenStore(ast.tokens, ast.comments);
/*
- * Actually, the first of nodes is always tokens, not comments.
- * But I think this test case is needed for completeness.
+ * A node must not start with a token: it can start with a comment or be empty.
+ * This test case is needed for completeness.
*/
const token = tokenStore.getFirstToken(
{ range: [ast.comments[0].range[0], ast.tokens[5].range[1]] },
const tokenStore = new TokenStore(ast.tokens, ast.comments);
/*
- * Actually, the first of nodes is always tokens, not comments.
- * But I think this test case is needed for completeness.
+ * A node must not start with a token: it can start with a comment or be empty.
+ * This test case is needed for completeness.
*/
const token = tokenStore.getFirstToken(
{ range: [ast.comments[0].range[0], ast.tokens[5].range[1]] }
assert.strictEqual(token.value, "c");
});
+ it("should retrieve the first token if the root node contains a trailing comment", () => {
+ const parser = require("../../fixtures/parsers/all-comments-parser");
+ const code = "foo // comment";
+ const ast = parser.parse(code, { loc: true, range: true, tokens: true, comment: true });
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
+ const token = tokenStore.getFirstToken(ast);
+
+ assert.strictEqual(token, ast.tokens[0]);
+ });
+
+ it("should return null if the source contains only comments", () => {
+ const code = "// comment";
+ const ast = espree.parse(code, { loc: true, range: true, tokens: true, comment: true });
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
+ const token = tokenStore.getFirstToken(ast, {
+ filter() {
+ assert.fail("Unexpected call to filter callback");
+ }
+ });
+
+ assert.strictEqual(token, null);
+ });
+
+ it("should return null if the source is empty", () => {
+ const code = "";
+ const ast = espree.parse(code, { loc: true, range: true, tokens: true, comment: true });
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
+ const token = tokenStore.getFirstToken(ast);
+
+ assert.strictEqual(token, null);
+ });
+
});
describe("when calling getLastTokens", () => {
const tokenStore = new TokenStore(ast.tokens, ast.comments);
/*
- * Actually, the last of nodes is always tokens, not comments.
- * But I think this test case is needed for completeness.
+ * A node must not end with a token: it can end with a comment or be empty.
+ * This test case is needed for completeness.
*/
const token = tokenStore.getLastToken(
{ range: [ast.tokens[0].range[0], ast.comments[0].range[1]] },
const tokenStore = new TokenStore(ast.tokens, ast.comments);
/*
- * Actually, the last of nodes is always tokens, not comments.
- * But I think this test case is needed for completeness.
+ * A node must not end with a token: it can end with a comment or be empty.
+ * This test case is needed for completeness.
*/
const token = tokenStore.getLastToken(
{ range: [ast.tokens[0].range[0], ast.comments[0].range[1]] }
assert.strictEqual(token.value, "b");
});
+ it("should retrieve the last token if the root node contains a trailing comment", () => {
+ const parser = require("../../fixtures/parsers/all-comments-parser");
+ const code = "foo // comment";
+ const ast = parser.parse(code, { loc: true, range: true, tokens: true, comment: true });
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
+ const token = tokenStore.getLastToken(ast);
+
+ assert.strictEqual(token, ast.tokens[0]);
+ });
+
+ it("should return null if the source contains only comments", () => {
+ const code = "// comment";
+ const ast = espree.parse(code, { loc: true, range: true, tokens: true, comment: true });
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
+ const token = tokenStore.getLastToken(ast, {
+ filter() {
+ assert.fail("Unexpected call to filter callback");
+ }
+ });
+
+ assert.strictEqual(token, null);
+ });
+
+ it("should return null if the source is empty", () => {
+ const code = "";
+ const ast = espree.parse(code, { loc: true, range: true, tokens: true, comment: true });
+ const tokenStore = new TokenStore(ast.tokens, ast.comments);
+ const token = tokenStore.getLastToken(ast);
+
+ assert.strictEqual(token, null);
+ });
+
});
describe("when calling getFirstTokensBetween", () => {
assert.isFunction(api.FlatESLint);
});
+ it("should have shouldUseFlatConfig exposed", () => {
+ assert.isFunction(api.shouldUseFlatConfig);
+ });
+
it("should have FlatRuleTester exposed", () => {
assert.isFunction(api.FlatRuleTester);
});
(function(){/*!
* JSHint, by JSHint Community.
*
- * This file (and this file only) is licensed under the same slightly modified
- * MIT license that JSLint is. It stops evil-doers everywhere:
+ * This file (and this file only) was licensed under the same slightly modified
+ * MIT license that JSLint is. After a relicensing in 2020 this is now MIT License (Expat).
+ * Relicensing: https://jshint.com/relicensing-2020/
+ * License-Url: https://github.com/jshint/jshint/blob/main/LICENSE
*
- * Copyright (c) 2002 Douglas Crockford (www.JSLint.com)
+ * Copyright 2012 Anton Kovalyov (http://jshint.com)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
- * The Software shall be used for Good, not Evil.
- *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
},{}]},{},["E/GbHF"])
;
JSHINT = require('jshint').JSHINT;
-}());
\ No newline at end of file
+}());
--- /dev/null
+#!/bin/bash
+
+#------------------------------------------------------------------------------
+# Commits the data files if any have changed
+#------------------------------------------------------------------------------
+
+if [ -z "$(git status --porcelain)" ]; then
+ echo "Data did not change."
+else
+ echo "Data changed!"
+
+ # commit the result
+ git add README.md
+ git commit -m "docs: Update README"
+
+ # push back to source control
+ git push origin HEAD
+fi
*
* To fetch info for just selected files (for use with lint-staged):
*
- * node tools/fetch-docs-links.js docs/src/user-guide/index.md
+ * node tools/fetch-docs-links.js docs/src/use/index.md
*
* @author Nicholas C. Zakas
*/
console.error("Could not fetch data for", url);
console.error(ex.message);
console.error(ex.stack);
- process.exit(1); // eslint-disable-line n/no-process-exit -- used in tools
+ process.exit(1);
}
}
}
linter,
count: crashTestCount,
checkAutofixes: false,
- progressCallback: elapsedErrors => {
+ progressCallback(elapsedErrors) {
progressBar.tick(1, { elapsedErrors });
progressBar.render();
}
linter,
count: autofixTestCount,
checkAutofixes: true,
- progressCallback: elapsedErrors => {
+ progressCallback(elapsedErrors) {
progressBar.tick(ESTIMATED_CRASH_AUTOFIX_PERFORMANCE_RATIO, { elapsedErrors: crashTestResults.length + elapsedErrors });
progressBar.render();
}
"lines-around-comment": "layout",
"lines-around-directive": "layout",
"lines-between-class-members": "layout",
+ "logical-assignment-operators": "suggestion",
"max-classes-per-file": "suggestion",
"max-depth": "suggestion",
"max-len": "layout",
"no-empty-character-class": "problem",
"no-empty-function": "suggestion",
"no-empty-pattern": "problem",
+ "no-empty-static-block": "suggestion",
"no-eq-null": "suggestion",
"no-eval": "suggestion",
"no-ex-assign": "problem",
"no-nested-ternary": "suggestion",
"no-new": "suggestion",
"no-new-func": "suggestion",
+ "no-new-native-nonconstructor": "problem",
"no-new-object": "suggestion",
"no-new-require": "suggestion",
"no-new-symbol": "problem",
--- /dev/null
+/**
+ * @fileoverview Script to update the eslint:all configuration.
+ * @author Nicholas C. Zakas
+ */
+
+"use strict";
+
+//-----------------------------------------------------------------------------
+// Requirements
+//-----------------------------------------------------------------------------
+
+const fs = require("fs");
+const builtInRules = require("../lib/rules");
+
+//------------------------------------------------------------------------------
+// Helpers
+//------------------------------------------------------------------------------
+
+const allRules = {};
+
+for (const [ruleId, rule] of builtInRules) {
+ if (!rule.meta.deprecated) {
+ allRules[ruleId] = "error";
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Main
+//-----------------------------------------------------------------------------
+
+const code = `/*
+ * WARNING: This file is autogenerated using the tools/update-eslint-all.js
+ * script. Do not edit manually.
+ */
+"use strict";
+
+/* eslint quote-props: off -- autogenerated so don't lint */
+
+module.exports = Object.freeze(${JSON.stringify({ rules: allRules }, null, 4)});
+`;
+
+fs.writeFileSync("./packages/js/src/configs/eslint-all.js", code, "utf8");
// Requirements
//-----------------------------------------------------------------------------
-const path = require("path");
const fs = require("fs");
const { stripIndents } = require("common-tags");
const ejs = require("ejs");
+const got = require("got");
//-----------------------------------------------------------------------------
// Data
//-----------------------------------------------------------------------------
-const README_FILE_PATH = path.resolve(__dirname, "../README.md");
-const WEBSITE_DATA_PATH = path.resolve(__dirname, "../../website/_data");
+const SPONSORS_URL = "https://raw.githubusercontent.com/eslint/eslint.org/main/src/_data/sponsors.json";
+const TEAM_URL = "https://raw.githubusercontent.com/eslint/eslint.org/main/src/_data/team.json";
+const README_FILE_PATH = "./README.md";
-const team = JSON.parse(fs.readFileSync(path.join(WEBSITE_DATA_PATH, "team.json")));
-const allSponsors = JSON.parse(fs.readFileSync(path.join(WEBSITE_DATA_PATH, "sponsors.json")));
const readme = fs.readFileSync(README_FILE_PATH, "utf8");
const heights = {
bronze: 32
};
-// remove backers from sponsors list - not shown on readme
-delete allSponsors.backers;
-
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
+/**
+ * Fetches the latest sponsors data from the website.
+ * @returns {Object} The sponsors data object.
+ */
+async function fetchSponsorsData() {
+ const data = await got(SPONSORS_URL).json();
+
+ // remove backers from sponsors list - not shown on readme
+ delete data.backers;
+
+ return data;
+}
+
+/**
+ * Fetches the latest team data from the website.
+ * @returns {Object} The sponsors data object.
+ */
+async function fetchTeamData() {
+ return got(TEAM_URL).json();
+}
+
/**
* Formats an array of team members for inclusion in the readme.
* @param {Array} members The array of members to format.
members.map((member, index) => `<td align="center" valign="top" width="11%">
<a href="https://github.com/${member.username}">
<img src="https://github.com/${member.username}.png?s=75" width="75" height="75"><br />
- ${member.name}
+ ${member.name.trim()}
</a>
</td>${(index + 1) % 9 === 0 ? "</tr><tr>" : ""}`).join("")
}</tr></tbody></table>`;
${
nonEmptySponsors.map(tier => `<h3>${tier[0].toUpperCase()}${tier.slice(1)} Sponsors</h3>
<p>${
- sponsors[tier].map(sponsor => `<a href="${sponsor.url}"><img src="${sponsor.image}" alt="${sponsor.name}" height="${heights[tier]}"></a>`).join(" ")
+ sponsors[tier].map(sponsor => `<a href="${sponsor.url || "#"}"><img src="${sponsor.image}" alt="${sponsor.name}" height="${heights[tier]}"></a>`).join(" ")
}</p>`).join("")
}
<!--sponsorsend-->`;
<%- formatTeamMembers(team.committers) %>
+ <% } %>
+
+ <% if (team.website.length > 0) { %>
+ ### Website Team
+
+ Team members who focus specifically on eslint.org
+
+ <%- formatTeamMembers(team.website) %>
+
<% } %>
<!--teamend-->
`;
-// replace all of the section
-let newReadme = readme.replace(/<!--teamstart-->[\w\W]*?<!--teamend-->/u, ejs.render(HTML_TEMPLATE, {
- team,
- formatTeamMembers
-}));
+(async () => {
+
+ const [allSponsors, team] = await Promise.all([
+ fetchSponsorsData(),
+ fetchTeamData()
+ ]);
+
+ // replace all of the section
+ let newReadme = readme.replace(/<!--teamstart-->[\w\W]*?<!--teamend-->/u, ejs.render(HTML_TEMPLATE, {
+ team,
+ formatTeamMembers
+ }));
+
+ newReadme = newReadme.replace(/<!--sponsorsstart-->[\w\W]*?<!--sponsorsend-->/u, formatSponsors(allSponsors));
-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");
-// 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");
-// output to the file
-fs.writeFileSync(README_FILE_PATH, newReadme, "utf8");
+})();